@decaf-ts/db-decorators 0.6.11 → 0.6.13
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/README.md +23 -3
- package/dist/db-decorators.cjs +2 -2989
- package/dist/db-decorators.cjs.map +1 -0
- package/dist/db-decorators.js +2 -0
- package/dist/db-decorators.js.map +1 -0
- package/lib/esm/identity/decorators.js +1 -1
- package/lib/esm/identity/decorators.js.map +1 -0
- package/lib/esm/identity/index.js +1 -1
- package/lib/esm/identity/index.js.map +1 -0
- package/lib/esm/identity/utils.js +1 -1
- package/lib/esm/identity/utils.js.map +1 -0
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js +2 -2
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/interfaces/BulkCrudOperator.js +1 -1
- package/lib/esm/interfaces/BulkCrudOperator.js.map +1 -0
- package/lib/esm/interfaces/Contextual.js +1 -1
- package/lib/esm/interfaces/Contextual.js.map +1 -0
- package/lib/esm/interfaces/CrudOperator.js +1 -1
- package/lib/esm/interfaces/CrudOperator.js.map +1 -0
- package/lib/esm/interfaces/IRepository.js +1 -1
- package/lib/esm/interfaces/IRepository.js.map +1 -0
- package/lib/esm/interfaces/index.js +1 -1
- package/lib/esm/interfaces/index.js.map +1 -0
- package/lib/esm/model/constants.js +1 -1
- package/lib/esm/model/constants.js.map +1 -0
- package/lib/esm/model/decorators.js +1 -1
- package/lib/esm/model/decorators.js.map +1 -0
- package/lib/esm/model/index.js +1 -1
- package/lib/esm/model/index.js.map +1 -0
- package/lib/esm/model/model.js +1 -1
- package/lib/esm/model/model.js.map +1 -0
- package/lib/esm/model/overrides.js +1 -1
- package/lib/esm/model/overrides.js.map +1 -0
- package/lib/esm/model/utils.js +1 -1
- package/lib/esm/model/utils.js.map +1 -0
- package/lib/esm/model/validation.js +1 -1
- package/lib/esm/model/validation.js.map +1 -0
- package/lib/esm/operations/Operations.js +1 -1
- package/lib/esm/operations/Operations.js.map +1 -0
- package/lib/esm/operations/OperationsRegistry.js +1 -1
- package/lib/esm/operations/OperationsRegistry.js.map +1 -0
- package/lib/esm/operations/constants.d.ts +2 -1
- package/lib/esm/operations/constants.js +2 -1
- package/lib/esm/operations/constants.js.map +1 -0
- package/lib/esm/operations/decorators.d.ts +66 -1
- package/lib/esm/operations/decorators.js +73 -1
- package/lib/esm/operations/decorators.js.map +1 -0
- package/lib/esm/operations/index.js +1 -1
- package/lib/esm/operations/index.js.map +1 -0
- package/lib/esm/operations/types.js +1 -1
- package/lib/esm/operations/types.js.map +1 -0
- package/lib/esm/repository/BaseRepository.js +1 -1
- package/lib/esm/repository/BaseRepository.js.map +1 -0
- package/lib/esm/repository/Context.js +1 -1
- package/lib/esm/repository/Context.js.map +1 -0
- package/lib/esm/repository/Repository.js +1 -1
- package/lib/esm/repository/Repository.js.map +1 -0
- package/lib/esm/repository/constants.js +1 -1
- package/lib/esm/repository/constants.js.map +1 -0
- package/lib/esm/repository/errors.js +1 -1
- package/lib/esm/repository/errors.js.map +1 -0
- package/lib/esm/repository/index.js +1 -1
- package/lib/esm/repository/index.js.map +1 -0
- package/lib/esm/repository/types.js +1 -1
- package/lib/esm/repository/types.js.map +1 -0
- package/lib/esm/repository/utils.js +1 -1
- package/lib/esm/repository/utils.js.map +1 -0
- package/lib/esm/repository/wrappers.js +1 -1
- package/lib/esm/repository/wrappers.js.map +1 -0
- package/lib/esm/validation/constants.js +1 -1
- package/lib/esm/validation/constants.js.map +1 -0
- package/lib/esm/validation/decorators.js +1 -1
- package/lib/esm/validation/decorators.js.map +1 -0
- package/lib/esm/validation/index.js +1 -1
- package/lib/esm/validation/index.js.map +1 -0
- package/lib/esm/validation/validation.js +1 -1
- package/lib/esm/validation/validation.js.map +1 -0
- package/lib/esm/validation/validators/ReadOnlyValidator.js +1 -1
- package/lib/esm/validation/validators/ReadOnlyValidator.js.map +1 -0
- package/lib/esm/validation/validators/TimestampValidator.js +1 -1
- package/lib/esm/validation/validators/TimestampValidator.js.map +1 -0
- package/lib/esm/validation/validators/UpdateValidator.js +1 -1
- package/lib/esm/validation/validators/UpdateValidator.js.map +1 -0
- package/lib/esm/validation/validators/index.js +1 -1
- package/lib/esm/validation/validators/index.js.map +1 -0
- package/lib/identity/decorators.cjs +1 -1
- package/lib/identity/decorators.js.map +1 -0
- package/lib/identity/index.cjs +1 -1
- package/lib/identity/index.js.map +1 -0
- package/lib/identity/utils.cjs +1 -1
- package/lib/identity/utils.js.map +1 -0
- package/lib/index.cjs +2 -2
- package/lib/index.d.ts +1 -1
- package/lib/index.js.map +1 -0
- package/lib/interfaces/BulkCrudOperator.cjs +1 -1
- package/lib/interfaces/BulkCrudOperator.js.map +1 -0
- package/lib/interfaces/Contextual.cjs +1 -1
- package/lib/interfaces/Contextual.js.map +1 -0
- package/lib/interfaces/CrudOperator.cjs +1 -1
- package/lib/interfaces/CrudOperator.js.map +1 -0
- package/lib/interfaces/IRepository.cjs +1 -1
- package/lib/interfaces/IRepository.js.map +1 -0
- package/lib/interfaces/index.cjs +1 -1
- package/lib/interfaces/index.js.map +1 -0
- package/lib/model/constants.cjs +1 -1
- package/lib/model/constants.js.map +1 -0
- package/lib/model/decorators.cjs +1 -1
- package/lib/model/decorators.js.map +1 -0
- package/lib/model/index.cjs +1 -1
- package/lib/model/index.js.map +1 -0
- package/lib/model/model.cjs +1 -1
- package/lib/model/model.js.map +1 -0
- package/lib/model/overrides.cjs +1 -1
- package/lib/model/overrides.js.map +1 -0
- package/lib/model/utils.cjs +1 -1
- package/lib/model/utils.js.map +1 -0
- package/lib/model/validation.cjs +1 -1
- package/lib/model/validation.js.map +1 -0
- package/lib/operations/Operations.cjs +1 -1
- package/lib/operations/Operations.js.map +1 -0
- package/lib/operations/OperationsRegistry.cjs +1 -1
- package/lib/operations/OperationsRegistry.js.map +1 -0
- package/lib/operations/constants.cjs +2 -1
- package/lib/operations/constants.d.ts +2 -1
- package/lib/operations/constants.js.map +1 -0
- package/lib/operations/decorators.cjs +76 -1
- package/lib/operations/decorators.d.ts +66 -1
- package/lib/operations/decorators.js.map +1 -0
- package/lib/operations/index.cjs +1 -1
- package/lib/operations/index.js.map +1 -0
- package/lib/operations/types.cjs +1 -1
- package/lib/operations/types.js.map +1 -0
- package/lib/repository/BaseRepository.cjs +1 -1
- package/lib/repository/BaseRepository.js.map +1 -0
- package/lib/repository/Context.cjs +1 -1
- package/lib/repository/Context.js.map +1 -0
- package/lib/repository/Repository.cjs +1 -1
- package/lib/repository/Repository.js.map +1 -0
- package/lib/repository/constants.cjs +1 -1
- package/lib/repository/constants.js.map +1 -0
- package/lib/repository/errors.cjs +1 -1
- package/lib/repository/errors.js.map +1 -0
- package/lib/repository/index.cjs +1 -1
- package/lib/repository/index.js.map +1 -0
- package/lib/repository/types.cjs +1 -1
- package/lib/repository/types.js.map +1 -0
- package/lib/repository/utils.cjs +1 -1
- package/lib/repository/utils.js.map +1 -0
- package/lib/repository/wrappers.cjs +1 -1
- package/lib/repository/wrappers.js.map +1 -0
- package/lib/validation/constants.cjs +1 -1
- package/lib/validation/constants.js.map +1 -0
- package/lib/validation/decorators.cjs +1 -1
- package/lib/validation/decorators.js.map +1 -0
- package/lib/validation/index.cjs +1 -1
- package/lib/validation/index.js.map +1 -0
- package/lib/validation/validation.cjs +1 -1
- package/lib/validation/validation.js.map +1 -0
- package/lib/validation/validators/ReadOnlyValidator.cjs +1 -1
- package/lib/validation/validators/ReadOnlyValidator.js.map +1 -0
- package/lib/validation/validators/TimestampValidator.cjs +1 -1
- package/lib/validation/validators/TimestampValidator.js.map +1 -0
- package/lib/validation/validators/UpdateValidator.cjs +1 -1
- package/lib/validation/validators/UpdateValidator.js.map +1 -0
- package/lib/validation/validators/index.cjs +1 -1
- package/lib/validation/validators/index.js.map +1 -0
- package/package.json +12 -50
- package/dist/db-decorators.esm.cjs +0 -2917
|
@@ -1,2917 +0,0 @@
|
|
|
1
|
-
import { ModelKeys, validator, Validator, DEFAULT_ERROR_MESSAGES as DEFAULT_ERROR_MESSAGES$1, Validation, Hashing, propMetadata, sf, Decoration, type, date, required, ValidationKeys, Model, ModelErrorDefinition, getValidationDecorators, toConditionalPromise, validate } from '@decaf-ts/decorator-validation';
|
|
2
|
-
import { __decorate, __metadata } from 'tslib';
|
|
3
|
-
import { isEqual, Reflection, apply, metadata } from '@decaf-ts/reflection';
|
|
4
|
-
import { ObjectAccumulator } from 'typed-object-accumulator';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @description Database reflection keys
|
|
8
|
-
* @summary Collection of keys used for reflection metadata in database operations
|
|
9
|
-
* @const DBKeys
|
|
10
|
-
* @memberOf module:db-decorators
|
|
11
|
-
*/
|
|
12
|
-
const DBKeys = {
|
|
13
|
-
REFLECT: `${ModelKeys.REFLECT}persistence.`,
|
|
14
|
-
REPOSITORY: "repository",
|
|
15
|
-
CLASS: "_class",
|
|
16
|
-
ID: "id",
|
|
17
|
-
INDEX: "index",
|
|
18
|
-
UNIQUE: "unique",
|
|
19
|
-
SERIALIZE: "serialize",
|
|
20
|
-
READONLY: "readonly",
|
|
21
|
-
TIMESTAMP: "timestamp",
|
|
22
|
-
TRANSIENT: "transient",
|
|
23
|
-
HASH: "hash",
|
|
24
|
-
COMPOSED: "composed",
|
|
25
|
-
VERSION: "version",
|
|
26
|
-
ORIGINAL: "__originalObj",
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* @description Default separator character for composite indexes
|
|
30
|
-
* @summary The default separator character used when concatenating multiple fields into a single index
|
|
31
|
-
* @const DefaultSeparator
|
|
32
|
-
* @memberOf module:db-decorators
|
|
33
|
-
*/
|
|
34
|
-
const DefaultSeparator = "_";
|
|
35
|
-
/**
|
|
36
|
-
* @description Default format for timestamp fields
|
|
37
|
-
* @summary Standard date format string used for timestamp fields in database models
|
|
38
|
-
* @const DEFAULT_TIMESTAMP_FORMAT
|
|
39
|
-
* @memberOf module:db-decorators
|
|
40
|
-
*/
|
|
41
|
-
const DEFAULT_TIMESTAMP_FORMAT = "dd/MM/yyyy HH:mm:ss:S";
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @description Collection of default error messages used by validators.
|
|
45
|
-
* @summary Holds the default error messages for various validation scenarios including ID validation, readonly properties, and timestamps.
|
|
46
|
-
* @typedef {Object} ErrorMessages
|
|
47
|
-
* @property {Object} ID - Error messages for ID validation
|
|
48
|
-
* @property {string} ID.INVALID - Error message when an ID is invalid
|
|
49
|
-
* @property {string} ID.REQUIRED - Error message when an ID is missing
|
|
50
|
-
* @property {Object} READONLY - Error messages for readonly properties
|
|
51
|
-
* @property {string} READONLY.INVALID - Error message when attempting to update a readonly property
|
|
52
|
-
* @property {Object} TIMESTAMP - Error messages for timestamp validation
|
|
53
|
-
* @property {string} TIMESTAMP.REQUIRED - Error message when a timestamp is missing
|
|
54
|
-
* @property {string} TIMESTAMP.DATE - Error message when a timestamp is not a valid date
|
|
55
|
-
* @property {string} TIMESTAMP.INVALID - Error message when a timestamp is not increasing
|
|
56
|
-
* @const DEFAULT_ERROR_MESSAGES
|
|
57
|
-
* @memberOf module:validation
|
|
58
|
-
*/
|
|
59
|
-
const DEFAULT_ERROR_MESSAGES = {
|
|
60
|
-
ID: {
|
|
61
|
-
INVALID: "This Id is invalid",
|
|
62
|
-
REQUIRED: "The Id is mandatory",
|
|
63
|
-
},
|
|
64
|
-
READONLY: {
|
|
65
|
-
INVALID: "This cannot be updated",
|
|
66
|
-
},
|
|
67
|
-
TIMESTAMP: {
|
|
68
|
-
REQUIRED: "Timestamp is Mandatory",
|
|
69
|
-
DATE: "The Timestamp must the a valid date",
|
|
70
|
-
INVALID: "This value must always increase",
|
|
71
|
-
},
|
|
72
|
-
};
|
|
73
|
-
/**
|
|
74
|
-
* @description Constants used for reflection-based validation during update operations.
|
|
75
|
-
* @summary Keys used for storing and retrieving validation metadata on model properties during update operations.
|
|
76
|
-
* @typedef {Object} ValidationKeys
|
|
77
|
-
* @property {string} REFLECT - Base reflection key prefix for update validation
|
|
78
|
-
* @property {string} TIMESTAMP - Key for timestamp validation
|
|
79
|
-
* @property {string} READONLY - Key for readonly property validation
|
|
80
|
-
* @const UpdateValidationKeys
|
|
81
|
-
* @memberOf module:validation
|
|
82
|
-
*/
|
|
83
|
-
const UpdateValidationKeys = {
|
|
84
|
-
REFLECT: "db.update.validation.",
|
|
85
|
-
TIMESTAMP: DBKeys.TIMESTAMP,
|
|
86
|
-
READONLY: DBKeys.READONLY,
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* @description A validator that ensures properties marked as readonly cannot be modified during updates.
|
|
91
|
-
* @summary Validator for the {@link readonly} decorator that checks if a value has been changed during an update operation. It compares the new value with the old value and returns an error message if they are not equal.
|
|
92
|
-
* @param {any} value - The value to be validated
|
|
93
|
-
* @param {any} oldValue - The previous value to compare against
|
|
94
|
-
* @param {string} [message] - Optional custom error message
|
|
95
|
-
* @class ReadOnlyValidator
|
|
96
|
-
* @example
|
|
97
|
-
* // Using ReadOnlyValidator with a readonly property
|
|
98
|
-
* class User {
|
|
99
|
-
* @readonly()
|
|
100
|
-
* id: string;
|
|
101
|
-
*
|
|
102
|
-
* name: string;
|
|
103
|
-
*
|
|
104
|
-
* constructor(id: string, name: string) {
|
|
105
|
-
* this.id = id;
|
|
106
|
-
* this.name = name;
|
|
107
|
-
* }
|
|
108
|
-
* }
|
|
109
|
-
*
|
|
110
|
-
* // This will trigger validation error when trying to update
|
|
111
|
-
* const user = new User('123', 'John');
|
|
112
|
-
* user.id = '456'; // Will be prevented by ReadOnlyValidator
|
|
113
|
-
* @category Validators
|
|
114
|
-
*/
|
|
115
|
-
let ReadOnlyValidator = class ReadOnlyValidator extends Validator {
|
|
116
|
-
constructor() {
|
|
117
|
-
super(DEFAULT_ERROR_MESSAGES.READONLY.INVALID);
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* @description Implementation of the base validator's hasErrors method.
|
|
121
|
-
* @summary This method is required by the Validator interface but not used in this validator as validation only happens during updates.
|
|
122
|
-
* @param {any} value - The value to validate
|
|
123
|
-
* @param {any[]} args - Additional arguments
|
|
124
|
-
* @return {string | undefined} Always returns undefined as this validator only works during updates
|
|
125
|
-
*/
|
|
126
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
127
|
-
hasErrors(value, ...args) {
|
|
128
|
-
return undefined;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* @description Checks if a value has been modified during an update operation.
|
|
132
|
-
* @summary Validates a value has not changed by comparing it with the previous value using deep equality.
|
|
133
|
-
* @param {any} value - The new value to validate
|
|
134
|
-
* @param {any} oldValue - The original value to compare against
|
|
135
|
-
* @param {string} [message] - Optional custom error message to override the default
|
|
136
|
-
* @return {string | undefined} An error message if validation fails, undefined otherwise
|
|
137
|
-
*/
|
|
138
|
-
updateHasErrors(value, oldValue, message) {
|
|
139
|
-
if (value === undefined)
|
|
140
|
-
return;
|
|
141
|
-
return isEqual(value, oldValue)
|
|
142
|
-
? undefined
|
|
143
|
-
: this.getMessage(message || this.message);
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
ReadOnlyValidator = __decorate([
|
|
147
|
-
validator(UpdateValidationKeys.READONLY),
|
|
148
|
-
__metadata("design:paramtypes", [])
|
|
149
|
-
], ReadOnlyValidator);
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* @description A validator that ensures timestamp values are only updated with newer timestamps.
|
|
153
|
-
* @summary Validates the update of a timestamp by comparing the new timestamp with the old one, ensuring the new timestamp is more recent.
|
|
154
|
-
* @param {Date|string|number} value - The timestamp value to validate
|
|
155
|
-
* @param {Date|string|number} oldValue - The previous timestamp to compare against
|
|
156
|
-
* @param {string} [message] - Optional custom error message
|
|
157
|
-
* @class TimestampValidator
|
|
158
|
-
* @example
|
|
159
|
-
* // Using TimestampValidator with a timestamp property
|
|
160
|
-
* class Document {
|
|
161
|
-
* @timestamp()
|
|
162
|
-
* updatedAt: Date;
|
|
163
|
-
*
|
|
164
|
-
* title: string;
|
|
165
|
-
*
|
|
166
|
-
* constructor(title: string) {
|
|
167
|
-
* this.title = title;
|
|
168
|
-
* this.updatedAt = new Date();
|
|
169
|
-
* }
|
|
170
|
-
* }
|
|
171
|
-
*
|
|
172
|
-
* // This will trigger validation error when trying to update with an older timestamp
|
|
173
|
-
* const doc = new Document('My Document');
|
|
174
|
-
* const oldDate = new Date(2020, 0, 1);
|
|
175
|
-
* doc.updatedAt = oldDate; // Will be prevented by TimestampValidator
|
|
176
|
-
* @category Validators
|
|
177
|
-
*/
|
|
178
|
-
let TimestampValidator = class TimestampValidator extends Validator {
|
|
179
|
-
constructor() {
|
|
180
|
-
super(DEFAULT_ERROR_MESSAGES.TIMESTAMP.INVALID);
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* @description Implementation of the base validator's hasErrors method.
|
|
184
|
-
* @summary This method is required by the Validator interface but not used in this validator as validation only happens during updates.
|
|
185
|
-
* @param {any} value - The timestamp value to validate
|
|
186
|
-
* @param {any[]} args - Additional arguments
|
|
187
|
-
* @return {string | undefined} Always returns undefined as this validator only works during updates
|
|
188
|
-
*/
|
|
189
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
190
|
-
hasErrors(value, ...args) {
|
|
191
|
-
return undefined;
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* @description Validates that a timestamp is newer than its previous value.
|
|
195
|
-
* @summary Checks if a timestamp has been updated with a more recent value by converting both values to Date objects and comparing them.
|
|
196
|
-
* @param {Date|string|number} value - The new timestamp value to validate
|
|
197
|
-
* @param {Date|string|number} oldValue - The original timestamp to compare against
|
|
198
|
-
* @param {string} [message] - Optional custom error message to override the default
|
|
199
|
-
* @return {string | undefined} An error message if validation fails (new timestamp is not newer), undefined otherwise
|
|
200
|
-
*/
|
|
201
|
-
updateHasErrors(value, oldValue, message) {
|
|
202
|
-
if (value === undefined)
|
|
203
|
-
return;
|
|
204
|
-
message = message || this.getMessage(message || this.message);
|
|
205
|
-
try {
|
|
206
|
-
value = new Date(value);
|
|
207
|
-
oldValue = new Date(oldValue);
|
|
208
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
209
|
-
}
|
|
210
|
-
catch (e) {
|
|
211
|
-
return message;
|
|
212
|
-
}
|
|
213
|
-
return value <= oldValue ? message : undefined;
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
TimestampValidator = __decorate([
|
|
217
|
-
validator(UpdateValidationKeys.TIMESTAMP),
|
|
218
|
-
__metadata("design:paramtypes", [])
|
|
219
|
-
], TimestampValidator);
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* @description Abstract base class for validators that compare new values with old values during updates.
|
|
223
|
-
* @summary Base class for an Update validator that provides a framework for implementing validation logic that compares a new value with its previous state.
|
|
224
|
-
* @param {string} [message] - Error message. Defaults to {@link DecoratorMessages#DEFAULT}
|
|
225
|
-
* @param {string[]} [acceptedTypes] - The accepted value types by the decorator
|
|
226
|
-
* @class UpdateValidator
|
|
227
|
-
* @example
|
|
228
|
-
* // Extending UpdateValidator to create a custom validator
|
|
229
|
-
* class MyCustomValidator extends UpdateValidator {
|
|
230
|
-
* constructor() {
|
|
231
|
-
* super("Custom validation failed");
|
|
232
|
-
* }
|
|
233
|
-
*
|
|
234
|
-
* public updateHasErrors(value: any, oldValue: any): string | undefined {
|
|
235
|
-
* // Custom validation logic
|
|
236
|
-
* if (value === oldValue) {
|
|
237
|
-
* return this.message;
|
|
238
|
-
* }
|
|
239
|
-
* return undefined;
|
|
240
|
-
* }
|
|
241
|
-
*
|
|
242
|
-
* hasErrors(value: any): string | undefined {
|
|
243
|
-
* return undefined; // Not used for update validators
|
|
244
|
-
* }
|
|
245
|
-
* }
|
|
246
|
-
* @category Validators
|
|
247
|
-
*/
|
|
248
|
-
class UpdateValidator extends Validator {
|
|
249
|
-
constructor(message = DEFAULT_ERROR_MESSAGES$1.DEFAULT, ...acceptedTypes) {
|
|
250
|
-
super(message, ...acceptedTypes);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* @description Generates a key for update validation metadata.
|
|
256
|
-
* @summary Builds the key to store as metadata under Reflections for update validation by prefixing the provided key with the update validation prefix.
|
|
257
|
-
* @param {string} key - The base key to be prefixed
|
|
258
|
-
* @return {string} The complete metadata key for update validation
|
|
259
|
-
* @function updateKey
|
|
260
|
-
* @memberOf module:db-decorators
|
|
261
|
-
*/
|
|
262
|
-
Validation.updateKey = function (key) {
|
|
263
|
-
return UpdateValidationKeys.REFLECT + key;
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* @description Database operation key constants
|
|
268
|
-
* @summary Enum defining CRUD operations and their lifecycle phases
|
|
269
|
-
* @enum {string}
|
|
270
|
-
* @readonly
|
|
271
|
-
* @memberOf module:db-decorators
|
|
272
|
-
*/
|
|
273
|
-
var OperationKeys;
|
|
274
|
-
(function (OperationKeys) {
|
|
275
|
-
OperationKeys["REFLECT"] = "decaf.model.db.operations.";
|
|
276
|
-
OperationKeys["CREATE"] = "create";
|
|
277
|
-
OperationKeys["READ"] = "read";
|
|
278
|
-
OperationKeys["UPDATE"] = "update";
|
|
279
|
-
OperationKeys["DELETE"] = "delete";
|
|
280
|
-
OperationKeys["ON"] = "on.";
|
|
281
|
-
OperationKeys["AFTER"] = "after.";
|
|
282
|
-
})(OperationKeys || (OperationKeys = {}));
|
|
283
|
-
/**
|
|
284
|
-
* @description Bulk database operation key constants
|
|
285
|
-
* @summary Enum defining bulk CRUD operations for handling multiple records at once
|
|
286
|
-
* @enum {string}
|
|
287
|
-
* @readonly
|
|
288
|
-
* @memberOf module:db-decorators
|
|
289
|
-
*/
|
|
290
|
-
var BulkCrudOperationKeys;
|
|
291
|
-
(function (BulkCrudOperationKeys) {
|
|
292
|
-
BulkCrudOperationKeys["CREATE_ALL"] = "createAll";
|
|
293
|
-
BulkCrudOperationKeys["READ_ALL"] = "readAll";
|
|
294
|
-
BulkCrudOperationKeys["UPDATE_ALL"] = "updateAll";
|
|
295
|
-
BulkCrudOperationKeys["DELETE_ALL"] = "deleteAll";
|
|
296
|
-
})(BulkCrudOperationKeys || (BulkCrudOperationKeys = {}));
|
|
297
|
-
/**
|
|
298
|
-
* @description Grouped CRUD operations for decorator mapping
|
|
299
|
-
* @summary Maps out groups of CRUD operations for easier mapping of decorators
|
|
300
|
-
* @const DBOperations
|
|
301
|
-
* @memberOf module:db-decorators
|
|
302
|
-
*/
|
|
303
|
-
const DBOperations = {
|
|
304
|
-
CREATE: [OperationKeys.CREATE],
|
|
305
|
-
READ: [OperationKeys.READ],
|
|
306
|
-
UPDATE: [OperationKeys.UPDATE],
|
|
307
|
-
DELETE: [OperationKeys.DELETE],
|
|
308
|
-
CREATE_UPDATE: [OperationKeys.CREATE, OperationKeys.UPDATE],
|
|
309
|
-
READ_CREATE: [OperationKeys.READ, OperationKeys.CREATE],
|
|
310
|
-
ALL: [
|
|
311
|
-
OperationKeys.CREATE,
|
|
312
|
-
OperationKeys.READ,
|
|
313
|
-
OperationKeys.UPDATE,
|
|
314
|
-
OperationKeys.DELETE,
|
|
315
|
-
],
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* @description Registry for database operation handlers
|
|
320
|
-
* @summary Manages and stores operation handlers for different model properties and operations
|
|
321
|
-
* @class OperationsRegistry
|
|
322
|
-
* @template M - Model type
|
|
323
|
-
* @template R - Repository type
|
|
324
|
-
* @template V - Metadata type
|
|
325
|
-
* @template F - Repository flags
|
|
326
|
-
* @template C - Context type
|
|
327
|
-
* @example
|
|
328
|
-
* // Create a registry and register a handler
|
|
329
|
-
* const registry = new OperationsRegistry();
|
|
330
|
-
* registry.register(myHandler, OperationKeys.CREATE, targetModel, 'propertyName');
|
|
331
|
-
*
|
|
332
|
-
* // Get handlers for a specific operation
|
|
333
|
-
* const handlers = registry.get(targetModel.constructor.name, 'propertyName', 'onCreate');
|
|
334
|
-
*
|
|
335
|
-
* @mermaid
|
|
336
|
-
* classDiagram
|
|
337
|
-
* class OperationsRegistry {
|
|
338
|
-
* -cache: Record~string, Record~string|symbol, Record~string, Record~string, OperationHandler~~~~
|
|
339
|
-
* +get(target, propKey, operation, accum)
|
|
340
|
-
* +register(handler, operation, target, propKey)
|
|
341
|
-
* }
|
|
342
|
-
*/
|
|
343
|
-
class OperationsRegistry {
|
|
344
|
-
constructor() {
|
|
345
|
-
this.cache = {};
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* @description Retrieves operation handlers for a specific target and operation
|
|
349
|
-
* @summary Finds all registered handlers for a given target, property, and operation, including from parent classes
|
|
350
|
-
* @template M - Model type extending Model
|
|
351
|
-
* @template R - Repository type extending IRepository
|
|
352
|
-
* @template V - Metadata type
|
|
353
|
-
* @template F - Repository flags extending RepositoryFlags
|
|
354
|
-
* @template C - Context type extending Context<F>
|
|
355
|
-
* @param {string | Record<string, any>} target - The target class name or object
|
|
356
|
-
* @param {string} propKey - The property key to get handlers for
|
|
357
|
-
* @param {string} operation - The operation key to get handlers for
|
|
358
|
-
* @param {OperationHandler[]} [accum] - Accumulator for recursive calls
|
|
359
|
-
* @return {OperationHandler[] | undefined} Array of handlers or undefined if none found
|
|
360
|
-
*/
|
|
361
|
-
get(target, propKey, operation, accum) {
|
|
362
|
-
accum = accum || [];
|
|
363
|
-
let name;
|
|
364
|
-
try {
|
|
365
|
-
name = typeof target === "string" ? target : target.constructor.name;
|
|
366
|
-
accum.unshift(...Object.values(this.cache[name][propKey][operation] || []));
|
|
367
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
368
|
-
}
|
|
369
|
-
catch (e) {
|
|
370
|
-
if (typeof target === "string" ||
|
|
371
|
-
target === Object.prototype ||
|
|
372
|
-
Object.getPrototypeOf(target) === Object.prototype)
|
|
373
|
-
return accum;
|
|
374
|
-
}
|
|
375
|
-
let proto = Object.getPrototypeOf(target);
|
|
376
|
-
if (proto.constructor.name === name)
|
|
377
|
-
proto = Object.getPrototypeOf(proto);
|
|
378
|
-
return this.get(proto, propKey, operation, accum);
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* @description Registers an operation handler for a specific target and operation
|
|
382
|
-
* @summary Stores a handler in the registry for a given target, property, and operation
|
|
383
|
-
* @template M - Model type extending Model
|
|
384
|
-
* @template R - Repository type extending IRepository
|
|
385
|
-
* @template V - Metadata type
|
|
386
|
-
* @template F - Repository flags extending RepositoryFlags
|
|
387
|
-
* @template C - Context type extending Context<F>
|
|
388
|
-
* @param {OperationHandler} handler - The handler function to register
|
|
389
|
-
* @param {OperationKeys} operation - The operation key to register the handler for
|
|
390
|
-
* @param {M} target - The target model instance
|
|
391
|
-
* @param {string | symbol} propKey - The property key to register the handler for
|
|
392
|
-
* @return {void}
|
|
393
|
-
*/
|
|
394
|
-
register(handler, operation, target, propKey) {
|
|
395
|
-
const name = target.constructor.name;
|
|
396
|
-
const handlerName = Operations.getHandlerName(handler);
|
|
397
|
-
if (!this.cache[name])
|
|
398
|
-
this.cache[name] = {};
|
|
399
|
-
if (!this.cache[name][propKey])
|
|
400
|
-
this.cache[name][propKey] = {};
|
|
401
|
-
if (!this.cache[name][propKey][operation])
|
|
402
|
-
this.cache[name][propKey][operation] = {};
|
|
403
|
-
if (this.cache[name][propKey][operation][handlerName])
|
|
404
|
-
return;
|
|
405
|
-
this.cache[name][propKey][operation][handlerName] = handler;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* @description Static utility class for database operation management
|
|
411
|
-
* @summary Provides functionality for registering, retrieving, and managing database operation handlers
|
|
412
|
-
* @class Operations
|
|
413
|
-
* @template M - Model type
|
|
414
|
-
* @template R - Repository type
|
|
415
|
-
* @template V - Metadata type
|
|
416
|
-
* @template F - Repository flags
|
|
417
|
-
* @template C - Context type
|
|
418
|
-
* @example
|
|
419
|
-
* // Register a handler for a create operation
|
|
420
|
-
* Operations.register(myHandler, OperationKeys.CREATE, targetModel, 'propertyName');
|
|
421
|
-
*
|
|
422
|
-
* // Get handlers for a specific operation
|
|
423
|
-
* const handlers = Operations.get(targetModel.constructor.name, 'propertyName', 'onCreate');
|
|
424
|
-
*
|
|
425
|
-
* @mermaid
|
|
426
|
-
* classDiagram
|
|
427
|
-
* class Operations {
|
|
428
|
-
* -registry: OperationsRegistry
|
|
429
|
-
* +getHandlerName(handler)
|
|
430
|
-
* +key(str)
|
|
431
|
-
* +get(targetName, propKey, operation)
|
|
432
|
-
* -getOpRegistry()
|
|
433
|
-
* +register(handler, operation, target, propKey)
|
|
434
|
-
* }
|
|
435
|
-
* Operations --> OperationsRegistry : uses
|
|
436
|
-
*/
|
|
437
|
-
class Operations {
|
|
438
|
-
constructor() { }
|
|
439
|
-
/**
|
|
440
|
-
* @description Gets a unique name for an operation handler
|
|
441
|
-
* @summary Returns the name of the handler function or generates a hash if name is not available
|
|
442
|
-
* @param {OperationHandler<any, any, any, any, any>} handler - The handler function to get the name for
|
|
443
|
-
* @return {string} The name of the handler or a generated hash
|
|
444
|
-
*/
|
|
445
|
-
static getHandlerName(handler) {
|
|
446
|
-
if (handler.name)
|
|
447
|
-
return handler.name;
|
|
448
|
-
console.warn("Handler name not defined. A name will be generated, but this is not desirable. please avoid using anonymous functions");
|
|
449
|
-
return Hashing.hash(handler.toString());
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* @description Generates a reflection metadata key
|
|
453
|
-
* @summary Creates a fully qualified metadata key by prefixing with the reflection namespace
|
|
454
|
-
* @param {string} str - The operation key string to prefix
|
|
455
|
-
* @return {string} The fully qualified metadata key
|
|
456
|
-
*/
|
|
457
|
-
static key(str) {
|
|
458
|
-
return OperationKeys.REFLECT + str;
|
|
459
|
-
}
|
|
460
|
-
/**
|
|
461
|
-
* @description Retrieves operation handlers for a specific target and operation
|
|
462
|
-
* @summary Gets registered handlers from the operations registry for a given target, property, and operation
|
|
463
|
-
* @template M - Model type extending Model
|
|
464
|
-
* @template R - Repository type extending IRepository
|
|
465
|
-
* @template V - Metadata type, defaults to object
|
|
466
|
-
* @template F - Repository flags extending RepositoryFlags
|
|
467
|
-
* @template C - Context type extending Context<F>
|
|
468
|
-
* @param {string | Record<string, any>} targetName - The target class name or object
|
|
469
|
-
* @param {string} propKey - The property key to get handlers for
|
|
470
|
-
* @param {string} operation - The operation key to get handlers for
|
|
471
|
-
* @return {any} The registered handlers for the specified target, property, and operation
|
|
472
|
-
*/
|
|
473
|
-
static get(targetName, propKey, operation) {
|
|
474
|
-
return Operations.registry.get(targetName, propKey, operation);
|
|
475
|
-
}
|
|
476
|
-
/**
|
|
477
|
-
* @description Gets or initializes the operations registry
|
|
478
|
-
* @summary Returns the existing registry or creates a new one if it doesn't exist
|
|
479
|
-
* @return {OperationsRegistry} The operations registry instance
|
|
480
|
-
* @private
|
|
481
|
-
*/
|
|
482
|
-
static getOpRegistry() {
|
|
483
|
-
if (!Operations.registry)
|
|
484
|
-
Operations.registry = new OperationsRegistry();
|
|
485
|
-
return Operations.registry;
|
|
486
|
-
}
|
|
487
|
-
/**
|
|
488
|
-
* @description Registers an operation handler for a specific target and operation
|
|
489
|
-
* @summary Adds a handler to the operations registry for a given target, property, and operation
|
|
490
|
-
* @template V - Model type extending Model
|
|
491
|
-
* @param {OperationHandler<V, any, any>} handler - The handler function to register
|
|
492
|
-
* @param {OperationKeys} operation - The operation key to register the handler for
|
|
493
|
-
* @param {V} target - The target model instance
|
|
494
|
-
* @param {string | symbol} propKey - The property key to register the handler for
|
|
495
|
-
* @return {void}
|
|
496
|
-
*/
|
|
497
|
-
static register(handler, operation, target, propKey) {
|
|
498
|
-
Operations.getOpRegistry().register(handler, operation, target, propKey);
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
/**
|
|
503
|
-
* @description Base error class for the repository module
|
|
504
|
-
* @summary Abstract base error class that all other error types extend from. Provides common error handling functionality and standardized HTTP code mapping.
|
|
505
|
-
* @param {string} name - The name of the error
|
|
506
|
-
* @param {string|Error} msg - The error message or Error object to wrap
|
|
507
|
-
* @param {number} code - The HTTP status code associated with this error
|
|
508
|
-
* @return {void}
|
|
509
|
-
* @class BaseError
|
|
510
|
-
* @example
|
|
511
|
-
* // This is an abstract class and should not be instantiated directly
|
|
512
|
-
* // Instead, use one of the concrete error classes:
|
|
513
|
-
* throw new ValidationError('Invalid data provided');
|
|
514
|
-
* @mermaid
|
|
515
|
-
* sequenceDiagram
|
|
516
|
-
* participant C as Caller
|
|
517
|
-
* participant E as BaseError
|
|
518
|
-
* C->>E: new BaseError(name,msg,code)
|
|
519
|
-
* E-->>C: Error instance with message and code
|
|
520
|
-
* @category Errors
|
|
521
|
-
*/
|
|
522
|
-
class BaseError extends Error {
|
|
523
|
-
constructor(name, msg, code) {
|
|
524
|
-
if (msg instanceof BaseError)
|
|
525
|
-
return msg;
|
|
526
|
-
const message = `[${name}] ${msg instanceof Error ? msg.message : msg}`;
|
|
527
|
-
super(message);
|
|
528
|
-
this.code = code;
|
|
529
|
-
if (msg instanceof Error)
|
|
530
|
-
this.stack = msg.stack;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* @description Error (40) thrown when a bad request is received
|
|
535
|
-
* @summary Represents a failure in the input data, typically thrown when a client sends invalid or incomplete data
|
|
536
|
-
* @param {string|Error} msg - The error message or Error object
|
|
537
|
-
* @return {BadRequestError} A new BadRequestError instance
|
|
538
|
-
* @class BadRequestError
|
|
539
|
-
* @category Errors
|
|
540
|
-
*/
|
|
541
|
-
class BadRequestError extends BaseError {
|
|
542
|
-
constructor(msg, name = BadRequestError.name, code = 400) {
|
|
543
|
-
super(name, msg, code);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
/**
|
|
547
|
-
* @description Error (422) thrown when validation fails
|
|
548
|
-
* @summary Represents a failure in the Model details, typically thrown when data validation fails
|
|
549
|
-
* @param {string|Error} msg - The error message or Error object
|
|
550
|
-
* @return {ValidationError} A new ValidationError instance
|
|
551
|
-
* @class ValidationError
|
|
552
|
-
* @example
|
|
553
|
-
* // Throw a validation error when data is invalid
|
|
554
|
-
* if (!isValid(data)) {
|
|
555
|
-
* throw new ValidationError('Invalid data format');
|
|
556
|
-
* }
|
|
557
|
-
* @category Errors
|
|
558
|
-
*/
|
|
559
|
-
class ValidationError extends BadRequestError {
|
|
560
|
-
constructor(msg) {
|
|
561
|
-
super(msg, ValidationError.name, 422);
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
/**
|
|
565
|
-
* @description Error (500) thrown for internal system failures
|
|
566
|
-
* @summary Represents an internal failure (should mean an error in code) with HTTP 500 status code
|
|
567
|
-
* @param {string|Error} msg - The error message or Error object
|
|
568
|
-
* @return {InternalError} A new InternalError instance
|
|
569
|
-
* @class InternalError
|
|
570
|
-
* @example
|
|
571
|
-
* // Throw an internal error when an unexpected condition occurs
|
|
572
|
-
* try {
|
|
573
|
-
* // Some operation
|
|
574
|
-
* } catch (error) {
|
|
575
|
-
* throw new InternalError('Unexpected internal error occurred');
|
|
576
|
-
* }
|
|
577
|
-
* @category Errors
|
|
578
|
-
*/
|
|
579
|
-
class InternalError extends BaseError {
|
|
580
|
-
constructor(msg, name = InternalError.name, code = 500) {
|
|
581
|
-
super(name, msg, code);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
/**
|
|
585
|
-
* @description Error (500) thrown when serialization or deserialization fails
|
|
586
|
-
* @summary Represents a failure in the Model de/serialization, typically when converting between data formats
|
|
587
|
-
* @param {string|Error} msg - The error message or Error object
|
|
588
|
-
* @return {SerializationError} A new SerializationError instance
|
|
589
|
-
* @class SerializationError
|
|
590
|
-
* @example
|
|
591
|
-
* // Throw a serialization error when JSON parsing fails
|
|
592
|
-
* try {
|
|
593
|
-
* const data = JSON.parse(invalidJson);
|
|
594
|
-
* } catch (error) {
|
|
595
|
-
* throw new SerializationError('Failed to parse JSON data');
|
|
596
|
-
* }
|
|
597
|
-
* @category Errors
|
|
598
|
-
*/
|
|
599
|
-
class SerializationError extends InternalError {
|
|
600
|
-
constructor(msg) {
|
|
601
|
-
super(msg, SerializationError.name, 500);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
/**
|
|
605
|
-
* @description Error thrown when a requested resource is not found
|
|
606
|
-
* @summary Represents a failure in finding a model, resulting in a 404 HTTP status code
|
|
607
|
-
* @param {string|Error} msg - The error message or Error object
|
|
608
|
-
* @return {NotFoundError} A new NotFoundError instance
|
|
609
|
-
* @class NotFoundError
|
|
610
|
-
* @example
|
|
611
|
-
* // Throw a not found error when a record doesn't exist
|
|
612
|
-
* const user = await repository.findById(id);
|
|
613
|
-
* if (!user) {
|
|
614
|
-
* throw new NotFoundError(`User with ID ${id} not found`);
|
|
615
|
-
* }
|
|
616
|
-
* @category Errors
|
|
617
|
-
*/
|
|
618
|
-
class NotFoundError extends BadRequestError {
|
|
619
|
-
constructor(msg) {
|
|
620
|
-
super(msg, NotFoundError.name, 404);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
/**
|
|
624
|
-
* @description Error thrown when a conflict occurs in the storage
|
|
625
|
-
* @summary Represents a conflict in the storage, typically when trying to create a duplicate resource
|
|
626
|
-
* @param {string|Error} msg - The error message or Error object
|
|
627
|
-
* @return {ConflictError} A new ConflictError instance
|
|
628
|
-
* @class ConflictError
|
|
629
|
-
* @example
|
|
630
|
-
* // Throw a conflict error when trying to create a duplicate record
|
|
631
|
-
* const existingUser = await repository.findByEmail(email);
|
|
632
|
-
* if (existingUser) {
|
|
633
|
-
* throw new ConflictError(`User with email ${email} already exists`);
|
|
634
|
-
* }
|
|
635
|
-
* @category Errors
|
|
636
|
-
*/
|
|
637
|
-
class ConflictError extends BadRequestError {
|
|
638
|
-
constructor(msg) {
|
|
639
|
-
super(msg, ConflictError.name, 409);
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
/**
|
|
644
|
-
* @summary retrieves the arguments for the handler
|
|
645
|
-
* @param {any} dec the decorator
|
|
646
|
-
* @param {string} prop the property name
|
|
647
|
-
* @param {{}} m the model
|
|
648
|
-
* @param {{}} [accum] accumulator used for internal recursiveness
|
|
649
|
-
*
|
|
650
|
-
* @function getHandlerArgs
|
|
651
|
-
* @memberOf module:db-decorators.Repository
|
|
652
|
-
*/
|
|
653
|
-
const getHandlerArgs = function (dec, prop, m, accum) {
|
|
654
|
-
const name = m.constructor.name;
|
|
655
|
-
if (!name)
|
|
656
|
-
throw new InternalError("Could not determine model class");
|
|
657
|
-
accum = accum || {};
|
|
658
|
-
if (dec.props.handlers[name] && dec.props.handlers[name][prop])
|
|
659
|
-
accum = { ...dec.props.handlers[name][prop], ...accum };
|
|
660
|
-
let proto = Object.getPrototypeOf(m);
|
|
661
|
-
if (proto === Object.prototype)
|
|
662
|
-
return accum;
|
|
663
|
-
if (proto.constructor.name === name)
|
|
664
|
-
proto = Object.getPrototypeOf(proto);
|
|
665
|
-
return getHandlerArgs(dec, prop, proto, accum);
|
|
666
|
-
};
|
|
667
|
-
/**
|
|
668
|
-
*
|
|
669
|
-
* @param {IRepository<T>} repo
|
|
670
|
-
* @param context
|
|
671
|
-
* @param {T} model
|
|
672
|
-
* @param operation
|
|
673
|
-
* @param prefix
|
|
674
|
-
*
|
|
675
|
-
* @param oldModel
|
|
676
|
-
* @function enforceDBPropertyDecoratorsAsync
|
|
677
|
-
*
|
|
678
|
-
* @memberOf db-decorators.utils
|
|
679
|
-
*/
|
|
680
|
-
async function enforceDBDecorators(repo, context, model, operation, prefix, oldModel) {
|
|
681
|
-
const decorators = getDbDecorators(model, operation, prefix);
|
|
682
|
-
if (!decorators)
|
|
683
|
-
return;
|
|
684
|
-
const hanlersDecorators = getHandlersDecorators(model, decorators, prefix);
|
|
685
|
-
const groupedDecorators = groupDecorators(hanlersDecorators);
|
|
686
|
-
const sortedDecorators = sortDecorators(groupedDecorators);
|
|
687
|
-
for (const dec of sortedDecorators) {
|
|
688
|
-
const args = [
|
|
689
|
-
context,
|
|
690
|
-
dec.data.length > 1 ? dec.data : dec.data[0],
|
|
691
|
-
dec.prop.length > 1 ? dec.prop : dec.prop[0],
|
|
692
|
-
model,
|
|
693
|
-
];
|
|
694
|
-
if (operation === OperationKeys.UPDATE && prefix === OperationKeys.ON) {
|
|
695
|
-
if (!oldModel)
|
|
696
|
-
throw new InternalError("Missing old model for update operation");
|
|
697
|
-
args.push(oldModel);
|
|
698
|
-
}
|
|
699
|
-
try {
|
|
700
|
-
await dec.handler.apply(repo, args);
|
|
701
|
-
}
|
|
702
|
-
catch (e) {
|
|
703
|
-
const msg = `Failed to execute handler ${dec.handler.name} for ${dec.prop} on ${model.constructor.name} due to error: ${e}`;
|
|
704
|
-
if (context.get("breakOnHandlerError"))
|
|
705
|
-
throw new InternalError(msg);
|
|
706
|
-
console.log(msg);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* Specific for DB Decorators
|
|
712
|
-
* @param {T} model
|
|
713
|
-
* @param {string} operation CRUD {@link OperationKeys}
|
|
714
|
-
* @param {string} [extraPrefix]
|
|
715
|
-
*
|
|
716
|
-
* @function getDbPropertyDecorators
|
|
717
|
-
*
|
|
718
|
-
* @memberOf db-decorators.utils
|
|
719
|
-
*/
|
|
720
|
-
function getDbDecorators(model, operation, extraPrefix) {
|
|
721
|
-
const decorators = Reflection.getAllPropertyDecorators(model,
|
|
722
|
-
// undefined,
|
|
723
|
-
OperationKeys.REFLECT + (extraPrefix ? extraPrefix : ""));
|
|
724
|
-
if (!decorators)
|
|
725
|
-
return;
|
|
726
|
-
return Object.keys(decorators).reduce((accum, decorator) => {
|
|
727
|
-
const dec = decorators[decorator].filter((d) => d.key === operation);
|
|
728
|
-
if (dec && dec.length) {
|
|
729
|
-
if (!accum)
|
|
730
|
-
accum = {};
|
|
731
|
-
accum[decorator] = dec;
|
|
732
|
-
}
|
|
733
|
-
return accum;
|
|
734
|
-
}, undefined);
|
|
735
|
-
}
|
|
736
|
-
/**
|
|
737
|
-
* @summary Retrieves the decorators for an object's properties prefixed by {@param prefixes} recursively
|
|
738
|
-
* @param model
|
|
739
|
-
* @param accum
|
|
740
|
-
* @param prefixes
|
|
741
|
-
*
|
|
742
|
-
* @function getAllPropertyDecoratorsRecursive
|
|
743
|
-
* @memberOf module:db-decorators.Repository
|
|
744
|
-
*/
|
|
745
|
-
const getAllPropertyDecoratorsRecursive = function (model, accum, ...prefixes) {
|
|
746
|
-
const accumulator = accum || {};
|
|
747
|
-
const mergeDecorators = function (decs) {
|
|
748
|
-
const pushOrSquash = (key, ...values) => {
|
|
749
|
-
values.forEach((val) => {
|
|
750
|
-
let match;
|
|
751
|
-
if (!(match = accumulator[key].find((e) => e.key === val.key)) ||
|
|
752
|
-
match.props.operation !== val.props.operation) {
|
|
753
|
-
accumulator[key].push(val);
|
|
754
|
-
return;
|
|
755
|
-
}
|
|
756
|
-
if (val.key === ModelKeys.TYPE)
|
|
757
|
-
return;
|
|
758
|
-
const { handlers, operation } = val.props;
|
|
759
|
-
if (!operation ||
|
|
760
|
-
!operation.match(new RegExp(`^(:?${OperationKeys.ON}|${OperationKeys.AFTER})(:?${OperationKeys.CREATE}|${OperationKeys.READ}|${OperationKeys.UPDATE}|${OperationKeys.DELETE})$`))) {
|
|
761
|
-
accumulator[key].push(val);
|
|
762
|
-
return;
|
|
763
|
-
}
|
|
764
|
-
const accumHandlers = match.props.handlers;
|
|
765
|
-
Object.entries(handlers).forEach(([clazz, handlerDef]) => {
|
|
766
|
-
if (!(clazz in accumHandlers)) {
|
|
767
|
-
accumHandlers[clazz] = handlerDef;
|
|
768
|
-
return;
|
|
769
|
-
}
|
|
770
|
-
Object.entries(handlerDef).forEach(([handlerProp, handler]) => {
|
|
771
|
-
if (!(handlerProp in accumHandlers[clazz])) {
|
|
772
|
-
accumHandlers[clazz][handlerProp] = handler;
|
|
773
|
-
return;
|
|
774
|
-
}
|
|
775
|
-
Object.entries(handler).forEach(([handlerKey, argsObj]) => {
|
|
776
|
-
if (!(handlerKey in accumHandlers[clazz][handlerProp])) {
|
|
777
|
-
accumHandlers[clazz][handlerProp][handlerKey] = argsObj;
|
|
778
|
-
return;
|
|
779
|
-
}
|
|
780
|
-
console.warn(`Skipping handler registration for ${clazz} under prop ${handlerProp} because handler is the same`);
|
|
781
|
-
});
|
|
782
|
-
});
|
|
783
|
-
});
|
|
784
|
-
});
|
|
785
|
-
};
|
|
786
|
-
Object.entries(decs).forEach(([key, value]) => {
|
|
787
|
-
accumulator[key] = accumulator[key] || [];
|
|
788
|
-
pushOrSquash(key, ...value);
|
|
789
|
-
});
|
|
790
|
-
};
|
|
791
|
-
const decs = Reflection.getAllPropertyDecorators(model, ...prefixes);
|
|
792
|
-
if (decs)
|
|
793
|
-
mergeDecorators(decs);
|
|
794
|
-
if (Object.getPrototypeOf(model) === Object.prototype)
|
|
795
|
-
return accumulator;
|
|
796
|
-
// const name = model.constructor.name;
|
|
797
|
-
const proto = Object.getPrototypeOf(model);
|
|
798
|
-
if (!proto)
|
|
799
|
-
return accumulator;
|
|
800
|
-
// if (proto.constructor && proto.constructor.name === name)
|
|
801
|
-
// proto = Object.getPrototypeOf(proto)
|
|
802
|
-
return getAllPropertyDecoratorsRecursive(proto, accumulator, ...prefixes);
|
|
803
|
-
};
|
|
804
|
-
|
|
805
|
-
const defaultPriority = 50;
|
|
806
|
-
const DefaultGroupSort = { priority: defaultPriority };
|
|
807
|
-
/**
|
|
808
|
-
* @description Internal function to register operation handlers
|
|
809
|
-
* @summary Registers an operation handler for a specific operation key on a target property
|
|
810
|
-
* @param {OperationKeys} op - The operation key to handle
|
|
811
|
-
* @param {OperationHandler<any, any, any, any, any>} handler - The handler function to register
|
|
812
|
-
* @return {PropertyDecorator} A decorator that registers the handler
|
|
813
|
-
* @function handle
|
|
814
|
-
* @category Property Decorators
|
|
815
|
-
*/
|
|
816
|
-
function handle(op, handler) {
|
|
817
|
-
return (target, propertyKey) => {
|
|
818
|
-
Operations.register(handler, op, target, propertyKey);
|
|
819
|
-
};
|
|
820
|
-
}
|
|
821
|
-
/**
|
|
822
|
-
* @description Retrieves decorator objects for handling database operations
|
|
823
|
-
* @summary Retrieves a list of decorator objects representing operation handlers for a given model and decorators
|
|
824
|
-
* @template M - Type for the model, defaults to Model<true | false>
|
|
825
|
-
* @template R - Type for the repository, defaults to IRepository<M, F, C>
|
|
826
|
-
* @template V - Type for metadata, defaults to object
|
|
827
|
-
* @template F - Type for repository flags, defaults to RepositoryFlags
|
|
828
|
-
* @template C - Type for context, defaults to Context<F>
|
|
829
|
-
* @param {Model} model - The model for which to retrieve decorator objects
|
|
830
|
-
* @param {Record<string, DecoratorMetadata[]>} decorators - The decorators associated with the model properties
|
|
831
|
-
* @param {string} prefix - The operation prefix (e.g., 'on', 'after')
|
|
832
|
-
* @return {DecoratorObject[]} An array of decorator objects representing operation handlers
|
|
833
|
-
* @function getHandlersDecorators
|
|
834
|
-
* @category Function
|
|
835
|
-
*/
|
|
836
|
-
function getHandlersDecorators(model, decorators, prefix) {
|
|
837
|
-
const accum = [];
|
|
838
|
-
for (const prop in decorators) {
|
|
839
|
-
const decs = decorators[prop];
|
|
840
|
-
for (const dec of decs) {
|
|
841
|
-
const { key } = dec;
|
|
842
|
-
const handlers = Operations.get(model, prop, prefix + key);
|
|
843
|
-
if (!handlers || !handlers.length)
|
|
844
|
-
throw new InternalError(`Could not find registered handler for the operation ${prefix + key} under property ${prop}`);
|
|
845
|
-
const handlerArgs = getHandlerArgs(dec, prop, model);
|
|
846
|
-
if (!handlerArgs || Object.values(handlerArgs).length !== handlers.length)
|
|
847
|
-
throw new InternalError("Args and handlers length do not match");
|
|
848
|
-
for (let i = 0; i < handlers.length; i++) {
|
|
849
|
-
const data = handlerArgs[handlers[i].name]
|
|
850
|
-
.data;
|
|
851
|
-
accum.push({
|
|
852
|
-
handler: handlers[i],
|
|
853
|
-
data: [data],
|
|
854
|
-
prop: [prop],
|
|
855
|
-
});
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
return accum;
|
|
860
|
-
}
|
|
861
|
-
/**
|
|
862
|
-
* @description Groups decorators based on their group property
|
|
863
|
-
* @summary Groups decorator objects by their group property, combining data and properties within each group
|
|
864
|
-
* @param {DecoratorObject[]} decorators - The array of decorator objects to group
|
|
865
|
-
* @return {DecoratorObject[]} An array of grouped decorator objects
|
|
866
|
-
* @function groupDecorators
|
|
867
|
-
* @category Function
|
|
868
|
-
*/
|
|
869
|
-
function groupDecorators(decorators) {
|
|
870
|
-
const grouped = decorators.reduce((acc, dec) => {
|
|
871
|
-
if (!dec || !dec.data || !dec.prop)
|
|
872
|
-
throw new InternalError("Missing decorator properties or data");
|
|
873
|
-
// If decorator have no group
|
|
874
|
-
if (!dec.data[0].group) {
|
|
875
|
-
acc.set(Symbol(), dec);
|
|
876
|
-
return acc;
|
|
877
|
-
}
|
|
878
|
-
const groupKey = dec.data[0].group;
|
|
879
|
-
if (!acc.has(groupKey)) {
|
|
880
|
-
// first handler is saved in the group
|
|
881
|
-
acc.set(groupKey, { ...dec });
|
|
882
|
-
}
|
|
883
|
-
else {
|
|
884
|
-
const existing = acc.get(groupKey);
|
|
885
|
-
acc.set(groupKey, {
|
|
886
|
-
handler: existing.handler,
|
|
887
|
-
data: [...existing.data, ...dec.data],
|
|
888
|
-
prop: [...existing.prop, ...dec.prop],
|
|
889
|
-
});
|
|
890
|
-
}
|
|
891
|
-
return acc;
|
|
892
|
-
}, new Map());
|
|
893
|
-
const groups = Array.from(grouped.values());
|
|
894
|
-
// Sort inside each group by priority
|
|
895
|
-
groups.forEach((group) => {
|
|
896
|
-
const combined = group.data.map((d, i) => ({
|
|
897
|
-
data: d,
|
|
898
|
-
prop: group.prop[i],
|
|
899
|
-
}));
|
|
900
|
-
combined.sort((a, b) => (a.data.groupPriority ?? 50) - (b.data.groupPriority ?? 50));
|
|
901
|
-
group.data = combined.map((c) => c.data);
|
|
902
|
-
group.prop = combined.map((c) => c.prop);
|
|
903
|
-
});
|
|
904
|
-
return groups;
|
|
905
|
-
}
|
|
906
|
-
/**
|
|
907
|
-
* @description Sorts decorator objects based on their priority
|
|
908
|
-
* @summary Sorts an array of decorator objects by the priority of their first data element
|
|
909
|
-
* @param {DecoratorObject[]} decorators - The array of decorator objects to sort
|
|
910
|
-
* @return {DecoratorObject[]} The sorted array of decorator objects
|
|
911
|
-
* @function sortDecorators
|
|
912
|
-
* @category Function
|
|
913
|
-
*/
|
|
914
|
-
function sortDecorators(decorators) {
|
|
915
|
-
// Sort by groupPriority
|
|
916
|
-
decorators.sort((a, b) => {
|
|
917
|
-
const priorityA = a.data[0].priority ?? defaultPriority;
|
|
918
|
-
const priorityB = b.data[0].priority ?? defaultPriority;
|
|
919
|
-
return priorityA - priorityB; // lower number = higher priority
|
|
920
|
-
});
|
|
921
|
-
return decorators;
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* @description Decorator for handling create and update operations
|
|
925
|
-
* @summary Defines a behavior to execute during both create and update operations
|
|
926
|
-
* @template V - Type for metadata, defaults to object
|
|
927
|
-
* @param {GeneralOperationHandler<any, any, V, any, any> | GeneralUpdateOperationHandler<any, any, V, any, any>} handler - The method called upon the operation
|
|
928
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
929
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
930
|
-
* @function onCreateUpdate
|
|
931
|
-
* @category Property Decorators
|
|
932
|
-
*/
|
|
933
|
-
function onCreateUpdate(handler, data, groupsort) {
|
|
934
|
-
return on(DBOperations.CREATE_UPDATE, handler, data, groupsort);
|
|
935
|
-
}
|
|
936
|
-
/**
|
|
937
|
-
* @description Decorator for handling update operations
|
|
938
|
-
* @summary Defines a behavior to execute during update operations
|
|
939
|
-
* @template V - Type for metadata, defaults to object
|
|
940
|
-
* @param {UpdateOperationHandler<any, any, V, any>} handler - The method called upon the operation
|
|
941
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
942
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
943
|
-
* @function onUpdate
|
|
944
|
-
* @category Property Decorators
|
|
945
|
-
*/
|
|
946
|
-
function onUpdate(handler, data, groupsort) {
|
|
947
|
-
return on(DBOperations.UPDATE, handler, data, groupsort);
|
|
948
|
-
}
|
|
949
|
-
/**
|
|
950
|
-
* @description Decorator for handling create operations
|
|
951
|
-
* @summary Defines a behavior to execute during create operations
|
|
952
|
-
* @template V - Type for metadata, defaults to object
|
|
953
|
-
* @param {GeneralOperationHandler<any, any, V, any, any>} handler - The method called upon the operation
|
|
954
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
955
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
956
|
-
* @function onCreate
|
|
957
|
-
* @category Property Decorators
|
|
958
|
-
*/
|
|
959
|
-
function onCreate(handler, data, groupsort) {
|
|
960
|
-
return on(DBOperations.CREATE, handler, data, groupsort);
|
|
961
|
-
}
|
|
962
|
-
/**
|
|
963
|
-
* @description Decorator for handling read operations
|
|
964
|
-
* @summary Defines a behavior to execute during read operations
|
|
965
|
-
* @template V - Type for metadata, defaults to object
|
|
966
|
-
* @param {IdOperationHandler<any, any, V, any, any>} handler - The method called upon the operation
|
|
967
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
968
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
969
|
-
* @function onRead
|
|
970
|
-
* @category Property Decorators
|
|
971
|
-
*/
|
|
972
|
-
function onRead(handler, data, groupsort) {
|
|
973
|
-
return on(DBOperations.READ, handler, data, groupsort);
|
|
974
|
-
}
|
|
975
|
-
/**
|
|
976
|
-
* @description Decorator for handling delete operations
|
|
977
|
-
* @summary Defines a behavior to execute during delete operations
|
|
978
|
-
* @template V - Type for metadata, defaults to object
|
|
979
|
-
* @param {OperationHandler<any, any, V, any, any>} handler - The method called upon the operation
|
|
980
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
981
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
982
|
-
* @function onDelete
|
|
983
|
-
* @category Property Decorators
|
|
984
|
-
*/
|
|
985
|
-
function onDelete(handler, data, groupsort) {
|
|
986
|
-
return on(DBOperations.DELETE, handler, data, groupsort);
|
|
987
|
-
}
|
|
988
|
-
/**
|
|
989
|
-
* @description Decorator for handling all operation types
|
|
990
|
-
* @summary Defines a behavior to execute during any database operation
|
|
991
|
-
* @template V - Type for metadata, defaults to object
|
|
992
|
-
* @param {OperationHandler<any, any, V, any, any>} handler - The method called upon the operation
|
|
993
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
994
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
995
|
-
* @function onAny
|
|
996
|
-
* @category Property Decorators
|
|
997
|
-
*/
|
|
998
|
-
function onAny(handler, data, groupsort) {
|
|
999
|
-
return on(DBOperations.ALL, handler, data, groupsort);
|
|
1000
|
-
}
|
|
1001
|
-
/**
|
|
1002
|
-
* @description Base decorator for handling database operations
|
|
1003
|
-
* @summary Defines a behavior to execute during specified database operations
|
|
1004
|
-
* @template V - Type for metadata, defaults to object
|
|
1005
|
-
* @param {OperationKeys[] | DBOperations} [op=DBOperations.ALL] - One or more operation types to handle
|
|
1006
|
-
* @param {OperationHandler<any, any, V, any, any>} handler - The method called upon the operation
|
|
1007
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
1008
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
1009
|
-
* @function on
|
|
1010
|
-
* @category Property Decorators
|
|
1011
|
-
* @example
|
|
1012
|
-
* // Example usage:
|
|
1013
|
-
* class MyModel {
|
|
1014
|
-
* @on(DBOperations.CREATE, myHandler)
|
|
1015
|
-
* myProperty: string;
|
|
1016
|
-
* }
|
|
1017
|
-
*/
|
|
1018
|
-
function on(op = DBOperations.ALL, handler, data, groupsort) {
|
|
1019
|
-
return operation(OperationKeys.ON, op, handler, data, groupsort);
|
|
1020
|
-
}
|
|
1021
|
-
/**
|
|
1022
|
-
* @description Decorator for handling post-create and post-update operations
|
|
1023
|
-
* @summary Defines a behavior to execute after both create and update operations
|
|
1024
|
-
* @template V - Type for metadata, defaults to object
|
|
1025
|
-
* @param {StandardOperationHandler<any, any, V, any, any> | UpdateOperationHandler<any, any, V, any, any>} handler - The method called after the operation
|
|
1026
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
1027
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
1028
|
-
* @function afterCreateUpdate
|
|
1029
|
-
* @category Property Decorators
|
|
1030
|
-
*/
|
|
1031
|
-
function afterCreateUpdate(handler, data, groupsort) {
|
|
1032
|
-
return after(DBOperations.CREATE_UPDATE, handler, data, groupsort);
|
|
1033
|
-
}
|
|
1034
|
-
/**
|
|
1035
|
-
* @description Decorator for handling post-update operations
|
|
1036
|
-
* @summary Defines a behavior to execute after update operations
|
|
1037
|
-
* @template V - Type for metadata, defaults to object
|
|
1038
|
-
* @param {UpdateOperationHandler<any, any, V, any, any>} handler - The method called after the operation
|
|
1039
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
1040
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
1041
|
-
* @function afterUpdate
|
|
1042
|
-
* @category Property Decorators
|
|
1043
|
-
*/
|
|
1044
|
-
function afterUpdate(handler, data, groupsort) {
|
|
1045
|
-
return after(DBOperations.UPDATE, handler, data, groupsort);
|
|
1046
|
-
}
|
|
1047
|
-
/**
|
|
1048
|
-
* @description Decorator for handling post-create operations
|
|
1049
|
-
* @summary Defines a behavior to execute after create operations
|
|
1050
|
-
* @template V - Type for metadata, defaults to object
|
|
1051
|
-
* @param {StandardOperationHandler<any, any, V, any, any>} handler - The method called after the operation
|
|
1052
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
1053
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
1054
|
-
* @function afterCreate
|
|
1055
|
-
* @category Property Decorators
|
|
1056
|
-
*/
|
|
1057
|
-
function afterCreate(handler, data, groupsort) {
|
|
1058
|
-
return after(DBOperations.CREATE, handler, data, groupsort);
|
|
1059
|
-
}
|
|
1060
|
-
/**
|
|
1061
|
-
* @description Decorator for handling post-read operations
|
|
1062
|
-
* @summary Defines a behavior to execute after read operations
|
|
1063
|
-
* @template V - Type for metadata, defaults to object
|
|
1064
|
-
* @param {StandardOperationHandler<any, any, V, any, any>} handler - The method called after the operation
|
|
1065
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
1066
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
1067
|
-
* @function afterRead
|
|
1068
|
-
* @category Property Decorators
|
|
1069
|
-
*/
|
|
1070
|
-
function afterRead(handler, data, groupsort) {
|
|
1071
|
-
return after(DBOperations.READ, handler, data, groupsort);
|
|
1072
|
-
}
|
|
1073
|
-
/**
|
|
1074
|
-
* @description Decorator for handling post-delete operations
|
|
1075
|
-
* @summary Defines a behavior to execute after delete operations
|
|
1076
|
-
* @template V - Type for metadata, defaults to object
|
|
1077
|
-
* @param {StandardOperationHandler<any, any, V, any, any>} handler - The method called after the operation
|
|
1078
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
1079
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
1080
|
-
* @function afterDelete
|
|
1081
|
-
* @category Property Decorators
|
|
1082
|
-
*/
|
|
1083
|
-
function afterDelete(handler, data, groupsort) {
|
|
1084
|
-
return after(DBOperations.DELETE, handler, data, groupsort);
|
|
1085
|
-
}
|
|
1086
|
-
/**
|
|
1087
|
-
* @description Decorator for handling post-operation for all operation types
|
|
1088
|
-
* @summary Defines a behavior to execute after any database operation
|
|
1089
|
-
* @template V - Type for metadata, defaults to object
|
|
1090
|
-
* @param {StandardOperationHandler<any, any, V, any, any>} handler - The method called after the operation
|
|
1091
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
1092
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
1093
|
-
* @function afterAny
|
|
1094
|
-
* @category Property Decorators
|
|
1095
|
-
*/
|
|
1096
|
-
function afterAny(handler, data, groupsort) {
|
|
1097
|
-
return after(DBOperations.ALL, handler, data, groupsort);
|
|
1098
|
-
}
|
|
1099
|
-
/**
|
|
1100
|
-
* @description Base decorator for handling post-operation behaviors
|
|
1101
|
-
* @summary Defines a behavior to execute after specified database operations
|
|
1102
|
-
* @template V - Type for metadata, defaults to object
|
|
1103
|
-
* @param {OperationKeys[] | DBOperations} [op=DBOperations.ALL] - One or more operation types to handle
|
|
1104
|
-
* @param {OperationHandler<any, any, V, any, any>} handler - The method called after the operation
|
|
1105
|
-
* @param {V} [data] - Optional metadata to pass to the handler
|
|
1106
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
1107
|
-
* @function after
|
|
1108
|
-
* @category Property Decorators
|
|
1109
|
-
* @example
|
|
1110
|
-
* // Example usage:
|
|
1111
|
-
* class MyModel {
|
|
1112
|
-
* @after(DBOperations.CREATE, myHandler)
|
|
1113
|
-
* myProperty: string;
|
|
1114
|
-
* }
|
|
1115
|
-
*/
|
|
1116
|
-
function after(op = DBOperations.ALL, handler, data, groupsort) {
|
|
1117
|
-
return operation(OperationKeys.AFTER, op, handler, data, groupsort);
|
|
1118
|
-
}
|
|
1119
|
-
/**
|
|
1120
|
-
* @description Core decorator factory for operation handlers
|
|
1121
|
-
* @summary Creates decorators that register handlers for database operations
|
|
1122
|
-
* @template V - Type for metadata, defaults to object
|
|
1123
|
-
* @param {OperationKeys.ON | OperationKeys.AFTER} baseOp - Whether the handler runs during or after the operation
|
|
1124
|
-
* @param {OperationKeys[]} [operation=DBOperations.ALL] - The specific operations to handle
|
|
1125
|
-
* @param {OperationHandler<any, any, V, any, any>} handler - The handler function to execute
|
|
1126
|
-
* @param {V} [dataToAdd] - Optional metadata to pass to the handler
|
|
1127
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
1128
|
-
* @function operation
|
|
1129
|
-
* @category Property Decorators
|
|
1130
|
-
* @mermaid
|
|
1131
|
-
* sequenceDiagram
|
|
1132
|
-
* participant Client
|
|
1133
|
-
* participant Decorator as @operation
|
|
1134
|
-
* participant Operations as Operations Registry
|
|
1135
|
-
* participant Handler
|
|
1136
|
-
*
|
|
1137
|
-
* Client->>Decorator: Apply to property
|
|
1138
|
-
* Decorator->>Operations: Register handler
|
|
1139
|
-
* Decorator->>Decorator: Store metadata
|
|
1140
|
-
*
|
|
1141
|
-
* Note over Client,Handler: Later, during operation execution
|
|
1142
|
-
* Client->>Operations: Execute operation
|
|
1143
|
-
* Operations->>Handler: Call registered handler
|
|
1144
|
-
* Handler-->>Operations: Return result
|
|
1145
|
-
* Operations-->>Client: Return final result
|
|
1146
|
-
*/
|
|
1147
|
-
function operation(baseOp, operation = DBOperations.ALL, handler, dataToAdd, groupsort = DefaultGroupSort) {
|
|
1148
|
-
return (target, propertyKey) => {
|
|
1149
|
-
const name = target.constructor.name;
|
|
1150
|
-
const decorators = operation.reduce((accum, op) => {
|
|
1151
|
-
const compoundKey = baseOp + op;
|
|
1152
|
-
let data = Reflect.getMetadata(Operations.key(compoundKey), target, propertyKey);
|
|
1153
|
-
if (!data)
|
|
1154
|
-
data = {
|
|
1155
|
-
operation: op,
|
|
1156
|
-
handlers: {},
|
|
1157
|
-
};
|
|
1158
|
-
const handlerKey = Operations.getHandlerName(handler);
|
|
1159
|
-
let mergeData = groupsort;
|
|
1160
|
-
if (dataToAdd) {
|
|
1161
|
-
if (Object.keys(dataToAdd).filter((key) => key in groupsort).length > 0)
|
|
1162
|
-
throw new InternalError(`Unable to merge groupSort into dataToAdd due to overlaping keys`);
|
|
1163
|
-
mergeData = { ...groupsort, ...dataToAdd };
|
|
1164
|
-
}
|
|
1165
|
-
if (!data.handlers[name] ||
|
|
1166
|
-
!data.handlers[name][propertyKey] ||
|
|
1167
|
-
!(handlerKey in data.handlers[name][propertyKey])) {
|
|
1168
|
-
data.handlers[name] = data.handlers[name] || {};
|
|
1169
|
-
data.handlers[name][propertyKey] =
|
|
1170
|
-
data.handlers[name][propertyKey] || {};
|
|
1171
|
-
data.handlers[name][propertyKey][handlerKey] = {
|
|
1172
|
-
data: mergeData,
|
|
1173
|
-
};
|
|
1174
|
-
accum.push(handle(compoundKey, handler), propMetadata(Operations.key(compoundKey), data));
|
|
1175
|
-
}
|
|
1176
|
-
return accum;
|
|
1177
|
-
}, []);
|
|
1178
|
-
return apply(...decorators)(target, propertyKey);
|
|
1179
|
-
};
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
/**
|
|
1183
|
-
* @description Default configuration flags for repository operations.
|
|
1184
|
-
* @summary Provides default values for repository operation flags, excluding the timestamp property.
|
|
1185
|
-
* These flags control behavior such as context handling, validation, error handling, and more.
|
|
1186
|
-
* @const DefaultRepositoryFlags
|
|
1187
|
-
* @memberOf module:db-decorators
|
|
1188
|
-
*/
|
|
1189
|
-
const DefaultRepositoryFlags = {
|
|
1190
|
-
parentContext: undefined,
|
|
1191
|
-
childContexts: [],
|
|
1192
|
-
ignoredValidationProperties: [],
|
|
1193
|
-
callArgs: [],
|
|
1194
|
-
writeOperation: false,
|
|
1195
|
-
affectedTables: [],
|
|
1196
|
-
operation: undefined,
|
|
1197
|
-
breakOnHandlerError: true,
|
|
1198
|
-
rebuildWithTransient: true,
|
|
1199
|
-
};
|
|
1200
|
-
|
|
1201
|
-
/**
|
|
1202
|
-
* @description Default factory for creating context instances.
|
|
1203
|
-
* @summary A factory function that creates new Context instances with the provided repository flags.
|
|
1204
|
-
* It automatically adds a timestamp to the context and returns a properly typed context instance.
|
|
1205
|
-
* @const DefaultContextFactory
|
|
1206
|
-
* @memberOf module:db-decorators
|
|
1207
|
-
*/
|
|
1208
|
-
const DefaultContextFactory = (arg) => {
|
|
1209
|
-
return new Context().accumulate(Object.assign({}, arg, { timestamp: new Date() }));
|
|
1210
|
-
};
|
|
1211
|
-
/**
|
|
1212
|
-
* @description A context management class for handling repository operations.
|
|
1213
|
-
* @summary The Context class provides a mechanism for managing repository operations with flags,
|
|
1214
|
-
* parent-child relationships, and state accumulation. It allows for hierarchical context chains
|
|
1215
|
-
* and maintains operation-specific configurations while supporting type safety through generics.
|
|
1216
|
-
*
|
|
1217
|
-
* @template F - Type extending RepositoryFlags that defines the context configuration
|
|
1218
|
-
*
|
|
1219
|
-
* @param {ObjectAccumulator<F>} cache - The internal cache storing accumulated values
|
|
1220
|
-
*
|
|
1221
|
-
* @class
|
|
1222
|
-
*
|
|
1223
|
-
* @example
|
|
1224
|
-
* ```typescript
|
|
1225
|
-
* // Creating a new context with repository flags
|
|
1226
|
-
* const context = new Context<RepositoryFlags>();
|
|
1227
|
-
*
|
|
1228
|
-
* // Accumulating values
|
|
1229
|
-
* const enrichedContext = context.accumulate({
|
|
1230
|
-
* writeOperation: true,
|
|
1231
|
-
* affectedTables: ['users'],
|
|
1232
|
-
* operation: OperationKeys.CREATE
|
|
1233
|
-
* });
|
|
1234
|
-
*
|
|
1235
|
-
* // Accessing values
|
|
1236
|
-
* const isWrite = enrichedContext.get('writeOperation'); // true
|
|
1237
|
-
* const tables = enrichedContext.get('affectedTables'); // ['users']
|
|
1238
|
-
* ```
|
|
1239
|
-
*
|
|
1240
|
-
* @mermaid
|
|
1241
|
-
* sequenceDiagram
|
|
1242
|
-
* participant C as Client
|
|
1243
|
-
* participant Ctx as Context
|
|
1244
|
-
* participant Cache as ObjectAccumulator
|
|
1245
|
-
*
|
|
1246
|
-
* C->>Ctx: new Context()
|
|
1247
|
-
* Ctx->>Cache: create cache
|
|
1248
|
-
*
|
|
1249
|
-
* C->>Ctx: accumulate(value)
|
|
1250
|
-
* Ctx->>Cache: accumulate(value)
|
|
1251
|
-
* Cache-->>Ctx: updated cache
|
|
1252
|
-
* Ctx-->>C: updated context
|
|
1253
|
-
*
|
|
1254
|
-
* C->>Ctx: get(key)
|
|
1255
|
-
* Ctx->>Cache: get(key)
|
|
1256
|
-
* alt Key exists in cache
|
|
1257
|
-
* Cache-->>Ctx: value
|
|
1258
|
-
* else Key not found
|
|
1259
|
-
* Ctx->>Ctx: check parent context
|
|
1260
|
-
* alt Parent exists
|
|
1261
|
-
* Ctx->>Parent: get(key)
|
|
1262
|
-
* Parent-->>Ctx: value
|
|
1263
|
-
* else No parent
|
|
1264
|
-
* Ctx-->>C: throw error
|
|
1265
|
-
* end
|
|
1266
|
-
* end
|
|
1267
|
-
* Ctx-->>C: requested value
|
|
1268
|
-
*/
|
|
1269
|
-
class Context {
|
|
1270
|
-
constructor() {
|
|
1271
|
-
this.cache = new ObjectAccumulator();
|
|
1272
|
-
Object.defineProperty(this, "cache", {
|
|
1273
|
-
value: new ObjectAccumulator(),
|
|
1274
|
-
writable: false,
|
|
1275
|
-
enumerable: false,
|
|
1276
|
-
configurable: true,
|
|
1277
|
-
});
|
|
1278
|
-
}
|
|
1279
|
-
static { this.factory = DefaultContextFactory; }
|
|
1280
|
-
/**
|
|
1281
|
-
* @description Accumulates new values into the context.
|
|
1282
|
-
* @summary Merges the provided value object with the existing context state,
|
|
1283
|
-
* creating a new immutable cache state.
|
|
1284
|
-
*/
|
|
1285
|
-
accumulate(value) {
|
|
1286
|
-
Object.defineProperty(this, "cache", {
|
|
1287
|
-
value: this.cache.accumulate(value),
|
|
1288
|
-
writable: false,
|
|
1289
|
-
enumerable: false,
|
|
1290
|
-
configurable: true,
|
|
1291
|
-
});
|
|
1292
|
-
return this;
|
|
1293
|
-
}
|
|
1294
|
-
get timestamp() {
|
|
1295
|
-
return this.cache.timestamp;
|
|
1296
|
-
}
|
|
1297
|
-
/**
|
|
1298
|
-
* @description Retrieves a value from the context by key.
|
|
1299
|
-
* @param {string} key
|
|
1300
|
-
* @return {any}
|
|
1301
|
-
*/
|
|
1302
|
-
get(key) {
|
|
1303
|
-
try {
|
|
1304
|
-
return this.cache.get(key);
|
|
1305
|
-
}
|
|
1306
|
-
catch (e) {
|
|
1307
|
-
const parent = this.cache.parentContext;
|
|
1308
|
-
if (parent)
|
|
1309
|
-
return parent.get(key);
|
|
1310
|
-
throw e;
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
/**
|
|
1314
|
-
* @description Creates a child context from another context
|
|
1315
|
-
*/
|
|
1316
|
-
static childFrom(context, overrides) {
|
|
1317
|
-
return Context.factory(Object.assign({}, context.cache, overrides || {}));
|
|
1318
|
-
}
|
|
1319
|
-
/**
|
|
1320
|
-
* @description Creates a new context from operation parameters
|
|
1321
|
-
*/
|
|
1322
|
-
static async from(operation, overrides, model,
|
|
1323
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1324
|
-
...args) {
|
|
1325
|
-
return Context.factory(Object.assign({}, DefaultRepositoryFlags, overrides, {
|
|
1326
|
-
operation: operation,
|
|
1327
|
-
model: model,
|
|
1328
|
-
}));
|
|
1329
|
-
}
|
|
1330
|
-
/**
|
|
1331
|
-
* @description Prepares arguments for context operations
|
|
1332
|
-
*/
|
|
1333
|
-
static async args(operation, model, args, contextual, overrides) {
|
|
1334
|
-
const last = args.pop();
|
|
1335
|
-
async function getContext() {
|
|
1336
|
-
if (contextual)
|
|
1337
|
-
return contextual.context(operation, overrides || {}, model, ...args);
|
|
1338
|
-
return Context.from(operation, overrides || {}, model, ...args);
|
|
1339
|
-
}
|
|
1340
|
-
let c;
|
|
1341
|
-
if (last) {
|
|
1342
|
-
if (last instanceof Context) {
|
|
1343
|
-
c = last;
|
|
1344
|
-
args.push(last);
|
|
1345
|
-
}
|
|
1346
|
-
else {
|
|
1347
|
-
args.push(last);
|
|
1348
|
-
c = (await getContext());
|
|
1349
|
-
args.push(c);
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
else {
|
|
1353
|
-
c = (await getContext());
|
|
1354
|
-
args.push(c);
|
|
1355
|
-
}
|
|
1356
|
-
return { context: c, args: args };
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
/**
|
|
1361
|
-
* @summary Util method to change a method of an object prefixing it with another
|
|
1362
|
-
* @param {any} obj The Base Object
|
|
1363
|
-
* @param {Function} after The original method
|
|
1364
|
-
* @param {Function} prefix The Prefix method. The output will be used as arguments in the original method
|
|
1365
|
-
* @param {string} [afterName] When the after function anme cannot be extracted, pass it here
|
|
1366
|
-
*
|
|
1367
|
-
* @function prefixMethod
|
|
1368
|
-
*
|
|
1369
|
-
* @memberOf module:db-decorators
|
|
1370
|
-
*/
|
|
1371
|
-
function prefixMethod(obj, after, prefix, afterName) {
|
|
1372
|
-
async function wrapper(...args) {
|
|
1373
|
-
const results = await Promise.resolve(prefix.call(this, ...args));
|
|
1374
|
-
return Promise.resolve(after.apply(this, results));
|
|
1375
|
-
}
|
|
1376
|
-
const wrapped = wrapper.bind(obj);
|
|
1377
|
-
const name = afterName ? afterName : after.name;
|
|
1378
|
-
Object.defineProperty(wrapped, "name", {
|
|
1379
|
-
enumerable: true,
|
|
1380
|
-
configurable: true,
|
|
1381
|
-
writable: false,
|
|
1382
|
-
value: name,
|
|
1383
|
-
});
|
|
1384
|
-
obj[name] = wrapped;
|
|
1385
|
-
}
|
|
1386
|
-
/**
|
|
1387
|
-
* @summary Util method to change a method of an object suffixing it with another
|
|
1388
|
-
* @param {any} obj The Base Object
|
|
1389
|
-
* @param {Function} before The original method
|
|
1390
|
-
* @param {Function} suffix The Prefix method. The output will be used as arguments in the original method
|
|
1391
|
-
* @param {string} [beforeName] When the after function anme cannot be extracted, pass it here
|
|
1392
|
-
*
|
|
1393
|
-
* @function suffixMethod
|
|
1394
|
-
*
|
|
1395
|
-
* @memberOf module:db-decorators.Repository
|
|
1396
|
-
*/
|
|
1397
|
-
function suffixMethod(obj, before, suffix, beforeName) {
|
|
1398
|
-
async function wrapper(...args) {
|
|
1399
|
-
const results = await Promise.resolve(before.call(this, ...args));
|
|
1400
|
-
return suffix.call(this, ...results);
|
|
1401
|
-
}
|
|
1402
|
-
const wrapped = wrapper.bind(obj);
|
|
1403
|
-
const name = beforeName ? beforeName : before.name;
|
|
1404
|
-
Object.defineProperty(wrapped, "name", {
|
|
1405
|
-
enumerable: true,
|
|
1406
|
-
configurable: true,
|
|
1407
|
-
writable: false,
|
|
1408
|
-
value: name,
|
|
1409
|
-
});
|
|
1410
|
-
obj[name] = wrapped;
|
|
1411
|
-
}
|
|
1412
|
-
/**
|
|
1413
|
-
* @summary Util method to wrap a method of an object with additional logic
|
|
1414
|
-
*
|
|
1415
|
-
* @param {any} obj The Base Object
|
|
1416
|
-
* @param {Function} before the method to be prefixed
|
|
1417
|
-
* @param {Function} method the method to be wrapped
|
|
1418
|
-
* @param {Function} after The method to be suffixed
|
|
1419
|
-
* @param {string} [methodName] When the after function anme cannot be extracted, pass it here
|
|
1420
|
-
*
|
|
1421
|
-
* @function wrapMethodWithContext
|
|
1422
|
-
*
|
|
1423
|
-
* @memberOf module:db-decorators
|
|
1424
|
-
*/
|
|
1425
|
-
function wrapMethodWithContext(obj, before, method, after, methodName) {
|
|
1426
|
-
const name = methodName ? methodName : method.name;
|
|
1427
|
-
obj[name] = new Proxy(obj[name], {
|
|
1428
|
-
apply: async (target, thisArg, argArray) => {
|
|
1429
|
-
let transformedArgs = before.call(thisArg, ...argArray);
|
|
1430
|
-
if (transformedArgs instanceof Promise)
|
|
1431
|
-
transformedArgs = await transformedArgs;
|
|
1432
|
-
const context = transformedArgs[transformedArgs.length - 1];
|
|
1433
|
-
if (!(context instanceof Context))
|
|
1434
|
-
throw new InternalError("Missing a context");
|
|
1435
|
-
let results = await target.call(thisArg, ...transformedArgs);
|
|
1436
|
-
if (results instanceof Promise)
|
|
1437
|
-
results = await results;
|
|
1438
|
-
results = after.call(thisArg, results, context);
|
|
1439
|
-
if (results instanceof Promise)
|
|
1440
|
-
results = await results;
|
|
1441
|
-
return results;
|
|
1442
|
-
},
|
|
1443
|
-
});
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
/**
|
|
1447
|
-
* @description Finds the primary key attribute for a model
|
|
1448
|
-
* @summary Searches in all the properties in the object for an {@link id} decorated property and returns the property key and metadata
|
|
1449
|
-
* @param {Model} model - The model object to search for primary key
|
|
1450
|
-
* @return {Object} An object containing the id property name and its metadata
|
|
1451
|
-
* @function findPrimaryKey
|
|
1452
|
-
* @mermaid
|
|
1453
|
-
* sequenceDiagram
|
|
1454
|
-
* participant Caller
|
|
1455
|
-
* participant findPrimaryKey
|
|
1456
|
-
* participant getAllPropertyDecoratorsRecursive
|
|
1457
|
-
*
|
|
1458
|
-
* Caller->>findPrimaryKey: model
|
|
1459
|
-
* findPrimaryKey->>getAllPropertyDecoratorsRecursive: get decorators
|
|
1460
|
-
* getAllPropertyDecoratorsRecursive-->>findPrimaryKey: decorators
|
|
1461
|
-
* findPrimaryKey->>findPrimaryKey: filter ID decorators
|
|
1462
|
-
* findPrimaryKey->>findPrimaryKey: validate single ID property
|
|
1463
|
-
* findPrimaryKey-->>Caller: {id, props}
|
|
1464
|
-
* @memberOf module:db-decorators
|
|
1465
|
-
*/
|
|
1466
|
-
function findPrimaryKey(model) {
|
|
1467
|
-
const decorators = getAllPropertyDecoratorsRecursive(model, undefined, DBKeys.REFLECT + DBKeys.ID);
|
|
1468
|
-
const idDecorators = Object.entries(decorators).reduce((accum, [prop, decs]) => {
|
|
1469
|
-
const filtered = decs.filter((d) => d.key !== ModelKeys.TYPE);
|
|
1470
|
-
if (filtered && filtered.length) {
|
|
1471
|
-
accum[prop] = accum[prop] || [];
|
|
1472
|
-
accum[prop].push(...filtered);
|
|
1473
|
-
}
|
|
1474
|
-
return accum;
|
|
1475
|
-
}, {});
|
|
1476
|
-
if (!idDecorators || !Object.keys(idDecorators).length)
|
|
1477
|
-
throw new InternalError("Could not find ID decorated Property");
|
|
1478
|
-
if (Object.keys(idDecorators).length > 1)
|
|
1479
|
-
throw new InternalError(sf(Object.keys(idDecorators).join(", ")));
|
|
1480
|
-
const idProp = Object.keys(idDecorators)[0];
|
|
1481
|
-
if (!idProp)
|
|
1482
|
-
throw new InternalError("Could not find ID decorated Property");
|
|
1483
|
-
return {
|
|
1484
|
-
id: idProp,
|
|
1485
|
-
props: idDecorators[idProp][0].props,
|
|
1486
|
-
};
|
|
1487
|
-
}
|
|
1488
|
-
/**
|
|
1489
|
-
* @description Retrieves the primary key value from a model
|
|
1490
|
-
* @summary Searches for the ID-decorated property in the model and returns its value
|
|
1491
|
-
* @param {Model} model - The model object to extract the ID from
|
|
1492
|
-
* @param {boolean} [returnEmpty=false] - Whether to return undefined if no ID value is found
|
|
1493
|
-
* @return {string | number | bigint} The primary key value
|
|
1494
|
-
* @function findModelId
|
|
1495
|
-
* @mermaid
|
|
1496
|
-
* sequenceDiagram
|
|
1497
|
-
* participant Caller
|
|
1498
|
-
* participant findModelId
|
|
1499
|
-
* participant findPrimaryKey
|
|
1500
|
-
*
|
|
1501
|
-
* Caller->>findModelId: model, returnEmpty
|
|
1502
|
-
* findModelId->>findPrimaryKey: model
|
|
1503
|
-
* findPrimaryKey-->>findModelId: {id, props}
|
|
1504
|
-
* findModelId->>findModelId: extract model[id]
|
|
1505
|
-
* findModelId->>findModelId: validate ID exists if required
|
|
1506
|
-
* findModelId-->>Caller: ID value
|
|
1507
|
-
* @memberOf module:db-decorators
|
|
1508
|
-
*/
|
|
1509
|
-
function findModelId(model, returnEmpty = false) {
|
|
1510
|
-
const idProp = findPrimaryKey(model).id;
|
|
1511
|
-
const modelId = model[idProp];
|
|
1512
|
-
if (typeof modelId === "undefined" && !returnEmpty)
|
|
1513
|
-
throw new InternalError(`No value for the Id is defined under the property ${idProp}`);
|
|
1514
|
-
return modelId;
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
/**
|
|
1518
|
-
* @description Base repository implementation providing CRUD operations for models.
|
|
1519
|
-
* @summary The BaseRepository class serves as a foundation for repository implementations, providing
|
|
1520
|
-
* abstract and concrete methods for creating, reading, updating, and deleting model instances.
|
|
1521
|
-
* It handles operation lifecycles including prefix and suffix operations, and enforces decorators.
|
|
1522
|
-
* @template M - The model type extending Model
|
|
1523
|
-
* @template F - The repository flags type, defaults to RepositoryFlags
|
|
1524
|
-
* @template C - The context type, defaults to Context<F>
|
|
1525
|
-
* @param {Constructor<M>} clazz - The constructor for the model class
|
|
1526
|
-
* @class BaseRepository
|
|
1527
|
-
* @example
|
|
1528
|
-
* class UserModel extends Model {
|
|
1529
|
-
* @id()
|
|
1530
|
-
* id: string;
|
|
1531
|
-
*
|
|
1532
|
-
* @required()
|
|
1533
|
-
* name: string;
|
|
1534
|
-
* }
|
|
1535
|
-
*
|
|
1536
|
-
* class UserRepository extends BaseRepository<UserModel> {
|
|
1537
|
-
* constructor() {
|
|
1538
|
-
* super(UserModel);
|
|
1539
|
-
* }
|
|
1540
|
-
*
|
|
1541
|
-
* async create(model: UserModel): Promise<UserModel> {
|
|
1542
|
-
* // Implementation
|
|
1543
|
-
* return model;
|
|
1544
|
-
* }
|
|
1545
|
-
*
|
|
1546
|
-
* async read(key: string): Promise<UserModel> {
|
|
1547
|
-
* // Implementation
|
|
1548
|
-
* return new UserModel({ id: key, name: 'User' });
|
|
1549
|
-
* }
|
|
1550
|
-
*
|
|
1551
|
-
* async update(model: UserModel): Promise<UserModel> {
|
|
1552
|
-
* // Implementation
|
|
1553
|
-
* return model;
|
|
1554
|
-
* }
|
|
1555
|
-
*
|
|
1556
|
-
* async delete(key: string): Promise<UserModel> {
|
|
1557
|
-
* // Implementation
|
|
1558
|
-
* const model = await this.read(key);
|
|
1559
|
-
* return model;
|
|
1560
|
-
* }
|
|
1561
|
-
* }
|
|
1562
|
-
*
|
|
1563
|
-
* @mermaid
|
|
1564
|
-
* sequenceDiagram
|
|
1565
|
-
* participant C as Client
|
|
1566
|
-
* participant R as Repository
|
|
1567
|
-
* participant P as Prefix Methods
|
|
1568
|
-
* participant D as Database
|
|
1569
|
-
* participant S as Suffix Methods
|
|
1570
|
-
* participant V as Validators/Decorators
|
|
1571
|
-
*
|
|
1572
|
-
* Note over C,V: Create Operation
|
|
1573
|
-
* C->>R: create(model)
|
|
1574
|
-
* R->>P: createPrefix(model)
|
|
1575
|
-
* P->>V: enforceDBDecorators(ON)
|
|
1576
|
-
* P->>D: Database operation
|
|
1577
|
-
* D->>S: createSuffix(model)
|
|
1578
|
-
* S->>V: enforceDBDecorators(AFTER)
|
|
1579
|
-
* S->>C: Return model
|
|
1580
|
-
*
|
|
1581
|
-
* Note over C,V: Read Operation
|
|
1582
|
-
* C->>R: read(key)
|
|
1583
|
-
* R->>P: readPrefix(key)
|
|
1584
|
-
* P->>V: enforceDBDecorators(ON)
|
|
1585
|
-
* P->>D: Database operation
|
|
1586
|
-
* D->>S: readSuffix(model)
|
|
1587
|
-
* S->>V: enforceDBDecorators(AFTER)
|
|
1588
|
-
* S->>C: Return model
|
|
1589
|
-
*
|
|
1590
|
-
* Note over C,V: Update Operation
|
|
1591
|
-
* C->>R: update(model)
|
|
1592
|
-
* R->>P: updatePrefix(model)
|
|
1593
|
-
* P->>V: enforceDBDecorators(ON)
|
|
1594
|
-
* P->>D: Database operation
|
|
1595
|
-
* D->>S: updateSuffix(model)
|
|
1596
|
-
* S->>V: enforceDBDecorators(AFTER)
|
|
1597
|
-
* S->>C: Return model
|
|
1598
|
-
*
|
|
1599
|
-
* Note over C,V: Delete Operation
|
|
1600
|
-
* C->>R: delete(key)
|
|
1601
|
-
* R->>P: deletePrefix(key)
|
|
1602
|
-
* P->>V: enforceDBDecorators(ON)
|
|
1603
|
-
* P->>D: Database operation
|
|
1604
|
-
* D->>S: deleteSuffix(model)
|
|
1605
|
-
* S->>V: enforceDBDecorators(AFTER)
|
|
1606
|
-
* S->>C: Return model
|
|
1607
|
-
*/
|
|
1608
|
-
class BaseRepository {
|
|
1609
|
-
/**
|
|
1610
|
-
* @description Gets the model class constructor.
|
|
1611
|
-
* @summary Retrieves the constructor for the model class associated with this repository.
|
|
1612
|
-
* Throws an error if no class definition is found.
|
|
1613
|
-
* @return {Constructor<M>} The constructor for the model class
|
|
1614
|
-
*/
|
|
1615
|
-
get class() {
|
|
1616
|
-
if (!this._class)
|
|
1617
|
-
throw new InternalError(`No class definition found for this repository`);
|
|
1618
|
-
return this._class;
|
|
1619
|
-
}
|
|
1620
|
-
/**
|
|
1621
|
-
* @description Gets the primary key property name of the model.
|
|
1622
|
-
* @summary Retrieves the name of the property that serves as the primary key for the model.
|
|
1623
|
-
* If not already determined, it finds the primary key using the model's decorators.
|
|
1624
|
-
* @return The name of the primary key property
|
|
1625
|
-
*/
|
|
1626
|
-
get pk() {
|
|
1627
|
-
if (!this._pk) {
|
|
1628
|
-
const { id, props } = findPrimaryKey(new this.class());
|
|
1629
|
-
this._pk = id;
|
|
1630
|
-
this._pkProps = props;
|
|
1631
|
-
}
|
|
1632
|
-
return this._pk;
|
|
1633
|
-
}
|
|
1634
|
-
/**
|
|
1635
|
-
* @description Gets the primary key properties.
|
|
1636
|
-
* @summary Retrieves the properties associated with the primary key of the model.
|
|
1637
|
-
* If not already determined, it triggers the pk getter to find the primary key properties.
|
|
1638
|
-
* @return {any} The properties of the primary key
|
|
1639
|
-
*/
|
|
1640
|
-
get pkProps() {
|
|
1641
|
-
if (!this._pkProps) {
|
|
1642
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1643
|
-
this.pk;
|
|
1644
|
-
}
|
|
1645
|
-
return this._pkProps;
|
|
1646
|
-
}
|
|
1647
|
-
constructor(clazz) {
|
|
1648
|
-
if (clazz)
|
|
1649
|
-
this._class = clazz;
|
|
1650
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1651
|
-
const self = this;
|
|
1652
|
-
[this.create, this.read, this.update, this.delete].forEach((m) => {
|
|
1653
|
-
const name = m.name;
|
|
1654
|
-
wrapMethodWithContext(self, self[name + "Prefix"], m, self[name + "Suffix"]);
|
|
1655
|
-
});
|
|
1656
|
-
}
|
|
1657
|
-
/**
|
|
1658
|
-
* @description Creates multiple model instances in the repository.
|
|
1659
|
-
* @summary Persists multiple model instances to the underlying data store by calling
|
|
1660
|
-
* the create method for each model in the array.
|
|
1661
|
-
* @param {M[]} models - The array of model instances to create
|
|
1662
|
-
* @param {any[]} args - Additional arguments for the create operation
|
|
1663
|
-
* @return {Promise<M[]>} A promise that resolves to an array of created model instances
|
|
1664
|
-
*/
|
|
1665
|
-
async createAll(models, ...args) {
|
|
1666
|
-
return Promise.all(models.map((m) => this.create(m, ...args)));
|
|
1667
|
-
}
|
|
1668
|
-
/**
|
|
1669
|
-
* @description Prepares a model for creation and executes pre-creation operations.
|
|
1670
|
-
* @summary Processes a model before it is created in the data store. This includes
|
|
1671
|
-
* creating a context, instantiating a new model instance, and enforcing any decorators
|
|
1672
|
-
* that should be applied before creation.
|
|
1673
|
-
* @param {M} model - The model instance to prepare for creation
|
|
1674
|
-
* @param {any[]} args - Additional arguments for the create operation
|
|
1675
|
-
* @return A promise that resolves to an array containing the prepared model and context arguments
|
|
1676
|
-
*/
|
|
1677
|
-
async createPrefix(model, ...args) {
|
|
1678
|
-
const contextArgs = await Context.args(OperationKeys.CREATE, this.class, args);
|
|
1679
|
-
model = new this.class(model);
|
|
1680
|
-
await enforceDBDecorators(this, contextArgs.context, model, OperationKeys.CREATE, OperationKeys.ON);
|
|
1681
|
-
return [model, ...contextArgs.args];
|
|
1682
|
-
}
|
|
1683
|
-
/**
|
|
1684
|
-
* @description Processes a model after creation and executes post-creation operations.
|
|
1685
|
-
* @summary Finalizes a model after it has been created in the data store. This includes
|
|
1686
|
-
* enforcing any decorators that should be applied after creation.
|
|
1687
|
-
* @param {M} model - The model instance that was created
|
|
1688
|
-
* @param {C} context - The context for the operation
|
|
1689
|
-
* @return {Promise<M>} A promise that resolves to the processed model instance
|
|
1690
|
-
*/
|
|
1691
|
-
async createSuffix(model, context) {
|
|
1692
|
-
await enforceDBDecorators(this, context, model, OperationKeys.CREATE, OperationKeys.AFTER);
|
|
1693
|
-
return model;
|
|
1694
|
-
}
|
|
1695
|
-
/**
|
|
1696
|
-
* @description Prepares multiple models for creation and executes pre-creation operations.
|
|
1697
|
-
* @summary Processes multiple models before they are created in the data store. This includes
|
|
1698
|
-
* creating a context, instantiating new model instances, and enforcing any decorators
|
|
1699
|
-
* that should be applied before creation for each model.
|
|
1700
|
-
* @param {M[]} models - The array of model instances to prepare for creation
|
|
1701
|
-
* @param {any[]} args - Additional arguments for the create operation
|
|
1702
|
-
* @return A promise that resolves to an array containing the prepared models and context arguments
|
|
1703
|
-
*/
|
|
1704
|
-
async createAllPrefix(models, ...args) {
|
|
1705
|
-
const contextArgs = await Context.args(OperationKeys.CREATE, this.class, args);
|
|
1706
|
-
await Promise.all(models.map(async (m) => {
|
|
1707
|
-
m = new this.class(m);
|
|
1708
|
-
await enforceDBDecorators(this, contextArgs.context, m, OperationKeys.CREATE, OperationKeys.ON);
|
|
1709
|
-
return m;
|
|
1710
|
-
}));
|
|
1711
|
-
return [models, ...contextArgs.args];
|
|
1712
|
-
}
|
|
1713
|
-
/**
|
|
1714
|
-
* @description Processes multiple models after creation and executes post-creation operations.
|
|
1715
|
-
* @summary Finalizes multiple models after they have been created in the data store. This includes
|
|
1716
|
-
* enforcing any decorators that should be applied after creation for each model.
|
|
1717
|
-
* @param {M[]} models - The array of model instances that were created
|
|
1718
|
-
* @param {C} context - The context for the operation
|
|
1719
|
-
* @return {Promise<M[]>} A promise that resolves to the array of processed model instances
|
|
1720
|
-
*/
|
|
1721
|
-
async createAllSuffix(models, context) {
|
|
1722
|
-
await Promise.all(models.map((m) => enforceDBDecorators(this, context, m, OperationKeys.CREATE, OperationKeys.AFTER)));
|
|
1723
|
-
return models;
|
|
1724
|
-
}
|
|
1725
|
-
/**
|
|
1726
|
-
* @description Retrieves multiple model instances from the repository by their primary keys.
|
|
1727
|
-
* @summary Fetches multiple model instances from the underlying data store using their primary keys
|
|
1728
|
-
* by calling the read method for each key in the array.
|
|
1729
|
-
* @param {string[] | number[]} keys - The array of primary keys of the models to retrieve
|
|
1730
|
-
* @param {any[]} args - Additional arguments for the read operation
|
|
1731
|
-
* @return {Promise<M[]>} A promise that resolves to an array of retrieved model instances
|
|
1732
|
-
*/
|
|
1733
|
-
async readAll(keys, ...args) {
|
|
1734
|
-
return await Promise.all(keys.map((id) => this.read(id, ...args)));
|
|
1735
|
-
}
|
|
1736
|
-
/**
|
|
1737
|
-
* @description Processes a model after retrieval and executes post-read operations.
|
|
1738
|
-
* @summary Finalizes a model after it has been retrieved from the data store. This includes
|
|
1739
|
-
* enforcing any decorators that should be applied after reading.
|
|
1740
|
-
* @param {M} model - The model instance that was retrieved
|
|
1741
|
-
* @param {C} context - The context for the operation
|
|
1742
|
-
* @return {Promise<M>} A promise that resolves to the processed model instance
|
|
1743
|
-
*/
|
|
1744
|
-
async readSuffix(model, context) {
|
|
1745
|
-
await enforceDBDecorators(this, context, model, OperationKeys.READ, OperationKeys.AFTER);
|
|
1746
|
-
return model;
|
|
1747
|
-
}
|
|
1748
|
-
/**
|
|
1749
|
-
* @description Prepares for reading a model and executes pre-read operations.
|
|
1750
|
-
* @summary Processes a key before a model is read from the data store. This includes
|
|
1751
|
-
* creating a context, instantiating a new model instance with the key, and enforcing any decorators
|
|
1752
|
-
* that should be applied before reading.
|
|
1753
|
-
* @param {string} key - The primary key of the model to read
|
|
1754
|
-
* @param {any[]} args - Additional arguments for the read operation
|
|
1755
|
-
* @return A promise that resolves to an array containing the key and context arguments
|
|
1756
|
-
*/
|
|
1757
|
-
async readPrefix(key, ...args) {
|
|
1758
|
-
const contextArgs = await Context.args(OperationKeys.READ, this.class, args);
|
|
1759
|
-
const model = new this.class();
|
|
1760
|
-
model[this.pk] = key;
|
|
1761
|
-
await enforceDBDecorators(this, contextArgs.context, model, OperationKeys.READ, OperationKeys.ON);
|
|
1762
|
-
return [key, ...contextArgs.args];
|
|
1763
|
-
}
|
|
1764
|
-
/**
|
|
1765
|
-
* @description Prepares for reading multiple models and executes pre-read operations.
|
|
1766
|
-
* @summary Processes multiple keys before models are read from the data store. This includes
|
|
1767
|
-
* creating a context, instantiating new model instances with the keys, and enforcing any decorators
|
|
1768
|
-
* that should be applied before reading for each key.
|
|
1769
|
-
* @param {string[] | number[]} keys - The array of primary keys of the models to read
|
|
1770
|
-
* @param {any[]} args - Additional arguments for the read operation
|
|
1771
|
-
* @return A promise that resolves to an array containing the keys and context arguments
|
|
1772
|
-
*/
|
|
1773
|
-
async readAllPrefix(keys, ...args) {
|
|
1774
|
-
const contextArgs = await Context.args(OperationKeys.READ, this.class, args);
|
|
1775
|
-
await Promise.all(keys.map(async (k) => {
|
|
1776
|
-
const m = new this.class();
|
|
1777
|
-
m[this.pk] = k;
|
|
1778
|
-
return enforceDBDecorators(this, contextArgs.context, m, OperationKeys.READ, OperationKeys.ON);
|
|
1779
|
-
}));
|
|
1780
|
-
return [keys, ...contextArgs.args];
|
|
1781
|
-
}
|
|
1782
|
-
/**
|
|
1783
|
-
* @description Processes multiple models after retrieval and executes post-read operations.
|
|
1784
|
-
* @summary Finalizes multiple models after they have been retrieved from the data store. This includes
|
|
1785
|
-
* enforcing any decorators that should be applied after reading for each model.
|
|
1786
|
-
* @param {M[]} models - The array of model instances that were retrieved
|
|
1787
|
-
* @param {C} context - The context for the operation
|
|
1788
|
-
* @return {Promise<M[]>} A promise that resolves to the array of processed model instances
|
|
1789
|
-
*/
|
|
1790
|
-
async readAllSuffix(models, context) {
|
|
1791
|
-
await Promise.all(models.map((m) => enforceDBDecorators(this, context, m, OperationKeys.READ, OperationKeys.AFTER)));
|
|
1792
|
-
return models;
|
|
1793
|
-
}
|
|
1794
|
-
/**
|
|
1795
|
-
* @description Updates multiple model instances in the repository.
|
|
1796
|
-
* @summary Updates multiple model instances in the underlying data store by calling
|
|
1797
|
-
* the update method for each model in the array.
|
|
1798
|
-
* @param {M[]} models - The array of model instances to update
|
|
1799
|
-
* @param {any[]} args - Additional arguments for the update operation
|
|
1800
|
-
* @return {Promise<M[]>} A promise that resolves to an array of updated model instances
|
|
1801
|
-
*/
|
|
1802
|
-
async updateAll(models, ...args) {
|
|
1803
|
-
return Promise.all(models.map((m) => this.update(m, ...args)));
|
|
1804
|
-
}
|
|
1805
|
-
/**
|
|
1806
|
-
* @description Processes a model after update and executes post-update operations.
|
|
1807
|
-
* @summary Finalizes a model after it has been updated in the data store. This includes
|
|
1808
|
-
* enforcing any decorators that should be applied after updating.
|
|
1809
|
-
* @param {M} model - The model instance that was updated
|
|
1810
|
-
* @param {C} context - The context for the operation
|
|
1811
|
-
* @return {Promise<M>} A promise that resolves to the processed model instance
|
|
1812
|
-
*/
|
|
1813
|
-
async updateSuffix(model, context) {
|
|
1814
|
-
await enforceDBDecorators(this, context, model, OperationKeys.UPDATE, OperationKeys.AFTER);
|
|
1815
|
-
return model;
|
|
1816
|
-
}
|
|
1817
|
-
/**
|
|
1818
|
-
* @description Prepares a model for update and executes pre-update operations.
|
|
1819
|
-
* @summary Processes a model before it is updated in the data store. This includes
|
|
1820
|
-
* creating a context, validating the primary key, retrieving the existing model,
|
|
1821
|
-
* and enforcing any decorators that should be applied before updating.
|
|
1822
|
-
* @param {M} model - The model instance to prepare for update
|
|
1823
|
-
* @param {any[]} args - Additional arguments for the update operation
|
|
1824
|
-
* @return A promise that resolves to an array containing the prepared model and context arguments
|
|
1825
|
-
*/
|
|
1826
|
-
async updatePrefix(model, ...args) {
|
|
1827
|
-
const contextArgs = await Context.args(OperationKeys.UPDATE, this.class, args);
|
|
1828
|
-
const id = model[this.pk];
|
|
1829
|
-
if (!id)
|
|
1830
|
-
throw new InternalError(`No value for the Id is defined under the property ${this.pk}`);
|
|
1831
|
-
const oldModel = await this.read(id);
|
|
1832
|
-
await enforceDBDecorators(this, contextArgs.context, model, OperationKeys.UPDATE, OperationKeys.ON, oldModel);
|
|
1833
|
-
return [model, ...contextArgs.args];
|
|
1834
|
-
}
|
|
1835
|
-
/**
|
|
1836
|
-
* @description Prepares multiple models for update and executes pre-update operations.
|
|
1837
|
-
* @summary Processes multiple models before they are updated in the data store. This includes
|
|
1838
|
-
* creating a context, instantiating new model instances, and enforcing any decorators
|
|
1839
|
-
* that should be applied before updating for each model.
|
|
1840
|
-
* @param {M[]} models - The array of model instances to prepare for update
|
|
1841
|
-
* @param {any[]} args - Additional arguments for the update operation
|
|
1842
|
-
* @return A promise that resolves to an array containing the prepared models and context arguments
|
|
1843
|
-
*/
|
|
1844
|
-
async updateAllPrefix(models, ...args) {
|
|
1845
|
-
const contextArgs = await Context.args(OperationKeys.UPDATE, this.class, args);
|
|
1846
|
-
await Promise.all(models.map((m) => {
|
|
1847
|
-
m = new this.class(m);
|
|
1848
|
-
enforceDBDecorators(this, contextArgs.context, m, OperationKeys.UPDATE, OperationKeys.ON);
|
|
1849
|
-
return m;
|
|
1850
|
-
}));
|
|
1851
|
-
return [models, ...contextArgs.args];
|
|
1852
|
-
}
|
|
1853
|
-
/**
|
|
1854
|
-
* @description Processes multiple models after update and executes post-update operations.
|
|
1855
|
-
* @summary Finalizes multiple models after they have been updated in the data store. This includes
|
|
1856
|
-
* enforcing any decorators that should be applied after updating for each model.
|
|
1857
|
-
* @param {M[]} models - The array of model instances that were updated
|
|
1858
|
-
* @param {C} context - The context for the operation
|
|
1859
|
-
* @return {Promise<M[]>} A promise that resolves to the array of processed model instances
|
|
1860
|
-
*/
|
|
1861
|
-
async updateAllSuffix(models, context) {
|
|
1862
|
-
await Promise.all(models.map((m) => enforceDBDecorators(this, context, m, OperationKeys.UPDATE, OperationKeys.AFTER)));
|
|
1863
|
-
return models;
|
|
1864
|
-
}
|
|
1865
|
-
/**
|
|
1866
|
-
* @description Deletes multiple model instances from the repository by their primary keys.
|
|
1867
|
-
* @summary Removes multiple model instances from the underlying data store using their primary keys
|
|
1868
|
-
* by calling the delete method for each key in the array.
|
|
1869
|
-
* @param {string[] | number[]} keys - The array of primary keys of the models to delete
|
|
1870
|
-
* @param {any[]} args - Additional arguments for the delete operation
|
|
1871
|
-
* @return {Promise<M[]>} A promise that resolves to an array of deleted model instances
|
|
1872
|
-
*/
|
|
1873
|
-
async deleteAll(keys, ...args) {
|
|
1874
|
-
return Promise.all(keys.map((k) => this.delete(k, ...args)));
|
|
1875
|
-
}
|
|
1876
|
-
/**
|
|
1877
|
-
* @description Processes a model after deletion and executes post-delete operations.
|
|
1878
|
-
* @summary Finalizes a model after it has been deleted from the data store. This includes
|
|
1879
|
-
* enforcing any decorators that should be applied after deletion.
|
|
1880
|
-
* @param {M} model - The model instance that was deleted
|
|
1881
|
-
* @param {C} context - The context for the operation
|
|
1882
|
-
* @return {Promise<M>} A promise that resolves to the processed model instance
|
|
1883
|
-
*/
|
|
1884
|
-
async deleteSuffix(model, context) {
|
|
1885
|
-
await enforceDBDecorators(this, context, model, OperationKeys.DELETE, OperationKeys.AFTER);
|
|
1886
|
-
return model;
|
|
1887
|
-
}
|
|
1888
|
-
/**
|
|
1889
|
-
* @description Prepares for deleting a model and executes pre-delete operations.
|
|
1890
|
-
* @summary Processes a key before a model is deleted from the data store. This includes
|
|
1891
|
-
* creating a context, retrieving the model to be deleted, and enforcing any decorators
|
|
1892
|
-
* that should be applied before deletion.
|
|
1893
|
-
* @param {any} key - The primary key of the model to delete
|
|
1894
|
-
* @param {any[]} args - Additional arguments for the delete operation
|
|
1895
|
-
* @return A promise that resolves to an array containing the key and context arguments
|
|
1896
|
-
*/
|
|
1897
|
-
async deletePrefix(key, ...args) {
|
|
1898
|
-
const contextArgs = await Context.args(OperationKeys.DELETE, this.class, args);
|
|
1899
|
-
const model = await this.read(key, ...contextArgs.args);
|
|
1900
|
-
await enforceDBDecorators(this, contextArgs.context, model, OperationKeys.DELETE, OperationKeys.ON);
|
|
1901
|
-
return [key, ...contextArgs.args];
|
|
1902
|
-
}
|
|
1903
|
-
/**
|
|
1904
|
-
* @description Prepares for deleting multiple models and executes pre-delete operations.
|
|
1905
|
-
* @summary Processes multiple keys before models are deleted from the data store. This includes
|
|
1906
|
-
* creating a context, retrieving the models to be deleted, and enforcing any decorators
|
|
1907
|
-
* that should be applied before deletion for each model.
|
|
1908
|
-
* @param {string[] | number[]} keys - The array of primary keys of the models to delete
|
|
1909
|
-
* @param {any[]} args - Additional arguments for the delete operation
|
|
1910
|
-
* @return A promise that resolves to an array containing the keys and context arguments
|
|
1911
|
-
*/
|
|
1912
|
-
async deleteAllPrefix(keys, ...args) {
|
|
1913
|
-
const contextArgs = await Context.args(OperationKeys.DELETE, this.class, args);
|
|
1914
|
-
const models = await this.readAll(keys, ...contextArgs.args);
|
|
1915
|
-
await Promise.all(models.map(async (m) => {
|
|
1916
|
-
return enforceDBDecorators(this, contextArgs.context, m, OperationKeys.DELETE, OperationKeys.ON);
|
|
1917
|
-
}));
|
|
1918
|
-
return [keys, ...contextArgs.args];
|
|
1919
|
-
}
|
|
1920
|
-
/**
|
|
1921
|
-
* @description Processes multiple models after deletion and executes post-delete operations.
|
|
1922
|
-
* @summary Finalizes multiple models after they have been deleted from the data store. This includes
|
|
1923
|
-
* enforcing any decorators that should be applied after deletion for each model.
|
|
1924
|
-
* @param {M[]} models - The array of model instances that were deleted
|
|
1925
|
-
* @param {C} context - The context for the operation
|
|
1926
|
-
* @return {Promise<M[]>} A promise that resolves to the array of processed model instances
|
|
1927
|
-
*/
|
|
1928
|
-
async deleteAllSuffix(models, context) {
|
|
1929
|
-
await Promise.all(models.map((m) => enforceDBDecorators(this, context, m, OperationKeys.DELETE, OperationKeys.AFTER)));
|
|
1930
|
-
return models;
|
|
1931
|
-
}
|
|
1932
|
-
/**
|
|
1933
|
-
* @description Merges two model instances into a new instance.
|
|
1934
|
-
* @summary Creates a new model instance by combining properties from an old model and a new model.
|
|
1935
|
-
* Properties from the new model override properties from the old model if they are defined.
|
|
1936
|
-
* @param {M} oldModel - The original model instance
|
|
1937
|
-
* @param {M} model - The new model instance with updated properties
|
|
1938
|
-
* @return {M} A new model instance with merged properties
|
|
1939
|
-
*/
|
|
1940
|
-
merge(oldModel, model) {
|
|
1941
|
-
const extract = (model) => Object.entries(model).reduce((accum, [key, val]) => {
|
|
1942
|
-
if (typeof val !== "undefined")
|
|
1943
|
-
accum[key] = val;
|
|
1944
|
-
return accum;
|
|
1945
|
-
}, {});
|
|
1946
|
-
return new this.class(Object.assign({}, extract(oldModel), extract(model)));
|
|
1947
|
-
}
|
|
1948
|
-
/**
|
|
1949
|
-
* @description Returns a string representation of the repository.
|
|
1950
|
-
* @summary Creates a string that identifies this repository by the name of its model class.
|
|
1951
|
-
* @return {string} A string representation of the repository
|
|
1952
|
-
*/
|
|
1953
|
-
toString() {
|
|
1954
|
-
return `${this.class.name} Repository`;
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1957
|
-
|
|
1958
|
-
/**
|
|
1959
|
-
* @description Concrete repository implementation with validation support.
|
|
1960
|
-
* @summary The Repository class extends BaseRepository to provide additional validation
|
|
1961
|
-
* functionality. It overrides prefix methods to perform model validation before database
|
|
1962
|
-
* operations and throws ValidationError when validation fails.
|
|
1963
|
-
* @template M - The model type extending Model
|
|
1964
|
-
* @template F - The repository flags type, defaults to RepositoryFlags
|
|
1965
|
-
* @template C - The context type, defaults to Context<F>
|
|
1966
|
-
* @class Repository
|
|
1967
|
-
* @example
|
|
1968
|
-
* class UserModel extends Model {
|
|
1969
|
-
* @id()
|
|
1970
|
-
* id: string;
|
|
1971
|
-
*
|
|
1972
|
-
* @required()
|
|
1973
|
-
* @minLength(3)
|
|
1974
|
-
* name: string;
|
|
1975
|
-
* }
|
|
1976
|
-
*
|
|
1977
|
-
* class UserRepository extends Repository<UserModel> {
|
|
1978
|
-
* constructor() {
|
|
1979
|
-
* super(UserModel);
|
|
1980
|
-
* }
|
|
1981
|
-
*
|
|
1982
|
-
* async create(model: UserModel): Promise<UserModel> {
|
|
1983
|
-
* // Implementation with automatic validation
|
|
1984
|
-
* return model;
|
|
1985
|
-
* }
|
|
1986
|
-
* }
|
|
1987
|
-
*
|
|
1988
|
-
* // Using the repository
|
|
1989
|
-
* const repo = new UserRepository();
|
|
1990
|
-
* try {
|
|
1991
|
-
* const user = await repo.create({ name: 'Jo' }); // Will throw ValidationError
|
|
1992
|
-
* } catch (error) {
|
|
1993
|
-
* console.error(error); // ValidationError: name must be at least 3 characters
|
|
1994
|
-
* }
|
|
1995
|
-
*/
|
|
1996
|
-
class Repository extends BaseRepository {
|
|
1997
|
-
constructor(clazz) {
|
|
1998
|
-
super(clazz);
|
|
1999
|
-
}
|
|
2000
|
-
/**
|
|
2001
|
-
* @description Prepares a model for creation with validation.
|
|
2002
|
-
* @summary Overrides the base createPrefix method to add validation checks.
|
|
2003
|
-
* Creates a context, instantiates a new model, enforces decorators, and validates
|
|
2004
|
-
* the model before allowing creation to proceed.
|
|
2005
|
-
* @param {M} model - The model instance to prepare for creation
|
|
2006
|
-
* @param {any[]} args - Additional arguments for the create operation
|
|
2007
|
-
* @return A promise that resolves to an array containing the validated model and context arguments
|
|
2008
|
-
* @throws {ValidationError} If the model fails validation
|
|
2009
|
-
*/
|
|
2010
|
-
async createPrefix(model, ...args) {
|
|
2011
|
-
const contextArgs = await Context.args(OperationKeys.CREATE, this.class, args);
|
|
2012
|
-
model = new this.class(model);
|
|
2013
|
-
await enforceDBDecorators(this, contextArgs.context, model, OperationKeys.CREATE, OperationKeys.ON);
|
|
2014
|
-
const errors = await Promise.resolve(model.hasErrors());
|
|
2015
|
-
if (errors)
|
|
2016
|
-
throw new ValidationError(errors.toString());
|
|
2017
|
-
return [model, ...contextArgs.args];
|
|
2018
|
-
}
|
|
2019
|
-
/**
|
|
2020
|
-
* @description Prepares multiple models for creation with validation.
|
|
2021
|
-
* @summary Overrides the base createAllPrefix method to add validation checks for multiple models.
|
|
2022
|
-
* Creates a context, instantiates new models, enforces decorators, and validates
|
|
2023
|
-
* each model before allowing creation to proceed. Collects validation errors from all models.
|
|
2024
|
-
* @param {M[]} models - The array of model instances to prepare for creation
|
|
2025
|
-
* @param {any[]} args - Additional arguments for the create operation
|
|
2026
|
-
* @return {Promise<any[]>} A promise that resolves to an array containing the validated models and context arguments
|
|
2027
|
-
* @throws {ValidationError} If any model fails validation, with details about which models failed
|
|
2028
|
-
*/
|
|
2029
|
-
async createAllPrefix(models, ...args) {
|
|
2030
|
-
const contextArgs = await Context.args(OperationKeys.CREATE, this.class, args);
|
|
2031
|
-
await Promise.all(models.map(async (m) => {
|
|
2032
|
-
m = new this.class(m);
|
|
2033
|
-
await enforceDBDecorators(this, contextArgs.context, m, OperationKeys.CREATE, OperationKeys.ON);
|
|
2034
|
-
return m;
|
|
2035
|
-
}));
|
|
2036
|
-
const modelsValidation = await Promise.all(models.map((m) => Promise.resolve(m.hasErrors())));
|
|
2037
|
-
const errors = modelsValidation.reduce((accum, e, i) => {
|
|
2038
|
-
if (e)
|
|
2039
|
-
accum =
|
|
2040
|
-
typeof accum === "string"
|
|
2041
|
-
? accum + `\n - ${i}: ${e.toString()}`
|
|
2042
|
-
: ` - ${i}: ${e.toString()}`;
|
|
2043
|
-
return accum;
|
|
2044
|
-
}, undefined);
|
|
2045
|
-
if (errors)
|
|
2046
|
-
throw new ValidationError(errors);
|
|
2047
|
-
return [models, ...contextArgs.args];
|
|
2048
|
-
}
|
|
2049
|
-
/**
|
|
2050
|
-
* @description Prepares a model for update with validation.
|
|
2051
|
-
* @summary Overrides the base updatePrefix method to add validation checks.
|
|
2052
|
-
* Creates a context, validates the primary key, retrieves the existing model,
|
|
2053
|
-
* merges the old and new models, enforces decorators, and validates the model
|
|
2054
|
-
* before allowing the update to proceed.
|
|
2055
|
-
* @param {M} model - The model instance to prepare for update
|
|
2056
|
-
* @param {any[]} args - Additional arguments for the update operation
|
|
2057
|
-
* @return A promise that resolves to an array containing the validated model and context arguments
|
|
2058
|
-
* @throws {InternalError} If the model doesn't have a primary key value
|
|
2059
|
-
* @throws {ValidationError} If the model fails validation
|
|
2060
|
-
*/
|
|
2061
|
-
async updatePrefix(model, ...args) {
|
|
2062
|
-
const contextArgs = await Context.args(OperationKeys.UPDATE, this.class, args);
|
|
2063
|
-
const pk = model[this.pk];
|
|
2064
|
-
if (!pk)
|
|
2065
|
-
throw new InternalError(`No value for the Id is defined under the property ${this.pk}`);
|
|
2066
|
-
const oldModel = await this.read(pk);
|
|
2067
|
-
model = this.merge(oldModel, model);
|
|
2068
|
-
await enforceDBDecorators(this, contextArgs.context, model, OperationKeys.UPDATE, OperationKeys.ON, oldModel);
|
|
2069
|
-
const errors = await Promise.resolve(model.hasErrors(oldModel));
|
|
2070
|
-
if (errors)
|
|
2071
|
-
throw new ValidationError(errors.toString());
|
|
2072
|
-
return [model, ...contextArgs.args];
|
|
2073
|
-
}
|
|
2074
|
-
/**
|
|
2075
|
-
* @description Prepares multiple models for update with validation.
|
|
2076
|
-
* @summary Overrides the base updateAllPrefix method to add validation checks for multiple models.
|
|
2077
|
-
* Creates a context, validates primary keys, retrieves existing models, merges old and new models,
|
|
2078
|
-
* enforces decorators, and validates each model before allowing updates to proceed.
|
|
2079
|
-
* Collects validation errors from all models.
|
|
2080
|
-
* @param {M[]} models - The array of model instances to prepare for update
|
|
2081
|
-
* @param {any[]} args - Additional arguments for the update operation
|
|
2082
|
-
* @return A promise that resolves to an array containing the validated models and context arguments
|
|
2083
|
-
* @throws {InternalError} If any model doesn't have a primary key value
|
|
2084
|
-
* @throws {ValidationError} If any model fails validation, with details about which models failed
|
|
2085
|
-
*/
|
|
2086
|
-
async updateAllPrefix(models, ...args) {
|
|
2087
|
-
const contextArgs = await Context.args(OperationKeys.UPDATE, this.class, args);
|
|
2088
|
-
const ids = models.map((m) => {
|
|
2089
|
-
const id = m[this.pk];
|
|
2090
|
-
if (typeof id === "undefined")
|
|
2091
|
-
throw new InternalError(`No value for the Id is defined under the property ${this.pk}`);
|
|
2092
|
-
return id;
|
|
2093
|
-
});
|
|
2094
|
-
const oldModels = await this.readAll(ids, ...contextArgs.args);
|
|
2095
|
-
models = models.map((m, i) => this.merge(oldModels[i], m));
|
|
2096
|
-
await Promise.all(models.map((m, i) => enforceDBDecorators(this, contextArgs.context, m, OperationKeys.UPDATE, OperationKeys.ON, oldModels[i])));
|
|
2097
|
-
const modelsValidation = await Promise.all(models.map((m, i) => Promise.resolve(m.hasErrors(oldModels[i]))));
|
|
2098
|
-
const errors = modelsValidation.reduce((accum, e, i) => {
|
|
2099
|
-
if (e)
|
|
2100
|
-
accum =
|
|
2101
|
-
typeof accum === "string"
|
|
2102
|
-
? accum + `\n - ${i}: ${e.toString()}`
|
|
2103
|
-
: ` - ${i}: ${e.toString()}`;
|
|
2104
|
-
return accum;
|
|
2105
|
-
}, undefined);
|
|
2106
|
-
if (errors)
|
|
2107
|
-
throw new ValidationError(errors);
|
|
2108
|
-
return [models, ...contextArgs.args];
|
|
2109
|
-
}
|
|
2110
|
-
/**
|
|
2111
|
-
* @description Creates a reflection key for database operations.
|
|
2112
|
-
* @summary Generates a key for storing metadata in the reflection system by prefixing
|
|
2113
|
-
* the provided key with the database reflection prefix.
|
|
2114
|
-
* @param {string} key - The base key to prefix
|
|
2115
|
-
* @return {string} The prefixed reflection key
|
|
2116
|
-
*/
|
|
2117
|
-
static key(key) {
|
|
2118
|
-
return DBKeys.REFLECT + key;
|
|
2119
|
-
}
|
|
2120
|
-
}
|
|
2121
|
-
|
|
2122
|
-
/**
|
|
2123
|
-
* @description Prevents a property from being modified after initial creation.
|
|
2124
|
-
* @summary Marks the property as readonly, causing validation errors if attempts are made to modify it during updates.
|
|
2125
|
-
* @param {string} [message] - The error message to display when validation fails. Defaults to {@link DEFAULT_ERROR_MESSAGES.READONLY.INVALID}
|
|
2126
|
-
* @return {PropertyDecorator} A decorator function that can be applied to class properties
|
|
2127
|
-
* @function readonly
|
|
2128
|
-
* @category Property Decorators
|
|
2129
|
-
*/
|
|
2130
|
-
function readonly(message = DEFAULT_ERROR_MESSAGES.READONLY.INVALID) {
|
|
2131
|
-
const key = Validation.updateKey(DBKeys.READONLY);
|
|
2132
|
-
return Decoration.for(key)
|
|
2133
|
-
.define(propMetadata(key, {
|
|
2134
|
-
message: message,
|
|
2135
|
-
}))
|
|
2136
|
-
.apply();
|
|
2137
|
-
}
|
|
2138
|
-
/**
|
|
2139
|
-
* @description Handler function that sets a timestamp property to the current timestamp.
|
|
2140
|
-
* @summary Updates a model property with the current timestamp from the repository context.
|
|
2141
|
-
* @template M - The model type extending Model
|
|
2142
|
-
* @template R - The repository type extending IRepository
|
|
2143
|
-
* @template V - The data type for the operation
|
|
2144
|
-
* @template F - The repository flags type
|
|
2145
|
-
* @template C - The context type
|
|
2146
|
-
* @param {C} context - The repository context containing the current timestamp
|
|
2147
|
-
* @param {V} data - The data being processed
|
|
2148
|
-
* @param key - The property key to update
|
|
2149
|
-
* @param {M} model - The model instance being updated
|
|
2150
|
-
* @return {Promise<void>} A promise that resolves when the timestamp has been set
|
|
2151
|
-
* @function timestampHandler
|
|
2152
|
-
*/
|
|
2153
|
-
async function timestampHandler(context, data, key, model) {
|
|
2154
|
-
model[key] = context.timestamp;
|
|
2155
|
-
}
|
|
2156
|
-
/**
|
|
2157
|
-
* @description Automatically manages timestamp properties for tracking creation and update times.
|
|
2158
|
-
* @summary Marks the property as a timestamp, making it required and ensuring it's a valid date. The property will be automatically updated with the current timestamp during specified operations.
|
|
2159
|
-
*
|
|
2160
|
-
* Date Format:
|
|
2161
|
-
*
|
|
2162
|
-
* <pre>
|
|
2163
|
-
* Using similar formatting as Moment.js, Class DateTimeFormatter (Java), and Class SimpleDateFormat (Java),
|
|
2164
|
-
* I implemented a comprehensive solution formatDate(date, patternStr) where the code is easy to read and modify.
|
|
2165
|
-
* You can display date, time, AM/PM, etc.
|
|
2166
|
-
*
|
|
2167
|
-
* Date and Time Patterns
|
|
2168
|
-
* yy = 2-digit year; yyyy = full year
|
|
2169
|
-
* M = digit month; MM = 2-digit month; MMM = short month name; MMMM = full month name
|
|
2170
|
-
* EEEE = full weekday name; EEE = short weekday name
|
|
2171
|
-
* d = digit day; dd = 2-digit day
|
|
2172
|
-
* h = hours am/pm; hh = 2-digit hours am/pm; H = hours; HH = 2-digit hours
|
|
2173
|
-
* m = minutes; mm = 2-digit minutes; aaa = AM/PM
|
|
2174
|
-
* s = seconds; ss = 2-digit seconds
|
|
2175
|
-
* S = miliseconds
|
|
2176
|
-
* </pre>
|
|
2177
|
-
*
|
|
2178
|
-
* @param {OperationKeys[]} operation - The operations to act on. Defaults to {@link DBOperations.CREATE_UPDATE}
|
|
2179
|
-
* @param {string} [format] - The timestamp format. Defaults to {@link DEFAULT_TIMESTAMP_FORMAT}
|
|
2180
|
-
* @return {PropertyDecorator} A decorator function that can be applied to class properties
|
|
2181
|
-
* @function timestamp
|
|
2182
|
-
* @category Property Decorators
|
|
2183
|
-
* @mermaid
|
|
2184
|
-
* sequenceDiagram
|
|
2185
|
-
* participant C as Client
|
|
2186
|
-
* participant M as Model
|
|
2187
|
-
* participant T as TimestampDecorator
|
|
2188
|
-
* participant V as Validator
|
|
2189
|
-
*
|
|
2190
|
-
* C->>M: Create/Update model
|
|
2191
|
-
* M->>T: Process timestamp property
|
|
2192
|
-
* T->>M: Apply required validation
|
|
2193
|
-
* T->>M: Apply date format validation
|
|
2194
|
-
*
|
|
2195
|
-
* alt Update operation
|
|
2196
|
-
* T->>V: Register timestamp validator
|
|
2197
|
-
* V->>M: Validate timestamp is newer
|
|
2198
|
-
* end
|
|
2199
|
-
*
|
|
2200
|
-
* T->>M: Set current timestamp
|
|
2201
|
-
* M->>C: Return updated model
|
|
2202
|
-
*/
|
|
2203
|
-
function timestamp(operation = DBOperations.CREATE_UPDATE, format = DEFAULT_TIMESTAMP_FORMAT) {
|
|
2204
|
-
const key = Validation.updateKey(DBKeys.TIMESTAMP);
|
|
2205
|
-
function ts(operation, format) {
|
|
2206
|
-
const decorators = [
|
|
2207
|
-
date(format, DEFAULT_ERROR_MESSAGES.TIMESTAMP.DATE),
|
|
2208
|
-
required(DEFAULT_ERROR_MESSAGES.TIMESTAMP.REQUIRED),
|
|
2209
|
-
propMetadata(Validation.key(DBKeys.TIMESTAMP), {
|
|
2210
|
-
operation: operation,
|
|
2211
|
-
format: format,
|
|
2212
|
-
}),
|
|
2213
|
-
on(operation, timestampHandler),
|
|
2214
|
-
];
|
|
2215
|
-
if (operation.indexOf(OperationKeys.UPDATE) !== -1)
|
|
2216
|
-
decorators.push(propMetadata(key, {
|
|
2217
|
-
message: DEFAULT_ERROR_MESSAGES.TIMESTAMP.INVALID,
|
|
2218
|
-
}));
|
|
2219
|
-
else
|
|
2220
|
-
decorators.push(readonly());
|
|
2221
|
-
return apply(...decorators);
|
|
2222
|
-
}
|
|
2223
|
-
return Decoration.for(key)
|
|
2224
|
-
.define({
|
|
2225
|
-
decorator: ts,
|
|
2226
|
-
args: [operation, format],
|
|
2227
|
-
})
|
|
2228
|
-
.apply();
|
|
2229
|
-
}
|
|
2230
|
-
/**
|
|
2231
|
-
* @description Handler function that serializes a property to JSON string during create and update operations.
|
|
2232
|
-
* @summary Converts a complex object property to a JSON string before storing it in the database.
|
|
2233
|
-
* @template M - The model type extending Model
|
|
2234
|
-
* @template R - The repository type extending IRepository
|
|
2235
|
-
* @template V - The data type for the operation
|
|
2236
|
-
* @template F - The repository flags type
|
|
2237
|
-
* @template C - The context type
|
|
2238
|
-
* @param {C} context - The repository context
|
|
2239
|
-
* @param {V} data - The data being processed
|
|
2240
|
-
* @param key - The property key to serialize
|
|
2241
|
-
* @param {M} model - The model instance being processed
|
|
2242
|
-
* @return {Promise<void>} A promise that resolves when the property has been serialized
|
|
2243
|
-
* @function serializeOnCreateUpdate
|
|
2244
|
-
*/
|
|
2245
|
-
async function serializeOnCreateUpdate(context, data, key, model) {
|
|
2246
|
-
if (!model[key])
|
|
2247
|
-
return;
|
|
2248
|
-
try {
|
|
2249
|
-
model[key] = JSON.stringify(model[key]);
|
|
2250
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2251
|
-
}
|
|
2252
|
-
catch (e) {
|
|
2253
|
-
throw new SerializationError(`Failed to serialize ${key.toString()} property of model ${model.constructor.name}: e`);
|
|
2254
|
-
}
|
|
2255
|
-
}
|
|
2256
|
-
/**
|
|
2257
|
-
* @description Handler function that deserializes a property from JSON string after database operations.
|
|
2258
|
-
* @summary Converts a JSON string property back to its original complex object form after retrieving it from the database.
|
|
2259
|
-
* @template M - The model type extending Model
|
|
2260
|
-
* @template R - The repository type extending IRepository
|
|
2261
|
-
* @template V - The data type for the operation
|
|
2262
|
-
* @template F - The repository flags type
|
|
2263
|
-
* @template C - The context type
|
|
2264
|
-
* @param {C} context - The repository context
|
|
2265
|
-
* @param {V} data - The data being processed
|
|
2266
|
-
* @param key - The property key to deserialize
|
|
2267
|
-
* @param {M} model - The model instance being processed
|
|
2268
|
-
* @return {Promise<void>} A promise that resolves when the property has been deserialized
|
|
2269
|
-
* @function serializeAfterAll
|
|
2270
|
-
*/
|
|
2271
|
-
async function serializeAfterAll(context, data, key, model) {
|
|
2272
|
-
if (!model[key])
|
|
2273
|
-
return;
|
|
2274
|
-
if (typeof model[key] !== "string")
|
|
2275
|
-
return;
|
|
2276
|
-
try {
|
|
2277
|
-
model[key] = JSON.parse(model[key]);
|
|
2278
|
-
}
|
|
2279
|
-
catch (e) {
|
|
2280
|
-
throw new SerializationError(`Failed to deserialize ${key.toString()} property of model ${model.constructor.name}: ${e}`);
|
|
2281
|
-
}
|
|
2282
|
-
}
|
|
2283
|
-
/**
|
|
2284
|
-
* @description Enables automatic JSON serialization and deserialization for complex object properties.
|
|
2285
|
-
* @summary Decorator that automatically converts complex objects to JSON strings before storing in the database and back to objects when retrieving them.
|
|
2286
|
-
* @return {PropertyDecorator} A decorator function that can be applied to class properties
|
|
2287
|
-
* @function serialize
|
|
2288
|
-
* @category Property Decorators
|
|
2289
|
-
* @mermaid
|
|
2290
|
-
* sequenceDiagram
|
|
2291
|
-
* participant C as Client
|
|
2292
|
-
* participant M as Model
|
|
2293
|
-
* participant S as SerializeDecorator
|
|
2294
|
-
* participant DB as Database
|
|
2295
|
-
*
|
|
2296
|
-
* Note over C,DB: Create/Update Flow
|
|
2297
|
-
* C->>M: Set complex object property
|
|
2298
|
-
* M->>S: Process property (create/update)
|
|
2299
|
-
* S->>M: Convert to JSON string
|
|
2300
|
-
* M->>DB: Store serialized data
|
|
2301
|
-
*
|
|
2302
|
-
* Note over C,DB: Retrieval Flow
|
|
2303
|
-
* C->>M: Request model
|
|
2304
|
-
* M->>DB: Fetch data
|
|
2305
|
-
* DB->>M: Return with serialized property
|
|
2306
|
-
* M->>S: Process property (after all ops)
|
|
2307
|
-
* S->>M: Parse JSON back to object
|
|
2308
|
-
* M->>C: Return model with deserialized property
|
|
2309
|
-
*/
|
|
2310
|
-
function serialize() {
|
|
2311
|
-
return apply(onCreateUpdate(serializeOnCreateUpdate), after(DBOperations.ALL, serializeAfterAll), type([String.name, Object.name]), metadata(Repository.key(DBKeys.SERIALIZE), {}));
|
|
2312
|
-
}
|
|
2313
|
-
|
|
2314
|
-
/**
|
|
2315
|
-
* @description Decorator that marks a property as an ID field
|
|
2316
|
-
* @summary Creates a composite decorator that marks a property as required, readonly, and as the ID field for database operations
|
|
2317
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
2318
|
-
* @function id
|
|
2319
|
-
* @category Property Decorators
|
|
2320
|
-
*/
|
|
2321
|
-
function id() {
|
|
2322
|
-
return apply(required(), readonly(), propMetadata(Repository.key(DBKeys.ID), {}));
|
|
2323
|
-
}
|
|
2324
|
-
|
|
2325
|
-
/**
|
|
2326
|
-
* @description
|
|
2327
|
-
* Retrieves validation decorator definitions from a model for update operations, including
|
|
2328
|
-
* support for special handling of list decorators.
|
|
2329
|
-
*
|
|
2330
|
-
* @summary
|
|
2331
|
-
* Iterates over the model's own enumerable properties and filters out those specified in the
|
|
2332
|
-
* `propsToIgnore` array. For each remaining property, retrieves validation decorators specific
|
|
2333
|
-
* to update operations using the `UpdateValidationKeys.REFLECT` key. Additionally, it explicitly
|
|
2334
|
-
* checks for and appends any `LIST` type decorators to ensure proper validation of collection types.
|
|
2335
|
-
*
|
|
2336
|
-
* @template M - A generic parameter extending the `Model` class, representing the model type being inspected.
|
|
2337
|
-
*
|
|
2338
|
-
* @param {M} model - The model instance whose properties are being inspected for update-related validations.
|
|
2339
|
-
* @param {string[]} propsToIgnore - A list of property names to exclude from the validation decorator retrieval process.
|
|
2340
|
-
*
|
|
2341
|
-
* @return {ValidationPropertyDecoratorDefinition[]} An array of validation decorator definitions, including both
|
|
2342
|
-
* update-specific and list-type decorators, excluding those for ignored properties.
|
|
2343
|
-
*
|
|
2344
|
-
* @function getValidatableUpdateProps
|
|
2345
|
-
*/
|
|
2346
|
-
function getValidatableUpdateProps(model, propsToIgnore) {
|
|
2347
|
-
const decoratedProperties = [];
|
|
2348
|
-
for (const prop in model) {
|
|
2349
|
-
if (Object.prototype.hasOwnProperty.call(model, prop) &&
|
|
2350
|
-
!propsToIgnore.includes(prop)) {
|
|
2351
|
-
const validationPropertyDefinition = getValidationDecorators(model, prop, UpdateValidationKeys.REFLECT);
|
|
2352
|
-
const listDecorator = getValidationDecorators(model, prop).decorators.find(({ key }) => key === ValidationKeys.LIST);
|
|
2353
|
-
if (listDecorator)
|
|
2354
|
-
validationPropertyDefinition.decorators.push(listDecorator);
|
|
2355
|
-
decoratedProperties.push(validationPropertyDefinition);
|
|
2356
|
-
}
|
|
2357
|
-
}
|
|
2358
|
-
return decoratedProperties;
|
|
2359
|
-
}
|
|
2360
|
-
function validateDecorator(newModel, oldModel, prop, decorator, async) {
|
|
2361
|
-
const validator = Validation.get(decorator.key);
|
|
2362
|
-
if (!validator) {
|
|
2363
|
-
throw new Error(`Missing validator for ${decorator.key}`);
|
|
2364
|
-
}
|
|
2365
|
-
// Skip validators that aren't UpdateValidators
|
|
2366
|
-
if (!validator.updateHasErrors)
|
|
2367
|
-
return toConditionalPromise(undefined, async);
|
|
2368
|
-
// skip async decorators if validateDecorators is called synchronously (async = false)
|
|
2369
|
-
if (!async && decorator.props.async)
|
|
2370
|
-
return toConditionalPromise(undefined, async);
|
|
2371
|
-
const decoratorProps = Object.values(decorator.props) || {};
|
|
2372
|
-
// const context = PathProxyEngine.create(obj, {
|
|
2373
|
-
// ignoreUndefined: true,
|
|
2374
|
-
// ignoreNull: true,
|
|
2375
|
-
// });
|
|
2376
|
-
const maybeError = validator.updateHasErrors(newModel[prop], oldModel[prop], ...decoratorProps);
|
|
2377
|
-
return toConditionalPromise(maybeError, async);
|
|
2378
|
-
}
|
|
2379
|
-
function validateDecorators(newModel, oldModel, prop, decorators, async) {
|
|
2380
|
-
const result = {};
|
|
2381
|
-
for (const decorator of decorators) {
|
|
2382
|
-
// skip async decorators if validateDecorators is called synchronously (async = false)
|
|
2383
|
-
if (!async && decorator.props.async)
|
|
2384
|
-
continue;
|
|
2385
|
-
let validationErrors = validateDecorator(newModel, oldModel, prop, decorator, async);
|
|
2386
|
-
/*
|
|
2387
|
-
If the decorator is a list, each element must be checked.
|
|
2388
|
-
When 'async' is true, the 'err' will always be a pending promise initially,
|
|
2389
|
-
so the '!err' check will evaluate to false (even if the promise later resolves with no errors)
|
|
2390
|
-
*/
|
|
2391
|
-
if (decorator.key === ValidationKeys.LIST && (!validationErrors || async)) {
|
|
2392
|
-
const newPropValue = newModel[prop];
|
|
2393
|
-
const oldPropValue = oldModel[prop];
|
|
2394
|
-
const newValues = newPropValue instanceof Set ? [...newPropValue] : newPropValue;
|
|
2395
|
-
const oldValues = oldPropValue instanceof Set ? [...oldPropValue] : oldPropValue;
|
|
2396
|
-
if (newValues && newValues.length > 0) {
|
|
2397
|
-
const types = decorator.props.class ||
|
|
2398
|
-
decorator.props.clazz ||
|
|
2399
|
-
decorator.props.customTypes;
|
|
2400
|
-
const allowedTypes = [types].flat().map((t) => {
|
|
2401
|
-
t = typeof t === "function" && !t.name ? t() : t;
|
|
2402
|
-
t = t.name ? t.name : t;
|
|
2403
|
-
return String(t).toLowerCase();
|
|
2404
|
-
});
|
|
2405
|
-
const errs = newValues.map((childValue) => {
|
|
2406
|
-
// find by id so the list elements order doesn't matter
|
|
2407
|
-
const id = findModelId(childValue, true);
|
|
2408
|
-
if (!id)
|
|
2409
|
-
return "Failed to find model id";
|
|
2410
|
-
const oldModel = oldValues.find((el) => id === findModelId(el, true));
|
|
2411
|
-
if (Model.isModel(childValue)) {
|
|
2412
|
-
return childValue.hasErrors(oldModel);
|
|
2413
|
-
}
|
|
2414
|
-
return allowedTypes.includes(typeof childValue)
|
|
2415
|
-
? undefined
|
|
2416
|
-
: "Value has no validatable type";
|
|
2417
|
-
});
|
|
2418
|
-
if (async) {
|
|
2419
|
-
validationErrors = Promise.all(errs).then((result) => {
|
|
2420
|
-
const allEmpty = result.every((r) => !r);
|
|
2421
|
-
return allEmpty ? undefined : result;
|
|
2422
|
-
});
|
|
2423
|
-
}
|
|
2424
|
-
else {
|
|
2425
|
-
const allEmpty = errs.every((r) => !r);
|
|
2426
|
-
validationErrors = errs.length > 0 && !allEmpty ? errs : undefined;
|
|
2427
|
-
}
|
|
2428
|
-
}
|
|
2429
|
-
}
|
|
2430
|
-
if (validationErrors)
|
|
2431
|
-
result[decorator.key] = validationErrors;
|
|
2432
|
-
}
|
|
2433
|
-
if (!async)
|
|
2434
|
-
return Object.keys(result).length > 0 ? result : undefined;
|
|
2435
|
-
const keys = Object.keys(result);
|
|
2436
|
-
const promises = Object.values(result);
|
|
2437
|
-
return Promise.all(promises).then((resolvedValues) => {
|
|
2438
|
-
const res = {};
|
|
2439
|
-
for (let i = 0; i < resolvedValues.length; i++) {
|
|
2440
|
-
const val = resolvedValues[i];
|
|
2441
|
-
if (val !== undefined) {
|
|
2442
|
-
res[keys[i]] = val;
|
|
2443
|
-
}
|
|
2444
|
-
}
|
|
2445
|
-
return Object.keys(res).length > 0 ? res : undefined;
|
|
2446
|
-
});
|
|
2447
|
-
}
|
|
2448
|
-
/**
|
|
2449
|
-
* @description Validates changes between two model versions
|
|
2450
|
-
* @summary Compares an old and new model version to validate update operations
|
|
2451
|
-
* @template M - Type extending Model
|
|
2452
|
-
* @param {M} oldModel - The original model version
|
|
2453
|
-
* @param {M} newModel - The updated model version
|
|
2454
|
-
* @param {boolean} async - A flag indicating whether validation should be asynchronous.
|
|
2455
|
-
* @param {...string[]} exceptions - Properties to exclude from validation
|
|
2456
|
-
* @return {ModelErrorDefinition|undefined} Error definition if validation fails, undefined otherwise
|
|
2457
|
-
* @function validateCompare
|
|
2458
|
-
* @memberOf module:db-decorators
|
|
2459
|
-
* @mermaid
|
|
2460
|
-
* sequenceDiagram
|
|
2461
|
-
* participant Caller
|
|
2462
|
-
* participant validateCompare
|
|
2463
|
-
* participant Reflection
|
|
2464
|
-
* participant Validation
|
|
2465
|
-
*
|
|
2466
|
-
* Caller->>validateCompare: oldModel, newModel, exceptions
|
|
2467
|
-
* validateCompare->>Reflection: get decorated properties
|
|
2468
|
-
* Reflection-->>validateCompare: property decorators
|
|
2469
|
-
* loop For each decorated property
|
|
2470
|
-
* validateCompare->>Validation: get validator
|
|
2471
|
-
* Validation-->>validateCompare: validator
|
|
2472
|
-
* validateCompare->>validateCompare: validate property update
|
|
2473
|
-
* end
|
|
2474
|
-
* loop For nested models
|
|
2475
|
-
* validateCompare->>validateCompare: validate nested models
|
|
2476
|
-
* end
|
|
2477
|
-
* validateCompare-->>Caller: validation errors or undefined
|
|
2478
|
-
*/
|
|
2479
|
-
function validateCompare(oldModel, newModel, async, ...exceptions) {
|
|
2480
|
-
const decoratedProperties = getValidatableUpdateProps(newModel, exceptions);
|
|
2481
|
-
const result = {};
|
|
2482
|
-
const nestedErrors = {};
|
|
2483
|
-
for (const { prop, decorators } of decoratedProperties) {
|
|
2484
|
-
const propKey = String(prop);
|
|
2485
|
-
let propValue = newModel[prop];
|
|
2486
|
-
if (!decorators?.length)
|
|
2487
|
-
continue;
|
|
2488
|
-
// Get the default type validator
|
|
2489
|
-
const designTypeDec = decorators.find((d) => [ModelKeys.TYPE, ValidationKeys.TYPE].includes(d.key));
|
|
2490
|
-
if (!designTypeDec)
|
|
2491
|
-
continue;
|
|
2492
|
-
const designType = designTypeDec.props.name;
|
|
2493
|
-
// Handle array or Set types and enforce the presence of @list decorator
|
|
2494
|
-
if ([Array.name, Set.name].includes(designType)) {
|
|
2495
|
-
const { decorators } = Reflection.getPropertyDecorators(ValidationKeys.REFLECT, newModel, propKey);
|
|
2496
|
-
if (!decorators.some((d) => d.key === ValidationKeys.LIST)) {
|
|
2497
|
-
result[propKey] = {
|
|
2498
|
-
[ValidationKeys.TYPE]: `Array or Set property '${propKey}' requires a @list decorator`,
|
|
2499
|
-
};
|
|
2500
|
-
continue;
|
|
2501
|
-
}
|
|
2502
|
-
if (propValue &&
|
|
2503
|
-
!(Array.isArray(propValue) || propValue instanceof Set)) {
|
|
2504
|
-
result[propKey] = {
|
|
2505
|
-
[ValidationKeys.TYPE]: `Property '${String(prop)}' must be either an array or a Set`,
|
|
2506
|
-
};
|
|
2507
|
-
continue;
|
|
2508
|
-
}
|
|
2509
|
-
// Remove design:type decorator, since @list decorator already ensures type
|
|
2510
|
-
for (let i = decorators.length - 1; i >= 0; i--) {
|
|
2511
|
-
if (decorators[i].key === ModelKeys.TYPE) {
|
|
2512
|
-
decorators.splice(i, 1);
|
|
2513
|
-
}
|
|
2514
|
-
}
|
|
2515
|
-
propValue = propValue instanceof Set ? [...propValue] : propValue;
|
|
2516
|
-
}
|
|
2517
|
-
const propErrors = validateDecorators(newModel, oldModel, propKey, decorators, async) || {};
|
|
2518
|
-
// Check for nested properties.
|
|
2519
|
-
// To prevent unnecessary processing, "propValue" must be defined and validatable
|
|
2520
|
-
const isConstr = Model.isPropertyModel(newModel, propKey);
|
|
2521
|
-
// if propValue !== undefined, null
|
|
2522
|
-
if (propValue && isConstr) {
|
|
2523
|
-
const instance = propValue;
|
|
2524
|
-
const isInvalidModel = typeof instance !== "object" ||
|
|
2525
|
-
!instance.hasErrors ||
|
|
2526
|
-
typeof instance.hasErrors !== "function";
|
|
2527
|
-
if (isInvalidModel) {
|
|
2528
|
-
// propErrors[ValidationKeys.TYPE] =
|
|
2529
|
-
// "Model should be validatable but it's not.";
|
|
2530
|
-
console.warn("Model should be validatable but it's not.");
|
|
2531
|
-
}
|
|
2532
|
-
else {
|
|
2533
|
-
nestedErrors[propKey] = instance.hasErrors(oldModel[prop]);
|
|
2534
|
-
}
|
|
2535
|
-
}
|
|
2536
|
-
// Add to the result if we have any errors
|
|
2537
|
-
// Async mode returns a Promise that resolves to undefined when no errors exist
|
|
2538
|
-
if (Object.keys(propErrors).length > 0 || async)
|
|
2539
|
-
result[propKey] = propErrors;
|
|
2540
|
-
// Then merge any nested errors
|
|
2541
|
-
if (!async) {
|
|
2542
|
-
Object.entries(nestedErrors[propKey] || {}).forEach(([key, error]) => {
|
|
2543
|
-
if (error !== undefined) {
|
|
2544
|
-
result[`${propKey}.${key}`] = error;
|
|
2545
|
-
}
|
|
2546
|
-
});
|
|
2547
|
-
}
|
|
2548
|
-
}
|
|
2549
|
-
// Synchronous return
|
|
2550
|
-
if (!async) {
|
|
2551
|
-
return (Object.keys(result).length > 0
|
|
2552
|
-
? new ModelErrorDefinition(result)
|
|
2553
|
-
: undefined);
|
|
2554
|
-
}
|
|
2555
|
-
const merged = result; // TODO: apply filtering
|
|
2556
|
-
const keys = Object.keys(merged);
|
|
2557
|
-
const promises = Object.values(merged);
|
|
2558
|
-
return Promise.allSettled(promises).then(async (results) => {
|
|
2559
|
-
const result = {};
|
|
2560
|
-
for (const [parentProp, nestedErrPromise] of Object.entries(nestedErrors)) {
|
|
2561
|
-
const nestedPropDecErrors = (await nestedErrPromise);
|
|
2562
|
-
if (nestedPropDecErrors)
|
|
2563
|
-
Object.entries(nestedPropDecErrors).forEach(([nestedProp, nestedPropDecError]) => {
|
|
2564
|
-
if (nestedPropDecError !== undefined) {
|
|
2565
|
-
const nestedKey = [parentProp, nestedProp].join(".");
|
|
2566
|
-
result[nestedKey] = nestedPropDecError;
|
|
2567
|
-
}
|
|
2568
|
-
});
|
|
2569
|
-
}
|
|
2570
|
-
for (let i = 0; i < results.length; i++) {
|
|
2571
|
-
const key = keys[i];
|
|
2572
|
-
const res = results[i];
|
|
2573
|
-
if (res.status === "fulfilled" && res.value !== undefined) {
|
|
2574
|
-
result[key] = res.value;
|
|
2575
|
-
}
|
|
2576
|
-
else if (res.status === "rejected") {
|
|
2577
|
-
result[key] =
|
|
2578
|
-
res.reason instanceof Error
|
|
2579
|
-
? res.reason.message
|
|
2580
|
-
: String(res.reason || "Validation failed");
|
|
2581
|
-
}
|
|
2582
|
-
}
|
|
2583
|
-
return Object.keys(result).length > 0
|
|
2584
|
-
? new ModelErrorDefinition(result)
|
|
2585
|
-
: undefined;
|
|
2586
|
-
});
|
|
2587
|
-
}
|
|
2588
|
-
|
|
2589
|
-
/**
|
|
2590
|
-
* @description Hashes a property value during create or update operations
|
|
2591
|
-
* @summary Callback function used by the hash decorator to apply hashing to a property value
|
|
2592
|
-
* @template M - Type extending Model
|
|
2593
|
-
* @template R - Type extending IRepository
|
|
2594
|
-
* @template V - Type for metadata
|
|
2595
|
-
* @template F - Type extending RepositoryFlags
|
|
2596
|
-
* @template C - Type extending Context
|
|
2597
|
-
* @param {C} context - The operation context
|
|
2598
|
-
* @param {V} data - Metadata for the operation
|
|
2599
|
-
* @param key - The property key to hash
|
|
2600
|
-
* @param {M} model - The model being processed
|
|
2601
|
-
* @param {M} [oldModel] - The previous model state (for updates)
|
|
2602
|
-
* @return {void}
|
|
2603
|
-
* @function hashOnCreateUpdate
|
|
2604
|
-
* @memberOf module:db-decorators
|
|
2605
|
-
*/
|
|
2606
|
-
function hashOnCreateUpdate(context, data, key, model, oldModel) {
|
|
2607
|
-
if (typeof model[key] === "undefined")
|
|
2608
|
-
return;
|
|
2609
|
-
const hash = Hashing.hash(model[key]);
|
|
2610
|
-
if (oldModel && model[key] === hash)
|
|
2611
|
-
return;
|
|
2612
|
-
model[key] = hash;
|
|
2613
|
-
}
|
|
2614
|
-
/**
|
|
2615
|
-
* @description Creates a decorator that hashes a property value
|
|
2616
|
-
* @summary Decorator that automatically hashes a property value during create and update operations
|
|
2617
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
2618
|
-
* @function hash
|
|
2619
|
-
* @category Property Decorators
|
|
2620
|
-
*/
|
|
2621
|
-
function hash() {
|
|
2622
|
-
return apply(onCreateUpdate(hashOnCreateUpdate), propMetadata(Repository.key(DBKeys.HASH), {}));
|
|
2623
|
-
}
|
|
2624
|
-
/**
|
|
2625
|
-
* @description Composes a property value from other properties during create or update operations
|
|
2626
|
-
* @summary Callback function used by composed decorators to generate a property value from other properties
|
|
2627
|
-
* @template M - Type extending Model
|
|
2628
|
-
* @template R - Type extending IRepository
|
|
2629
|
-
* @template V - Type extending ComposedFromMetadata
|
|
2630
|
-
* @template F - Type extending RepositoryFlags
|
|
2631
|
-
* @template C - Type extending Context
|
|
2632
|
-
* @param {C} context - The operation context
|
|
2633
|
-
* @param {V} data - Metadata for the composition
|
|
2634
|
-
* @param key - The property key to set the composed value on
|
|
2635
|
-
* @param {M} model - The model being processed
|
|
2636
|
-
* @return {void}
|
|
2637
|
-
* @function composedFromCreateUpdate
|
|
2638
|
-
* @memberOf module:db-decorators
|
|
2639
|
-
*/
|
|
2640
|
-
function composedFromCreateUpdate(context, data, key, model) {
|
|
2641
|
-
try {
|
|
2642
|
-
const { args, type, prefix, suffix, separator } = data;
|
|
2643
|
-
const composed = args.map((arg) => {
|
|
2644
|
-
if (!(arg in model))
|
|
2645
|
-
throw new InternalError(`Property ${arg} not found to compose from`);
|
|
2646
|
-
if (type === "keys")
|
|
2647
|
-
return arg;
|
|
2648
|
-
if (typeof model[arg] === "undefined")
|
|
2649
|
-
throw new InternalError(`Property ${args} does not contain a value to compose from`);
|
|
2650
|
-
return model[arg].toString();
|
|
2651
|
-
});
|
|
2652
|
-
if (prefix)
|
|
2653
|
-
composed.unshift(prefix);
|
|
2654
|
-
if (suffix)
|
|
2655
|
-
composed.push(suffix);
|
|
2656
|
-
model[key] = composed.join(separator);
|
|
2657
|
-
}
|
|
2658
|
-
catch (e) {
|
|
2659
|
-
throw new InternalError(`Failed to compose value: ${e}`);
|
|
2660
|
-
}
|
|
2661
|
-
}
|
|
2662
|
-
/**
|
|
2663
|
-
* @description Creates a decorator that composes a property value from other properties
|
|
2664
|
-
* @summary Base function for creating property composition decorators
|
|
2665
|
-
* @param {string[]} args - Property names to compose from
|
|
2666
|
-
* @param {boolean} [hashResult=false] - Whether to hash the composed result
|
|
2667
|
-
* @param {string} [separator=DefaultSeparator] - Character used to join the composed values
|
|
2668
|
-
* @param {"keys"|"values"} [type="values"] - Whether to use property keys or values
|
|
2669
|
-
* @param {string} [prefix=""] - Optional prefix to add to the composed value
|
|
2670
|
-
* @param {string} [suffix=""] - Optional suffix to add to the composed value
|
|
2671
|
-
* @param {GroupSort} groupsort - GroupSort configuration
|
|
2672
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
2673
|
-
* @function composedFrom
|
|
2674
|
-
* @category PropertyDecorators
|
|
2675
|
-
*/
|
|
2676
|
-
function composedFrom(args, hashResult = false, separator = DefaultSeparator, type = "values", prefix = "", suffix = "", groupsort = { priority: 55 }) {
|
|
2677
|
-
const data = {
|
|
2678
|
-
args: args,
|
|
2679
|
-
hashResult: hashResult,
|
|
2680
|
-
separator: separator,
|
|
2681
|
-
type: type,
|
|
2682
|
-
prefix: prefix,
|
|
2683
|
-
suffix: suffix,
|
|
2684
|
-
};
|
|
2685
|
-
const decorators = [
|
|
2686
|
-
onCreateUpdate(composedFromCreateUpdate, data, groupsort),
|
|
2687
|
-
propMetadata(Repository.key(DBKeys.COMPOSED), data),
|
|
2688
|
-
];
|
|
2689
|
-
if (hashResult)
|
|
2690
|
-
decorators.push(hash());
|
|
2691
|
-
return apply(...decorators);
|
|
2692
|
-
}
|
|
2693
|
-
/**
|
|
2694
|
-
* @description Creates a decorator that composes a property value from property keys
|
|
2695
|
-
* @summary Decorator that generates a property value by joining the names of other properties
|
|
2696
|
-
* @param {string[]} args - Property names to compose from
|
|
2697
|
-
* @param {string} [separator=DefaultSeparator] - Character used to join the property names
|
|
2698
|
-
* @param {boolean} [hash=false] - Whether to hash the composed result
|
|
2699
|
-
* @param {string} [prefix=""] - Optional prefix to add to the composed value
|
|
2700
|
-
* @param {string} [suffix=""] - Optional suffix to add to the composed value
|
|
2701
|
-
* @param {GroupSort} groupsort - GroupSort configuration
|
|
2702
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
2703
|
-
* @function composedFromKeys
|
|
2704
|
-
* @category PropertyDecorators
|
|
2705
|
-
*/
|
|
2706
|
-
function composedFromKeys(args, separator = DefaultSeparator, hash = false, prefix = "", suffix = "", groupsort = { priority: 55 }) {
|
|
2707
|
-
return composedFrom(args, hash, separator, "keys", prefix, suffix, groupsort);
|
|
2708
|
-
}
|
|
2709
|
-
/**
|
|
2710
|
-
* @description Creates a decorator that composes a property value from property values
|
|
2711
|
-
* @summary Decorator that generates a property value by joining the values of other properties
|
|
2712
|
-
* @param {string[]} args - Property names whose values will be composed
|
|
2713
|
-
* @param {string} [separator=DefaultSeparator] - Character used to join the property values
|
|
2714
|
-
* @param {boolean} [hash=false] - Whether to hash the composed result
|
|
2715
|
-
* @param {string} [prefix=""] - Optional prefix to add to the composed value
|
|
2716
|
-
* @param {string} [suffix=""] - Optional suffix to add to the composed value
|
|
2717
|
-
* @param {GroupSort} groupsort - GroupSort configuration
|
|
2718
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
2719
|
-
* @function composed
|
|
2720
|
-
* @category PropertyDecorators
|
|
2721
|
-
*/
|
|
2722
|
-
function composed(args, separator = DefaultSeparator, hash = false, prefix = "", suffix = "", groupsort = { priority: 55 }) {
|
|
2723
|
-
return composedFrom(args, hash, separator, "values", prefix, suffix, groupsort);
|
|
2724
|
-
}
|
|
2725
|
-
/**
|
|
2726
|
-
* @description Creates a function that updates a version property during operations
|
|
2727
|
-
* @summary Factory function that generates a callback for incrementing version numbers
|
|
2728
|
-
* @param {CrudOperations} operation - The type of operation (CREATE or UPDATE)
|
|
2729
|
-
* @return {Function} A callback function that updates the version property
|
|
2730
|
-
* @template M - Type extending Model
|
|
2731
|
-
* @template R - Type extending IRepository
|
|
2732
|
-
* @template V - Type for metadata
|
|
2733
|
-
* @template F - Type extending RepositoryFlags
|
|
2734
|
-
* @template C - Type extending Context
|
|
2735
|
-
* @function versionCreateUpdate
|
|
2736
|
-
* @memberOf module:db-decorators
|
|
2737
|
-
* @mermaid
|
|
2738
|
-
* sequenceDiagram
|
|
2739
|
-
* participant Caller
|
|
2740
|
-
* participant versionCreateUpdate
|
|
2741
|
-
*
|
|
2742
|
-
* Caller->>versionCreateUpdate: operation
|
|
2743
|
-
* versionCreateUpdate-->>Caller: callback function
|
|
2744
|
-
* Note over Caller,versionCreateUpdate: When callback is executed:
|
|
2745
|
-
* Caller->>versionCreateUpdate: context, data, key, model
|
|
2746
|
-
* alt operation is CREATE
|
|
2747
|
-
* versionCreateUpdate->>versionCreateUpdate: set version to 1
|
|
2748
|
-
* else operation is UPDATE
|
|
2749
|
-
* versionCreateUpdate->>versionCreateUpdate: increment version
|
|
2750
|
-
* else invalid operation
|
|
2751
|
-
* versionCreateUpdate->>versionCreateUpdate: throw error
|
|
2752
|
-
* end
|
|
2753
|
-
* versionCreateUpdate-->>Caller: void
|
|
2754
|
-
*/
|
|
2755
|
-
function versionCreateUpdate(operation) {
|
|
2756
|
-
return function versionCreateUpdate(context, data, key, model) {
|
|
2757
|
-
try {
|
|
2758
|
-
switch (operation) {
|
|
2759
|
-
case OperationKeys.CREATE:
|
|
2760
|
-
model[key] = 1;
|
|
2761
|
-
break;
|
|
2762
|
-
case OperationKeys.UPDATE:
|
|
2763
|
-
model[key]++;
|
|
2764
|
-
break;
|
|
2765
|
-
default:
|
|
2766
|
-
throw new InternalError(`Invalid operation: ${operation}`);
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
|
-
catch (e) {
|
|
2770
|
-
throw new InternalError(`Failed to update version: ${e}`);
|
|
2771
|
-
}
|
|
2772
|
-
};
|
|
2773
|
-
}
|
|
2774
|
-
/**
|
|
2775
|
-
* @description Creates a decorator for versioning a property in a model
|
|
2776
|
-
* @summary This decorator applies multiple sub-decorators to handle version management during create and update operations
|
|
2777
|
-
* @return {PropertyDecorator} A composite decorator that sets the type to Number, manages version updates, and adds versioning metadata
|
|
2778
|
-
* @function version
|
|
2779
|
-
* @category PropertyDecorators
|
|
2780
|
-
*/
|
|
2781
|
-
function version() {
|
|
2782
|
-
const key = Repository.key(DBKeys.VERSION);
|
|
2783
|
-
return Decoration.for(key)
|
|
2784
|
-
.define(type(Number.name), onCreate(versionCreateUpdate(OperationKeys.CREATE)), onUpdate(versionCreateUpdate(OperationKeys.UPDATE)), propMetadata(key, true))
|
|
2785
|
-
.apply();
|
|
2786
|
-
}
|
|
2787
|
-
/**
|
|
2788
|
-
* @description Creates a decorator that marks a property as transient
|
|
2789
|
-
* @summary Decorator that indicates a property should not be persisted to the database
|
|
2790
|
-
* @return {PropertyDecorator} A decorator that can be applied to class properties
|
|
2791
|
-
* @function transient
|
|
2792
|
-
* @category PropertyDecorators
|
|
2793
|
-
*/
|
|
2794
|
-
function transient() {
|
|
2795
|
-
const key = Repository.key(DBKeys.TRANSIENT);
|
|
2796
|
-
return Decoration.for(key)
|
|
2797
|
-
.define(function transient(model, attribute) {
|
|
2798
|
-
propMetadata(Repository.key(DBKeys.TRANSIENT), true)(model, attribute);
|
|
2799
|
-
propMetadata(Repository.key(DBKeys.TRANSIENT), true)(model.constructor);
|
|
2800
|
-
})
|
|
2801
|
-
.apply();
|
|
2802
|
-
}
|
|
2803
|
-
|
|
2804
|
-
/**
|
|
2805
|
-
* @description Validates the model and checks for errors
|
|
2806
|
-
* @summary Validates the current model state and optionally compares with a previous version
|
|
2807
|
-
* @template M - Type extending Model
|
|
2808
|
-
* @param {M|any} [previousVersion] - Optional previous version of the model for comparison
|
|
2809
|
-
* @param {...any[]} exclusions - Properties to exclude from validation
|
|
2810
|
-
* @return {ModelErrorDefinition|undefined} Error definition if validation fails, undefined otherwise
|
|
2811
|
-
* @function hasErrors
|
|
2812
|
-
* @memberOf module:db-decorators
|
|
2813
|
-
*/
|
|
2814
|
-
Model.prototype.hasErrors = function (previousVersion, ...exclusions) {
|
|
2815
|
-
if (previousVersion && !(previousVersion instanceof Model)) {
|
|
2816
|
-
exclusions.unshift(previousVersion);
|
|
2817
|
-
previousVersion = undefined;
|
|
2818
|
-
}
|
|
2819
|
-
const async = this.isAsync();
|
|
2820
|
-
const errs = validate(this, async, ...exclusions);
|
|
2821
|
-
if (async) {
|
|
2822
|
-
return Promise.resolve(errs).then((resolvedErrs) => {
|
|
2823
|
-
if (resolvedErrs || !previousVersion) {
|
|
2824
|
-
return resolvedErrs;
|
|
2825
|
-
}
|
|
2826
|
-
return validateCompare(previousVersion, this, async, ...exclusions);
|
|
2827
|
-
});
|
|
2828
|
-
}
|
|
2829
|
-
if (errs || !previousVersion)
|
|
2830
|
-
return errs;
|
|
2831
|
-
// @ts-expect-error Overriding Model prototype method with dynamic conditional return type.
|
|
2832
|
-
return validateCompare(previousVersion, this, async, ...exclusions);
|
|
2833
|
-
};
|
|
2834
|
-
|
|
2835
|
-
/**
|
|
2836
|
-
* @description Checks if a model is marked as transient
|
|
2837
|
-
* @summary Determines whether a model class has been decorated with the transient decorator
|
|
2838
|
-
* @template M - Type extending Model
|
|
2839
|
-
* @param {M} model - The model instance to check
|
|
2840
|
-
* @return {boolean} True if the model is transient, false otherwise
|
|
2841
|
-
* @function isTransient
|
|
2842
|
-
* @memberOf module:db-decorators
|
|
2843
|
-
*/
|
|
2844
|
-
function isTransient(model) {
|
|
2845
|
-
return !!(Reflect.getMetadata(Repository.key(DBKeys.TRANSIENT), model.constructor) ||
|
|
2846
|
-
Reflect.getMetadata(Repository.key(DBKeys.TRANSIENT), Model.get(model.constructor.name)));
|
|
2847
|
-
}
|
|
2848
|
-
/**
|
|
2849
|
-
* @description Separates transient properties from a model
|
|
2850
|
-
* @summary Extracts properties marked as transient into a separate object
|
|
2851
|
-
* @template M - Type extending Model
|
|
2852
|
-
* @param {M} model - The model instance to process
|
|
2853
|
-
* @return {Object} Object containing the model without transient properties and a separate transient object
|
|
2854
|
-
* @property {M} model - The model with transient properties removed
|
|
2855
|
-
* @property {Record<string, any>} [transient] - Object containing the transient properties
|
|
2856
|
-
* @function modelToTransient
|
|
2857
|
-
* @memberOf module:db-decorators
|
|
2858
|
-
* @mermaid
|
|
2859
|
-
* sequenceDiagram
|
|
2860
|
-
* participant Caller
|
|
2861
|
-
* participant modelToTransient
|
|
2862
|
-
* participant isTransient
|
|
2863
|
-
* participant getAllPropertyDecoratorsRecursive
|
|
2864
|
-
*
|
|
2865
|
-
* Caller->>modelToTransient: model
|
|
2866
|
-
* modelToTransient->>isTransient: check if model is transient
|
|
2867
|
-
* isTransient-->>modelToTransient: transient status
|
|
2868
|
-
* alt model is not transient
|
|
2869
|
-
* modelToTransient-->>Caller: {model}
|
|
2870
|
-
* else model is transient
|
|
2871
|
-
* modelToTransient->>getAllPropertyDecoratorsRecursive: get transient properties
|
|
2872
|
-
* getAllPropertyDecoratorsRecursive-->>modelToTransient: property decorators
|
|
2873
|
-
* modelToTransient->>modelToTransient: separate properties
|
|
2874
|
-
* modelToTransient->>Model.build: rebuild model without transient props
|
|
2875
|
-
* modelToTransient-->>Caller: {model, transient}
|
|
2876
|
-
* end
|
|
2877
|
-
*/
|
|
2878
|
-
function modelToTransient(model) {
|
|
2879
|
-
if (!isTransient(model))
|
|
2880
|
-
return { model: model };
|
|
2881
|
-
const decs = getAllPropertyDecoratorsRecursive(model, undefined, Repository.key(DBKeys.TRANSIENT));
|
|
2882
|
-
const result = Object.entries(decs).reduce((accum, [k, val]) => {
|
|
2883
|
-
const transient = val.find((el) => el.key === "");
|
|
2884
|
-
if (transient) {
|
|
2885
|
-
accum.transient = accum.transient || {};
|
|
2886
|
-
try {
|
|
2887
|
-
accum.transient[k] = model[k];
|
|
2888
|
-
}
|
|
2889
|
-
catch (e) {
|
|
2890
|
-
throw new SerializationError(`Failed to serialize transient property ${k}: ${e}`);
|
|
2891
|
-
}
|
|
2892
|
-
}
|
|
2893
|
-
else {
|
|
2894
|
-
accum.model = accum.model || {};
|
|
2895
|
-
accum.model[k] = model[k];
|
|
2896
|
-
}
|
|
2897
|
-
return accum;
|
|
2898
|
-
}, {});
|
|
2899
|
-
result.model = Model.build(result.model, model.constructor.name);
|
|
2900
|
-
return result;
|
|
2901
|
-
}
|
|
2902
|
-
|
|
2903
|
-
/**
|
|
2904
|
-
* @description Database decorators for TypeScript applications
|
|
2905
|
-
* @summary A comprehensive library providing decorators and utilities for database operations, model definitions, validation, and repository patterns in TypeScript applications
|
|
2906
|
-
* @module db-decorators
|
|
2907
|
-
*/
|
|
2908
|
-
/**
|
|
2909
|
-
* @description Current version of the reflection package
|
|
2910
|
-
* @summary Stores the semantic version number of the package
|
|
2911
|
-
* @const VERSION
|
|
2912
|
-
* @memberOf module:db-decorators
|
|
2913
|
-
*/
|
|
2914
|
-
const VERSION = "0.6.11";
|
|
2915
|
-
|
|
2916
|
-
export { BadRequestError, BaseError, BaseRepository, BulkCrudOperationKeys, ConflictError, Context, DBKeys, DBOperations, DEFAULT_ERROR_MESSAGES, DEFAULT_TIMESTAMP_FORMAT, DefaultContextFactory, DefaultRepositoryFlags, DefaultSeparator, InternalError, NotFoundError, OperationKeys, Operations, OperationsRegistry, ReadOnlyValidator, Repository, SerializationError, TimestampValidator, UpdateValidationKeys, UpdateValidator, VERSION, ValidationError, after, afterAny, afterCreate, afterCreateUpdate, afterDelete, afterRead, afterUpdate, composed, composedFromCreateUpdate, composedFromKeys, enforceDBDecorators, findModelId, findPrimaryKey, getAllPropertyDecoratorsRecursive, getDbDecorators, getHandlerArgs, getHandlersDecorators, getValidatableUpdateProps, groupDecorators, hash, hashOnCreateUpdate, id, isTransient, modelToTransient, on, onAny, onCreate, onCreateUpdate, onDelete, onRead, onUpdate, operation, prefixMethod, readonly, serialize, serializeAfterAll, serializeOnCreateUpdate, sortDecorators, suffixMethod, timestamp, timestampHandler, transient, validateCompare, validateDecorator, validateDecorators, version, versionCreateUpdate, wrapMethodWithContext };
|
|
2917
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGItZGVjb3JhdG9ycy5lc20uY2pzIiwic291cmNlcyI6WyIuLi9zcmMvbW9kZWwvY29uc3RhbnRzLnRzIiwiLi4vc3JjL3ZhbGlkYXRpb24vY29uc3RhbnRzLnRzIiwiLi4vc3JjL3ZhbGlkYXRpb24vdmFsaWRhdG9ycy9SZWFkT25seVZhbGlkYXRvci50cyIsIi4uL3NyYy92YWxpZGF0aW9uL3ZhbGlkYXRvcnMvVGltZXN0YW1wVmFsaWRhdG9yLnRzIiwiLi4vc3JjL3ZhbGlkYXRpb24vdmFsaWRhdG9ycy9VcGRhdGVWYWxpZGF0b3IudHMiLCIuLi9zcmMvdmFsaWRhdGlvbi92YWxpZGF0aW9uLnRzIiwiLi4vc3JjL29wZXJhdGlvbnMvY29uc3RhbnRzLnRzIiwiLi4vc3JjL29wZXJhdGlvbnMvT3BlcmF0aW9uc1JlZ2lzdHJ5LnRzIiwiLi4vc3JjL29wZXJhdGlvbnMvT3BlcmF0aW9ucy50cyIsIi4uL3NyYy9yZXBvc2l0b3J5L2Vycm9ycy50cyIsIi4uL3NyYy9yZXBvc2l0b3J5L3V0aWxzLnRzIiwiLi4vc3JjL29wZXJhdGlvbnMvZGVjb3JhdG9ycy50cyIsIi4uL3NyYy9yZXBvc2l0b3J5L2NvbnN0YW50cy50cyIsIi4uL3NyYy9yZXBvc2l0b3J5L0NvbnRleHQudHMiLCIuLi9zcmMvcmVwb3NpdG9yeS93cmFwcGVycy50cyIsIi4uL3NyYy9pZGVudGl0eS91dGlscy50cyIsIi4uL3NyYy9yZXBvc2l0b3J5L0Jhc2VSZXBvc2l0b3J5LnRzIiwiLi4vc3JjL3JlcG9zaXRvcnkvUmVwb3NpdG9yeS50cyIsIi4uL3NyYy92YWxpZGF0aW9uL2RlY29yYXRvcnMudHMiLCIuLi9zcmMvaWRlbnRpdHkvZGVjb3JhdG9ycy50cyIsIi4uL3NyYy9tb2RlbC92YWxpZGF0aW9uLnRzIiwiLi4vc3JjL21vZGVsL2RlY29yYXRvcnMudHMiLCIuLi9zcmMvbW9kZWwvb3ZlcnJpZGVzLnRzIiwiLi4vc3JjL21vZGVsL3V0aWxzLnRzIiwiLi4vc3JjL2luZGV4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE1vZGVsS2V5cyB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGF0YWJhc2UgcmVmbGVjdGlvbiBrZXlzXG4gKiBAc3VtbWFyeSBDb2xsZWN0aW9uIG9mIGtleXMgdXNlZCBmb3IgcmVmbGVjdGlvbiBtZXRhZGF0YSBpbiBkYXRhYmFzZSBvcGVyYXRpb25zXG4gKiBAY29uc3QgREJLZXlzXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmRiLWRlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGNvbnN0IERCS2V5cyA9IHtcbiAgUkVGTEVDVDogYCR7TW9kZWxLZXlzLlJFRkxFQ1R9cGVyc2lzdGVuY2UuYCxcbiAgUkVQT1NJVE9SWTogXCJyZXBvc2l0b3J5XCIsXG4gIENMQVNTOiBcIl9jbGFzc1wiLFxuICBJRDogXCJpZFwiLFxuICBJTkRFWDogXCJpbmRleFwiLFxuICBVTklRVUU6IFwidW5pcXVlXCIsXG4gIFNFUklBTElaRTogXCJzZXJpYWxpemVcIixcbiAgUkVBRE9OTFk6IFwicmVhZG9ubHlcIixcbiAgVElNRVNUQU1QOiBcInRpbWVzdGFtcFwiLFxuICBUUkFOU0lFTlQ6IFwidHJhbnNpZW50XCIsXG4gIEhBU0g6IFwiaGFzaFwiLFxuICBDT01QT1NFRDogXCJjb21wb3NlZFwiLFxuICBWRVJTSU9OOiBcInZlcnNpb25cIixcbiAgT1JJR0lOQUw6IFwiX19vcmlnaW5hbE9ialwiLFxufTtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVmYXVsdCBzZXBhcmF0b3IgY2hhcmFjdGVyIGZvciBjb21wb3NpdGUgaW5kZXhlc1xuICogQHN1bW1hcnkgVGhlIGRlZmF1bHQgc2VwYXJhdG9yIGNoYXJhY3RlciB1c2VkIHdoZW4gY29uY2F0ZW5hdGluZyBtdWx0aXBsZSBmaWVsZHMgaW50byBhIHNpbmdsZSBpbmRleFxuICogQGNvbnN0IERlZmF1bHRTZXBhcmF0b3JcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9yc1xuICovXG5leHBvcnQgY29uc3QgRGVmYXVsdFNlcGFyYXRvciA9IFwiX1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBEZWZhdWx0IGZvcm1hdCBmb3IgdGltZXN0YW1wIGZpZWxkc1xuICogQHN1bW1hcnkgU3RhbmRhcmQgZGF0ZSBmb3JtYXQgc3RyaW5nIHVzZWQgZm9yIHRpbWVzdGFtcCBmaWVsZHMgaW4gZGF0YWJhc2UgbW9kZWxzXG4gKiBAY29uc3QgREVGQVVMVF9USU1FU1RBTVBfRk9STUFUXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmRiLWRlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfVElNRVNUQU1QX0ZPUk1BVCA9IFwiZGQvTU0veXl5eSBISDptbTpzczpTXCI7XG4iLCJpbXBvcnQgeyBEQktleXMgfSBmcm9tIFwiLi4vbW9kZWwvY29uc3RhbnRzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbGxlY3Rpb24gb2YgZGVmYXVsdCBlcnJvciBtZXNzYWdlcyB1c2VkIGJ5IHZhbGlkYXRvcnMuXG4gKiBAc3VtbWFyeSBIb2xkcyB0aGUgZGVmYXVsdCBlcnJvciBtZXNzYWdlcyBmb3IgdmFyaW91cyB2YWxpZGF0aW9uIHNjZW5hcmlvcyBpbmNsdWRpbmcgSUQgdmFsaWRhdGlvbiwgcmVhZG9ubHkgcHJvcGVydGllcywgYW5kIHRpbWVzdGFtcHMuXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBFcnJvck1lc3NhZ2VzXG4gKiBAcHJvcGVydHkge09iamVjdH0gSUQgLSBFcnJvciBtZXNzYWdlcyBmb3IgSUQgdmFsaWRhdGlvblxuICogQHByb3BlcnR5IHtzdHJpbmd9IElELklOVkFMSUQgLSBFcnJvciBtZXNzYWdlIHdoZW4gYW4gSUQgaXMgaW52YWxpZFxuICogQHByb3BlcnR5IHtzdHJpbmd9IElELlJFUVVJUkVEIC0gRXJyb3IgbWVzc2FnZSB3aGVuIGFuIElEIGlzIG1pc3NpbmdcbiAqIEBwcm9wZXJ0eSB7T2JqZWN0fSBSRUFET05MWSAtIEVycm9yIG1lc3NhZ2VzIGZvciByZWFkb25seSBwcm9wZXJ0aWVzXG4gKiBAcHJvcGVydHkge3N0cmluZ30gUkVBRE9OTFkuSU5WQUxJRCAtIEVycm9yIG1lc3NhZ2Ugd2hlbiBhdHRlbXB0aW5nIHRvIHVwZGF0ZSBhIHJlYWRvbmx5IHByb3BlcnR5XG4gKiBAcHJvcGVydHkge09iamVjdH0gVElNRVNUQU1QIC0gRXJyb3IgbWVzc2FnZXMgZm9yIHRpbWVzdGFtcCB2YWxpZGF0aW9uXG4gKiBAcHJvcGVydHkge3N0cmluZ30gVElNRVNUQU1QLlJFUVVJUkVEIC0gRXJyb3IgbWVzc2FnZSB3aGVuIGEgdGltZXN0YW1wIGlzIG1pc3NpbmdcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBUSU1FU1RBTVAuREFURSAtIEVycm9yIG1lc3NhZ2Ugd2hlbiBhIHRpbWVzdGFtcCBpcyBub3QgYSB2YWxpZCBkYXRlXG4gKiBAcHJvcGVydHkge3N0cmluZ30gVElNRVNUQU1QLklOVkFMSUQgLSBFcnJvciBtZXNzYWdlIHdoZW4gYSB0aW1lc3RhbXAgaXMgbm90IGluY3JlYXNpbmdcbiAqIEBjb25zdCBERUZBVUxUX0VSUk9SX01FU1NBR0VTXG4gKiBAbWVtYmVyT2YgbW9kdWxlOnZhbGlkYXRpb25cbiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfRVJST1JfTUVTU0FHRVMgPSB7XG4gIElEOiB7XG4gICAgSU5WQUxJRDogXCJUaGlzIElkIGlzIGludmFsaWRcIixcbiAgICBSRVFVSVJFRDogXCJUaGUgSWQgaXMgbWFuZGF0b3J5XCIsXG4gIH0sXG4gIFJFQURPTkxZOiB7XG4gICAgSU5WQUxJRDogXCJUaGlzIGNhbm5vdCBiZSB1cGRhdGVkXCIsXG4gIH0sXG4gIFRJTUVTVEFNUDoge1xuICAgIFJFUVVJUkVEOiBcIlRpbWVzdGFtcCBpcyBNYW5kYXRvcnlcIixcbiAgICBEQVRFOiBcIlRoZSBUaW1lc3RhbXAgbXVzdCB0aGUgYSB2YWxpZCBkYXRlXCIsXG4gICAgSU5WQUxJRDogXCJUaGlzIHZhbHVlIG11c3QgYWx3YXlzIGluY3JlYXNlXCIsXG4gIH0sXG59O1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDb25zdGFudHMgdXNlZCBmb3IgcmVmbGVjdGlvbi1iYXNlZCB2YWxpZGF0aW9uIGR1cmluZyB1cGRhdGUgb3BlcmF0aW9ucy5cbiAqIEBzdW1tYXJ5IEtleXMgdXNlZCBmb3Igc3RvcmluZyBhbmQgcmV0cmlldmluZyB2YWxpZGF0aW9uIG1ldGFkYXRhIG9uIG1vZGVsIHByb3BlcnRpZXMgZHVyaW5nIHVwZGF0ZSBvcGVyYXRpb25zLlxuICogQHR5cGVkZWYge09iamVjdH0gVmFsaWRhdGlvbktleXNcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBSRUZMRUNUIC0gQmFzZSByZWZsZWN0aW9uIGtleSBwcmVmaXggZm9yIHVwZGF0ZSB2YWxpZGF0aW9uXG4gKiBAcHJvcGVydHkge3N0cmluZ30gVElNRVNUQU1QIC0gS2V5IGZvciB0aW1lc3RhbXAgdmFsaWRhdGlvblxuICogQHByb3BlcnR5IHtzdHJpbmd9IFJFQURPTkxZIC0gS2V5IGZvciByZWFkb25seSBwcm9wZXJ0eSB2YWxpZGF0aW9uXG4gKiBAY29uc3QgVXBkYXRlVmFsaWRhdGlvbktleXNcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dmFsaWRhdGlvblxuICovXG5leHBvcnQgY29uc3QgVXBkYXRlVmFsaWRhdGlvbktleXMgPSB7XG4gIFJFRkxFQ1Q6IFwiZGIudXBkYXRlLnZhbGlkYXRpb24uXCIsXG4gIFRJTUVTVEFNUDogREJLZXlzLlRJTUVTVEFNUCxcbiAgUkVBRE9OTFk6IERCS2V5cy5SRUFET05MWSxcbn07XG4iLCJpbXBvcnQgeyB2YWxpZGF0b3IsIFZhbGlkYXRvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IERFRkFVTFRfRVJST1JfTUVTU0FHRVMsIFVwZGF0ZVZhbGlkYXRpb25LZXlzIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgaXNFcXVhbCB9IGZyb20gXCJAZGVjYWYtdHMvcmVmbGVjdGlvblwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBBIHZhbGlkYXRvciB0aGF0IGVuc3VyZXMgcHJvcGVydGllcyBtYXJrZWQgYXMgcmVhZG9ubHkgY2Fubm90IGJlIG1vZGlmaWVkIGR1cmluZyB1cGRhdGVzLlxuICogQHN1bW1hcnkgVmFsaWRhdG9yIGZvciB0aGUge0BsaW5rIHJlYWRvbmx5fSBkZWNvcmF0b3IgdGhhdCBjaGVja3MgaWYgYSB2YWx1ZSBoYXMgYmVlbiBjaGFuZ2VkIGR1cmluZyBhbiB1cGRhdGUgb3BlcmF0aW9uLiBJdCBjb21wYXJlcyB0aGUgbmV3IHZhbHVlIHdpdGggdGhlIG9sZCB2YWx1ZSBhbmQgcmV0dXJucyBhbiBlcnJvciBtZXNzYWdlIGlmIHRoZXkgYXJlIG5vdCBlcXVhbC5cbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSB2YWxpZGF0ZWRcbiAqIEBwYXJhbSB7YW55fSBvbGRWYWx1ZSAtIFRoZSBwcmV2aW91cyB2YWx1ZSB0byBjb21wYXJlIGFnYWluc3RcbiAqIEBwYXJhbSB7c3RyaW5nfSBbbWVzc2FnZV0gLSBPcHRpb25hbCBjdXN0b20gZXJyb3IgbWVzc2FnZVxuICogQGNsYXNzIFJlYWRPbmx5VmFsaWRhdG9yXG4gKiBAZXhhbXBsZVxuICogLy8gVXNpbmcgUmVhZE9ubHlWYWxpZGF0b3Igd2l0aCBhIHJlYWRvbmx5IHByb3BlcnR5XG4gKiBjbGFzcyBVc2VyIHtcbiAqICAgQHJlYWRvbmx5KClcbiAqICAgaWQ6IHN0cmluZztcbiAqICAgXG4gKiAgIG5hbWU6IHN0cmluZztcbiAqICAgXG4gKiAgIGNvbnN0cnVjdG9yKGlkOiBzdHJpbmcsIG5hbWU6IHN0cmluZykge1xuICogICAgIHRoaXMuaWQgPSBpZDtcbiAqICAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICogICB9XG4gKiB9XG4gKiBcbiAqIC8vIFRoaXMgd2lsbCB0cmlnZ2VyIHZhbGlkYXRpb24gZXJyb3Igd2hlbiB0cnlpbmcgdG8gdXBkYXRlXG4gKiBjb25zdCB1c2VyID0gbmV3IFVzZXIoJzEyMycsICdKb2huJyk7XG4gKiB1c2VyLmlkID0gJzQ1Nic7IC8vIFdpbGwgYmUgcHJldmVudGVkIGJ5IFJlYWRPbmx5VmFsaWRhdG9yXG4gKiBAY2F0ZWdvcnkgVmFsaWRhdG9yc1xuICovXG5AdmFsaWRhdG9yKFVwZGF0ZVZhbGlkYXRpb25LZXlzLlJFQURPTkxZKVxuZXhwb3J0IGNsYXNzIFJlYWRPbmx5VmFsaWRhdG9yIGV4dGVuZHMgVmFsaWRhdG9yIHtcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoREVGQVVMVF9FUlJPUl9NRVNTQUdFUy5SRUFET05MWS5JTlZBTElEKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSW1wbGVtZW50YXRpb24gb2YgdGhlIGJhc2UgdmFsaWRhdG9yJ3MgaGFzRXJyb3JzIG1ldGhvZC5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgaXMgcmVxdWlyZWQgYnkgdGhlIFZhbGlkYXRvciBpbnRlcmZhY2UgYnV0IG5vdCB1c2VkIGluIHRoaXMgdmFsaWRhdG9yIGFzIHZhbGlkYXRpb24gb25seSBoYXBwZW5zIGR1cmluZyB1cGRhdGVzLlxuICAgKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gdmFsaWRhdGVcbiAgICogQHBhcmFtIHthbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge3N0cmluZyB8IHVuZGVmaW5lZH0gQWx3YXlzIHJldHVybnMgdW5kZWZpbmVkIGFzIHRoaXMgdmFsaWRhdG9yIG9ubHkgd29ya3MgZHVyaW5nIHVwZGF0ZXNcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgaGFzRXJyb3JzKHZhbHVlOiBhbnksIC4uLmFyZ3M6IGFueVtdKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDaGVja3MgaWYgYSB2YWx1ZSBoYXMgYmVlbiBtb2RpZmllZCBkdXJpbmcgYW4gdXBkYXRlIG9wZXJhdGlvbi5cbiAgICogQHN1bW1hcnkgVmFsaWRhdGVzIGEgdmFsdWUgaGFzIG5vdCBjaGFuZ2VkIGJ5IGNvbXBhcmluZyBpdCB3aXRoIHRoZSBwcmV2aW91cyB2YWx1ZSB1c2luZyBkZWVwIGVxdWFsaXR5LlxuICAgKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgbmV3IHZhbHVlIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSB7YW55fSBvbGRWYWx1ZSAtIFRoZSBvcmlnaW5hbCB2YWx1ZSB0byBjb21wYXJlIGFnYWluc3RcbiAgICogQHBhcmFtIHtzdHJpbmd9IFttZXNzYWdlXSAtIE9wdGlvbmFsIGN1c3RvbSBlcnJvciBtZXNzYWdlIHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0XG4gICAqIEByZXR1cm4ge3N0cmluZyB8IHVuZGVmaW5lZH0gQW4gZXJyb3IgbWVzc2FnZSBpZiB2YWxpZGF0aW9uIGZhaWxzLCB1bmRlZmluZWQgb3RoZXJ3aXNlXG4gICAqL1xuICBwdWJsaWMgdXBkYXRlSGFzRXJyb3JzKFxuICAgIHZhbHVlOiBhbnksXG4gICAgb2xkVmFsdWU6IGFueSxcbiAgICBtZXNzYWdlPzogc3RyaW5nLFxuICApOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm47XG5cbiAgICByZXR1cm4gaXNFcXVhbCh2YWx1ZSwgb2xkVmFsdWUpXG4gICAgICA/IHVuZGVmaW5lZFxuICAgICAgOiB0aGlzLmdldE1lc3NhZ2UobWVzc2FnZSB8fCB0aGlzLm1lc3NhZ2UpO1xuICB9XG59XG4iLCJpbXBvcnQgeyB2YWxpZGF0b3IsIFZhbGlkYXRvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IERFRkFVTFRfRVJST1JfTUVTU0FHRVMsIFVwZGF0ZVZhbGlkYXRpb25LZXlzIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBBIHZhbGlkYXRvciB0aGF0IGVuc3VyZXMgdGltZXN0YW1wIHZhbHVlcyBhcmUgb25seSB1cGRhdGVkIHdpdGggbmV3ZXIgdGltZXN0YW1wcy5cbiAqIEBzdW1tYXJ5IFZhbGlkYXRlcyB0aGUgdXBkYXRlIG9mIGEgdGltZXN0YW1wIGJ5IGNvbXBhcmluZyB0aGUgbmV3IHRpbWVzdGFtcCB3aXRoIHRoZSBvbGQgb25lLCBlbnN1cmluZyB0aGUgbmV3IHRpbWVzdGFtcCBpcyBtb3JlIHJlY2VudC5cbiAqIEBwYXJhbSB7RGF0ZXxzdHJpbmd8bnVtYmVyfSB2YWx1ZSAtIFRoZSB0aW1lc3RhbXAgdmFsdWUgdG8gdmFsaWRhdGVcbiAqIEBwYXJhbSB7RGF0ZXxzdHJpbmd8bnVtYmVyfSBvbGRWYWx1ZSAtIFRoZSBwcmV2aW91cyB0aW1lc3RhbXAgdG8gY29tcGFyZSBhZ2FpbnN0XG4gKiBAcGFyYW0ge3N0cmluZ30gW21lc3NhZ2VdIC0gT3B0aW9uYWwgY3VzdG9tIGVycm9yIG1lc3NhZ2VcbiAqIEBjbGFzcyBUaW1lc3RhbXBWYWxpZGF0b3JcbiAqIEBleGFtcGxlXG4gKiAvLyBVc2luZyBUaW1lc3RhbXBWYWxpZGF0b3Igd2l0aCBhIHRpbWVzdGFtcCBwcm9wZXJ0eVxuICogY2xhc3MgRG9jdW1lbnQge1xuICogICBAdGltZXN0YW1wKClcbiAqICAgdXBkYXRlZEF0OiBEYXRlO1xuICogICBcbiAqICAgdGl0bGU6IHN0cmluZztcbiAqICAgXG4gKiAgIGNvbnN0cnVjdG9yKHRpdGxlOiBzdHJpbmcpIHtcbiAqICAgICB0aGlzLnRpdGxlID0gdGl0bGU7XG4gKiAgICAgdGhpcy51cGRhdGVkQXQgPSBuZXcgRGF0ZSgpO1xuICogICB9XG4gKiB9XG4gKiBcbiAqIC8vIFRoaXMgd2lsbCB0cmlnZ2VyIHZhbGlkYXRpb24gZXJyb3Igd2hlbiB0cnlpbmcgdG8gdXBkYXRlIHdpdGggYW4gb2xkZXIgdGltZXN0YW1wXG4gKiBjb25zdCBkb2MgPSBuZXcgRG9jdW1lbnQoJ015IERvY3VtZW50Jyk7XG4gKiBjb25zdCBvbGREYXRlID0gbmV3IERhdGUoMjAyMCwgMCwgMSk7XG4gKiBkb2MudXBkYXRlZEF0ID0gb2xkRGF0ZTsgLy8gV2lsbCBiZSBwcmV2ZW50ZWQgYnkgVGltZXN0YW1wVmFsaWRhdG9yXG4gKiBAY2F0ZWdvcnkgVmFsaWRhdG9yc1xuICovXG5AdmFsaWRhdG9yKFVwZGF0ZVZhbGlkYXRpb25LZXlzLlRJTUVTVEFNUClcbmV4cG9ydCBjbGFzcyBUaW1lc3RhbXBWYWxpZGF0b3IgZXh0ZW5kcyBWYWxpZGF0b3Ige1xuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBzdXBlcihERUZBVUxUX0VSUk9SX01FU1NBR0VTLlRJTUVTVEFNUC5JTlZBTElEKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSW1wbGVtZW50YXRpb24gb2YgdGhlIGJhc2UgdmFsaWRhdG9yJ3MgaGFzRXJyb3JzIG1ldGhvZC5cbiAgICogQHN1bW1hcnkgVGhpcyBtZXRob2QgaXMgcmVxdWlyZWQgYnkgdGhlIFZhbGlkYXRvciBpbnRlcmZhY2UgYnV0IG5vdCB1c2VkIGluIHRoaXMgdmFsaWRhdG9yIGFzIHZhbGlkYXRpb24gb25seSBoYXBwZW5zIGR1cmluZyB1cGRhdGVzLlxuICAgKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdGltZXN0YW1wIHZhbHVlIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSB7YW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xuICAgKiBAcmV0dXJuIHtzdHJpbmcgfCB1bmRlZmluZWR9IEFsd2F5cyByZXR1cm5zIHVuZGVmaW5lZCBhcyB0aGlzIHZhbGlkYXRvciBvbmx5IHdvcmtzIGR1cmluZyB1cGRhdGVzXG4gICAqL1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIGhhc0Vycm9ycyh2YWx1ZTogYW55LCAuLi5hcmdzOiBhbnlbXSk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVmFsaWRhdGVzIHRoYXQgYSB0aW1lc3RhbXAgaXMgbmV3ZXIgdGhhbiBpdHMgcHJldmlvdXMgdmFsdWUuXG4gICAqIEBzdW1tYXJ5IENoZWNrcyBpZiBhIHRpbWVzdGFtcCBoYXMgYmVlbiB1cGRhdGVkIHdpdGggYSBtb3JlIHJlY2VudCB2YWx1ZSBieSBjb252ZXJ0aW5nIGJvdGggdmFsdWVzIHRvIERhdGUgb2JqZWN0cyBhbmQgY29tcGFyaW5nIHRoZW0uXG4gICAqIEBwYXJhbSB7RGF0ZXxzdHJpbmd8bnVtYmVyfSB2YWx1ZSAtIFRoZSBuZXcgdGltZXN0YW1wIHZhbHVlIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSB7RGF0ZXxzdHJpbmd8bnVtYmVyfSBvbGRWYWx1ZSAtIFRoZSBvcmlnaW5hbCB0aW1lc3RhbXAgdG8gY29tcGFyZSBhZ2FpbnN0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbbWVzc2FnZV0gLSBPcHRpb25hbCBjdXN0b20gZXJyb3IgbWVzc2FnZSB0byBvdmVycmlkZSB0aGUgZGVmYXVsdFxuICAgKiBAcmV0dXJuIHtzdHJpbmcgfCB1bmRlZmluZWR9IEFuIGVycm9yIG1lc3NhZ2UgaWYgdmFsaWRhdGlvbiBmYWlscyAobmV3IHRpbWVzdGFtcCBpcyBub3QgbmV3ZXIpLCB1bmRlZmluZWQgb3RoZXJ3aXNlXG4gICAqL1xuICBwdWJsaWMgdXBkYXRlSGFzRXJyb3JzKFxuICAgIHZhbHVlOiBEYXRlIHwgc3RyaW5nIHwgbnVtYmVyLFxuICAgIG9sZFZhbHVlOiBEYXRlIHwgc3RyaW5nIHwgbnVtYmVyLFxuICAgIG1lc3NhZ2U/OiBzdHJpbmdcbiAgKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuXG4gICAgbWVzc2FnZSA9IG1lc3NhZ2UgfHwgdGhpcy5nZXRNZXNzYWdlKG1lc3NhZ2UgfHwgdGhpcy5tZXNzYWdlKTtcblxuICAgIHRyeSB7XG4gICAgICB2YWx1ZSA9IG5ldyBEYXRlKHZhbHVlKTtcbiAgICAgIG9sZFZhbHVlID0gbmV3IERhdGUob2xkVmFsdWUpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBtZXNzYWdlO1xuICAgIH1cblxuICAgIHJldHVybiB2YWx1ZSA8PSBvbGRWYWx1ZSA/IG1lc3NhZ2UgOiB1bmRlZmluZWQ7XG4gIH1cbn1cbiIsImltcG9ydCB7XG4gIERFRkFVTFRfRVJST1JfTUVTU0FHRVMgYXMgRGVjb3JhdG9yTWVzc2FnZXMsXG4gIFZhbGlkYXRvcixcbn0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBBYnN0cmFjdCBiYXNlIGNsYXNzIGZvciB2YWxpZGF0b3JzIHRoYXQgY29tcGFyZSBuZXcgdmFsdWVzIHdpdGggb2xkIHZhbHVlcyBkdXJpbmcgdXBkYXRlcy5cbiAqIEBzdW1tYXJ5IEJhc2UgY2xhc3MgZm9yIGFuIFVwZGF0ZSB2YWxpZGF0b3IgdGhhdCBwcm92aWRlcyBhIGZyYW1ld29yayBmb3IgaW1wbGVtZW50aW5nIHZhbGlkYXRpb24gbG9naWMgdGhhdCBjb21wYXJlcyBhIG5ldyB2YWx1ZSB3aXRoIGl0cyBwcmV2aW91cyBzdGF0ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbbWVzc2FnZV0gLSBFcnJvciBtZXNzYWdlLiBEZWZhdWx0cyB0byB7QGxpbmsgRGVjb3JhdG9yTWVzc2FnZXMjREVGQVVMVH1cbiAqIEBwYXJhbSB7c3RyaW5nW119IFthY2NlcHRlZFR5cGVzXSAtIFRoZSBhY2NlcHRlZCB2YWx1ZSB0eXBlcyBieSB0aGUgZGVjb3JhdG9yXG4gKiBAY2xhc3MgVXBkYXRlVmFsaWRhdG9yXG4gKiBAZXhhbXBsZVxuICogLy8gRXh0ZW5kaW5nIFVwZGF0ZVZhbGlkYXRvciB0byBjcmVhdGUgYSBjdXN0b20gdmFsaWRhdG9yXG4gKiBjbGFzcyBNeUN1c3RvbVZhbGlkYXRvciBleHRlbmRzIFVwZGF0ZVZhbGlkYXRvciB7XG4gKiAgIGNvbnN0cnVjdG9yKCkge1xuICogICAgIHN1cGVyKFwiQ3VzdG9tIHZhbGlkYXRpb24gZmFpbGVkXCIpO1xuICogICB9XG4gKiAgIFxuICogICBwdWJsaWMgdXBkYXRlSGFzRXJyb3JzKHZhbHVlOiBhbnksIG9sZFZhbHVlOiBhbnkpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICogICAgIC8vIEN1c3RvbSB2YWxpZGF0aW9uIGxvZ2ljXG4gKiAgICAgaWYgKHZhbHVlID09PSBvbGRWYWx1ZSkge1xuICogICAgICAgcmV0dXJuIHRoaXMubWVzc2FnZTtcbiAqICAgICB9XG4gKiAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAqICAgfVxuICogICBcbiAqICAgaGFzRXJyb3JzKHZhbHVlOiBhbnkpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICogICAgIHJldHVybiB1bmRlZmluZWQ7IC8vIE5vdCB1c2VkIGZvciB1cGRhdGUgdmFsaWRhdG9yc1xuICogICB9XG4gKiB9XG4gKiBAY2F0ZWdvcnkgVmFsaWRhdG9yc1xuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgVXBkYXRlVmFsaWRhdG9yIGV4dGVuZHMgVmFsaWRhdG9yIHtcbiAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKFxuICAgIG1lc3NhZ2U6IHN0cmluZyA9IERlY29yYXRvck1lc3NhZ2VzLkRFRkFVTFQsXG4gICAgLi4uYWNjZXB0ZWRUeXBlczogc3RyaW5nW11cbiAgKSB7XG4gICAgc3VwZXIobWVzc2FnZSwgLi4uYWNjZXB0ZWRUeXBlcyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFic3RyYWN0IG1ldGhvZCB0aGF0IG11c3QgYmUgaW1wbGVtZW50ZWQgYnkgc3ViY2xhc3NlcyB0byBwZXJmb3JtIHVwZGF0ZSB2YWxpZGF0aW9uLlxuICAgKiBAc3VtbWFyeSBWYWxpZGF0ZXMgYSB2YWx1ZSBieSBjb21wYXJpbmcgaXQgdG8gaXRzIG9sZCB2ZXJzaW9uIHRvIGRldGVybWluZSBpZiB0aGUgdXBkYXRlIGlzIHZhbGlkLlxuICAgKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgbmV3IHZhbHVlIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSB7YW55fSBvbGRWYWx1ZSAtIFRoZSBwcmV2aW91cyB2YWx1ZSB0byBjb21wYXJlIGFnYWluc3RcbiAgICogQHBhcmFtIHthbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIHRoYXQgbWF5IGJlIG5lZWRlZCBmb3IgdmFsaWRhdGlvblxuICAgKiBAcmV0dXJuIHtzdHJpbmcgfCB1bmRlZmluZWR9IEFuIGVycm9yIG1lc3NhZ2UgaWYgdmFsaWRhdGlvbiBmYWlscywgdW5kZWZpbmVkIGlmIHZhbGlkYXRpb24gcGFzc2VzXG4gICAqL1xuICBwdWJsaWMgYWJzdHJhY3QgdXBkYXRlSGFzRXJyb3JzKFxuICAgIHZhbHVlOiBhbnksXG4gICAgb2xkVmFsdWU6IGFueSxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG59XG4iLCJpbXBvcnQge1xuICBWYWxpZGF0b3IsXG4gIFZhbGlkYXRpb24sXG4gIFZhbGlkYXRvckRlZmluaXRpb24sXG4gIElWYWxpZGF0b3JSZWdpc3RyeSxcbn0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgVXBkYXRlVmFsaWRhdGlvbktleXMgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gR2VuZXJhdGVzIGEga2V5IGZvciB1cGRhdGUgdmFsaWRhdGlvbiBtZXRhZGF0YS5cbiAqIEBzdW1tYXJ5IEJ1aWxkcyB0aGUga2V5IHRvIHN0b3JlIGFzIG1ldGFkYXRhIHVuZGVyIFJlZmxlY3Rpb25zIGZvciB1cGRhdGUgdmFsaWRhdGlvbiBieSBwcmVmaXhpbmcgdGhlIHByb3ZpZGVkIGtleSB3aXRoIHRoZSB1cGRhdGUgdmFsaWRhdGlvbiBwcmVmaXguXG4gKiBAcGFyYW0ge3N0cmluZ30ga2V5IC0gVGhlIGJhc2Uga2V5IHRvIGJlIHByZWZpeGVkXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBjb21wbGV0ZSBtZXRhZGF0YSBrZXkgZm9yIHVwZGF0ZSB2YWxpZGF0aW9uXG4gKiBAZnVuY3Rpb24gdXBkYXRlS2V5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmRiLWRlY29yYXRvcnNcbiAqL1xuVmFsaWRhdGlvbi51cGRhdGVLZXkgPSBmdW5jdGlvbiAoa2V5OiBzdHJpbmcpIHtcbiAgcmV0dXJuIFVwZGF0ZVZhbGlkYXRpb25LZXlzLlJFRkxFQ1QgKyBrZXk7XG59O1xuXG5kZWNsYXJlIG1vZHVsZSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiIHtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9iYW4tdHMtY29tbWVudFxuICAvLyBAdHMtZXhwZWN0LWVycm9yXG4gIGRlY2xhcmUgY2xhc3MgVmFsaWRhdGlvbiB7XG4gICAgcHJpdmF0ZSBzdGF0aWMgYWN0aW5nVmFsaWRhdG9yUmVnaXN0cnk/O1xuICAgIHByaXZhdGUgY29uc3RydWN0b3IoKTtcbiAgICAvKipcbiAgICAgKiBAc3VtbWFyeSBEZWZpbmVzIHRoZSBhY3RpbmcgVmFsaWRhdG9yUmVnaXN0cnlcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7SVZhbGlkYXRvclJlZ2lzdHJ5fSB2YWxpZGF0b3JSZWdpc3RyeSB0aGUgbmV3IGltcGxlbWVudGF0aW9uIG9mIHRoZSB2YWxpZGF0b3IgUmVnaXN0cnlcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9uKFZhbGlkYXRvcik6IFZhbGlkYXRvcn0gW21pZ3JhdGlvbkhhbmRsZXJdIHRoZSBtZXRob2QgdG8gbWFwIHRoZSB2YWxpZGF0b3IgaWYgcmVxdWlyZWQ7XG4gICAgICovXG4gICAgc3RhdGljIHNldFJlZ2lzdHJ5KFxuICAgICAgdmFsaWRhdG9yUmVnaXN0cnk6IElWYWxpZGF0b3JSZWdpc3RyeTxWYWxpZGF0b3I+LFxuICAgICAgbWlncmF0aW9uSGFuZGxlcj86ICh2YWxpZGF0b3I6IFZhbGlkYXRvcikgPT4gVmFsaWRhdG9yXG4gICAgKTogdm9pZDtcbiAgICAvKipcbiAgICAgKiBAc3VtbWFyeSBSZXR1cm5zIHRoZSBjdXJyZW50IFZhbGlkYXRvclJlZ2lzdHJ5XG4gICAgICpcbiAgICAgKiBAcmV0dXJuIElWYWxpZGF0b3JSZWdpc3RyeSwgZGVmYXVsdHMgdG8ge0BsaW5rIFZhbGlkYXRvclJlZ2lzdHJ5fVxuICAgICAqL1xuICAgIHByaXZhdGUgc3RhdGljIGdldFJlZ2lzdHJ5O1xuICAgIC8qKlxuICAgICAqIEBzdW1tYXJ5IFJldHJpZXZlcyBhIHZhbGlkYXRvclxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHZhbGlkYXRvcktleSBvbmUgb2YgdGhlIHtAbGluayBWYWxpZGF0aW9uS2V5c31cbiAgICAgKiBAcmV0dXJuIHtWYWxpZGF0b3IgfCB1bmRlZmluZWR9IHRoZSByZWdpc3RlcmVkIFZhbGlkYXRvciBvciB1bmRlZmluZWQgaWYgdGhlcmUgaXMgbm9ubyBtYXRjaGluZyB0aGUgcHJvdmlkZWQga2V5XG4gICAgICovXG4gICAgc3RhdGljIGdldDxUIGV4dGVuZHMgVmFsaWRhdG9yPih2YWxpZGF0b3JLZXk6IHN0cmluZyk6IFQgfCB1bmRlZmluZWQ7XG4gICAgLyoqXG4gICAgICogQHN1bW1hcnkgUmVnaXN0ZXJzIHRoZSBwcm92aWRlZCB2YWxpZGF0b3JzIG9udG8gdGhlIHJlZ2lzdHJ5XG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1RbXSB8IFZhbGlkYXRvckRlZmluaXRpb25bXX0gdmFsaWRhdG9yXG4gICAgICovXG4gICAgc3RhdGljIHJlZ2lzdGVyPFQgZXh0ZW5kcyBWYWxpZGF0b3I+KFxuICAgICAgLi4udmFsaWRhdG9yOiAoVmFsaWRhdG9yRGVmaW5pdGlvbiB8IFQpW11cbiAgICApOiB2b2lkO1xuICAgIC8qKlxuICAgICAqIEBzdW1tYXJ5IEJ1aWxkcyB0aGUga2V5IHRvIHN0b3JlIGFzIE1ldGFkYXRhIHVuZGVyIFJlZmxlY3Rpb25zXG4gICAgICogQGRlc2NyaXB0aW9uIGNvbmNhdGVuYXRlcyB7QGxpbmsgVmFsaWRhdGlvbktleXMjUkVGTEVDVH0gd2l0aCB0aGUgcHJvdmlkZWQga2V5XG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5XG4gICAgICovXG4gICAgc3RhdGljIGtleShrZXk6IHN0cmluZyk6IHN0cmluZztcblxuICAgIHN0YXRpYyB1cGRhdGVLZXkoa2V5OiBzdHJpbmcpOiBzdHJpbmc7XG4gIH1cbn1cbiIsIi8qKlxuICogQGRlc2NyaXB0aW9uIERhdGFiYXNlIG9wZXJhdGlvbiBrZXkgY29uc3RhbnRzXG4gKiBAc3VtbWFyeSBFbnVtIGRlZmluaW5nIENSVUQgb3BlcmF0aW9ucyBhbmQgdGhlaXIgbGlmZWN5Y2xlIHBoYXNlc1xuICogQGVudW0ge3N0cmluZ31cbiAqIEByZWFkb25seVxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBlbnVtIE9wZXJhdGlvbktleXMge1xuICBSRUZMRUNUID0gXCJkZWNhZi5tb2RlbC5kYi5vcGVyYXRpb25zLlwiLFxuICBDUkVBVEUgPSBcImNyZWF0ZVwiLFxuICBSRUFEID0gXCJyZWFkXCIsXG4gIFVQREFURSA9IFwidXBkYXRlXCIsXG4gIERFTEVURSA9IFwiZGVsZXRlXCIsXG4gIE9OID0gXCJvbi5cIixcbiAgQUZURVIgPSBcImFmdGVyLlwiLFxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBUeXBlIGZvciBiYXNpYyBDUlVEIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IFVuaW9uIHR5cGUgb2YgdGhlIGZvdXIgYmFzaWMgZGF0YWJhc2Ugb3BlcmF0aW9uczogY3JlYXRlLCByZWFkLCB1cGRhdGUsIGRlbGV0ZVxuICogQHR5cGVkZWYge3N0cmluZ30gQ3J1ZE9wZXJhdGlvbnNcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9yc1xuICovXG5leHBvcnQgdHlwZSBDcnVkT3BlcmF0aW9ucyA9XG4gIHwgT3BlcmF0aW9uS2V5cy5DUkVBVEVcbiAgfCBPcGVyYXRpb25LZXlzLlJFQURcbiAgfCBPcGVyYXRpb25LZXlzLlVQREFURVxuICB8IE9wZXJhdGlvbktleXMuREVMRVRFO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBCdWxrIGRhdGFiYXNlIG9wZXJhdGlvbiBrZXkgY29uc3RhbnRzXG4gKiBAc3VtbWFyeSBFbnVtIGRlZmluaW5nIGJ1bGsgQ1JVRCBvcGVyYXRpb25zIGZvciBoYW5kbGluZyBtdWx0aXBsZSByZWNvcmRzIGF0IG9uY2VcbiAqIEBlbnVtIHtzdHJpbmd9XG4gKiBAcmVhZG9ubHlcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9yc1xuICovXG5leHBvcnQgZW51bSBCdWxrQ3J1ZE9wZXJhdGlvbktleXMge1xuICBDUkVBVEVfQUxMID0gXCJjcmVhdGVBbGxcIixcbiAgUkVBRF9BTEwgPSBcInJlYWRBbGxcIixcbiAgVVBEQVRFX0FMTCA9IFwidXBkYXRlQWxsXCIsXG4gIERFTEVURV9BTEwgPSBcImRlbGV0ZUFsbFwiLFxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBUeXBlIGZvciBidWxrIENSVUQgb3BlcmF0aW9uc1xuICogQHN1bW1hcnkgVW5pb24gdHlwZSBvZiB0aGUgZm91ciBidWxrIGRhdGFiYXNlIG9wZXJhdGlvbnMgZm9yIGhhbmRsaW5nIG11bHRpcGxlIHJlY29yZHMgYXQgb25jZVxuICogQHR5cGVkZWYge3N0cmluZ30gQnVsa0NydWRPcGVyYXRpb25zXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmRiLWRlY29yYXRvcnNcbiAqL1xuZXhwb3J0IHR5cGUgQnVsa0NydWRPcGVyYXRpb25zID1cbiAgfCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuQ1JFQVRFX0FMTFxuICB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cy5SRUFEX0FMTFxuICB8IEJ1bGtDcnVkT3BlcmF0aW9uS2V5cy5VUERBVEVfQUxMXG4gIHwgQnVsa0NydWRPcGVyYXRpb25LZXlzLkRFTEVURV9BTEw7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEdyb3VwZWQgQ1JVRCBvcGVyYXRpb25zIGZvciBkZWNvcmF0b3IgbWFwcGluZ1xuICogQHN1bW1hcnkgTWFwcyBvdXQgZ3JvdXBzIG9mIENSVUQgb3BlcmF0aW9ucyBmb3IgZWFzaWVyIG1hcHBpbmcgb2YgZGVjb3JhdG9yc1xuICogQGNvbnN0IERCT3BlcmF0aW9uc1xuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBjb25zdCBEQk9wZXJhdGlvbnM6IFJlY29yZDxzdHJpbmcsIENydWRPcGVyYXRpb25zW10+ID0ge1xuICBDUkVBVEU6IFtPcGVyYXRpb25LZXlzLkNSRUFURV0sXG4gIFJFQUQ6IFtPcGVyYXRpb25LZXlzLlJFQURdLFxuICBVUERBVEU6IFtPcGVyYXRpb25LZXlzLlVQREFURV0sXG4gIERFTEVURTogW09wZXJhdGlvbktleXMuREVMRVRFXSxcbiAgQ1JFQVRFX1VQREFURTogW09wZXJhdGlvbktleXMuQ1JFQVRFLCBPcGVyYXRpb25LZXlzLlVQREFURV0sXG4gIFJFQURfQ1JFQVRFOiBbT3BlcmF0aW9uS2V5cy5SRUFELCBPcGVyYXRpb25LZXlzLkNSRUFURV0sXG4gIEFMTDogW1xuICAgIE9wZXJhdGlvbktleXMuQ1JFQVRFLFxuICAgIE9wZXJhdGlvbktleXMuUkVBRCxcbiAgICBPcGVyYXRpb25LZXlzLlVQREFURSxcbiAgICBPcGVyYXRpb25LZXlzLkRFTEVURSxcbiAgXSxcbn07XG4iLCJpbXBvcnQgeyBPcGVyYXRpb25IYW5kbGVyIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IE9wZXJhdGlvbktleXMgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IElSZXBvc2l0b3J5IH0gZnJvbSBcIi4uL2ludGVyZmFjZXMvSVJlcG9zaXRvcnlcIjtcbmltcG9ydCB7IE9wZXJhdGlvbnMgfSBmcm9tIFwiLi9PcGVyYXRpb25zXCI7XG5pbXBvcnQgeyBNb2RlbCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IENvbnRleHQgfSBmcm9tIFwiLi4vcmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgUmVwb3NpdG9yeUZsYWdzIH0gZnJvbSBcIi4uL3JlcG9zaXRvcnkvdHlwZXNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmVnaXN0cnkgZm9yIGRhdGFiYXNlIG9wZXJhdGlvbiBoYW5kbGVyc1xuICogQHN1bW1hcnkgTWFuYWdlcyBhbmQgc3RvcmVzIG9wZXJhdGlvbiBoYW5kbGVycyBmb3IgZGlmZmVyZW50IG1vZGVsIHByb3BlcnRpZXMgYW5kIG9wZXJhdGlvbnNcbiAqIEBjbGFzcyBPcGVyYXRpb25zUmVnaXN0cnlcbiAqIEB0ZW1wbGF0ZSBNIC0gTW9kZWwgdHlwZVxuICogQHRlbXBsYXRlIFIgLSBSZXBvc2l0b3J5IHR5cGVcbiAqIEB0ZW1wbGF0ZSBWIC0gTWV0YWRhdGEgdHlwZVxuICogQHRlbXBsYXRlIEYgLSBSZXBvc2l0b3J5IGZsYWdzXG4gKiBAdGVtcGxhdGUgQyAtIENvbnRleHQgdHlwZVxuICogQGV4YW1wbGVcbiAqIC8vIENyZWF0ZSBhIHJlZ2lzdHJ5IGFuZCByZWdpc3RlciBhIGhhbmRsZXJcbiAqIGNvbnN0IHJlZ2lzdHJ5ID0gbmV3IE9wZXJhdGlvbnNSZWdpc3RyeSgpO1xuICogcmVnaXN0cnkucmVnaXN0ZXIobXlIYW5kbGVyLCBPcGVyYXRpb25LZXlzLkNSRUFURSwgdGFyZ2V0TW9kZWwsICdwcm9wZXJ0eU5hbWUnKTtcbiAqXG4gKiAvLyBHZXQgaGFuZGxlcnMgZm9yIGEgc3BlY2lmaWMgb3BlcmF0aW9uXG4gKiBjb25zdCBoYW5kbGVycyA9IHJlZ2lzdHJ5LmdldCh0YXJnZXRNb2RlbC5jb25zdHJ1Y3Rvci5uYW1lLCAncHJvcGVydHlOYW1lJywgJ29uQ3JlYXRlJyk7XG4gKlxuICogQG1lcm1haWRcbiAqIGNsYXNzRGlhZ3JhbVxuICogICBjbGFzcyBPcGVyYXRpb25zUmVnaXN0cnkge1xuICogICAgIC1jYWNoZTogUmVjb3JkfnN0cmluZywgUmVjb3JkfnN0cmluZ3xzeW1ib2wsIFJlY29yZH5zdHJpbmcsIFJlY29yZH5zdHJpbmcsIE9wZXJhdGlvbkhhbmRsZXJ+fn5+XG4gKiAgICAgK2dldCh0YXJnZXQsIHByb3BLZXksIG9wZXJhdGlvbiwgYWNjdW0pXG4gKiAgICAgK3JlZ2lzdGVyKGhhbmRsZXIsIG9wZXJhdGlvbiwgdGFyZ2V0LCBwcm9wS2V5KVxuICogICB9XG4gKi9cbmV4cG9ydCBjbGFzcyBPcGVyYXRpb25zUmVnaXN0cnkge1xuICBwcml2YXRlIHJlYWRvbmx5IGNhY2hlOiBSZWNvcmQ8XG4gICAgc3RyaW5nLFxuICAgIFJlY29yZDxcbiAgICAgIHN0cmluZyB8IHN5bWJvbCxcbiAgICAgIFJlY29yZDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIE9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIGFueSwgYW55LCBhbnk+Pj5cbiAgICA+XG4gID4gPSB7fTtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJldHJpZXZlcyBvcGVyYXRpb24gaGFuZGxlcnMgZm9yIGEgc3BlY2lmaWMgdGFyZ2V0IGFuZCBvcGVyYXRpb25cbiAgICogQHN1bW1hcnkgRmluZHMgYWxsIHJlZ2lzdGVyZWQgaGFuZGxlcnMgZm9yIGEgZ2l2ZW4gdGFyZ2V0LCBwcm9wZXJ0eSwgYW5kIG9wZXJhdGlvbiwgaW5jbHVkaW5nIGZyb20gcGFyZW50IGNsYXNzZXNcbiAgICogQHRlbXBsYXRlIE0gLSBNb2RlbCB0eXBlIGV4dGVuZGluZyBNb2RlbFxuICAgKiBAdGVtcGxhdGUgUiAtIFJlcG9zaXRvcnkgdHlwZSBleHRlbmRpbmcgSVJlcG9zaXRvcnlcbiAgICogQHRlbXBsYXRlIFYgLSBNZXRhZGF0YSB0eXBlXG4gICAqIEB0ZW1wbGF0ZSBGIC0gUmVwb3NpdG9yeSBmbGFncyBleHRlbmRpbmcgUmVwb3NpdG9yeUZsYWdzXG4gICAqIEB0ZW1wbGF0ZSBDIC0gQ29udGV4dCB0eXBlIGV4dGVuZGluZyBDb250ZXh0PEY+XG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgUmVjb3JkPHN0cmluZywgYW55Pn0gdGFyZ2V0IC0gVGhlIHRhcmdldCBjbGFzcyBuYW1lIG9yIG9iamVjdFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcEtleSAtIFRoZSBwcm9wZXJ0eSBrZXkgdG8gZ2V0IGhhbmRsZXJzIGZvclxuICAgKiBAcGFyYW0ge3N0cmluZ30gb3BlcmF0aW9uIC0gVGhlIG9wZXJhdGlvbiBrZXkgdG8gZ2V0IGhhbmRsZXJzIGZvclxuICAgKiBAcGFyYW0ge09wZXJhdGlvbkhhbmRsZXJbXX0gW2FjY3VtXSAtIEFjY3VtdWxhdG9yIGZvciByZWN1cnNpdmUgY2FsbHNcbiAgICogQHJldHVybiB7T3BlcmF0aW9uSGFuZGxlcltdIHwgdW5kZWZpbmVkfSBBcnJheSBvZiBoYW5kbGVycyBvciB1bmRlZmluZWQgaWYgbm9uZSBmb3VuZFxuICAgKi9cbiAgZ2V0PFxuICAgIE0gZXh0ZW5kcyBNb2RlbCxcbiAgICBSIGV4dGVuZHMgSVJlcG9zaXRvcnk8TSwgRiwgQz4sXG4gICAgVixcbiAgICBGIGV4dGVuZHMgUmVwb3NpdG9yeUZsYWdzLFxuICAgIEMgZXh0ZW5kcyBDb250ZXh0PEY+LFxuICA+KFxuICAgIHRhcmdldDogc3RyaW5nIHwgUmVjb3JkPHN0cmluZywgYW55PixcbiAgICBwcm9wS2V5OiBzdHJpbmcsXG4gICAgb3BlcmF0aW9uOiBzdHJpbmcsXG4gICAgYWNjdW0/OiBPcGVyYXRpb25IYW5kbGVyPE0sIFIsIFYsIEYsIEM+W11cbiAgKTogT3BlcmF0aW9uSGFuZGxlcjxNLCBSLCBWLCBGLCBDPltdIHwgdW5kZWZpbmVkIHtcbiAgICBhY2N1bSA9IGFjY3VtIHx8IFtdO1xuICAgIGxldCBuYW1lO1xuICAgIHRyeSB7XG4gICAgICBuYW1lID0gdHlwZW9mIHRhcmdldCA9PT0gXCJzdHJpbmdcIiA/IHRhcmdldCA6IHRhcmdldC5jb25zdHJ1Y3Rvci5uYW1lO1xuICAgICAgYWNjdW0udW5zaGlmdChcbiAgICAgICAgLi4uT2JqZWN0LnZhbHVlcyh0aGlzLmNhY2hlW25hbWVdW3Byb3BLZXldW29wZXJhdGlvbl0gfHwgW10pXG4gICAgICApO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGlmIChcbiAgICAgICAgdHlwZW9mIHRhcmdldCA9PT0gXCJzdHJpbmdcIiB8fFxuICAgICAgICB0YXJnZXQgPT09IE9iamVjdC5wcm90b3R5cGUgfHxcbiAgICAgICAgT2JqZWN0LmdldFByb3RvdHlwZU9mKHRhcmdldCkgPT09IE9iamVjdC5wcm90b3R5cGVcbiAgICAgIClcbiAgICAgICAgcmV0dXJuIGFjY3VtO1xuICAgIH1cblxuICAgIGxldCBwcm90byA9IE9iamVjdC5nZXRQcm90b3R5cGVPZih0YXJnZXQpO1xuICAgIGlmIChwcm90by5jb25zdHJ1Y3Rvci5uYW1lID09PSBuYW1lKSBwcm90byA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihwcm90byk7XG5cbiAgICByZXR1cm4gdGhpcy5nZXQ8TSwgUiwgViwgRiwgQz4ocHJvdG8sIHByb3BLZXksIG9wZXJhdGlvbiwgYWNjdW0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWdpc3RlcnMgYW4gb3BlcmF0aW9uIGhhbmRsZXIgZm9yIGEgc3BlY2lmaWMgdGFyZ2V0IGFuZCBvcGVyYXRpb25cbiAgICogQHN1bW1hcnkgU3RvcmVzIGEgaGFuZGxlciBpbiB0aGUgcmVnaXN0cnkgZm9yIGEgZ2l2ZW4gdGFyZ2V0LCBwcm9wZXJ0eSwgYW5kIG9wZXJhdGlvblxuICAgKiBAdGVtcGxhdGUgTSAtIE1vZGVsIHR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gICAqIEB0ZW1wbGF0ZSBSIC0gUmVwb3NpdG9yeSB0eXBlIGV4dGVuZGluZyBJUmVwb3NpdG9yeVxuICAgKiBAdGVtcGxhdGUgViAtIE1ldGFkYXRhIHR5cGVcbiAgICogQHRlbXBsYXRlIEYgLSBSZXBvc2l0b3J5IGZsYWdzIGV4dGVuZGluZyBSZXBvc2l0b3J5RmxhZ3NcbiAgICogQHRlbXBsYXRlIEMgLSBDb250ZXh0IHR5cGUgZXh0ZW5kaW5nIENvbnRleHQ8Rj5cbiAgICogQHBhcmFtIHtPcGVyYXRpb25IYW5kbGVyfSBoYW5kbGVyIC0gVGhlIGhhbmRsZXIgZnVuY3Rpb24gdG8gcmVnaXN0ZXJcbiAgICogQHBhcmFtIHtPcGVyYXRpb25LZXlzfSBvcGVyYXRpb24gLSBUaGUgb3BlcmF0aW9uIGtleSB0byByZWdpc3RlciB0aGUgaGFuZGxlciBmb3JcbiAgICogQHBhcmFtIHtNfSB0YXJnZXQgLSBUaGUgdGFyZ2V0IG1vZGVsIGluc3RhbmNlXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgc3ltYm9sfSBwcm9wS2V5IC0gVGhlIHByb3BlcnR5IGtleSB0byByZWdpc3RlciB0aGUgaGFuZGxlciBmb3JcbiAgICogQHJldHVybiB7dm9pZH1cbiAgICovXG4gIHJlZ2lzdGVyPFxuICAgIE0gZXh0ZW5kcyBNb2RlbCxcbiAgICBSIGV4dGVuZHMgSVJlcG9zaXRvcnk8TSwgRiwgQz4sXG4gICAgVixcbiAgICBGIGV4dGVuZHMgUmVwb3NpdG9yeUZsYWdzLFxuICAgIEMgZXh0ZW5kcyBDb250ZXh0PEY+LFxuICA+KFxuICAgIGhhbmRsZXI6IE9wZXJhdGlvbkhhbmRsZXI8TSwgUiwgViwgRiwgQz4sXG4gICAgb3BlcmF0aW9uOiBPcGVyYXRpb25LZXlzLFxuICAgIHRhcmdldDogTSxcbiAgICBwcm9wS2V5OiBzdHJpbmcgfCBzeW1ib2xcbiAgKTogdm9pZCB7XG4gICAgY29uc3QgbmFtZSA9IHRhcmdldC5jb25zdHJ1Y3Rvci5uYW1lO1xuICAgIGNvbnN0IGhhbmRsZXJOYW1lID0gT3BlcmF0aW9ucy5nZXRIYW5kbGVyTmFtZShoYW5kbGVyKTtcblxuICAgIGlmICghdGhpcy5jYWNoZVtuYW1lXSkgdGhpcy5jYWNoZVtuYW1lXSA9IHt9O1xuICAgIGlmICghdGhpcy5jYWNoZVtuYW1lXVtwcm9wS2V5XSkgdGhpcy5jYWNoZVtuYW1lXVtwcm9wS2V5XSA9IHt9O1xuICAgIGlmICghdGhpcy5jYWNoZVtuYW1lXVtwcm9wS2V5XVtvcGVyYXRpb25dKVxuICAgICAgdGhpcy5jYWNoZVtuYW1lXVtwcm9wS2V5XVtvcGVyYXRpb25dID0ge307XG4gICAgaWYgKHRoaXMuY2FjaGVbbmFtZV1bcHJvcEtleV1bb3BlcmF0aW9uXVtoYW5kbGVyTmFtZV0pIHJldHVybjtcbiAgICB0aGlzLmNhY2hlW25hbWVdW3Byb3BLZXldW29wZXJhdGlvbl1baGFuZGxlck5hbWVdID0gaGFuZGxlcjtcbiAgfVxufVxuIiwiaW1wb3J0IHsgSGFzaGluZywgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBPcGVyYXRpb25IYW5kbGVyIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IE9wZXJhdGlvbnNSZWdpc3RyeSB9IGZyb20gXCIuL09wZXJhdGlvbnNSZWdpc3RyeVwiO1xuaW1wb3J0IHsgT3BlcmF0aW9uS2V5cyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgSVJlcG9zaXRvcnkgfSBmcm9tIFwiLi4vaW50ZXJmYWNlc1wiO1xuaW1wb3J0IHsgQ29udGV4dCB9IGZyb20gXCIuLi9yZXBvc2l0b3J5XCI7XG5pbXBvcnQgeyBSZXBvc2l0b3J5RmxhZ3MgfSBmcm9tIFwiLi4vcmVwb3NpdG9yeS90eXBlc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBTdGF0aWMgdXRpbGl0eSBjbGFzcyBmb3IgZGF0YWJhc2Ugb3BlcmF0aW9uIG1hbmFnZW1lbnRcbiAqIEBzdW1tYXJ5IFByb3ZpZGVzIGZ1bmN0aW9uYWxpdHkgZm9yIHJlZ2lzdGVyaW5nLCByZXRyaWV2aW5nLCBhbmQgbWFuYWdpbmcgZGF0YWJhc2Ugb3BlcmF0aW9uIGhhbmRsZXJzXG4gKiBAY2xhc3MgT3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIE0gLSBNb2RlbCB0eXBlXG4gKiBAdGVtcGxhdGUgUiAtIFJlcG9zaXRvcnkgdHlwZVxuICogQHRlbXBsYXRlIFYgLSBNZXRhZGF0YSB0eXBlXG4gKiBAdGVtcGxhdGUgRiAtIFJlcG9zaXRvcnkgZmxhZ3NcbiAqIEB0ZW1wbGF0ZSBDIC0gQ29udGV4dCB0eXBlXG4gKiBAZXhhbXBsZVxuICogLy8gUmVnaXN0ZXIgYSBoYW5kbGVyIGZvciBhIGNyZWF0ZSBvcGVyYXRpb25cbiAqIE9wZXJhdGlvbnMucmVnaXN0ZXIobXlIYW5kbGVyLCBPcGVyYXRpb25LZXlzLkNSRUFURSwgdGFyZ2V0TW9kZWwsICdwcm9wZXJ0eU5hbWUnKTtcbiAqIFxuICogLy8gR2V0IGhhbmRsZXJzIGZvciBhIHNwZWNpZmljIG9wZXJhdGlvblxuICogY29uc3QgaGFuZGxlcnMgPSBPcGVyYXRpb25zLmdldCh0YXJnZXRNb2RlbC5jb25zdHJ1Y3Rvci5uYW1lLCAncHJvcGVydHlOYW1lJywgJ29uQ3JlYXRlJyk7XG4gKiBcbiAqIEBtZXJtYWlkXG4gKiBjbGFzc0RpYWdyYW1cbiAqICAgY2xhc3MgT3BlcmF0aW9ucyB7XG4gKiAgICAgLXJlZ2lzdHJ5OiBPcGVyYXRpb25zUmVnaXN0cnlcbiAqICAgICArZ2V0SGFuZGxlck5hbWUoaGFuZGxlcilcbiAqICAgICAra2V5KHN0cilcbiAqICAgICArZ2V0KHRhcmdldE5hbWUsIHByb3BLZXksIG9wZXJhdGlvbilcbiAqICAgICAtZ2V0T3BSZWdpc3RyeSgpXG4gKiAgICAgK3JlZ2lzdGVyKGhhbmRsZXIsIG9wZXJhdGlvbiwgdGFyZ2V0LCBwcm9wS2V5KVxuICogICB9XG4gKiAgIE9wZXJhdGlvbnMgLS0+IE9wZXJhdGlvbnNSZWdpc3RyeSA6IHVzZXNcbiAqL1xuZXhwb3J0IGNsYXNzIE9wZXJhdGlvbnMge1xuICBwcml2YXRlIHN0YXRpYyByZWdpc3RyeTogT3BlcmF0aW9uc1JlZ2lzdHJ5O1xuXG4gIHByaXZhdGUgY29uc3RydWN0b3IoKSB7fVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2V0cyBhIHVuaXF1ZSBuYW1lIGZvciBhbiBvcGVyYXRpb24gaGFuZGxlclxuICAgKiBAc3VtbWFyeSBSZXR1cm5zIHRoZSBuYW1lIG9mIHRoZSBoYW5kbGVyIGZ1bmN0aW9uIG9yIGdlbmVyYXRlcyBhIGhhc2ggaWYgbmFtZSBpcyBub3QgYXZhaWxhYmxlXG4gICAqIEBwYXJhbSB7T3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgYW55LCBhbnksIGFueT59IGhhbmRsZXIgLSBUaGUgaGFuZGxlciBmdW5jdGlvbiB0byBnZXQgdGhlIG5hbWUgZm9yXG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIG5hbWUgb2YgdGhlIGhhbmRsZXIgb3IgYSBnZW5lcmF0ZWQgaGFzaFxuICAgKi9cbiAgc3RhdGljIGdldEhhbmRsZXJOYW1lKGhhbmRsZXI6IE9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIGFueSwgYW55LCBhbnk+KSB7XG4gICAgaWYgKGhhbmRsZXIubmFtZSkgcmV0dXJuIGhhbmRsZXIubmFtZTtcblxuICAgIGNvbnNvbGUud2FybihcbiAgICAgIFwiSGFuZGxlciBuYW1lIG5vdCBkZWZpbmVkLiBBIG5hbWUgd2lsbCBiZSBnZW5lcmF0ZWQsIGJ1dCB0aGlzIGlzIG5vdCBkZXNpcmFibGUuIHBsZWFzZSBhdm9pZCB1c2luZyBhbm9ueW1vdXMgZnVuY3Rpb25zXCJcbiAgICApO1xuICAgIHJldHVybiBIYXNoaW5nLmhhc2goaGFuZGxlci50b1N0cmluZygpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2VuZXJhdGVzIGEgcmVmbGVjdGlvbiBtZXRhZGF0YSBrZXlcbiAgICogQHN1bW1hcnkgQ3JlYXRlcyBhIGZ1bGx5IHF1YWxpZmllZCBtZXRhZGF0YSBrZXkgYnkgcHJlZml4aW5nIHdpdGggdGhlIHJlZmxlY3Rpb24gbmFtZXNwYWNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzdHIgLSBUaGUgb3BlcmF0aW9uIGtleSBzdHJpbmcgdG8gcHJlZml4XG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGZ1bGx5IHF1YWxpZmllZCBtZXRhZGF0YSBrZXlcbiAgICovXG4gIHN0YXRpYyBrZXkoc3RyOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gT3BlcmF0aW9uS2V5cy5SRUZMRUNUICsgc3RyO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXRyaWV2ZXMgb3BlcmF0aW9uIGhhbmRsZXJzIGZvciBhIHNwZWNpZmljIHRhcmdldCBhbmQgb3BlcmF0aW9uXG4gICAqIEBzdW1tYXJ5IEdldHMgcmVnaXN0ZXJlZCBoYW5kbGVycyBmcm9tIHRoZSBvcGVyYXRpb25zIHJlZ2lzdHJ5IGZvciBhIGdpdmVuIHRhcmdldCwgcHJvcGVydHksIGFuZCBvcGVyYXRpb25cbiAgICogQHRlbXBsYXRlIE0gLSBNb2RlbCB0eXBlIGV4dGVuZGluZyBNb2RlbFxuICAgKiBAdGVtcGxhdGUgUiAtIFJlcG9zaXRvcnkgdHlwZSBleHRlbmRpbmcgSVJlcG9zaXRvcnlcbiAgICogQHRlbXBsYXRlIFYgLSBNZXRhZGF0YSB0eXBlLCBkZWZhdWx0cyB0byBvYmplY3RcbiAgICogQHRlbXBsYXRlIEYgLSBSZXBvc2l0b3J5IGZsYWdzIGV4dGVuZGluZyBSZXBvc2l0b3J5RmxhZ3NcbiAgICogQHRlbXBsYXRlIEMgLSBDb250ZXh0IHR5cGUgZXh0ZW5kaW5nIENvbnRleHQ8Rj5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBSZWNvcmQ8c3RyaW5nLCBhbnk+fSB0YXJnZXROYW1lIC0gVGhlIHRhcmdldCBjbGFzcyBuYW1lIG9yIG9iamVjdFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcEtleSAtIFRoZSBwcm9wZXJ0eSBrZXkgdG8gZ2V0IGhhbmRsZXJzIGZvclxuICAgKiBAcGFyYW0ge3N0cmluZ30gb3BlcmF0aW9uIC0gVGhlIG9wZXJhdGlvbiBrZXkgdG8gZ2V0IGhhbmRsZXJzIGZvclxuICAgKiBAcmV0dXJuIHthbnl9IFRoZSByZWdpc3RlcmVkIGhhbmRsZXJzIGZvciB0aGUgc3BlY2lmaWVkIHRhcmdldCwgcHJvcGVydHksIGFuZCBvcGVyYXRpb25cbiAgICovXG4gIHN0YXRpYyBnZXQ8XG4gICAgTSBleHRlbmRzIE1vZGVsLFxuICAgIFIgZXh0ZW5kcyBJUmVwb3NpdG9yeTxNLCBGLCBDPixcbiAgICBWID0gb2JqZWN0LFxuICAgIEYgZXh0ZW5kcyBSZXBvc2l0b3J5RmxhZ3MgPSBSZXBvc2l0b3J5RmxhZ3MsXG4gICAgQyBleHRlbmRzIENvbnRleHQ8Rj4gPSBDb250ZXh0PEY+LFxuICA+KFxuICAgIHRhcmdldE5hbWU6IHN0cmluZyB8IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgcHJvcEtleTogc3RyaW5nLFxuICAgIG9wZXJhdGlvbjogc3RyaW5nXG4gICkge1xuICAgIHJldHVybiBPcGVyYXRpb25zLnJlZ2lzdHJ5LmdldDxNLCBSLCBWLCBGLCBDPihcbiAgICAgIHRhcmdldE5hbWUsXG4gICAgICBwcm9wS2V5LFxuICAgICAgb3BlcmF0aW9uXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2V0cyBvciBpbml0aWFsaXplcyB0aGUgb3BlcmF0aW9ucyByZWdpc3RyeVxuICAgKiBAc3VtbWFyeSBSZXR1cm5zIHRoZSBleGlzdGluZyByZWdpc3RyeSBvciBjcmVhdGVzIGEgbmV3IG9uZSBpZiBpdCBkb2Vzbid0IGV4aXN0XG4gICAqIEByZXR1cm4ge09wZXJhdGlvbnNSZWdpc3RyeX0gVGhlIG9wZXJhdGlvbnMgcmVnaXN0cnkgaW5zdGFuY2VcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGdldE9wUmVnaXN0cnkoKSB7XG4gICAgaWYgKCFPcGVyYXRpb25zLnJlZ2lzdHJ5KSBPcGVyYXRpb25zLnJlZ2lzdHJ5ID0gbmV3IE9wZXJhdGlvbnNSZWdpc3RyeSgpO1xuICAgIHJldHVybiBPcGVyYXRpb25zLnJlZ2lzdHJ5O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWdpc3RlcnMgYW4gb3BlcmF0aW9uIGhhbmRsZXIgZm9yIGEgc3BlY2lmaWMgdGFyZ2V0IGFuZCBvcGVyYXRpb25cbiAgICogQHN1bW1hcnkgQWRkcyBhIGhhbmRsZXIgdG8gdGhlIG9wZXJhdGlvbnMgcmVnaXN0cnkgZm9yIGEgZ2l2ZW4gdGFyZ2V0LCBwcm9wZXJ0eSwgYW5kIG9wZXJhdGlvblxuICAgKiBAdGVtcGxhdGUgViAtIE1vZGVsIHR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gICAqIEBwYXJhbSB7T3BlcmF0aW9uSGFuZGxlcjxWLCBhbnksIGFueT59IGhhbmRsZXIgLSBUaGUgaGFuZGxlciBmdW5jdGlvbiB0byByZWdpc3RlclxuICAgKiBAcGFyYW0ge09wZXJhdGlvbktleXN9IG9wZXJhdGlvbiAtIFRoZSBvcGVyYXRpb24ga2V5IHRvIHJlZ2lzdGVyIHRoZSBoYW5kbGVyIGZvclxuICAgKiBAcGFyYW0ge1Z9IHRhcmdldCAtIFRoZSB0YXJnZXQgbW9kZWwgaW5zdGFuY2VcbiAgICogQHBhcmFtIHtzdHJpbmcgfCBzeW1ib2x9IHByb3BLZXkgLSBUaGUgcHJvcGVydHkga2V5IHRvIHJlZ2lzdGVyIHRoZSBoYW5kbGVyIGZvclxuICAgKiBAcmV0dXJuIHt2b2lkfVxuICAgKi9cbiAgc3RhdGljIHJlZ2lzdGVyPFYgZXh0ZW5kcyBNb2RlbD4oXG4gICAgaGFuZGxlcjogT3BlcmF0aW9uSGFuZGxlcjxWLCBhbnksIGFueT4sXG4gICAgb3BlcmF0aW9uOiBPcGVyYXRpb25LZXlzLFxuICAgIHRhcmdldDogVixcbiAgICBwcm9wS2V5OiBzdHJpbmcgfCBzeW1ib2xcbiAgKSB7XG4gICAgT3BlcmF0aW9ucy5nZXRPcFJlZ2lzdHJ5KCkucmVnaXN0ZXIoXG4gICAgICBoYW5kbGVyIGFzIGFueSxcbiAgICAgIG9wZXJhdGlvbixcbiAgICAgIHRhcmdldCxcbiAgICAgIHByb3BLZXlcbiAgICApO1xuICB9XG59XG4iLCIvKipcbiAqIEBkZXNjcmlwdGlvbiBCYXNlIGVycm9yIGNsYXNzIGZvciB0aGUgcmVwb3NpdG9yeSBtb2R1bGVcbiAqIEBzdW1tYXJ5IEFic3RyYWN0IGJhc2UgZXJyb3IgY2xhc3MgdGhhdCBhbGwgb3RoZXIgZXJyb3IgdHlwZXMgZXh0ZW5kIGZyb20uIFByb3ZpZGVzIGNvbW1vbiBlcnJvciBoYW5kbGluZyBmdW5jdGlvbmFsaXR5IGFuZCBzdGFuZGFyZGl6ZWQgSFRUUCBjb2RlIG1hcHBpbmcuXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBlcnJvclxuICogQHBhcmFtIHtzdHJpbmd8RXJyb3J9IG1zZyAtIFRoZSBlcnJvciBtZXNzYWdlIG9yIEVycm9yIG9iamVjdCB0byB3cmFwXG4gKiBAcGFyYW0ge251bWJlcn0gY29kZSAtIFRoZSBIVFRQIHN0YXR1cyBjb2RlIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGVycm9yXG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGNsYXNzIEJhc2VFcnJvclxuICogQGV4YW1wbGVcbiAqIC8vIFRoaXMgaXMgYW4gYWJzdHJhY3QgY2xhc3MgYW5kIHNob3VsZCBub3QgYmUgaW5zdGFudGlhdGVkIGRpcmVjdGx5XG4gKiAvLyBJbnN0ZWFkLCB1c2Ugb25lIG9mIHRoZSBjb25jcmV0ZSBlcnJvciBjbGFzc2VzOlxuICogdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcignSW52YWxpZCBkYXRhIHByb3ZpZGVkJyk7XG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEMgYXMgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IEUgYXMgQmFzZUVycm9yXG4gKiAgIEMtPj5FOiBuZXcgQmFzZUVycm9yKG5hbWUsbXNnLGNvZGUpXG4gKiAgIEUtLT4+QzogRXJyb3IgaW5zdGFuY2Ugd2l0aCBtZXNzYWdlIGFuZCBjb2RlXG4gKiBAY2F0ZWdvcnkgRXJyb3JzXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNlRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIHJlYWRvbmx5IGNvZGUhOiBudW1iZXI7XG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihuYW1lOiBzdHJpbmcsIG1zZzogc3RyaW5nIHwgRXJyb3IsIGNvZGU6IG51bWJlcikge1xuICAgIGlmIChtc2cgaW5zdGFuY2VvZiBCYXNlRXJyb3IpIHJldHVybiBtc2c7XG4gICAgY29uc3QgbWVzc2FnZSA9IGBbJHtuYW1lfV0gJHttc2cgaW5zdGFuY2VvZiBFcnJvciA/IG1zZy5tZXNzYWdlIDogbXNnfWA7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5jb2RlID0gY29kZTtcbiAgICBpZiAobXNnIGluc3RhbmNlb2YgRXJyb3IpIHRoaXMuc3RhY2sgPSBtc2cuc3RhY2s7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRXJyb3IgKDQwKSB0aHJvd24gd2hlbiBhIGJhZCByZXF1ZXN0IGlzIHJlY2VpdmVkXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGEgZmFpbHVyZSBpbiB0aGUgaW5wdXQgZGF0YSwgdHlwaWNhbGx5IHRocm93biB3aGVuIGEgY2xpZW50IHNlbmRzIGludmFsaWQgb3IgaW5jb21wbGV0ZSBkYXRhXG4gKiBAcGFyYW0ge3N0cmluZ3xFcnJvcn0gbXNnIC0gVGhlIGVycm9yIG1lc3NhZ2Ugb3IgRXJyb3Igb2JqZWN0XG4gKiBAcmV0dXJuIHtCYWRSZXF1ZXN0RXJyb3J9IEEgbmV3IEJhZFJlcXVlc3RFcnJvciBpbnN0YW5jZVxuICogQGNsYXNzIEJhZFJlcXVlc3RFcnJvclxuICogQGNhdGVnb3J5IEVycm9yc1xuICovXG5leHBvcnQgY2xhc3MgQmFkUmVxdWVzdEVycm9yIGV4dGVuZHMgQmFzZUVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvciwgbmFtZSA9IEJhZFJlcXVlc3RFcnJvci5uYW1lLCBjb2RlID0gNDAwKSB7XG4gICAgc3VwZXIobmFtZSwgbXNnLCBjb2RlKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFcnJvciAoNDIyKSB0aHJvd24gd2hlbiB2YWxpZGF0aW9uIGZhaWxzXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGEgZmFpbHVyZSBpbiB0aGUgTW9kZWwgZGV0YWlscywgdHlwaWNhbGx5IHRocm93biB3aGVuIGRhdGEgdmFsaWRhdGlvbiBmYWlsc1xuICogQHBhcmFtIHtzdHJpbmd8RXJyb3J9IG1zZyAtIFRoZSBlcnJvciBtZXNzYWdlIG9yIEVycm9yIG9iamVjdFxuICogQHJldHVybiB7VmFsaWRhdGlvbkVycm9yfSBBIG5ldyBWYWxpZGF0aW9uRXJyb3IgaW5zdGFuY2VcbiAqIEBjbGFzcyBWYWxpZGF0aW9uRXJyb3JcbiAqIEBleGFtcGxlXG4gKiAvLyBUaHJvdyBhIHZhbGlkYXRpb24gZXJyb3Igd2hlbiBkYXRhIGlzIGludmFsaWRcbiAqIGlmICghaXNWYWxpZChkYXRhKSkge1xuICogICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKCdJbnZhbGlkIGRhdGEgZm9ybWF0Jyk7XG4gKiB9XG4gKiBAY2F0ZWdvcnkgRXJyb3JzXG4gKi9cbmV4cG9ydCBjbGFzcyBWYWxpZGF0aW9uRXJyb3IgZXh0ZW5kcyBCYWRSZXF1ZXN0RXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBWYWxpZGF0aW9uRXJyb3IubmFtZSwgNDIyKTtcbiAgfVxufVxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRXJyb3IgKDUwMCkgdGhyb3duIGZvciBpbnRlcm5hbCBzeXN0ZW0gZmFpbHVyZXNcbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYW4gaW50ZXJuYWwgZmFpbHVyZSAoc2hvdWxkIG1lYW4gYW4gZXJyb3IgaW4gY29kZSkgd2l0aCBIVFRQIDUwMCBzdGF0dXMgY29kZVxuICogQHBhcmFtIHtzdHJpbmd8RXJyb3J9IG1zZyAtIFRoZSBlcnJvciBtZXNzYWdlIG9yIEVycm9yIG9iamVjdFxuICogQHJldHVybiB7SW50ZXJuYWxFcnJvcn0gQSBuZXcgSW50ZXJuYWxFcnJvciBpbnN0YW5jZVxuICogQGNsYXNzIEludGVybmFsRXJyb3JcbiAqIEBleGFtcGxlXG4gKiAvLyBUaHJvdyBhbiBpbnRlcm5hbCBlcnJvciB3aGVuIGFuIHVuZXhwZWN0ZWQgY29uZGl0aW9uIG9jY3Vyc1xuICogdHJ5IHtcbiAqICAgLy8gU29tZSBvcGVyYXRpb25cbiAqIH0gY2F0Y2ggKGVycm9yKSB7XG4gKiAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKCdVbmV4cGVjdGVkIGludGVybmFsIGVycm9yIG9jY3VycmVkJyk7XG4gKiB9XG4gKiBAY2F0ZWdvcnkgRXJyb3JzXG4gKi9cbmV4cG9ydCBjbGFzcyBJbnRlcm5hbEVycm9yIGV4dGVuZHMgQmFzZUVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvciwgbmFtZSA9IEludGVybmFsRXJyb3IubmFtZSwgY29kZSA9IDUwMCkge1xuICAgIHN1cGVyKG5hbWUsIG1zZywgY29kZSk7XG4gIH1cbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVycm9yICg1MDApIHRocm93biB3aGVuIHNlcmlhbGl6YXRpb24gb3IgZGVzZXJpYWxpemF0aW9uIGZhaWxzXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGEgZmFpbHVyZSBpbiB0aGUgTW9kZWwgZGUvc2VyaWFsaXphdGlvbiwgdHlwaWNhbGx5IHdoZW4gY29udmVydGluZyBiZXR3ZWVuIGRhdGEgZm9ybWF0c1xuICogQHBhcmFtIHtzdHJpbmd8RXJyb3J9IG1zZyAtIFRoZSBlcnJvciBtZXNzYWdlIG9yIEVycm9yIG9iamVjdFxuICogQHJldHVybiB7U2VyaWFsaXphdGlvbkVycm9yfSBBIG5ldyBTZXJpYWxpemF0aW9uRXJyb3IgaW5zdGFuY2VcbiAqIEBjbGFzcyBTZXJpYWxpemF0aW9uRXJyb3JcbiAqIEBleGFtcGxlXG4gKiAvLyBUaHJvdyBhIHNlcmlhbGl6YXRpb24gZXJyb3Igd2hlbiBKU09OIHBhcnNpbmcgZmFpbHNcbiAqIHRyeSB7XG4gKiAgIGNvbnN0IGRhdGEgPSBKU09OLnBhcnNlKGludmFsaWRKc29uKTtcbiAqIH0gY2F0Y2ggKGVycm9yKSB7XG4gKiAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoJ0ZhaWxlZCB0byBwYXJzZSBKU09OIGRhdGEnKTtcbiAqIH1cbiAqIEBjYXRlZ29yeSBFcnJvcnNcbiAqL1xuZXhwb3J0IGNsYXNzIFNlcmlhbGl6YXRpb25FcnJvciBleHRlbmRzIEludGVybmFsRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBTZXJpYWxpemF0aW9uRXJyb3IubmFtZSwgNTAwKTtcbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBFcnJvciB0aHJvd24gd2hlbiBhIHJlcXVlc3RlZCByZXNvdXJjZSBpcyBub3QgZm91bmRcbiAqIEBzdW1tYXJ5IFJlcHJlc2VudHMgYSBmYWlsdXJlIGluIGZpbmRpbmcgYSBtb2RlbCwgcmVzdWx0aW5nIGluIGEgNDA0IEhUVFAgc3RhdHVzIGNvZGVcbiAqIEBwYXJhbSB7c3RyaW5nfEVycm9yfSBtc2cgLSBUaGUgZXJyb3IgbWVzc2FnZSBvciBFcnJvciBvYmplY3RcbiAqIEByZXR1cm4ge05vdEZvdW5kRXJyb3J9IEEgbmV3IE5vdEZvdW5kRXJyb3IgaW5zdGFuY2VcbiAqIEBjbGFzcyBOb3RGb3VuZEVycm9yXG4gKiBAZXhhbXBsZVxuICogLy8gVGhyb3cgYSBub3QgZm91bmQgZXJyb3Igd2hlbiBhIHJlY29yZCBkb2Vzbid0IGV4aXN0XG4gKiBjb25zdCB1c2VyID0gYXdhaXQgcmVwb3NpdG9yeS5maW5kQnlJZChpZCk7XG4gKiBpZiAoIXVzZXIpIHtcbiAqICAgdGhyb3cgbmV3IE5vdEZvdW5kRXJyb3IoYFVzZXIgd2l0aCBJRCAke2lkfSBub3QgZm91bmRgKTtcbiAqIH1cbiAqIEBjYXRlZ29yeSBFcnJvcnNcbiAqL1xuZXhwb3J0IGNsYXNzIE5vdEZvdW5kRXJyb3IgZXh0ZW5kcyBCYWRSZXF1ZXN0RXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yKSB7XG4gICAgc3VwZXIobXNnLCBOb3RGb3VuZEVycm9yLm5hbWUsIDQwNCk7XG4gIH1cbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVycm9yIHRocm93biB3aGVuIGEgY29uZmxpY3Qgb2NjdXJzIGluIHRoZSBzdG9yYWdlXG4gKiBAc3VtbWFyeSBSZXByZXNlbnRzIGEgY29uZmxpY3QgaW4gdGhlIHN0b3JhZ2UsIHR5cGljYWxseSB3aGVuIHRyeWluZyB0byBjcmVhdGUgYSBkdXBsaWNhdGUgcmVzb3VyY2VcbiAqIEBwYXJhbSB7c3RyaW5nfEVycm9yfSBtc2cgLSBUaGUgZXJyb3IgbWVzc2FnZSBvciBFcnJvciBvYmplY3RcbiAqIEByZXR1cm4ge0NvbmZsaWN0RXJyb3J9IEEgbmV3IENvbmZsaWN0RXJyb3IgaW5zdGFuY2VcbiAqIEBjbGFzcyBDb25mbGljdEVycm9yXG4gKiBAZXhhbXBsZVxuICogLy8gVGhyb3cgYSBjb25mbGljdCBlcnJvciB3aGVuIHRyeWluZyB0byBjcmVhdGUgYSBkdXBsaWNhdGUgcmVjb3JkXG4gKiBjb25zdCBleGlzdGluZ1VzZXIgPSBhd2FpdCByZXBvc2l0b3J5LmZpbmRCeUVtYWlsKGVtYWlsKTtcbiAqIGlmIChleGlzdGluZ1VzZXIpIHtcbiAqICAgdGhyb3cgbmV3IENvbmZsaWN0RXJyb3IoYFVzZXIgd2l0aCBlbWFpbCAke2VtYWlsfSBhbHJlYWR5IGV4aXN0c2ApO1xuICogfVxuICogQGNhdGVnb3J5IEVycm9yc1xuICovXG5leHBvcnQgY2xhc3MgQ29uZmxpY3RFcnJvciBleHRlbmRzIEJhZFJlcXVlc3RFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihtc2csIENvbmZsaWN0RXJyb3IubmFtZSwgNDA5KTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgSVJlcG9zaXRvcnkgfSBmcm9tIFwiLi4vaW50ZXJmYWNlcy9JUmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgT3BlcmF0aW9uS2V5cyB9IGZyb20gXCIuLi9vcGVyYXRpb25zL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgRGVjb3JhdG9yTWV0YWRhdGEsIFJlZmxlY3Rpb24gfSBmcm9tIFwiQGRlY2FmLXRzL3JlZmxlY3Rpb25cIjtcbmltcG9ydCB7IEludGVybmFsRXJyb3IgfSBmcm9tIFwiLi9lcnJvcnNcIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yLCBNb2RlbCwgTW9kZWxLZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgQ29udGV4dCB9IGZyb20gXCIuL0NvbnRleHRcIjtcbmltcG9ydCB7IFJlcG9zaXRvcnlGbGFncyB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQge1xuICBnZXRIYW5kbGVyc0RlY29yYXRvcnMsXG4gIGdyb3VwRGVjb3JhdG9ycyxcbiAgc29ydERlY29yYXRvcnMsXG59IGZyb20gXCIuLi9vcGVyYXRpb25zL2RlY29yYXRvcnNcIjtcbmltcG9ydCB7IFVwZGF0ZU9wZXJhdGlvbkhhbmRsZXIgfSBmcm9tIFwiLi4vb3BlcmF0aW9ucy90eXBlc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDb250ZXh0IGFyZ3VtZW50cyBmb3IgcmVwb3NpdG9yeSBvcGVyYXRpb25zLlxuICogQHN1bW1hcnkgUmVwcmVzZW50cyB0aGUgY29udGV4dCBhbmQgYXJndW1lbnRzIGZvciByZXBvc2l0b3J5IG9wZXJhdGlvbnMuXG4gKiBUaGlzIHR5cGUgaXMgdXNlZCB0byBwYXNzIGNvbnRleHQgYW5kIGFyZ3VtZW50cyBiZXR3ZWVuIHJlcG9zaXRvcnkgbWV0aG9kcy5cbiAqIEB0ZW1wbGF0ZSBGIC0gVGhlIHJlcG9zaXRvcnkgZmxhZ3MgdHlwZSwgZGVmYXVsdHMgdG8gUmVwb3NpdG9yeUZsYWdzXG4gKiBAdGVtcGxhdGUgQyAtIFRoZSBjb250ZXh0IHR5cGUsIGRlZmF1bHRzIHRvIENvbnRleHQ8Rj5cbiAqIEB0eXBlZGVmIHtPYmplY3R9IENvbnRleHRBcmdzXG4gKiBAcHJvcGVydHkge0N9IGNvbnRleHQgLSBUaGUgb3BlcmF0aW9uIGNvbnRleHRcbiAqIEBwcm9wZXJ0eSB7YW55W119IGFyZ3MgLSBUaGUgb3BlcmF0aW9uIGFyZ3VtZW50c1xuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCB0eXBlIENvbnRleHRBcmdzPFxuICBGIGV4dGVuZHMgUmVwb3NpdG9yeUZsYWdzID0gUmVwb3NpdG9yeUZsYWdzLFxuICBDIGV4dGVuZHMgQ29udGV4dDxGPiA9IENvbnRleHQ8Rj4sXG4+ID0ge1xuICBjb250ZXh0OiBDO1xuICBhcmdzOiBhbnlbXTtcbn07XG5cbi8qKlxuICogQHN1bW1hcnkgcmV0cmlldmVzIHRoZSBhcmd1bWVudHMgZm9yIHRoZSBoYW5kbGVyXG4gKiBAcGFyYW0ge2FueX0gZGVjIHRoZSBkZWNvcmF0b3JcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wIHRoZSBwcm9wZXJ0eSBuYW1lXG4gKiBAcGFyYW0ge3t9fSBtIHRoZSBtb2RlbFxuICogQHBhcmFtIHt7fX0gW2FjY3VtXSBhY2N1bXVsYXRvciB1c2VkIGZvciBpbnRlcm5hbCByZWN1cnNpdmVuZXNzXG4gKlxuICogQGZ1bmN0aW9uIGdldEhhbmRsZXJBcmdzXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmRiLWRlY29yYXRvcnMuUmVwb3NpdG9yeVxuICovXG5leHBvcnQgY29uc3QgZ2V0SGFuZGxlckFyZ3MgPSBmdW5jdGlvbiAoXG4gIGRlYzogYW55LFxuICBwcm9wOiBzdHJpbmcsXG4gIG06IENvbnN0cnVjdG9yPGFueT4sXG4gIGFjY3VtPzogUmVjb3JkPHN0cmluZywgeyBhcmdzOiBzdHJpbmdbXSB9PlxuKTogUmVjb3JkPHN0cmluZywgeyBhcmdzOiBzdHJpbmdbXSB9PiB8IHZvaWQge1xuICBjb25zdCBuYW1lID0gbS5jb25zdHJ1Y3Rvci5uYW1lO1xuICBpZiAoIW5hbWUpIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiQ291bGQgbm90IGRldGVybWluZSBtb2RlbCBjbGFzc1wiKTtcbiAgYWNjdW0gPSBhY2N1bSB8fCB7fTtcblxuICBpZiAoZGVjLnByb3BzLmhhbmRsZXJzW25hbWVdICYmIGRlYy5wcm9wcy5oYW5kbGVyc1tuYW1lXVtwcm9wXSlcbiAgICBhY2N1bSA9IHsgLi4uZGVjLnByb3BzLmhhbmRsZXJzW25hbWVdW3Byb3BdLCAuLi5hY2N1bSB9O1xuXG4gIGxldCBwcm90byA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihtKTtcbiAgaWYgKHByb3RvID09PSBPYmplY3QucHJvdG90eXBlKSByZXR1cm4gYWNjdW07XG4gIGlmIChwcm90by5jb25zdHJ1Y3Rvci5uYW1lID09PSBuYW1lKSBwcm90byA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihwcm90byk7XG5cbiAgcmV0dXJuIGdldEhhbmRsZXJBcmdzKGRlYywgcHJvcCwgcHJvdG8sIGFjY3VtKTtcbn07XG5cbi8qKlxuICpcbiAqIEBwYXJhbSB7SVJlcG9zaXRvcnk8VD59IHJlcG9cbiAqIEBwYXJhbSBjb250ZXh0XG4gKiBAcGFyYW0ge1R9IG1vZGVsXG4gKiBAcGFyYW0gb3BlcmF0aW9uXG4gKiBAcGFyYW0gcHJlZml4XG4gKlxuICogQHBhcmFtIG9sZE1vZGVsXG4gKiBAZnVuY3Rpb24gZW5mb3JjZURCUHJvcGVydHlEZWNvcmF0b3JzQXN5bmNcbiAqXG4gKiBAbWVtYmVyT2YgZGItZGVjb3JhdG9ycy51dGlsc1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZW5mb3JjZURCRGVjb3JhdG9yczxcbiAgTSBleHRlbmRzIE1vZGVsPHRydWUgfCBmYWxzZT4sXG4gIFIgZXh0ZW5kcyBJUmVwb3NpdG9yeTxNLCBGLCBDPixcbiAgViBleHRlbmRzIG9iamVjdCA9IG9iamVjdCxcbiAgRiBleHRlbmRzIFJlcG9zaXRvcnlGbGFncyA9IFJlcG9zaXRvcnlGbGFncyxcbiAgQyBleHRlbmRzIENvbnRleHQ8Rj4gPSBDb250ZXh0PEY+LFxuPihcbiAgcmVwbzogUixcbiAgY29udGV4dDogQyxcbiAgbW9kZWw6IE0sXG4gIG9wZXJhdGlvbjogc3RyaW5nLFxuICBwcmVmaXg6IHN0cmluZyxcbiAgb2xkTW9kZWw/OiBNXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgZGVjb3JhdG9yczogUmVjb3JkPHN0cmluZywgRGVjb3JhdG9yTWV0YWRhdGFbXT4gfCB1bmRlZmluZWQgPVxuICAgIGdldERiRGVjb3JhdG9ycyhtb2RlbCwgb3BlcmF0aW9uLCBwcmVmaXgpO1xuXG4gIGlmICghZGVjb3JhdG9ycykgcmV0dXJuO1xuXG4gIGNvbnN0IGhhbmxlcnNEZWNvcmF0b3JzID0gZ2V0SGFuZGxlcnNEZWNvcmF0b3JzKG1vZGVsLCBkZWNvcmF0b3JzLCBwcmVmaXgpO1xuICBjb25zdCBncm91cGVkRGVjb3JhdG9ycyA9IGdyb3VwRGVjb3JhdG9ycyhoYW5sZXJzRGVjb3JhdG9ycyk7XG4gIGNvbnN0IHNvcnRlZERlY29yYXRvcnMgPSBzb3J0RGVjb3JhdG9ycyhncm91cGVkRGVjb3JhdG9ycyk7XG5cbiAgZm9yIChjb25zdCBkZWMgb2Ygc29ydGVkRGVjb3JhdG9ycykge1xuICAgIGNvbnN0IGFyZ3M6IGFueVtdID0gW1xuICAgICAgY29udGV4dCxcbiAgICAgIGRlYy5kYXRhLmxlbmd0aCA+IDEgPyBkZWMuZGF0YSA6IGRlYy5kYXRhWzBdLFxuICAgICAgZGVjLnByb3AubGVuZ3RoID4gMSA/IGRlYy5wcm9wIDogZGVjLnByb3BbMF0sXG4gICAgICBtb2RlbCxcbiAgICBdO1xuXG4gICAgaWYgKG9wZXJhdGlvbiA9PT0gT3BlcmF0aW9uS2V5cy5VUERBVEUgJiYgcHJlZml4ID09PSBPcGVyYXRpb25LZXlzLk9OKSB7XG4gICAgICBpZiAoIW9sZE1vZGVsKVxuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIk1pc3Npbmcgb2xkIG1vZGVsIGZvciB1cGRhdGUgb3BlcmF0aW9uXCIpO1xuICAgICAgYXJncy5wdXNoKG9sZE1vZGVsKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IChkZWMuaGFuZGxlciBhcyBVcGRhdGVPcGVyYXRpb25IYW5kbGVyPE0sIFIsIFYsIEYsIEM+KS5hcHBseShcbiAgICAgICAgcmVwbyxcbiAgICAgICAgYXJncyBhcyBbQywgViwga2V5b2YgTSwgTSwgTV1cbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgY29uc3QgbXNnID0gYEZhaWxlZCB0byBleGVjdXRlIGhhbmRsZXIgJHtkZWMuaGFuZGxlci5uYW1lfSBmb3IgJHtkZWMucHJvcH0gb24gJHttb2RlbC5jb25zdHJ1Y3Rvci5uYW1lfSBkdWUgdG8gZXJyb3I6ICR7ZX1gO1xuICAgICAgaWYgKGNvbnRleHQuZ2V0KFwiYnJlYWtPbkhhbmRsZXJFcnJvclwiKSkgdGhyb3cgbmV3IEludGVybmFsRXJyb3IobXNnKTtcbiAgICAgIGNvbnNvbGUubG9nKG1zZyk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogU3BlY2lmaWMgZm9yIERCIERlY29yYXRvcnNcbiAqIEBwYXJhbSB7VH0gbW9kZWxcbiAqIEBwYXJhbSB7c3RyaW5nfSBvcGVyYXRpb24gQ1JVRCB7QGxpbmsgT3BlcmF0aW9uS2V5c31cbiAqIEBwYXJhbSB7c3RyaW5nfSBbZXh0cmFQcmVmaXhdXG4gKlxuICogQGZ1bmN0aW9uIGdldERiUHJvcGVydHlEZWNvcmF0b3JzXG4gKlxuICogQG1lbWJlck9mIGRiLWRlY29yYXRvcnMudXRpbHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldERiRGVjb3JhdG9yczxUIGV4dGVuZHMgTW9kZWw+KFxuICBtb2RlbDogVCxcbiAgb3BlcmF0aW9uOiBzdHJpbmcsXG4gIGV4dHJhUHJlZml4Pzogc3RyaW5nXG4pOiBSZWNvcmQ8c3RyaW5nLCBEZWNvcmF0b3JNZXRhZGF0YVtdPiB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGRlY29yYXRvcnM6IFJlY29yZDxzdHJpbmcsIERlY29yYXRvck1ldGFkYXRhW10+IHwgdW5kZWZpbmVkID1cbiAgICBSZWZsZWN0aW9uLmdldEFsbFByb3BlcnR5RGVjb3JhdG9ycyhcbiAgICAgIG1vZGVsLFxuICAgICAgLy8gdW5kZWZpbmVkLFxuICAgICAgT3BlcmF0aW9uS2V5cy5SRUZMRUNUICsgKGV4dHJhUHJlZml4ID8gZXh0cmFQcmVmaXggOiBcIlwiKVxuICAgICk7XG4gIGlmICghZGVjb3JhdG9ycykgcmV0dXJuO1xuICByZXR1cm4gT2JqZWN0LmtleXMoZGVjb3JhdG9ycykucmVkdWNlKFxuICAgIChhY2N1bTogUmVjb3JkPHN0cmluZywgRGVjb3JhdG9yTWV0YWRhdGFbXT4gfCB1bmRlZmluZWQsIGRlY29yYXRvcikgPT4ge1xuICAgICAgY29uc3QgZGVjID0gZGVjb3JhdG9yc1tkZWNvcmF0b3JdLmZpbHRlcigoZCkgPT4gZC5rZXkgPT09IG9wZXJhdGlvbik7XG4gICAgICBpZiAoZGVjICYmIGRlYy5sZW5ndGgpIHtcbiAgICAgICAgaWYgKCFhY2N1bSkgYWNjdW0gPSB7fTtcbiAgICAgICAgYWNjdW1bZGVjb3JhdG9yXSA9IGRlYztcbiAgICAgIH1cbiAgICAgIHJldHVybiBhY2N1bTtcbiAgICB9LFxuICAgIHVuZGVmaW5lZFxuICApO1xufVxuXG4vKipcbiAqIEBzdW1tYXJ5IFJldHJpZXZlcyB0aGUgZGVjb3JhdG9ycyBmb3IgYW4gb2JqZWN0J3MgcHJvcGVydGllcyBwcmVmaXhlZCBieSB7QHBhcmFtIHByZWZpeGVzfSByZWN1cnNpdmVseVxuICogQHBhcmFtIG1vZGVsXG4gKiBAcGFyYW0gYWNjdW1cbiAqIEBwYXJhbSBwcmVmaXhlc1xuICpcbiAqIEBmdW5jdGlvbiBnZXRBbGxQcm9wZXJ0eURlY29yYXRvcnNSZWN1cnNpdmVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9ycy5SZXBvc2l0b3J5XG4gKi9cbmV4cG9ydCBjb25zdCBnZXRBbGxQcm9wZXJ0eURlY29yYXRvcnNSZWN1cnNpdmUgPSBmdW5jdGlvbiA8VCBleHRlbmRzIE1vZGVsPihcbiAgbW9kZWw6IFQsXG4gIGFjY3VtOiB7IFtpbmRleGVyOiBzdHJpbmddOiBhbnlbXSB9IHwgdW5kZWZpbmVkLFxuICAuLi5wcmVmaXhlczogc3RyaW5nW11cbik6IHsgW2luZGV4ZXI6IHN0cmluZ106IGFueVtdIH0gfCB1bmRlZmluZWQge1xuICBjb25zdCBhY2N1bXVsYXRvciA9IGFjY3VtIHx8IHt9O1xuICBjb25zdCBtZXJnZURlY29yYXRvcnMgPSBmdW5jdGlvbiAoZGVjczogeyBbaW5kZXhlcjogc3RyaW5nXTogYW55W10gfSkge1xuICAgIGNvbnN0IHB1c2hPclNxdWFzaCA9IChrZXk6IHN0cmluZywgLi4udmFsdWVzOiBhbnlbXSkgPT4ge1xuICAgICAgdmFsdWVzLmZvckVhY2goKHZhbCkgPT4ge1xuICAgICAgICBsZXQgbWF0Y2g6IGFueTtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICEobWF0Y2ggPSBhY2N1bXVsYXRvcltrZXldLmZpbmQoKGUpID0+IGUua2V5ID09PSB2YWwua2V5KSkgfHxcbiAgICAgICAgICBtYXRjaC5wcm9wcy5vcGVyYXRpb24gIT09IHZhbC5wcm9wcy5vcGVyYXRpb25cbiAgICAgICAgKSB7XG4gICAgICAgICAgYWNjdW11bGF0b3Jba2V5XS5wdXNoKHZhbCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHZhbC5rZXkgPT09IE1vZGVsS2V5cy5UWVBFKSByZXR1cm47XG5cbiAgICAgICAgY29uc3QgeyBoYW5kbGVycywgb3BlcmF0aW9uIH0gPSB2YWwucHJvcHM7XG5cbiAgICAgICAgaWYgKFxuICAgICAgICAgICFvcGVyYXRpb24gfHxcbiAgICAgICAgICAhb3BlcmF0aW9uLm1hdGNoKFxuICAgICAgICAgICAgbmV3IFJlZ0V4cChcbiAgICAgICAgICAgICAgYF4oOj8ke09wZXJhdGlvbktleXMuT059fCR7T3BlcmF0aW9uS2V5cy5BRlRFUn0pKDo/JHtPcGVyYXRpb25LZXlzLkNSRUFURX18JHtPcGVyYXRpb25LZXlzLlJFQUR9fCR7T3BlcmF0aW9uS2V5cy5VUERBVEV9fCR7T3BlcmF0aW9uS2V5cy5ERUxFVEV9KSRgXG4gICAgICAgICAgICApXG4gICAgICAgICAgKVxuICAgICAgICApIHtcbiAgICAgICAgICBhY2N1bXVsYXRvcltrZXldLnB1c2godmFsKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBhY2N1bUhhbmRsZXJzID0gbWF0Y2gucHJvcHMuaGFuZGxlcnM7XG5cbiAgICAgICAgT2JqZWN0LmVudHJpZXMoaGFuZGxlcnMpLmZvckVhY2goKFtjbGF6eiwgaGFuZGxlckRlZl0pID0+IHtcbiAgICAgICAgICBpZiAoIShjbGF6eiBpbiBhY2N1bUhhbmRsZXJzKSkge1xuICAgICAgICAgICAgYWNjdW1IYW5kbGVyc1tjbGF6el0gPSBoYW5kbGVyRGVmO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIE9iamVjdC5lbnRyaWVzKGhhbmRsZXJEZWYgYXMgb2JqZWN0KS5mb3JFYWNoKFxuICAgICAgICAgICAgKFtoYW5kbGVyUHJvcCwgaGFuZGxlcl0pID0+IHtcbiAgICAgICAgICAgICAgaWYgKCEoaGFuZGxlclByb3AgaW4gYWNjdW1IYW5kbGVyc1tjbGF6el0pKSB7XG4gICAgICAgICAgICAgICAgYWNjdW1IYW5kbGVyc1tjbGF6el1baGFuZGxlclByb3BdID0gaGFuZGxlcjtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBPYmplY3QuZW50cmllcyhoYW5kbGVyIGFzIG9iamVjdCkuZm9yRWFjaChcbiAgICAgICAgICAgICAgICAoW2hhbmRsZXJLZXksIGFyZ3NPYmpdKSA9PiB7XG4gICAgICAgICAgICAgICAgICBpZiAoIShoYW5kbGVyS2V5IGluIGFjY3VtSGFuZGxlcnNbY2xhenpdW2hhbmRsZXJQcm9wXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgYWNjdW1IYW5kbGVyc1tjbGF6el1baGFuZGxlclByb3BdW2hhbmRsZXJLZXldID0gYXJnc09iajtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgICAgICAgICBgU2tpcHBpbmcgaGFuZGxlciByZWdpc3RyYXRpb24gZm9yICR7Y2xhenp9IHVuZGVyIHByb3AgJHtoYW5kbGVyUHJvcH0gYmVjYXVzZSBoYW5kbGVyIGlzIHRoZSBzYW1lYFxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9O1xuXG4gICAgT2JqZWN0LmVudHJpZXMoZGVjcykuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICBhY2N1bXVsYXRvcltrZXldID0gYWNjdW11bGF0b3Jba2V5XSB8fCBbXTtcbiAgICAgIHB1c2hPclNxdWFzaChrZXksIC4uLnZhbHVlKTtcbiAgICB9KTtcbiAgfTtcblxuICBjb25zdCBkZWNzOiB7IFtpbmRleGVyOiBzdHJpbmddOiBhbnlbXSB9IHwgdW5kZWZpbmVkID1cbiAgICBSZWZsZWN0aW9uLmdldEFsbFByb3BlcnR5RGVjb3JhdG9ycyhtb2RlbCwgLi4ucHJlZml4ZXMpO1xuICBpZiAoZGVjcykgbWVyZ2VEZWNvcmF0b3JzKGRlY3MpO1xuXG4gIGlmIChPYmplY3QuZ2V0UHJvdG90eXBlT2YobW9kZWwpID09PSBPYmplY3QucHJvdG90eXBlKSByZXR1cm4gYWNjdW11bGF0b3I7XG5cbiAgLy8gY29uc3QgbmFtZSA9IG1vZGVsLmNvbnN0cnVjdG9yLm5hbWU7XG4gIGNvbnN0IHByb3RvID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKG1vZGVsKTtcbiAgaWYgKCFwcm90bykgcmV0dXJuIGFjY3VtdWxhdG9yO1xuICAvLyBpZiAocHJvdG8uY29uc3RydWN0b3IgJiYgcHJvdG8uY29uc3RydWN0b3IubmFtZSA9PT0gbmFtZSlcbiAgLy8gICAgIHByb3RvID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKHByb3RvKVxuICByZXR1cm4gZ2V0QWxsUHJvcGVydHlEZWNvcmF0b3JzUmVjdXJzaXZlKHByb3RvLCBhY2N1bXVsYXRvciwgLi4ucHJlZml4ZXMpO1xufTtcbiIsImltcG9ydCB7XG4gIEdlbmVyYWxPcGVyYXRpb25IYW5kbGVyLFxuICBHZW5lcmFsVXBkYXRlT3BlcmF0aW9uSGFuZGxlcixcbiAgSWRPcGVyYXRpb25IYW5kbGVyLFxuICBPcGVyYXRpb25IYW5kbGVyLFxuICBTdGFuZGFyZE9wZXJhdGlvbkhhbmRsZXIsXG4gIFVwZGF0ZU9wZXJhdGlvbkhhbmRsZXIsXG59IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBEQk9wZXJhdGlvbnMsIE9wZXJhdGlvbktleXMgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IE9wZXJhdGlvbnMgfSBmcm9tIFwiLi9PcGVyYXRpb25zXCI7XG5pbXBvcnQgeyBhcHBseSB9IGZyb20gXCJAZGVjYWYtdHMvcmVmbGVjdGlvblwiO1xuaW1wb3J0IHsgTW9kZWwsIHByb3BNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IElSZXBvc2l0b3J5IH0gZnJvbSBcIi4uL2ludGVyZmFjZXNcIjtcbmltcG9ydCB7IFJlcG9zaXRvcnlGbGFncyB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L3R5cGVzXCI7XG5pbXBvcnQgeyBDb250ZXh0IH0gZnJvbSBcIi4uL3JlcG9zaXRvcnkvQ29udGV4dFwiO1xuaW1wb3J0IHsgSW50ZXJuYWxFcnJvciB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L2Vycm9yc1wiO1xuaW1wb3J0IHsgZ2V0SGFuZGxlckFyZ3MgfSBmcm9tIFwiLi4vcmVwb3NpdG9yeS91dGlsc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXByZXNlbnRzIHNvcnRpbmcgcGFyYW1ldGVycyBmb3IgZ3JvdXBpbmcgZGVjb3JhdG9yc1xuICogQHN1bW1hcnkgRGVmaW5lcyB0aGUgc3RydWN0dXJlIGZvciBzcGVjaWZ5aW5nIGdyb3VwIHNvcnRpbmcgb3B0aW9uc1xuICogQHR5cGVkZWYge09iamVjdH0gR3JvdXBTb3J0XG4gKiBAcHJvcGVydHkge251bWJlcn0gcHJpb3JpdHkgLSBUaGUgcHJpb3JpdHkgb2YgdGhlIHNvcnRpbmcgb3BlcmF0aW9uLCBsb3dlciBudW1iZXJzIHJlcHJlc2VudCBoaWdoZXIgcHJpb3JpdHlcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBbZ3JvdXBdIC0gT3B0aW9uYWwgcHJvcGVydHkgdG8gZ3JvdXAgZGVjb3JhdG9ycywgdXNlZCBmb3IgZ3JvdXBpbmcgcmVsYXRlZCBvcGVyYXRpb25zXG4gKiBAcHJvcGVydHkge251bWJlcn0gW2dyb3VwUHJpb3JpdHldIC0gT3B0aW9uYWwgcHJvcGVydHkgdG8gc3BlY2lmeSB0aGUgcHJpb3JpdHkgd2l0aGluIGEgZ3JvdXAsIGxvd2VyIG51bWJlcnMgcmVwcmVzZW50IGhpZ2hlciBwcmlvcml0eSB3aXRoaW4gdGhlIGdyb3VwXG4gKiBAY2F0ZWdvcnkgVHlwZSBEZWZpbml0aW9uc1xuICovXG5leHBvcnQgdHlwZSBHcm91cFNvcnQgPSB7XG4gIHByaW9yaXR5OiBudW1iZXI7XG4gIGdyb3VwPzogc3RyaW5nO1xuICBncm91cFByaW9yaXR5PzogbnVtYmVyO1xufTtcblxuY29uc3QgZGVmYXVsdFByaW9yaXR5ID0gNTA7XG5cbmNvbnN0IERlZmF1bHRHcm91cFNvcnQ6IEdyb3VwU29ydCA9IHsgcHJpb3JpdHk6IGRlZmF1bHRQcmlvcml0eSB9O1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBEZWNvcmF0b3JPYmplY3QgdHlwZSBkZWZpbml0aW9uXG4gKiBAc3VtbWFyeSBEZWZpbmVzIHRoZSBzdHJ1Y3R1cmUgb2YgYW4gb2JqZWN0IHVzZWQgdG8gcmVwcmVzZW50IGEgZGVjb3JhdG9yIGluIHRoZSBjb250ZXh0IG9mIGRhdGFiYXNlIG9wZXJhdGlvbnMuXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBEZWNvcmF0b3JPYmplY3RcbiAqIEBwcm9wZXJ0eSB7T3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgYW55LCBhbnksIGFueT59IGhhbmRsZXIgLSBUaGUgaGFuZGxlciBmdW5jdGlvbiB0byBiZSBleGVjdXRlZCBkdXJpbmcgdGhlIG9wZXJhdGlvblxuICogQHByb3BlcnR5IHtvYmplY3R9IGRhdGEgLSBPcHRpb25hbCBtZXRhZGF0YSB0byBiZSBwYXNzZWQgdG8gdGhlIGhhbmRsZXIgZnVuY3Rpb25cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBwcm9wIC0gVGhlIHByb3BlcnR5IGtleSB0byB3aGljaCB0aGUgZGVjb3JhdG9yIGlzIGFwcGxpZWRcbiAqIEBjYXRlZ29yeSBUeXBlIERlZmluaXRpb25zXG4gKi9cbmV4cG9ydCB0eXBlIERlY29yYXRvck9iamVjdCA9IHtcbiAgaGFuZGxlcjogT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgYW55LCBhbnksIGFueT47XG4gIGRhdGE6IFJlY29yZDxzdHJpbmcsIGFueT5bXTtcbiAgcHJvcDogc3RyaW5nW107XG59O1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBJbnRlcm5hbCBmdW5jdGlvbiB0byByZWdpc3RlciBvcGVyYXRpb24gaGFuZGxlcnNcbiAqIEBzdW1tYXJ5IFJlZ2lzdGVycyBhbiBvcGVyYXRpb24gaGFuZGxlciBmb3IgYSBzcGVjaWZpYyBvcGVyYXRpb24ga2V5IG9uIGEgdGFyZ2V0IHByb3BlcnR5XG4gKiBAcGFyYW0ge09wZXJhdGlvbktleXN9IG9wIC0gVGhlIG9wZXJhdGlvbiBrZXkgdG8gaGFuZGxlXG4gKiBAcGFyYW0ge09wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIGFueSwgYW55LCBhbnk+fSBoYW5kbGVyIC0gVGhlIGhhbmRsZXIgZnVuY3Rpb24gdG8gcmVnaXN0ZXJcbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciB0aGF0IHJlZ2lzdGVycyB0aGUgaGFuZGxlclxuICogQGZ1bmN0aW9uIGhhbmRsZVxuICogQGNhdGVnb3J5IFByb3BlcnR5IERlY29yYXRvcnNcbiAqL1xuZnVuY3Rpb24gaGFuZGxlKFxuICBvcDogT3BlcmF0aW9uS2V5cyxcbiAgaGFuZGxlcjogT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgYW55LCBhbnksIGFueT5cbikge1xuICByZXR1cm4gKHRhcmdldDogYW55LCBwcm9wZXJ0eUtleTogc3RyaW5nKSA9PiB7XG4gICAgT3BlcmF0aW9ucy5yZWdpc3RlcihoYW5kbGVyLCBvcCwgdGFyZ2V0LCBwcm9wZXJ0eUtleSk7XG4gIH07XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFJldHJpZXZlcyBkZWNvcmF0b3Igb2JqZWN0cyBmb3IgaGFuZGxpbmcgZGF0YWJhc2Ugb3BlcmF0aW9uc1xuICogQHN1bW1hcnkgUmV0cmlldmVzIGEgbGlzdCBvZiBkZWNvcmF0b3Igb2JqZWN0cyByZXByZXNlbnRpbmcgb3BlcmF0aW9uIGhhbmRsZXJzIGZvciBhIGdpdmVuIG1vZGVsIGFuZCBkZWNvcmF0b3JzXG4gKiBAdGVtcGxhdGUgTSAtIFR5cGUgZm9yIHRoZSBtb2RlbCwgZGVmYXVsdHMgdG8gTW9kZWw8dHJ1ZSB8IGZhbHNlPlxuICogQHRlbXBsYXRlIFIgLSBUeXBlIGZvciB0aGUgcmVwb3NpdG9yeSwgZGVmYXVsdHMgdG8gSVJlcG9zaXRvcnk8TSwgRiwgQz5cbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBmb3IgbWV0YWRhdGEsIGRlZmF1bHRzIHRvIG9iamVjdFxuICogQHRlbXBsYXRlIEYgLSBUeXBlIGZvciByZXBvc2l0b3J5IGZsYWdzLCBkZWZhdWx0cyB0byBSZXBvc2l0b3J5RmxhZ3NcbiAqIEB0ZW1wbGF0ZSBDIC0gVHlwZSBmb3IgY29udGV4dCwgZGVmYXVsdHMgdG8gQ29udGV4dDxGPlxuICogQHBhcmFtIHtNb2RlbH0gbW9kZWwgLSBUaGUgbW9kZWwgZm9yIHdoaWNoIHRvIHJldHJpZXZlIGRlY29yYXRvciBvYmplY3RzXG4gKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIERlY29yYXRvck1ldGFkYXRhW10+fSBkZWNvcmF0b3JzIC0gVGhlIGRlY29yYXRvcnMgYXNzb2NpYXRlZCB3aXRoIHRoZSBtb2RlbCBwcm9wZXJ0aWVzXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gVGhlIG9wZXJhdGlvbiBwcmVmaXggKGUuZy4sICdvbicsICdhZnRlcicpXG4gKiBAcmV0dXJuIHtEZWNvcmF0b3JPYmplY3RbXX0gQW4gYXJyYXkgb2YgZGVjb3JhdG9yIG9iamVjdHMgcmVwcmVzZW50aW5nIG9wZXJhdGlvbiBoYW5kbGVyc1xuICogQGZ1bmN0aW9uIGdldEhhbmRsZXJzRGVjb3JhdG9yc1xuICogQGNhdGVnb3J5IEZ1bmN0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRIYW5kbGVyc0RlY29yYXRvcnM8XG4gIE0gZXh0ZW5kcyBNb2RlbDx0cnVlIHwgZmFsc2U+LFxuICBSIGV4dGVuZHMgSVJlcG9zaXRvcnk8TSwgRiwgQz4sXG4gIFYgZXh0ZW5kcyBvYmplY3QgPSBvYmplY3QsXG4gIEYgZXh0ZW5kcyBSZXBvc2l0b3J5RmxhZ3MgPSBSZXBvc2l0b3J5RmxhZ3MsXG4gIEMgZXh0ZW5kcyBDb250ZXh0PEY+ID0gQ29udGV4dDxGPixcbj4oXG4gIG1vZGVsOiBNb2RlbCxcbiAgZGVjb3JhdG9yczogUmVjb3JkPHN0cmluZywgRGVjb3JhdG9yTWV0YWRhdGFbXT4sXG4gIHByZWZpeDogc3RyaW5nXG4pOiBEZWNvcmF0b3JPYmplY3RbXSB7XG4gIGNvbnN0IGFjY3VtOiBEZWNvcmF0b3JPYmplY3RbXSA9IFtdO1xuICBmb3IgKGNvbnN0IHByb3AgaW4gZGVjb3JhdG9ycykge1xuICAgIGNvbnN0IGRlY3M6IERlY29yYXRvck1ldGFkYXRhW10gPSBkZWNvcmF0b3JzW3Byb3BdO1xuICAgIGZvciAoY29uc3QgZGVjIG9mIGRlY3MpIHtcbiAgICAgIGNvbnN0IHsga2V5IH0gPSBkZWMhO1xuICAgICAgY29uc3QgaGFuZGxlcnM6IE9wZXJhdGlvbkhhbmRsZXI8TSwgUiwgViwgRiwgQz5bXSB8IHVuZGVmaW5lZCA9XG4gICAgICAgIE9wZXJhdGlvbnMuZ2V0PE0sIFIsIFYsIEYsIEM+KG1vZGVsLCBwcm9wLCBwcmVmaXggKyBrZXkpO1xuICAgICAgaWYgKCFoYW5kbGVycyB8fCAhaGFuZGxlcnMubGVuZ3RoKVxuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICBgQ291bGQgbm90IGZpbmQgcmVnaXN0ZXJlZCBoYW5kbGVyIGZvciB0aGUgb3BlcmF0aW9uICR7cHJlZml4ICsga2V5fSB1bmRlciBwcm9wZXJ0eSAke3Byb3B9YFxuICAgICAgICApO1xuXG4gICAgICBjb25zdCBoYW5kbGVyQXJncyA9IGdldEhhbmRsZXJBcmdzKGRlYywgcHJvcCwgbW9kZWwgYXMgYW55KTtcblxuICAgICAgaWYgKCFoYW5kbGVyQXJncyB8fCBPYmplY3QudmFsdWVzKGhhbmRsZXJBcmdzKS5sZW5ndGggIT09IGhhbmRsZXJzLmxlbmd0aClcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJBcmdzIGFuZCBoYW5kbGVycyBsZW5ndGggZG8gbm90IG1hdGNoXCIpO1xuXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGhhbmRsZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSAoaGFuZGxlckFyZ3NbaGFuZGxlcnNbaV0ubmFtZV0gYXMgUmVjb3JkPHN0cmluZywgYW55PilcbiAgICAgICAgICAuZGF0YTtcbiAgICAgICAgYWNjdW0ucHVzaCh7XG4gICAgICAgICAgaGFuZGxlcjogaGFuZGxlcnNbaV0sXG4gICAgICAgICAgZGF0YTogW2RhdGFdLFxuICAgICAgICAgIHByb3A6IFtwcm9wXSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBhY2N1bTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gR3JvdXBzIGRlY29yYXRvcnMgYmFzZWQgb24gdGhlaXIgZ3JvdXAgcHJvcGVydHlcbiAqIEBzdW1tYXJ5IEdyb3VwcyBkZWNvcmF0b3Igb2JqZWN0cyBieSB0aGVpciBncm91cCBwcm9wZXJ0eSwgY29tYmluaW5nIGRhdGEgYW5kIHByb3BlcnRpZXMgd2l0aGluIGVhY2ggZ3JvdXBcbiAqIEBwYXJhbSB7RGVjb3JhdG9yT2JqZWN0W119IGRlY29yYXRvcnMgLSBUaGUgYXJyYXkgb2YgZGVjb3JhdG9yIG9iamVjdHMgdG8gZ3JvdXBcbiAqIEByZXR1cm4ge0RlY29yYXRvck9iamVjdFtdfSBBbiBhcnJheSBvZiBncm91cGVkIGRlY29yYXRvciBvYmplY3RzXG4gKiBAZnVuY3Rpb24gZ3JvdXBEZWNvcmF0b3JzXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdyb3VwRGVjb3JhdG9ycyhcbiAgZGVjb3JhdG9yczogRGVjb3JhdG9yT2JqZWN0W11cbik6IERlY29yYXRvck9iamVjdFtdIHtcbiAgY29uc3QgZ3JvdXBlZCA9IGRlY29yYXRvcnMucmVkdWNlPE1hcDxzdHJpbmcgfCBzeW1ib2wsIERlY29yYXRvck9iamVjdD4+KFxuICAgIChhY2MsIGRlYykgPT4ge1xuICAgICAgaWYgKCFkZWMgfHwgIWRlYy5kYXRhIHx8ICFkZWMucHJvcClcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJNaXNzaW5nIGRlY29yYXRvciBwcm9wZXJ0aWVzIG9yIGRhdGFcIik7XG5cbiAgICAgIC8vIElmIGRlY29yYXRvciBoYXZlIG5vIGdyb3VwXG4gICAgICBpZiAoIWRlYy5kYXRhWzBdLmdyb3VwKSB7XG4gICAgICAgIGFjYy5zZXQoU3ltYm9sKCksIGRlYyk7XG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGdyb3VwS2V5ID0gZGVjLmRhdGFbMF0uZ3JvdXA7XG5cbiAgICAgIGlmICghYWNjLmhhcyhncm91cEtleSkpIHtcbiAgICAgICAgLy8gZmlyc3QgaGFuZGxlciBpcyBzYXZlZCBpbiB0aGUgZ3JvdXBcbiAgICAgICAgYWNjLnNldChncm91cEtleSwgeyAuLi5kZWMgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBleGlzdGluZyA9IGFjYy5nZXQoZ3JvdXBLZXkpITtcblxuICAgICAgICBhY2Muc2V0KGdyb3VwS2V5LCB7XG4gICAgICAgICAgaGFuZGxlcjogZXhpc3RpbmcuaGFuZGxlcixcbiAgICAgICAgICBkYXRhOiBbLi4uZXhpc3RpbmcuZGF0YSwgLi4uZGVjLmRhdGFdLFxuICAgICAgICAgIHByb3A6IFsuLi5leGlzdGluZy5wcm9wLCAuLi5kZWMucHJvcF0sXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sXG4gICAgbmV3IE1hcCgpXG4gICk7XG5cbiAgY29uc3QgZ3JvdXBzID0gQXJyYXkuZnJvbShncm91cGVkLnZhbHVlcygpKTtcblxuICAvLyBTb3J0IGluc2lkZSBlYWNoIGdyb3VwIGJ5IHByaW9yaXR5XG4gIGdyb3Vwcy5mb3JFYWNoKChncm91cCkgPT4ge1xuICAgIGNvbnN0IGNvbWJpbmVkID0gZ3JvdXAuZGF0YS5tYXAoKGQsIGkpID0+ICh7XG4gICAgICBkYXRhOiBkLFxuICAgICAgcHJvcDogZ3JvdXAucHJvcFtpXSxcbiAgICB9KSk7XG5cbiAgICBjb21iaW5lZC5zb3J0KFxuICAgICAgKGEsIGIpID0+IChhLmRhdGEuZ3JvdXBQcmlvcml0eSA/PyA1MCkgLSAoYi5kYXRhLmdyb3VwUHJpb3JpdHkgPz8gNTApXG4gICAgKTtcblxuICAgIGdyb3VwLmRhdGEgPSBjb21iaW5lZC5tYXAoKGMpID0+IGMuZGF0YSk7XG4gICAgZ3JvdXAucHJvcCA9IGNvbWJpbmVkLm1hcCgoYykgPT4gYy5wcm9wKTtcbiAgfSk7XG5cbiAgcmV0dXJuIGdyb3Vwcztcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU29ydHMgZGVjb3JhdG9yIG9iamVjdHMgYmFzZWQgb24gdGhlaXIgcHJpb3JpdHlcbiAqIEBzdW1tYXJ5IFNvcnRzIGFuIGFycmF5IG9mIGRlY29yYXRvciBvYmplY3RzIGJ5IHRoZSBwcmlvcml0eSBvZiB0aGVpciBmaXJzdCBkYXRhIGVsZW1lbnRcbiAqIEBwYXJhbSB7RGVjb3JhdG9yT2JqZWN0W119IGRlY29yYXRvcnMgLSBUaGUgYXJyYXkgb2YgZGVjb3JhdG9yIG9iamVjdHMgdG8gc29ydFxuICogQHJldHVybiB7RGVjb3JhdG9yT2JqZWN0W119IFRoZSBzb3J0ZWQgYXJyYXkgb2YgZGVjb3JhdG9yIG9iamVjdHNcbiAqIEBmdW5jdGlvbiBzb3J0RGVjb3JhdG9yc1xuICogQGNhdGVnb3J5IEZ1bmN0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzb3J0RGVjb3JhdG9ycyhcbiAgZGVjb3JhdG9yczogRGVjb3JhdG9yT2JqZWN0W11cbik6IERlY29yYXRvck9iamVjdFtdIHtcbiAgLy8gU29ydCBieSBncm91cFByaW9yaXR5XG4gIGRlY29yYXRvcnMuc29ydCgoYSwgYikgPT4ge1xuICAgIGNvbnN0IHByaW9yaXR5QSA9IGEuZGF0YVswXS5wcmlvcml0eSA/PyBkZWZhdWx0UHJpb3JpdHk7XG4gICAgY29uc3QgcHJpb3JpdHlCID0gYi5kYXRhWzBdLnByaW9yaXR5ID8/IGRlZmF1bHRQcmlvcml0eTtcbiAgICByZXR1cm4gcHJpb3JpdHlBIC0gcHJpb3JpdHlCOyAvLyBsb3dlciBudW1iZXIgPSBoaWdoZXIgcHJpb3JpdHlcbiAgfSk7XG5cbiAgcmV0dXJuIGRlY29yYXRvcnM7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERlY29yYXRvciBmb3IgaGFuZGxpbmcgY3JlYXRlIGFuZCB1cGRhdGUgb3BlcmF0aW9uc1xuICogQHN1bW1hcnkgRGVmaW5lcyBhIGJlaGF2aW9yIHRvIGV4ZWN1dGUgZHVyaW5nIGJvdGggY3JlYXRlIGFuZCB1cGRhdGUgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIFYgLSBUeXBlIGZvciBtZXRhZGF0YSwgZGVmYXVsdHMgdG8gb2JqZWN0XG4gKiBAcGFyYW0ge0dlbmVyYWxPcGVyYXRpb25IYW5kbGVyPGFueSwgYW55LCBWLCBhbnksIGFueT4gfCBHZW5lcmFsVXBkYXRlT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+fSBoYW5kbGVyIC0gVGhlIG1ldGhvZCBjYWxsZWQgdXBvbiB0aGUgb3BlcmF0aW9uXG4gKiBAcGFyYW0ge1Z9IFtkYXRhXSAtIE9wdGlvbmFsIG1ldGFkYXRhIHRvIHBhc3MgdG8gdGhlIGhhbmRsZXJcbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGNsYXNzIHByb3BlcnRpZXNcbiAqIEBmdW5jdGlvbiBvbkNyZWF0ZVVwZGF0ZVxuICogQGNhdGVnb3J5IFByb3BlcnR5IERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG9uQ3JlYXRlVXBkYXRlPFYgPSBvYmplY3Q+KFxuICBoYW5kbGVyOlxuICAgIHwgR2VuZXJhbE9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55PlxuICAgIHwgR2VuZXJhbFVwZGF0ZU9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55PixcbiAgZGF0YT86IFYsXG4gIGdyb3Vwc29ydD86IEdyb3VwU29ydFxuKSB7XG4gIHJldHVybiBvbihEQk9wZXJhdGlvbnMuQ1JFQVRFX1VQREFURSwgaGFuZGxlciwgZGF0YSwgZ3JvdXBzb3J0KTtcbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIERlY29yYXRvciBmb3IgaGFuZGxpbmcgdXBkYXRlIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IERlZmluZXMgYSBiZWhhdmlvciB0byBleGVjdXRlIGR1cmluZyB1cGRhdGUgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIFYgLSBUeXBlIGZvciBtZXRhZGF0YSwgZGVmYXVsdHMgdG8gb2JqZWN0XG4gKiBAcGFyYW0ge1VwZGF0ZU9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueT59IGhhbmRsZXIgLSBUaGUgbWV0aG9kIGNhbGxlZCB1cG9uIHRoZSBvcGVyYXRpb25cbiAqIEBwYXJhbSB7Vn0gW2RhdGFdIC0gT3B0aW9uYWwgbWV0YWRhdGEgdG8gcGFzcyB0byB0aGUgaGFuZGxlclxuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgZGVjb3JhdG9yIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gY2xhc3MgcHJvcGVydGllc1xuICogQGZ1bmN0aW9uIG9uVXBkYXRlXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gb25VcGRhdGU8ViA9IG9iamVjdD4oXG4gIGhhbmRsZXI6IFVwZGF0ZU9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueT4sXG4gIGRhdGE/OiBWLFxuICBncm91cHNvcnQ/OiBHcm91cFNvcnRcbikge1xuICByZXR1cm4gb24oREJPcGVyYXRpb25zLlVQREFURSwgaGFuZGxlciwgZGF0YSwgZ3JvdXBzb3J0KTtcbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIERlY29yYXRvciBmb3IgaGFuZGxpbmcgY3JlYXRlIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IERlZmluZXMgYSBiZWhhdmlvciB0byBleGVjdXRlIGR1cmluZyBjcmVhdGUgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIFYgLSBUeXBlIGZvciBtZXRhZGF0YSwgZGVmYXVsdHMgdG8gb2JqZWN0XG4gKiBAcGFyYW0ge0dlbmVyYWxPcGVyYXRpb25IYW5kbGVyPGFueSwgYW55LCBWLCBhbnksIGFueT59IGhhbmRsZXIgLSBUaGUgbWV0aG9kIGNhbGxlZCB1cG9uIHRoZSBvcGVyYXRpb25cbiAqIEBwYXJhbSB7Vn0gW2RhdGFdIC0gT3B0aW9uYWwgbWV0YWRhdGEgdG8gcGFzcyB0byB0aGUgaGFuZGxlclxuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgZGVjb3JhdG9yIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gY2xhc3MgcHJvcGVydGllc1xuICogQGZ1bmN0aW9uIG9uQ3JlYXRlXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gb25DcmVhdGU8ViA9IG9iamVjdD4oXG4gIGhhbmRsZXI6IEdlbmVyYWxPcGVyYXRpb25IYW5kbGVyPGFueSwgYW55LCBWLCBhbnksIGFueT4sXG4gIGRhdGE/OiBWLFxuICBncm91cHNvcnQ/OiBHcm91cFNvcnRcbikge1xuICByZXR1cm4gb24oREJPcGVyYXRpb25zLkNSRUFURSwgaGFuZGxlciwgZGF0YSwgZ3JvdXBzb3J0KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVjb3JhdG9yIGZvciBoYW5kbGluZyByZWFkIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IERlZmluZXMgYSBiZWhhdmlvciB0byBleGVjdXRlIGR1cmluZyByZWFkIG9wZXJhdGlvbnNcbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBmb3IgbWV0YWRhdGEsIGRlZmF1bHRzIHRvIG9iamVjdFxuICogQHBhcmFtIHtJZE9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55Pn0gaGFuZGxlciAtIFRoZSBtZXRob2QgY2FsbGVkIHVwb24gdGhlIG9wZXJhdGlvblxuICogQHBhcmFtIHtWfSBbZGF0YV0gLSBPcHRpb25hbCBtZXRhZGF0YSB0byBwYXNzIHRvIHRoZSBoYW5kbGVyXG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gb25SZWFkXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gb25SZWFkPFYgPSBvYmplY3Q+KFxuICBoYW5kbGVyOiBJZE9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55PixcbiAgZGF0YTogVixcbiAgZ3JvdXBzb3J0PzogR3JvdXBTb3J0XG4pIHtcbiAgcmV0dXJuIG9uKERCT3BlcmF0aW9ucy5SRUFELCBoYW5kbGVyLCBkYXRhLCBncm91cHNvcnQpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBEZWNvcmF0b3IgZm9yIGhhbmRsaW5nIGRlbGV0ZSBvcGVyYXRpb25zXG4gKiBAc3VtbWFyeSBEZWZpbmVzIGEgYmVoYXZpb3IgdG8gZXhlY3V0ZSBkdXJpbmcgZGVsZXRlIG9wZXJhdGlvbnNcbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBmb3IgbWV0YWRhdGEsIGRlZmF1bHRzIHRvIG9iamVjdFxuICogQHBhcmFtIHtPcGVyYXRpb25IYW5kbGVyPGFueSwgYW55LCBWLCBhbnksIGFueT59IGhhbmRsZXIgLSBUaGUgbWV0aG9kIGNhbGxlZCB1cG9uIHRoZSBvcGVyYXRpb25cbiAqIEBwYXJhbSB7Vn0gW2RhdGFdIC0gT3B0aW9uYWwgbWV0YWRhdGEgdG8gcGFzcyB0byB0aGUgaGFuZGxlclxuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgZGVjb3JhdG9yIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gY2xhc3MgcHJvcGVydGllc1xuICogQGZ1bmN0aW9uIG9uRGVsZXRlXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gb25EZWxldGU8ViA9IG9iamVjdD4oXG4gIGhhbmRsZXI6IE9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55PixcbiAgZGF0YTogVixcbiAgZ3JvdXBzb3J0PzogR3JvdXBTb3J0XG4pIHtcbiAgcmV0dXJuIG9uKERCT3BlcmF0aW9ucy5ERUxFVEUsIGhhbmRsZXIsIGRhdGEsIGdyb3Vwc29ydCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERlY29yYXRvciBmb3IgaGFuZGxpbmcgYWxsIG9wZXJhdGlvbiB0eXBlc1xuICogQHN1bW1hcnkgRGVmaW5lcyBhIGJlaGF2aW9yIHRvIGV4ZWN1dGUgZHVyaW5nIGFueSBkYXRhYmFzZSBvcGVyYXRpb25cbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBmb3IgbWV0YWRhdGEsIGRlZmF1bHRzIHRvIG9iamVjdFxuICogQHBhcmFtIHtPcGVyYXRpb25IYW5kbGVyPGFueSwgYW55LCBWLCBhbnksIGFueT59IGhhbmRsZXIgLSBUaGUgbWV0aG9kIGNhbGxlZCB1cG9uIHRoZSBvcGVyYXRpb25cbiAqIEBwYXJhbSB7Vn0gW2RhdGFdIC0gT3B0aW9uYWwgbWV0YWRhdGEgdG8gcGFzcyB0byB0aGUgaGFuZGxlclxuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgZGVjb3JhdG9yIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gY2xhc3MgcHJvcGVydGllc1xuICogQGZ1bmN0aW9uIG9uQW55XG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gb25Bbnk8ViA9IG9iamVjdD4oXG4gIGhhbmRsZXI6IE9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55PixcbiAgZGF0YTogVixcbiAgZ3JvdXBzb3J0PzogR3JvdXBTb3J0XG4pIHtcbiAgcmV0dXJuIG9uKERCT3BlcmF0aW9ucy5BTEwsIGhhbmRsZXIsIGRhdGEsIGdyb3Vwc29ydCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEJhc2UgZGVjb3JhdG9yIGZvciBoYW5kbGluZyBkYXRhYmFzZSBvcGVyYXRpb25zXG4gKiBAc3VtbWFyeSBEZWZpbmVzIGEgYmVoYXZpb3IgdG8gZXhlY3V0ZSBkdXJpbmcgc3BlY2lmaWVkIGRhdGFiYXNlIG9wZXJhdGlvbnNcbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBmb3IgbWV0YWRhdGEsIGRlZmF1bHRzIHRvIG9iamVjdFxuICogQHBhcmFtIHtPcGVyYXRpb25LZXlzW10gfCBEQk9wZXJhdGlvbnN9IFtvcD1EQk9wZXJhdGlvbnMuQUxMXSAtIE9uZSBvciBtb3JlIG9wZXJhdGlvbiB0eXBlcyB0byBoYW5kbGVcbiAqIEBwYXJhbSB7T3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+fSBoYW5kbGVyIC0gVGhlIG1ldGhvZCBjYWxsZWQgdXBvbiB0aGUgb3BlcmF0aW9uXG4gKiBAcGFyYW0ge1Z9IFtkYXRhXSAtIE9wdGlvbmFsIG1ldGFkYXRhIHRvIHBhc3MgdG8gdGhlIGhhbmRsZXJcbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGNsYXNzIHByb3BlcnRpZXNcbiAqIEBmdW5jdGlvbiBvblxuICogQGNhdGVnb3J5IFByb3BlcnR5IERlY29yYXRvcnNcbiAqIEBleGFtcGxlXG4gKiAvLyBFeGFtcGxlIHVzYWdlOlxuICogY2xhc3MgTXlNb2RlbCB7XG4gKiAgIEBvbihEQk9wZXJhdGlvbnMuQ1JFQVRFLCBteUhhbmRsZXIpXG4gKiAgIG15UHJvcGVydHk6IHN0cmluZztcbiAqIH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG9uPFYgPSBvYmplY3Q+KFxuICBvcDogT3BlcmF0aW9uS2V5c1tdID0gREJPcGVyYXRpb25zLkFMTCxcbiAgaGFuZGxlcjogT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+LFxuICBkYXRhPzogVixcbiAgZ3JvdXBzb3J0PzogR3JvdXBTb3J0XG4pIHtcbiAgcmV0dXJuIG9wZXJhdGlvbihPcGVyYXRpb25LZXlzLk9OLCBvcCwgaGFuZGxlciwgZGF0YSwgZ3JvdXBzb3J0KTtcbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIERlY29yYXRvciBmb3IgaGFuZGxpbmcgcG9zdC1jcmVhdGUgYW5kIHBvc3QtdXBkYXRlIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IERlZmluZXMgYSBiZWhhdmlvciB0byBleGVjdXRlIGFmdGVyIGJvdGggY3JlYXRlIGFuZCB1cGRhdGUgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIFYgLSBUeXBlIGZvciBtZXRhZGF0YSwgZGVmYXVsdHMgdG8gb2JqZWN0XG4gKiBAcGFyYW0ge1N0YW5kYXJkT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+IHwgVXBkYXRlT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+fSBoYW5kbGVyIC0gVGhlIG1ldGhvZCBjYWxsZWQgYWZ0ZXIgdGhlIG9wZXJhdGlvblxuICogQHBhcmFtIHtWfSBbZGF0YV0gLSBPcHRpb25hbCBtZXRhZGF0YSB0byBwYXNzIHRvIHRoZSBoYW5kbGVyXG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gYWZ0ZXJDcmVhdGVVcGRhdGVcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eSBEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZnRlckNyZWF0ZVVwZGF0ZTxWID0gb2JqZWN0PihcbiAgaGFuZGxlcjpcbiAgICB8IFN0YW5kYXJkT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+XG4gICAgfCBVcGRhdGVPcGVyYXRpb25IYW5kbGVyPGFueSwgYW55LCBWLCBhbnksIGFueT4sXG4gIGRhdGE6IFYsXG4gIGdyb3Vwc29ydD86IEdyb3VwU29ydFxuKSB7XG4gIHJldHVybiBhZnRlcihEQk9wZXJhdGlvbnMuQ1JFQVRFX1VQREFURSwgaGFuZGxlciwgZGF0YSwgZ3JvdXBzb3J0KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVjb3JhdG9yIGZvciBoYW5kbGluZyBwb3N0LXVwZGF0ZSBvcGVyYXRpb25zXG4gKiBAc3VtbWFyeSBEZWZpbmVzIGEgYmVoYXZpb3IgdG8gZXhlY3V0ZSBhZnRlciB1cGRhdGUgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIFYgLSBUeXBlIGZvciBtZXRhZGF0YSwgZGVmYXVsdHMgdG8gb2JqZWN0XG4gKiBAcGFyYW0ge1VwZGF0ZU9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55Pn0gaGFuZGxlciAtIFRoZSBtZXRob2QgY2FsbGVkIGFmdGVyIHRoZSBvcGVyYXRpb25cbiAqIEBwYXJhbSB7Vn0gW2RhdGFdIC0gT3B0aW9uYWwgbWV0YWRhdGEgdG8gcGFzcyB0byB0aGUgaGFuZGxlclxuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgZGVjb3JhdG9yIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gY2xhc3MgcHJvcGVydGllc1xuICogQGZ1bmN0aW9uIGFmdGVyVXBkYXRlXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gYWZ0ZXJVcGRhdGU8ViA9IG9iamVjdD4oXG4gIGhhbmRsZXI6IFVwZGF0ZU9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55PixcbiAgZGF0YTogVixcbiAgZ3JvdXBzb3J0PzogR3JvdXBTb3J0XG4pIHtcbiAgcmV0dXJuIGFmdGVyKERCT3BlcmF0aW9ucy5VUERBVEUsIGhhbmRsZXIsIGRhdGEsIGdyb3Vwc29ydCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERlY29yYXRvciBmb3IgaGFuZGxpbmcgcG9zdC1jcmVhdGUgb3BlcmF0aW9uc1xuICogQHN1bW1hcnkgRGVmaW5lcyBhIGJlaGF2aW9yIHRvIGV4ZWN1dGUgYWZ0ZXIgY3JlYXRlIG9wZXJhdGlvbnNcbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBmb3IgbWV0YWRhdGEsIGRlZmF1bHRzIHRvIG9iamVjdFxuICogQHBhcmFtIHtTdGFuZGFyZE9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55Pn0gaGFuZGxlciAtIFRoZSBtZXRob2QgY2FsbGVkIGFmdGVyIHRoZSBvcGVyYXRpb25cbiAqIEBwYXJhbSB7Vn0gW2RhdGFdIC0gT3B0aW9uYWwgbWV0YWRhdGEgdG8gcGFzcyB0byB0aGUgaGFuZGxlclxuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgZGVjb3JhdG9yIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gY2xhc3MgcHJvcGVydGllc1xuICogQGZ1bmN0aW9uIGFmdGVyQ3JlYXRlXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gYWZ0ZXJDcmVhdGU8ViA9IG9iamVjdD4oXG4gIGhhbmRsZXI6IFN0YW5kYXJkT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+LFxuICBkYXRhOiBWLFxuICBncm91cHNvcnQ/OiBHcm91cFNvcnRcbikge1xuICByZXR1cm4gYWZ0ZXIoREJPcGVyYXRpb25zLkNSRUFURSwgaGFuZGxlciwgZGF0YSwgZ3JvdXBzb3J0KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVjb3JhdG9yIGZvciBoYW5kbGluZyBwb3N0LXJlYWQgb3BlcmF0aW9uc1xuICogQHN1bW1hcnkgRGVmaW5lcyBhIGJlaGF2aW9yIHRvIGV4ZWN1dGUgYWZ0ZXIgcmVhZCBvcGVyYXRpb25zXG4gKiBAdGVtcGxhdGUgViAtIFR5cGUgZm9yIG1ldGFkYXRhLCBkZWZhdWx0cyB0byBvYmplY3RcbiAqIEBwYXJhbSB7U3RhbmRhcmRPcGVyYXRpb25IYW5kbGVyPGFueSwgYW55LCBWLCBhbnksIGFueT59IGhhbmRsZXIgLSBUaGUgbWV0aG9kIGNhbGxlZCBhZnRlciB0aGUgb3BlcmF0aW9uXG4gKiBAcGFyYW0ge1Z9IFtkYXRhXSAtIE9wdGlvbmFsIG1ldGFkYXRhIHRvIHBhc3MgdG8gdGhlIGhhbmRsZXJcbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGNsYXNzIHByb3BlcnRpZXNcbiAqIEBmdW5jdGlvbiBhZnRlclJlYWRcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eSBEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZnRlclJlYWQ8ViA9IG9iamVjdD4oXG4gIGhhbmRsZXI6IFN0YW5kYXJkT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+LFxuICBkYXRhPzogVixcbiAgZ3JvdXBzb3J0PzogR3JvdXBTb3J0XG4pIHtcbiAgcmV0dXJuIGFmdGVyKERCT3BlcmF0aW9ucy5SRUFELCBoYW5kbGVyLCBkYXRhLCBncm91cHNvcnQpO1xufVxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVjb3JhdG9yIGZvciBoYW5kbGluZyBwb3N0LWRlbGV0ZSBvcGVyYXRpb25zXG4gKiBAc3VtbWFyeSBEZWZpbmVzIGEgYmVoYXZpb3IgdG8gZXhlY3V0ZSBhZnRlciBkZWxldGUgb3BlcmF0aW9uc1xuICogQHRlbXBsYXRlIFYgLSBUeXBlIGZvciBtZXRhZGF0YSwgZGVmYXVsdHMgdG8gb2JqZWN0XG4gKiBAcGFyYW0ge1N0YW5kYXJkT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+fSBoYW5kbGVyIC0gVGhlIG1ldGhvZCBjYWxsZWQgYWZ0ZXIgdGhlIG9wZXJhdGlvblxuICogQHBhcmFtIHtWfSBbZGF0YV0gLSBPcHRpb25hbCBtZXRhZGF0YSB0byBwYXNzIHRvIHRoZSBoYW5kbGVyXG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gYWZ0ZXJEZWxldGVcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eSBEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZnRlckRlbGV0ZTxWID0gb2JqZWN0PihcbiAgaGFuZGxlcjogU3RhbmRhcmRPcGVyYXRpb25IYW5kbGVyPGFueSwgYW55LCBWLCBhbnksIGFueT4sXG4gIGRhdGE/OiBWLFxuICBncm91cHNvcnQ/OiBHcm91cFNvcnRcbikge1xuICByZXR1cm4gYWZ0ZXIoREJPcGVyYXRpb25zLkRFTEVURSwgaGFuZGxlciwgZGF0YSwgZ3JvdXBzb3J0KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVjb3JhdG9yIGZvciBoYW5kbGluZyBwb3N0LW9wZXJhdGlvbiBmb3IgYWxsIG9wZXJhdGlvbiB0eXBlc1xuICogQHN1bW1hcnkgRGVmaW5lcyBhIGJlaGF2aW9yIHRvIGV4ZWN1dGUgYWZ0ZXIgYW55IGRhdGFiYXNlIG9wZXJhdGlvblxuICogQHRlbXBsYXRlIFYgLSBUeXBlIGZvciBtZXRhZGF0YSwgZGVmYXVsdHMgdG8gb2JqZWN0XG4gKiBAcGFyYW0ge1N0YW5kYXJkT3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+fSBoYW5kbGVyIC0gVGhlIG1ldGhvZCBjYWxsZWQgYWZ0ZXIgdGhlIG9wZXJhdGlvblxuICogQHBhcmFtIHtWfSBbZGF0YV0gLSBPcHRpb25hbCBtZXRhZGF0YSB0byBwYXNzIHRvIHRoZSBoYW5kbGVyXG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gYWZ0ZXJBbnlcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eSBEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZnRlckFueTxWID0gb2JqZWN0PihcbiAgaGFuZGxlcjogU3RhbmRhcmRPcGVyYXRpb25IYW5kbGVyPGFueSwgYW55LCBWLCBhbnksIGFueT4sXG4gIGRhdGE/OiBWLFxuICBncm91cHNvcnQ/OiBHcm91cFNvcnRcbikge1xuICByZXR1cm4gYWZ0ZXIoREJPcGVyYXRpb25zLkFMTCwgaGFuZGxlciwgZGF0YSwgZ3JvdXBzb3J0KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQmFzZSBkZWNvcmF0b3IgZm9yIGhhbmRsaW5nIHBvc3Qtb3BlcmF0aW9uIGJlaGF2aW9yc1xuICogQHN1bW1hcnkgRGVmaW5lcyBhIGJlaGF2aW9yIHRvIGV4ZWN1dGUgYWZ0ZXIgc3BlY2lmaWVkIGRhdGFiYXNlIG9wZXJhdGlvbnNcbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBmb3IgbWV0YWRhdGEsIGRlZmF1bHRzIHRvIG9iamVjdFxuICogQHBhcmFtIHtPcGVyYXRpb25LZXlzW10gfCBEQk9wZXJhdGlvbnN9IFtvcD1EQk9wZXJhdGlvbnMuQUxMXSAtIE9uZSBvciBtb3JlIG9wZXJhdGlvbiB0eXBlcyB0byBoYW5kbGVcbiAqIEBwYXJhbSB7T3BlcmF0aW9uSGFuZGxlcjxhbnksIGFueSwgViwgYW55LCBhbnk+fSBoYW5kbGVyIC0gVGhlIG1ldGhvZCBjYWxsZWQgYWZ0ZXIgdGhlIG9wZXJhdGlvblxuICogQHBhcmFtIHtWfSBbZGF0YV0gLSBPcHRpb25hbCBtZXRhZGF0YSB0byBwYXNzIHRvIHRoZSBoYW5kbGVyXG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gYWZ0ZXJcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eSBEZWNvcmF0b3JzXG4gKiBAZXhhbXBsZVxuICogLy8gRXhhbXBsZSB1c2FnZTpcbiAqIGNsYXNzIE15TW9kZWwge1xuICogICBAYWZ0ZXIoREJPcGVyYXRpb25zLkNSRUFURSwgbXlIYW5kbGVyKVxuICogICBteVByb3BlcnR5OiBzdHJpbmc7XG4gKiB9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZnRlcjxWID0gb2JqZWN0PihcbiAgb3A6IE9wZXJhdGlvbktleXNbXSA9IERCT3BlcmF0aW9ucy5BTEwsXG4gIGhhbmRsZXI6IE9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55PixcbiAgZGF0YT86IFYsXG4gIGdyb3Vwc29ydD86IEdyb3VwU29ydFxuKSB7XG4gIHJldHVybiBvcGVyYXRpb24oT3BlcmF0aW9uS2V5cy5BRlRFUiwgb3AsIGhhbmRsZXIsIGRhdGEsIGdyb3Vwc29ydCk7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvcmUgZGVjb3JhdG9yIGZhY3RvcnkgZm9yIG9wZXJhdGlvbiBoYW5kbGVyc1xuICogQHN1bW1hcnkgQ3JlYXRlcyBkZWNvcmF0b3JzIHRoYXQgcmVnaXN0ZXIgaGFuZGxlcnMgZm9yIGRhdGFiYXNlIG9wZXJhdGlvbnNcbiAqIEB0ZW1wbGF0ZSBWIC0gVHlwZSBmb3IgbWV0YWRhdGEsIGRlZmF1bHRzIHRvIG9iamVjdFxuICogQHBhcmFtIHtPcGVyYXRpb25LZXlzLk9OIHwgT3BlcmF0aW9uS2V5cy5BRlRFUn0gYmFzZU9wIC0gV2hldGhlciB0aGUgaGFuZGxlciBydW5zIGR1cmluZyBvciBhZnRlciB0aGUgb3BlcmF0aW9uXG4gKiBAcGFyYW0ge09wZXJhdGlvbktleXNbXX0gW29wZXJhdGlvbj1EQk9wZXJhdGlvbnMuQUxMXSAtIFRoZSBzcGVjaWZpYyBvcGVyYXRpb25zIHRvIGhhbmRsZVxuICogQHBhcmFtIHtPcGVyYXRpb25IYW5kbGVyPGFueSwgYW55LCBWLCBhbnksIGFueT59IGhhbmRsZXIgLSBUaGUgaGFuZGxlciBmdW5jdGlvbiB0byBleGVjdXRlXG4gKiBAcGFyYW0ge1Z9IFtkYXRhVG9BZGRdIC0gT3B0aW9uYWwgbWV0YWRhdGEgdG8gcGFzcyB0byB0aGUgaGFuZGxlclxuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgZGVjb3JhdG9yIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gY2xhc3MgcHJvcGVydGllc1xuICogQGZ1bmN0aW9uIG9wZXJhdGlvblxuICogQGNhdGVnb3J5IFByb3BlcnR5IERlY29yYXRvcnNcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2xpZW50XG4gKiAgIHBhcnRpY2lwYW50IERlY29yYXRvciBhcyBAb3BlcmF0aW9uXG4gKiAgIHBhcnRpY2lwYW50IE9wZXJhdGlvbnMgYXMgT3BlcmF0aW9ucyBSZWdpc3RyeVxuICogICBwYXJ0aWNpcGFudCBIYW5kbGVyXG4gKlxuICogICBDbGllbnQtPj5EZWNvcmF0b3I6IEFwcGx5IHRvIHByb3BlcnR5XG4gKiAgIERlY29yYXRvci0+Pk9wZXJhdGlvbnM6IFJlZ2lzdGVyIGhhbmRsZXJcbiAqICAgRGVjb3JhdG9yLT4+RGVjb3JhdG9yOiBTdG9yZSBtZXRhZGF0YVxuICpcbiAqICAgTm90ZSBvdmVyIENsaWVudCxIYW5kbGVyOiBMYXRlciwgZHVyaW5nIG9wZXJhdGlvbiBleGVjdXRpb25cbiAqICAgQ2xpZW50LT4+T3BlcmF0aW9uczogRXhlY3V0ZSBvcGVyYXRpb25cbiAqICAgT3BlcmF0aW9ucy0+PkhhbmRsZXI6IENhbGwgcmVnaXN0ZXJlZCBoYW5kbGVyXG4gKiAgIEhhbmRsZXItLT4+T3BlcmF0aW9uczogUmV0dXJuIHJlc3VsdFxuICogICBPcGVyYXRpb25zLS0+PkNsaWVudDogUmV0dXJuIGZpbmFsIHJlc3VsdFxuICovXG5leHBvcnQgZnVuY3Rpb24gb3BlcmF0aW9uPFYgPSBvYmplY3Q+KFxuICBiYXNlT3A6IE9wZXJhdGlvbktleXMuT04gfCBPcGVyYXRpb25LZXlzLkFGVEVSLFxuICBvcGVyYXRpb246IE9wZXJhdGlvbktleXNbXSA9IERCT3BlcmF0aW9ucy5BTEwsXG4gIGhhbmRsZXI6IE9wZXJhdGlvbkhhbmRsZXI8YW55LCBhbnksIFYsIGFueSwgYW55PixcbiAgZGF0YVRvQWRkPzogVixcbiAgZ3JvdXBzb3J0OiBHcm91cFNvcnQgPSBEZWZhdWx0R3JvdXBTb3J0XG4pIHtcbiAgcmV0dXJuICh0YXJnZXQ6IGFueSwgcHJvcGVydHlLZXk/OiBhbnkpID0+IHtcbiAgICBjb25zdCBuYW1lID0gdGFyZ2V0LmNvbnN0cnVjdG9yLm5hbWU7XG4gICAgY29uc3QgZGVjb3JhdG9ycyA9IG9wZXJhdGlvbi5yZWR1Y2UoKGFjY3VtOiBhbnlbXSwgb3ApID0+IHtcbiAgICAgIGNvbnN0IGNvbXBvdW5kS2V5ID0gYmFzZU9wICsgb3A7XG4gICAgICBsZXQgZGF0YSA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEoXG4gICAgICAgIE9wZXJhdGlvbnMua2V5KGNvbXBvdW5kS2V5KSxcbiAgICAgICAgdGFyZ2V0LFxuICAgICAgICBwcm9wZXJ0eUtleVxuICAgICAgKTtcbiAgICAgIGlmICghZGF0YSlcbiAgICAgICAgZGF0YSA9IHtcbiAgICAgICAgICBvcGVyYXRpb246IG9wLFxuICAgICAgICAgIGhhbmRsZXJzOiB7fSxcbiAgICAgICAgfTtcblxuICAgICAgY29uc3QgaGFuZGxlcktleSA9IE9wZXJhdGlvbnMuZ2V0SGFuZGxlck5hbWUoaGFuZGxlcik7XG5cbiAgICAgIGxldCBtZXJnZURhdGEgPSBncm91cHNvcnQ7XG5cbiAgICAgIGlmIChkYXRhVG9BZGQpIHtcbiAgICAgICAgaWYgKE9iamVjdC5rZXlzKGRhdGFUb0FkZCkuZmlsdGVyKChrZXkpID0+IGtleSBpbiBncm91cHNvcnQpLmxlbmd0aCA+IDApXG4gICAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgICAgICBgVW5hYmxlIHRvIG1lcmdlIGdyb3VwU29ydCBpbnRvIGRhdGFUb0FkZCBkdWUgdG8gb3ZlcmxhcGluZyBrZXlzYFxuICAgICAgICAgICk7XG5cbiAgICAgICAgbWVyZ2VEYXRhID0geyAuLi5ncm91cHNvcnQsIC4uLmRhdGFUb0FkZCB9O1xuICAgICAgfVxuXG4gICAgICBpZiAoXG4gICAgICAgICFkYXRhLmhhbmRsZXJzW25hbWVdIHx8XG4gICAgICAgICFkYXRhLmhhbmRsZXJzW25hbWVdW3Byb3BlcnR5S2V5XSB8fFxuICAgICAgICAhKGhhbmRsZXJLZXkgaW4gZGF0YS5oYW5kbGVyc1tuYW1lXVtwcm9wZXJ0eUtleV0pXG4gICAgICApIHtcbiAgICAgICAgZGF0YS5oYW5kbGVyc1tuYW1lXSA9IGRhdGEuaGFuZGxlcnNbbmFtZV0gfHwge307XG4gICAgICAgIGRhdGEuaGFuZGxlcnNbbmFtZV1bcHJvcGVydHlLZXldID1cbiAgICAgICAgICBkYXRhLmhhbmRsZXJzW25hbWVdW3Byb3BlcnR5S2V5XSB8fCB7fTtcbiAgICAgICAgZGF0YS5oYW5kbGVyc1tuYW1lXVtwcm9wZXJ0eUtleV1baGFuZGxlcktleV0gPSB7XG4gICAgICAgICAgZGF0YTogbWVyZ2VEYXRhLFxuICAgICAgICB9O1xuXG4gICAgICAgIGFjY3VtLnB1c2goXG4gICAgICAgICAgaGFuZGxlKGNvbXBvdW5kS2V5IGFzIE9wZXJhdGlvbktleXMsIGhhbmRsZXIpLFxuICAgICAgICAgIHByb3BNZXRhZGF0YShPcGVyYXRpb25zLmtleShjb21wb3VuZEtleSksIGRhdGEpXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICByZXR1cm4gYWNjdW07XG4gICAgfSwgW10pO1xuICAgIHJldHVybiBhcHBseSguLi5kZWNvcmF0b3JzKSh0YXJnZXQsIHByb3BlcnR5S2V5KTtcbiAgfTtcbn1cbiIsImltcG9ydCB7IFJlcG9zaXRvcnlGbGFncyB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERlZmF1bHQgY29uZmlndXJhdGlvbiBmbGFncyBmb3IgcmVwb3NpdG9yeSBvcGVyYXRpb25zLlxuICogQHN1bW1hcnkgUHJvdmlkZXMgZGVmYXVsdCB2YWx1ZXMgZm9yIHJlcG9zaXRvcnkgb3BlcmF0aW9uIGZsYWdzLCBleGNsdWRpbmcgdGhlIHRpbWVzdGFtcCBwcm9wZXJ0eS5cbiAqIFRoZXNlIGZsYWdzIGNvbnRyb2wgYmVoYXZpb3Igc3VjaCBhcyBjb250ZXh0IGhhbmRsaW5nLCB2YWxpZGF0aW9uLCBlcnJvciBoYW5kbGluZywgYW5kIG1vcmUuXG4gKiBAY29uc3QgRGVmYXVsdFJlcG9zaXRvcnlGbGFnc1xuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBjb25zdCBEZWZhdWx0UmVwb3NpdG9yeUZsYWdzOiBPbWl0PFJlcG9zaXRvcnlGbGFncywgXCJ0aW1lc3RhbXBcIj4gPSB7XG4gIHBhcmVudENvbnRleHQ6IHVuZGVmaW5lZCxcbiAgY2hpbGRDb250ZXh0czogW10sXG4gIGlnbm9yZWRWYWxpZGF0aW9uUHJvcGVydGllczogW10sXG4gIGNhbGxBcmdzOiBbXSxcbiAgd3JpdGVPcGVyYXRpb246IGZhbHNlLFxuICBhZmZlY3RlZFRhYmxlczogW10sXG4gIG9wZXJhdGlvbjogdW5kZWZpbmVkLFxuICBicmVha09uSGFuZGxlckVycm9yOiB0cnVlLFxuICByZWJ1aWxkV2l0aFRyYW5zaWVudDogdHJ1ZSxcbn07XG4iLCJpbXBvcnQgeyBDb250ZXh0QXJncyB9IGZyb20gXCIuL3V0aWxzXCI7XG5pbXBvcnQgeyBDb250ZXh0dWFsIH0gZnJvbSBcIi4uL2ludGVyZmFjZXMvQ29udGV4dHVhbFwiO1xuaW1wb3J0IHsgT3BlcmF0aW9uS2V5cyB9IGZyb20gXCIuLi9vcGVyYXRpb25zL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IsIE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgRGVmYXVsdFJlcG9zaXRvcnlGbGFncyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgT2JqZWN0QWNjdW11bGF0b3IgfSBmcm9tIFwidHlwZWQtb2JqZWN0LWFjY3VtdWxhdG9yXCI7XG5pbXBvcnQgeyBSZXBvc2l0b3J5RmxhZ3MgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBGYWN0b3J5IHR5cGUgZm9yIGNyZWF0aW5nIGNvbnRleHQgaW5zdGFuY2VzLlxuICogQHN1bW1hcnkgRGVmaW5lcyBhIGZ1bmN0aW9uIHR5cGUgdGhhdCBjcmVhdGVzIGNvbnRleHQgaW5zdGFuY2VzIHdpdGggc3BlY2lmaWMgcmVwb3NpdG9yeSBmbGFncy5cbiAqIEB0ZW1wbGF0ZSBGIC0gVGhlIHJlcG9zaXRvcnkgZmxhZ3MgdHlwZSBleHRlbmRpbmcgUmVwb3NpdG9yeUZsYWdzXG4gKiBAdHlwZWRlZiB7RnVuY3Rpb259IENvbnRleHRGYWN0b3J5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmRiLWRlY29yYXRvcnNcbiAqL1xuZXhwb3J0IHR5cGUgQ29udGV4dEZhY3Rvcnk8RiBleHRlbmRzIFJlcG9zaXRvcnlGbGFncz4gPSA8QyBleHRlbmRzIENvbnRleHQ8Rj4+KFxuICBhcmc6IE9taXQ8RiwgXCJ0aW1lc3RhbXBcIj5cbikgPT4gQztcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRGVmYXVsdCBmYWN0b3J5IGZvciBjcmVhdGluZyBjb250ZXh0IGluc3RhbmNlcy5cbiAqIEBzdW1tYXJ5IEEgZmFjdG9yeSBmdW5jdGlvbiB0aGF0IGNyZWF0ZXMgbmV3IENvbnRleHQgaW5zdGFuY2VzIHdpdGggdGhlIHByb3ZpZGVkIHJlcG9zaXRvcnkgZmxhZ3MuXG4gKiBJdCBhdXRvbWF0aWNhbGx5IGFkZHMgYSB0aW1lc3RhbXAgdG8gdGhlIGNvbnRleHQgYW5kIHJldHVybnMgYSBwcm9wZXJseSB0eXBlZCBjb250ZXh0IGluc3RhbmNlLlxuICogQGNvbnN0IERlZmF1bHRDb250ZXh0RmFjdG9yeVxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBjb25zdCBEZWZhdWx0Q29udGV4dEZhY3Rvcnk6IENvbnRleHRGYWN0b3J5PGFueT4gPSA8XG4gIEYgZXh0ZW5kcyBSZXBvc2l0b3J5RmxhZ3MsXG4gIEMgZXh0ZW5kcyBDb250ZXh0PEY+LFxuPihcbiAgYXJnOiBPbWl0PEYsIFwidGltZXN0YW1wXCI+XG4pID0+IHtcbiAgcmV0dXJuIG5ldyBDb250ZXh0PEY+KCkuYWNjdW11bGF0ZShcbiAgICBPYmplY3QuYXNzaWduKHt9LCBhcmcsIHsgdGltZXN0YW1wOiBuZXcgRGF0ZSgpIH0pIGFzIEZcbiAgKSBhcyBDO1xufTtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQSBjb250ZXh0IG1hbmFnZW1lbnQgY2xhc3MgZm9yIGhhbmRsaW5nIHJlcG9zaXRvcnkgb3BlcmF0aW9ucy5cbiAqIEBzdW1tYXJ5IFRoZSBDb250ZXh0IGNsYXNzIHByb3ZpZGVzIGEgbWVjaGFuaXNtIGZvciBtYW5hZ2luZyByZXBvc2l0b3J5IG9wZXJhdGlvbnMgd2l0aCBmbGFncyxcbiAqIHBhcmVudC1jaGlsZCByZWxhdGlvbnNoaXBzLCBhbmQgc3RhdGUgYWNjdW11bGF0aW9uLiBJdCBhbGxvd3MgZm9yIGhpZXJhcmNoaWNhbCBjb250ZXh0IGNoYWluc1xuICogYW5kIG1haW50YWlucyBvcGVyYXRpb24tc3BlY2lmaWMgY29uZmlndXJhdGlvbnMgd2hpbGUgc3VwcG9ydGluZyB0eXBlIHNhZmV0eSB0aHJvdWdoIGdlbmVyaWNzLlxuICpcbiAqIEB0ZW1wbGF0ZSBGIC0gVHlwZSBleHRlbmRpbmcgUmVwb3NpdG9yeUZsYWdzIHRoYXQgZGVmaW5lcyB0aGUgY29udGV4dCBjb25maWd1cmF0aW9uXG4gKlxuICogQHBhcmFtIHtPYmplY3RBY2N1bXVsYXRvcjxGPn0gY2FjaGUgLSBUaGUgaW50ZXJuYWwgY2FjaGUgc3RvcmluZyBhY2N1bXVsYXRlZCB2YWx1ZXNcbiAqXG4gKiBAY2xhc3NcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gQ3JlYXRpbmcgYSBuZXcgY29udGV4dCB3aXRoIHJlcG9zaXRvcnkgZmxhZ3NcbiAqIGNvbnN0IGNvbnRleHQgPSBuZXcgQ29udGV4dDxSZXBvc2l0b3J5RmxhZ3M+KCk7XG4gKlxuICogLy8gQWNjdW11bGF0aW5nIHZhbHVlc1xuICogY29uc3QgZW5yaWNoZWRDb250ZXh0ID0gY29udGV4dC5hY2N1bXVsYXRlKHtcbiAqICAgd3JpdGVPcGVyYXRpb246IHRydWUsXG4gKiAgIGFmZmVjdGVkVGFibGVzOiBbJ3VzZXJzJ10sXG4gKiAgIG9wZXJhdGlvbjogT3BlcmF0aW9uS2V5cy5DUkVBVEVcbiAqIH0pO1xuICpcbiAqIC8vIEFjY2Vzc2luZyB2YWx1ZXNcbiAqIGNvbnN0IGlzV3JpdGUgPSBlbnJpY2hlZENvbnRleHQuZ2V0KCd3cml0ZU9wZXJhdGlvbicpOyAvLyB0cnVlXG4gKiBjb25zdCB0YWJsZXMgPSBlbnJpY2hlZENvbnRleHQuZ2V0KCdhZmZlY3RlZFRhYmxlcycpOyAvLyBbJ3VzZXJzJ11cbiAqIGBgYFxuICpcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQyBhcyBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgQ3R4IGFzIENvbnRleHRcbiAqICAgcGFydGljaXBhbnQgQ2FjaGUgYXMgT2JqZWN0QWNjdW11bGF0b3JcbiAqXG4gKiAgIEMtPj5DdHg6IG5ldyBDb250ZXh0KClcbiAqICAgQ3R4LT4+Q2FjaGU6IGNyZWF0ZSBjYWNoZVxuICpcbiAqICAgQy0+PkN0eDogYWNjdW11bGF0ZSh2YWx1ZSlcbiAqICAgQ3R4LT4+Q2FjaGU6IGFjY3VtdWxhdGUodmFsdWUpXG4gKiAgIENhY2hlLS0+PkN0eDogdXBkYXRlZCBjYWNoZVxuICogICBDdHgtLT4+QzogdXBkYXRlZCBjb250ZXh0XG4gKlxuICogICBDLT4+Q3R4OiBnZXQoa2V5KVxuICogICBDdHgtPj5DYWNoZTogZ2V0KGtleSlcbiAqICAgYWx0IEtleSBleGlzdHMgaW4gY2FjaGVcbiAqICAgICBDYWNoZS0tPj5DdHg6IHZhbHVlXG4gKiAgIGVsc2UgS2V5IG5vdCBmb3VuZFxuICogICAgIEN0eC0+PkN0eDogY2hlY2sgcGFyZW50IGNvbnRleHRcbiAqICAgICBhbHQgUGFyZW50IGV4aXN0c1xuICogICAgICAgQ3R4LT4+UGFyZW50OiBnZXQoa2V5KVxuICogICAgICAgUGFyZW50LS0+PkN0eDogdmFsdWVcbiAqICAgICBlbHNlIE5vIHBhcmVudFxuICogICAgICAgQ3R4LS0+PkM6IHRocm93IGVycm9yXG4gKiAgICAgZW5kXG4gKiAgIGVuZFxuICogICBDdHgtLT4+QzogcmVxdWVzdGVkIHZhbHVlXG4gKi9cbmV4cG9ydCBjbGFzcyBDb250ZXh0PEYgZXh0ZW5kcyBSZXBvc2l0b3J5RmxhZ3M+IHtcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIFwiY2FjaGVcIiwge1xuICAgICAgdmFsdWU6IG5ldyBPYmplY3RBY2N1bXVsYXRvcjxGPigpLFxuICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgfSk7XG4gIH1cblxuICBzdGF0aWMgZmFjdG9yeTogQ29udGV4dEZhY3Rvcnk8YW55PiA9IERlZmF1bHRDb250ZXh0RmFjdG9yeTtcblxuICByZWFkb25seSBjYWNoZTogUmVwb3NpdG9yeUZsYWdzICYgT2JqZWN0QWNjdW11bGF0b3I8YW55PiA9XG4gICAgbmV3IE9iamVjdEFjY3VtdWxhdG9yKCkgYXMgdW5rbm93biBhcyBSZXBvc2l0b3J5RmxhZ3MgJlxuICAgICAgT2JqZWN0QWNjdW11bGF0b3I8YW55PjtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEFjY3VtdWxhdGVzIG5ldyB2YWx1ZXMgaW50byB0aGUgY29udGV4dC5cbiAgICogQHN1bW1hcnkgTWVyZ2VzIHRoZSBwcm92aWRlZCB2YWx1ZSBvYmplY3Qgd2l0aCB0aGUgZXhpc3RpbmcgY29udGV4dCBzdGF0ZSxcbiAgICogY3JlYXRpbmcgYSBuZXcgaW1tdXRhYmxlIGNhY2hlIHN0YXRlLlxuICAgKi9cbiAgYWNjdW11bGF0ZTxWIGV4dGVuZHMgb2JqZWN0Pih2YWx1ZTogVikge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBcImNhY2hlXCIsIHtcbiAgICAgIHZhbHVlOiAodGhpcy5jYWNoZSBhcyBPYmplY3RBY2N1bXVsYXRvcjxhbnk+KS5hY2N1bXVsYXRlKHZhbHVlKSxcbiAgICAgIHdyaXRhYmxlOiBmYWxzZSxcbiAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgIH0pO1xuICAgIHJldHVybiB0aGlzIGFzIHVua25vd24gYXMgQ29udGV4dDxGICYgVj47XG4gIH1cblxuICBnZXQgdGltZXN0YW1wKCkge1xuICAgIHJldHVybiAodGhpcy5jYWNoZSBhcyBhbnkpLnRpbWVzdGFtcCBhcyBGW1widGltZXN0YW1wXCJdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZXRyaWV2ZXMgYSB2YWx1ZSBmcm9tIHRoZSBjb250ZXh0IGJ5IGtleS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleVxuICAgKiBAcmV0dXJuIHthbnl9XG4gICAqL1xuICBnZXQ8SyBleHRlbmRzIGtleW9mIEY+KGtleTogSyk6IEZbS10ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gKHRoaXMuY2FjaGUgYXMgT2JqZWN0QWNjdW11bGF0b3I8YW55PikuZ2V0KFxuICAgICAgICBrZXkgYXMgdW5rbm93biBhcyBzdHJpbmdcbiAgICAgICkgYXMgRltLXTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICBjb25zdCBwYXJlbnQgPSAodGhpcy5jYWNoZSBhcyBhbnkpLnBhcmVudENvbnRleHQgYXNcbiAgICAgICAgfCBDb250ZXh0PEY+XG4gICAgICAgIHwgdW5kZWZpbmVkO1xuICAgICAgaWYgKHBhcmVudCkgcmV0dXJuIHBhcmVudC5nZXQoa2V5KTtcbiAgICAgIHRocm93IGU7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgY2hpbGQgY29udGV4dCBmcm9tIGFub3RoZXIgY29udGV4dFxuICAgKi9cbiAgc3RhdGljIGNoaWxkRnJvbTxGIGV4dGVuZHMgUmVwb3NpdG9yeUZsYWdzLCBDIGV4dGVuZHMgQ29udGV4dDxGPj4oXG4gICAgY29udGV4dDogQyxcbiAgICBvdmVycmlkZXM/OiBQYXJ0aWFsPEY+XG4gICk6IEMge1xuICAgIHJldHVybiBDb250ZXh0LmZhY3RvcnkoXG4gICAgICBPYmplY3QuYXNzaWduKHt9LCAoY29udGV4dCBhcyBhbnkpLmNhY2hlLCBvdmVycmlkZXMgfHwge30pXG4gICAgKSBhcyB1bmtub3duIGFzIEM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgY29udGV4dCBmcm9tIG9wZXJhdGlvbiBwYXJhbWV0ZXJzXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZnJvbTxcbiAgICBNIGV4dGVuZHMgTW9kZWwsXG4gICAgRiBleHRlbmRzIFJlcG9zaXRvcnlGbGFncyxcbiAgICBDIGV4dGVuZHMgQ29udGV4dDxGPixcbiAgPihcbiAgICBvcGVyYXRpb246XG4gICAgICB8IE9wZXJhdGlvbktleXMuQ1JFQVRFXG4gICAgICB8IE9wZXJhdGlvbktleXMuUkVBRFxuICAgICAgfCBPcGVyYXRpb25LZXlzLlVQREFURVxuICAgICAgfCBPcGVyYXRpb25LZXlzLkRFTEVURSxcbiAgICBvdmVycmlkZXM6IFBhcnRpYWw8Rj4sXG4gICAgbW9kZWw6IENvbnN0cnVjdG9yPE0+LFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPEM+IHtcbiAgICByZXR1cm4gQ29udGV4dC5mYWN0b3J5KFxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgRGVmYXVsdFJlcG9zaXRvcnlGbGFncyBhcyBSZXBvc2l0b3J5RmxhZ3MsIG92ZXJyaWRlcywge1xuICAgICAgICBvcGVyYXRpb246IG9wZXJhdGlvbixcbiAgICAgICAgbW9kZWw6IG1vZGVsLFxuICAgICAgfSlcbiAgICApIGFzIEM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIGFyZ3VtZW50cyBmb3IgY29udGV4dCBvcGVyYXRpb25zXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgYXJnczxcbiAgICBNIGV4dGVuZHMgTW9kZWw8YW55PixcbiAgICBDIGV4dGVuZHMgQ29udGV4dDxGPixcbiAgICBGIGV4dGVuZHMgUmVwb3NpdG9yeUZsYWdzLFxuICA+KFxuICAgIG9wZXJhdGlvbjpcbiAgICAgIHwgT3BlcmF0aW9uS2V5cy5DUkVBVEVcbiAgICAgIHwgT3BlcmF0aW9uS2V5cy5SRUFEXG4gICAgICB8IE9wZXJhdGlvbktleXMuVVBEQVRFXG4gICAgICB8IE9wZXJhdGlvbktleXMuREVMRVRFLFxuICAgIG1vZGVsOiBDb25zdHJ1Y3RvcjxNPixcbiAgICBhcmdzOiBhbnlbXSxcbiAgICBjb250ZXh0dWFsPzogQ29udGV4dHVhbDxGPixcbiAgICBvdmVycmlkZXM/OiBQYXJ0aWFsPEY+XG4gICk6IFByb21pc2U8Q29udGV4dEFyZ3M8RiwgQz4+IHtcbiAgICBjb25zdCBsYXN0ID0gYXJncy5wb3AoKTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIGdldENvbnRleHQoKSB7XG4gICAgICBpZiAoY29udGV4dHVhbClcbiAgICAgICAgcmV0dXJuIGNvbnRleHR1YWwuY29udGV4dChvcGVyYXRpb24sIG92ZXJyaWRlcyB8fCB7fSwgbW9kZWwsIC4uLmFyZ3MpO1xuICAgICAgcmV0dXJuIENvbnRleHQuZnJvbShvcGVyYXRpb24sIG92ZXJyaWRlcyB8fCB7fSwgbW9kZWwsIC4uLmFyZ3MpO1xuICAgIH1cblxuICAgIGxldCBjOiBDO1xuICAgIGlmIChsYXN0KSB7XG4gICAgICBpZiAobGFzdCBpbnN0YW5jZW9mIENvbnRleHQpIHtcbiAgICAgICAgYyA9IGxhc3QgYXMgQztcbiAgICAgICAgYXJncy5wdXNoKGxhc3QpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYXJncy5wdXNoKGxhc3QpO1xuICAgICAgICBjID0gKGF3YWl0IGdldENvbnRleHQoKSkgYXMgQztcbiAgICAgICAgYXJncy5wdXNoKGMpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBjID0gKGF3YWl0IGdldENvbnRleHQoKSkgYXMgQztcbiAgICAgIGFyZ3MucHVzaChjKTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBjb250ZXh0OiBjLCBhcmdzOiBhcmdzIH07XG4gIH1cbn1cbiIsImltcG9ydCB7IENvbnRleHQgfSBmcm9tIFwiLi9Db250ZXh0XCI7XG5pbXBvcnQgeyBJbnRlcm5hbEVycm9yIH0gZnJvbSBcIi4vZXJyb3JzXCI7XG5cbi8qKlxuICogQHN1bW1hcnkgVXRpbCBtZXRob2QgdG8gY2hhbmdlIGEgbWV0aG9kIG9mIGFuIG9iamVjdCBwcmVmaXhpbmcgaXQgd2l0aCBhbm90aGVyXG4gKiBAcGFyYW0ge2FueX0gb2JqIFRoZSBCYXNlIE9iamVjdFxuICogQHBhcmFtIHtGdW5jdGlvbn0gYWZ0ZXIgVGhlIG9yaWdpbmFsIG1ldGhvZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gcHJlZml4IFRoZSBQcmVmaXggbWV0aG9kLiBUaGUgb3V0cHV0IHdpbGwgYmUgdXNlZCBhcyBhcmd1bWVudHMgaW4gdGhlIG9yaWdpbmFsIG1ldGhvZFxuICogQHBhcmFtIHtzdHJpbmd9IFthZnRlck5hbWVdIFdoZW4gdGhlIGFmdGVyIGZ1bmN0aW9uIGFubWUgY2Fubm90IGJlIGV4dHJhY3RlZCwgcGFzcyBpdCBoZXJlXG4gKlxuICogQGZ1bmN0aW9uIHByZWZpeE1ldGhvZFxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gcHJlZml4TWV0aG9kKFxuICBvYmo6IGFueSxcbiAgYWZ0ZXI6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55LFxuICBwcmVmaXg6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55LFxuICBhZnRlck5hbWU/OiBzdHJpbmdcbikge1xuICBhc3luYyBmdW5jdGlvbiB3cmFwcGVyKHRoaXM6IGFueSwgLi4uYXJnczogYW55W10pIHtcbiAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5yZXNvbHZlKHByZWZpeC5jYWxsKHRoaXMsIC4uLmFyZ3MpKTtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGFmdGVyLmFwcGx5KHRoaXMsIHJlc3VsdHMpKTtcbiAgfVxuICBjb25zdCB3cmFwcGVkID0gd3JhcHBlci5iaW5kKG9iaik7XG4gIGNvbnN0IG5hbWUgPSBhZnRlck5hbWUgPyBhZnRlck5hbWUgOiBhZnRlci5uYW1lO1xuICBPYmplY3QuZGVmaW5lUHJvcGVydHkod3JhcHBlZCwgXCJuYW1lXCIsIHtcbiAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgdmFsdWU6IG5hbWUsXG4gIH0pO1xuICBvYmpbbmFtZV0gPSB3cmFwcGVkO1xufVxuXG4vKipcbiAqIEBzdW1tYXJ5IFV0aWwgbWV0aG9kIHRvIGNoYW5nZSBhIG1ldGhvZCBvZiBhbiBvYmplY3Qgc3VmZml4aW5nIGl0IHdpdGggYW5vdGhlclxuICogQHBhcmFtIHthbnl9IG9iaiBUaGUgQmFzZSBPYmplY3RcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGJlZm9yZSBUaGUgb3JpZ2luYWwgbWV0aG9kXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzdWZmaXggVGhlIFByZWZpeCBtZXRob2QuIFRoZSBvdXRwdXQgd2lsbCBiZSB1c2VkIGFzIGFyZ3VtZW50cyBpbiB0aGUgb3JpZ2luYWwgbWV0aG9kXG4gKiBAcGFyYW0ge3N0cmluZ30gW2JlZm9yZU5hbWVdIFdoZW4gdGhlIGFmdGVyIGZ1bmN0aW9uIGFubWUgY2Fubm90IGJlIGV4dHJhY3RlZCwgcGFzcyBpdCBoZXJlXG4gKlxuICogQGZ1bmN0aW9uIHN1ZmZpeE1ldGhvZFxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9ycy5SZXBvc2l0b3J5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzdWZmaXhNZXRob2QoXG4gIG9iajogYW55LFxuICBiZWZvcmU6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55LFxuICBzdWZmaXg6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55LFxuICBiZWZvcmVOYW1lPzogc3RyaW5nXG4pIHtcbiAgYXN5bmMgZnVuY3Rpb24gd3JhcHBlcih0aGlzOiBhbnksIC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IFByb21pc2UucmVzb2x2ZShiZWZvcmUuY2FsbCh0aGlzLCAuLi5hcmdzKSk7XG4gICAgcmV0dXJuIHN1ZmZpeC5jYWxsKHRoaXMsIC4uLnJlc3VsdHMpO1xuICB9XG4gIGNvbnN0IHdyYXBwZWQgPSB3cmFwcGVyLmJpbmQob2JqKTtcbiAgY29uc3QgbmFtZSA9IGJlZm9yZU5hbWUgPyBiZWZvcmVOYW1lIDogYmVmb3JlLm5hbWU7XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3cmFwcGVkLCBcIm5hbWVcIiwge1xuICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgIHdyaXRhYmxlOiBmYWxzZSxcbiAgICB2YWx1ZTogbmFtZSxcbiAgfSk7XG4gIG9ialtuYW1lXSA9IHdyYXBwZWQ7XG59XG5cbi8qKlxuICogQHN1bW1hcnkgVXRpbCBtZXRob2QgdG8gd3JhcCBhIG1ldGhvZCBvZiBhbiBvYmplY3Qgd2l0aCBhZGRpdGlvbmFsIGxvZ2ljXG4gKlxuICogQHBhcmFtIHthbnl9IG9iaiBUaGUgQmFzZSBPYmplY3RcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGJlZm9yZSB0aGUgbWV0aG9kIHRvIGJlIHByZWZpeGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBtZXRob2QgdGhlIG1ldGhvZCB0byBiZSB3cmFwcGVkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBhZnRlciBUaGUgbWV0aG9kIHRvIGJlIHN1ZmZpeGVkXG4gKiBAcGFyYW0ge3N0cmluZ30gW21ldGhvZE5hbWVdIFdoZW4gdGhlIGFmdGVyIGZ1bmN0aW9uIGFubWUgY2Fubm90IGJlIGV4dHJhY3RlZCwgcGFzcyBpdCBoZXJlXG4gKlxuICogQGZ1bmN0aW9uIHdyYXBNZXRob2RXaXRoQ29udGV4dFxuICpcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gd3JhcE1ldGhvZFdpdGhDb250ZXh0KFxuICBvYmo6IGFueSxcbiAgYmVmb3JlOiAoLi4uYXJnczogYW55W10pID0+IGFueSxcbiAgbWV0aG9kOiAoLi4uYXJnczogYW55W10pID0+IGFueSxcbiAgYWZ0ZXI6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55LFxuICBtZXRob2ROYW1lPzogc3RyaW5nXG4pIHtcbiAgY29uc3QgbmFtZSA9IG1ldGhvZE5hbWUgPyBtZXRob2ROYW1lIDogbWV0aG9kLm5hbWU7XG4gIG9ialtuYW1lXSA9IG5ldyBQcm94eShvYmpbbmFtZV0sIHtcbiAgICBhcHBseTogYXN5bmMgKHRhcmdldCwgdGhpc0FyZywgYXJnQXJyYXkpID0+IHtcbiAgICAgIGxldCB0cmFuc2Zvcm1lZEFyZ3MgPSBiZWZvcmUuY2FsbCh0aGlzQXJnLCAuLi5hcmdBcnJheSk7XG4gICAgICBpZiAodHJhbnNmb3JtZWRBcmdzIGluc3RhbmNlb2YgUHJvbWlzZSlcbiAgICAgICAgdHJhbnNmb3JtZWRBcmdzID0gYXdhaXQgdHJhbnNmb3JtZWRBcmdzO1xuICAgICAgY29uc3QgY29udGV4dCA9IHRyYW5zZm9ybWVkQXJnc1t0cmFuc2Zvcm1lZEFyZ3MubGVuZ3RoIC0gMV0gYXMgYW55O1xuICAgICAgaWYgKCEoY29udGV4dCBpbnN0YW5jZW9mIENvbnRleHQpKVxuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIk1pc3NpbmcgYSBjb250ZXh0XCIpO1xuICAgICAgbGV0IHJlc3VsdHMgPSBhd2FpdCB0YXJnZXQuY2FsbCh0aGlzQXJnLCAuLi50cmFuc2Zvcm1lZEFyZ3MpO1xuICAgICAgaWYgKHJlc3VsdHMgaW5zdGFuY2VvZiBQcm9taXNlKSByZXN1bHRzID0gYXdhaXQgcmVzdWx0cztcbiAgICAgIHJlc3VsdHMgPSBhZnRlci5jYWxsKHRoaXNBcmcsIHJlc3VsdHMsIGNvbnRleHQpO1xuICAgICAgaWYgKHJlc3VsdHMgaW5zdGFuY2VvZiBQcm9taXNlKSByZXN1bHRzID0gYXdhaXQgcmVzdWx0cztcbiAgICAgIHJldHVybiByZXN1bHRzO1xuICAgIH0sXG4gIH0pO1xufVxuIiwiaW1wb3J0IHsgREJLZXlzIH0gZnJvbSBcIi4uL21vZGVsL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgZ2V0QWxsUHJvcGVydHlEZWNvcmF0b3JzUmVjdXJzaXZlIH0gZnJvbSBcIi4uL3JlcG9zaXRvcnkvdXRpbHNcIjtcbmltcG9ydCB7IE1vZGVsLCBNb2RlbEtleXMsIHNmIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgSW50ZXJuYWxFcnJvciB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L2Vycm9yc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBGaW5kcyB0aGUgcHJpbWFyeSBrZXkgYXR0cmlidXRlIGZvciBhIG1vZGVsXG4gKiBAc3VtbWFyeSBTZWFyY2hlcyBpbiBhbGwgdGhlIHByb3BlcnRpZXMgaW4gdGhlIG9iamVjdCBmb3IgYW4ge0BsaW5rIGlkfSBkZWNvcmF0ZWQgcHJvcGVydHkgYW5kIHJldHVybnMgdGhlIHByb3BlcnR5IGtleSBhbmQgbWV0YWRhdGFcbiAqIEBwYXJhbSB7TW9kZWx9IG1vZGVsIC0gVGhlIG1vZGVsIG9iamVjdCB0byBzZWFyY2ggZm9yIHByaW1hcnkga2V5XG4gKiBAcmV0dXJuIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBpZCBwcm9wZXJ0eSBuYW1lIGFuZCBpdHMgbWV0YWRhdGFcbiAqIEBmdW5jdGlvbiBmaW5kUHJpbWFyeUtleVxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgZmluZFByaW1hcnlLZXlcbiAqICAgcGFydGljaXBhbnQgZ2V0QWxsUHJvcGVydHlEZWNvcmF0b3JzUmVjdXJzaXZlXG4gKlxuICogICBDYWxsZXItPj5maW5kUHJpbWFyeUtleTogbW9kZWxcbiAqICAgZmluZFByaW1hcnlLZXktPj5nZXRBbGxQcm9wZXJ0eURlY29yYXRvcnNSZWN1cnNpdmU6IGdldCBkZWNvcmF0b3JzXG4gKiAgIGdldEFsbFByb3BlcnR5RGVjb3JhdG9yc1JlY3Vyc2l2ZS0tPj5maW5kUHJpbWFyeUtleTogZGVjb3JhdG9yc1xuICogICBmaW5kUHJpbWFyeUtleS0+PmZpbmRQcmltYXJ5S2V5OiBmaWx0ZXIgSUQgZGVjb3JhdG9yc1xuICogICBmaW5kUHJpbWFyeUtleS0+PmZpbmRQcmltYXJ5S2V5OiB2YWxpZGF0ZSBzaW5nbGUgSUQgcHJvcGVydHlcbiAqICAgZmluZFByaW1hcnlLZXktLT4+Q2FsbGVyOiB7aWQsIHByb3BzfVxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaW5kUHJpbWFyeUtleTxNIGV4dGVuZHMgTW9kZWw+KG1vZGVsOiBNKSB7XG4gIGNvbnN0IGRlY29yYXRvcnMgPSBnZXRBbGxQcm9wZXJ0eURlY29yYXRvcnNSZWN1cnNpdmUoXG4gICAgbW9kZWwsXG4gICAgdW5kZWZpbmVkLFxuICAgIERCS2V5cy5SRUZMRUNUICsgREJLZXlzLklEXG4gICk7XG4gIGNvbnN0IGlkRGVjb3JhdG9ycyA9IE9iamVjdC5lbnRyaWVzKGRlY29yYXRvcnMgYXMgb2JqZWN0KS5yZWR1Y2UoXG4gICAgKGFjY3VtOiB7IFtpbmRleGVyOiBzdHJpbmddOiBhbnlbXSB9LCBbcHJvcCwgZGVjc10pID0+IHtcbiAgICAgIGNvbnN0IGZpbHRlcmVkID0gKGRlY3MgYXMgeyBrZXk6IHN0cmluZyB9W10pLmZpbHRlcihcbiAgICAgICAgKGQpID0+IGQua2V5ICE9PSBNb2RlbEtleXMuVFlQRVxuICAgICAgKTtcbiAgICAgIGlmIChmaWx0ZXJlZCAmJiBmaWx0ZXJlZC5sZW5ndGgpIHtcbiAgICAgICAgYWNjdW1bcHJvcF0gPSBhY2N1bVtwcm9wXSB8fCBbXTtcbiAgICAgICAgYWNjdW1bcHJvcF0ucHVzaCguLi5maWx0ZXJlZCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gYWNjdW07XG4gICAgfSxcbiAgICB7fVxuICApO1xuXG4gIGlmICghaWREZWNvcmF0b3JzIHx8ICFPYmplY3Qua2V5cyhpZERlY29yYXRvcnMpLmxlbmd0aClcbiAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIkNvdWxkIG5vdCBmaW5kIElEIGRlY29yYXRlZCBQcm9wZXJ0eVwiKTtcbiAgaWYgKE9iamVjdC5rZXlzKGlkRGVjb3JhdG9ycykubGVuZ3RoID4gMSlcbiAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihzZihPYmplY3Qua2V5cyhpZERlY29yYXRvcnMpLmpvaW4oXCIsIFwiKSkpO1xuICBjb25zdCBpZFByb3AgPSBPYmplY3Qua2V5cyhpZERlY29yYXRvcnMpWzBdO1xuICBpZiAoIWlkUHJvcCkgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJDb3VsZCBub3QgZmluZCBJRCBkZWNvcmF0ZWQgUHJvcGVydHlcIik7XG4gIHJldHVybiB7XG4gICAgaWQ6IGlkUHJvcCBhcyBrZXlvZiBNLFxuICAgIHByb3BzOiBpZERlY29yYXRvcnNbaWRQcm9wXVswXS5wcm9wcyxcbiAgfTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmV0cmlldmVzIHRoZSBwcmltYXJ5IGtleSB2YWx1ZSBmcm9tIGEgbW9kZWxcbiAqIEBzdW1tYXJ5IFNlYXJjaGVzIGZvciB0aGUgSUQtZGVjb3JhdGVkIHByb3BlcnR5IGluIHRoZSBtb2RlbCBhbmQgcmV0dXJucyBpdHMgdmFsdWVcbiAqIEBwYXJhbSB7TW9kZWx9IG1vZGVsIC0gVGhlIG1vZGVsIG9iamVjdCB0byBleHRyYWN0IHRoZSBJRCBmcm9tXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtyZXR1cm5FbXB0eT1mYWxzZV0gLSBXaGV0aGVyIHRvIHJldHVybiB1bmRlZmluZWQgaWYgbm8gSUQgdmFsdWUgaXMgZm91bmRcbiAqIEByZXR1cm4ge3N0cmluZyB8IG51bWJlciB8IGJpZ2ludH0gVGhlIHByaW1hcnkga2V5IHZhbHVlXG4gKiBAZnVuY3Rpb24gZmluZE1vZGVsSWRcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQ2FsbGVyXG4gKiAgIHBhcnRpY2lwYW50IGZpbmRNb2RlbElkXG4gKiAgIHBhcnRpY2lwYW50IGZpbmRQcmltYXJ5S2V5XG4gKlxuICogICBDYWxsZXItPj5maW5kTW9kZWxJZDogbW9kZWwsIHJldHVybkVtcHR5XG4gKiAgIGZpbmRNb2RlbElkLT4+ZmluZFByaW1hcnlLZXk6IG1vZGVsXG4gKiAgIGZpbmRQcmltYXJ5S2V5LS0+PmZpbmRNb2RlbElkOiB7aWQsIHByb3BzfVxuICogICBmaW5kTW9kZWxJZC0+PmZpbmRNb2RlbElkOiBleHRyYWN0IG1vZGVsW2lkXVxuICogICBmaW5kTW9kZWxJZC0+PmZpbmRNb2RlbElkOiB2YWxpZGF0ZSBJRCBleGlzdHMgaWYgcmVxdWlyZWRcbiAqICAgZmluZE1vZGVsSWQtLT4+Q2FsbGVyOiBJRCB2YWx1ZVxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaW5kTW9kZWxJZDxNIGV4dGVuZHMgTW9kZWw+KFxuICBtb2RlbDogTSxcbiAgcmV0dXJuRW1wdHkgPSBmYWxzZVxuKTogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50IHtcbiAgY29uc3QgaWRQcm9wID0gZmluZFByaW1hcnlLZXkobW9kZWwpLmlkO1xuICBjb25zdCBtb2RlbElkID0gbW9kZWxbaWRQcm9wXTtcbiAgaWYgKHR5cGVvZiBtb2RlbElkID09PSBcInVuZGVmaW5lZFwiICYmICFyZXR1cm5FbXB0eSlcbiAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgIGBObyB2YWx1ZSBmb3IgdGhlIElkIGlzIGRlZmluZWQgdW5kZXIgdGhlIHByb3BlcnR5ICR7aWRQcm9wIGFzIHN0cmluZ31gXG4gICAgKTtcbiAgcmV0dXJuIG1vZGVsSWQgYXMgc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50O1xufVxuIiwiaW1wb3J0IHsgSVJlcG9zaXRvcnkgfSBmcm9tIFwiLi4vaW50ZXJmYWNlcy9JUmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IsIE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgZW5mb3JjZURCRGVjb3JhdG9ycyB9IGZyb20gXCIuL3V0aWxzXCI7XG5pbXBvcnQgeyBPcGVyYXRpb25LZXlzIH0gZnJvbSBcIi4uL29wZXJhdGlvbnMvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBJbnRlcm5hbEVycm9yIH0gZnJvbSBcIi4vZXJyb3JzXCI7XG5pbXBvcnQgeyB3cmFwTWV0aG9kV2l0aENvbnRleHQgfSBmcm9tIFwiLi93cmFwcGVyc1wiO1xuaW1wb3J0IHsgZmluZFByaW1hcnlLZXkgfSBmcm9tIFwiLi4vaWRlbnRpdHkvdXRpbHNcIjtcbmltcG9ydCB7IENvbnRleHQgfSBmcm9tIFwiLi9Db250ZXh0XCI7XG5pbXBvcnQgeyBSZXBvc2l0b3J5RmxhZ3MgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBCYXNlIHJlcG9zaXRvcnkgaW1wbGVtZW50YXRpb24gcHJvdmlkaW5nIENSVUQgb3BlcmF0aW9ucyBmb3IgbW9kZWxzLlxuICogQHN1bW1hcnkgVGhlIEJhc2VSZXBvc2l0b3J5IGNsYXNzIHNlcnZlcyBhcyBhIGZvdW5kYXRpb24gZm9yIHJlcG9zaXRvcnkgaW1wbGVtZW50YXRpb25zLCBwcm92aWRpbmdcbiAqIGFic3RyYWN0IGFuZCBjb25jcmV0ZSBtZXRob2RzIGZvciBjcmVhdGluZywgcmVhZGluZywgdXBkYXRpbmcsIGFuZCBkZWxldGluZyBtb2RlbCBpbnN0YW5jZXMuXG4gKiBJdCBoYW5kbGVzIG9wZXJhdGlvbiBsaWZlY3ljbGVzIGluY2x1ZGluZyBwcmVmaXggYW5kIHN1ZmZpeCBvcGVyYXRpb25zLCBhbmQgZW5mb3JjZXMgZGVjb3JhdG9ycy5cbiAqIEB0ZW1wbGF0ZSBNIC0gVGhlIG1vZGVsIHR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgRiAtIFRoZSByZXBvc2l0b3J5IGZsYWdzIHR5cGUsIGRlZmF1bHRzIHRvIFJlcG9zaXRvcnlGbGFnc1xuICogQHRlbXBsYXRlIEMgLSBUaGUgY29udGV4dCB0eXBlLCBkZWZhdWx0cyB0byBDb250ZXh0PEY+XG4gKiBAcGFyYW0ge0NvbnN0cnVjdG9yPE0+fSBjbGF6eiAtIFRoZSBjb25zdHJ1Y3RvciBmb3IgdGhlIG1vZGVsIGNsYXNzXG4gKiBAY2xhc3MgQmFzZVJlcG9zaXRvcnlcbiAqIEBleGFtcGxlXG4gKiBjbGFzcyBVc2VyTW9kZWwgZXh0ZW5kcyBNb2RlbCB7XG4gKiAgIEBpZCgpXG4gKiAgIGlkOiBzdHJpbmc7XG4gKlxuICogICBAcmVxdWlyZWQoKVxuICogICBuYW1lOiBzdHJpbmc7XG4gKiB9XG4gKlxuICogY2xhc3MgVXNlclJlcG9zaXRvcnkgZXh0ZW5kcyBCYXNlUmVwb3NpdG9yeTxVc2VyTW9kZWw+IHtcbiAqICAgY29uc3RydWN0b3IoKSB7XG4gKiAgICAgc3VwZXIoVXNlck1vZGVsKTtcbiAqICAgfVxuICpcbiAqICAgYXN5bmMgY3JlYXRlKG1vZGVsOiBVc2VyTW9kZWwpOiBQcm9taXNlPFVzZXJNb2RlbD4ge1xuICogICAgIC8vIEltcGxlbWVudGF0aW9uXG4gKiAgICAgcmV0dXJuIG1vZGVsO1xuICogICB9XG4gKlxuICogICBhc3luYyByZWFkKGtleTogc3RyaW5nKTogUHJvbWlzZTxVc2VyTW9kZWw+IHtcbiAqICAgICAvLyBJbXBsZW1lbnRhdGlvblxuICogICAgIHJldHVybiBuZXcgVXNlck1vZGVsKHsgaWQ6IGtleSwgbmFtZTogJ1VzZXInIH0pO1xuICogICB9XG4gKlxuICogICBhc3luYyB1cGRhdGUobW9kZWw6IFVzZXJNb2RlbCk6IFByb21pc2U8VXNlck1vZGVsPiB7XG4gKiAgICAgLy8gSW1wbGVtZW50YXRpb25cbiAqICAgICByZXR1cm4gbW9kZWw7XG4gKiAgIH1cbiAqXG4gKiAgIGFzeW5jIGRlbGV0ZShrZXk6IHN0cmluZyk6IFByb21pc2U8VXNlck1vZGVsPiB7XG4gKiAgICAgLy8gSW1wbGVtZW50YXRpb25cbiAqICAgICBjb25zdCBtb2RlbCA9IGF3YWl0IHRoaXMucmVhZChrZXkpO1xuICogICAgIHJldHVybiBtb2RlbDtcbiAqICAgfVxuICogfVxuICpcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQyBhcyBDbGllbnRcbiAqICAgcGFydGljaXBhbnQgUiBhcyBSZXBvc2l0b3J5XG4gKiAgIHBhcnRpY2lwYW50IFAgYXMgUHJlZml4IE1ldGhvZHNcbiAqICAgcGFydGljaXBhbnQgRCBhcyBEYXRhYmFzZVxuICogICBwYXJ0aWNpcGFudCBTIGFzIFN1ZmZpeCBNZXRob2RzXG4gKiAgIHBhcnRpY2lwYW50IFYgYXMgVmFsaWRhdG9ycy9EZWNvcmF0b3JzXG4gKlxuICogICBOb3RlIG92ZXIgQyxWOiBDcmVhdGUgT3BlcmF0aW9uXG4gKiAgIEMtPj5SOiBjcmVhdGUobW9kZWwpXG4gKiAgIFItPj5QOiBjcmVhdGVQcmVmaXgobW9kZWwpXG4gKiAgIFAtPj5WOiBlbmZvcmNlREJEZWNvcmF0b3JzKE9OKVxuICogICBQLT4+RDogRGF0YWJhc2Ugb3BlcmF0aW9uXG4gKiAgIEQtPj5TOiBjcmVhdGVTdWZmaXgobW9kZWwpXG4gKiAgIFMtPj5WOiBlbmZvcmNlREJEZWNvcmF0b3JzKEFGVEVSKVxuICogICBTLT4+QzogUmV0dXJuIG1vZGVsXG4gKlxuICogICBOb3RlIG92ZXIgQyxWOiBSZWFkIE9wZXJhdGlvblxuICogICBDLT4+UjogcmVhZChrZXkpXG4gKiAgIFItPj5QOiByZWFkUHJlZml4KGtleSlcbiAqICAgUC0+PlY6IGVuZm9yY2VEQkRlY29yYXRvcnMoT04pXG4gKiAgIFAtPj5EOiBEYXRhYmFzZSBvcGVyYXRpb25cbiAqICAgRC0+PlM6IHJlYWRTdWZmaXgobW9kZWwpXG4gKiAgIFMtPj5WOiBlbmZvcmNlREJEZWNvcmF0b3JzKEFGVEVSKVxuICogICBTLT4+QzogUmV0dXJuIG1vZGVsXG4gKlxuICogICBOb3RlIG92ZXIgQyxWOiBVcGRhdGUgT3BlcmF0aW9uXG4gKiAgIEMtPj5SOiB1cGRhdGUobW9kZWwpXG4gKiAgIFItPj5QOiB1cGRhdGVQcmVmaXgobW9kZWwpXG4gKiAgIFAtPj5WOiBlbmZvcmNlREJEZWNvcmF0b3JzKE9OKVxuICogICBQLT4+RDogRGF0YWJhc2Ugb3BlcmF0aW9uXG4gKiAgIEQtPj5TOiB1cGRhdGVTdWZmaXgobW9kZWwpXG4gKiAgIFMtPj5WOiBlbmZvcmNlREJEZWNvcmF0b3JzKEFGVEVSKVxuICogICBTLT4+QzogUmV0dXJuIG1vZGVsXG4gKlxuICogICBOb3RlIG92ZXIgQyxWOiBEZWxldGUgT3BlcmF0aW9uXG4gKiAgIEMtPj5SOiBkZWxldGUoa2V5KVxuICogICBSLT4+UDogZGVsZXRlUHJlZml4KGtleSlcbiAqICAgUC0+PlY6IGVuZm9yY2VEQkRlY29yYXRvcnMoT04pXG4gKiAgIFAtPj5EOiBEYXRhYmFzZSBvcGVyYXRpb25cbiAqICAgRC0+PlM6IGRlbGV0ZVN1ZmZpeChtb2RlbClcbiAqICAgUy0+PlY6IGVuZm9yY2VEQkRlY29yYXRvcnMoQUZURVIpXG4gKiAgIFMtPj5DOiBSZXR1cm4gbW9kZWxcbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEJhc2VSZXBvc2l0b3J5PFxuICBNIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4sXG4gIEYgZXh0ZW5kcyBSZXBvc2l0b3J5RmxhZ3MgPSBSZXBvc2l0b3J5RmxhZ3MsXG4gIEMgZXh0ZW5kcyBDb250ZXh0PEY+ID0gQ29udGV4dDxGPixcbj4gaW1wbGVtZW50cyBJUmVwb3NpdG9yeTxNLCBGLCBDPlxue1xuICBwcml2YXRlIHJlYWRvbmx5IF9jbGFzcyE6IENvbnN0cnVjdG9yPE0+O1xuICBwcml2YXRlIF9wayE6IGtleW9mIE07XG4gIHByaXZhdGUgX3BrUHJvcHMhOiBhbnk7XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZXRzIHRoZSBtb2RlbCBjbGFzcyBjb25zdHJ1Y3Rvci5cbiAgICogQHN1bW1hcnkgUmV0cmlldmVzIHRoZSBjb25zdHJ1Y3RvciBmb3IgdGhlIG1vZGVsIGNsYXNzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHJlcG9zaXRvcnkuXG4gICAqIFRocm93cyBhbiBlcnJvciBpZiBubyBjbGFzcyBkZWZpbml0aW9uIGlzIGZvdW5kLlxuICAgKiBAcmV0dXJuIHtDb25zdHJ1Y3RvcjxNPn0gVGhlIGNvbnN0cnVjdG9yIGZvciB0aGUgbW9kZWwgY2xhc3NcbiAgICovXG4gIGdldCBjbGFzcygpIHtcbiAgICBpZiAoIXRoaXMuX2NsYXNzKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYE5vIGNsYXNzIGRlZmluaXRpb24gZm91bmQgZm9yIHRoaXMgcmVwb3NpdG9yeWApO1xuICAgIHJldHVybiB0aGlzLl9jbGFzcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2V0cyB0aGUgcHJpbWFyeSBrZXkgcHJvcGVydHkgbmFtZSBvZiB0aGUgbW9kZWwuXG4gICAqIEBzdW1tYXJ5IFJldHJpZXZlcyB0aGUgbmFtZSBvZiB0aGUgcHJvcGVydHkgdGhhdCBzZXJ2ZXMgYXMgdGhlIHByaW1hcnkga2V5IGZvciB0aGUgbW9kZWwuXG4gICAqIElmIG5vdCBhbHJlYWR5IGRldGVybWluZWQsIGl0IGZpbmRzIHRoZSBwcmltYXJ5IGtleSB1c2luZyB0aGUgbW9kZWwncyBkZWNvcmF0b3JzLlxuICAgKiBAcmV0dXJuIFRoZSBuYW1lIG9mIHRoZSBwcmltYXJ5IGtleSBwcm9wZXJ0eVxuICAgKi9cbiAgZ2V0IHBrKCk6IGtleW9mIE0ge1xuICAgIGlmICghdGhpcy5fcGspIHtcbiAgICAgIGNvbnN0IHsgaWQsIHByb3BzIH0gPSBmaW5kUHJpbWFyeUtleShuZXcgdGhpcy5jbGFzcygpKTtcbiAgICAgIHRoaXMuX3BrID0gaWQ7XG4gICAgICB0aGlzLl9wa1Byb3BzID0gcHJvcHM7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9waztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2V0cyB0aGUgcHJpbWFyeSBrZXkgcHJvcGVydGllcy5cbiAgICogQHN1bW1hcnkgUmV0cmlldmVzIHRoZSBwcm9wZXJ0aWVzIGFzc29jaWF0ZWQgd2l0aCB0aGUgcHJpbWFyeSBrZXkgb2YgdGhlIG1vZGVsLlxuICAgKiBJZiBub3QgYWxyZWFkeSBkZXRlcm1pbmVkLCBpdCB0cmlnZ2VycyB0aGUgcGsgZ2V0dGVyIHRvIGZpbmQgdGhlIHByaW1hcnkga2V5IHByb3BlcnRpZXMuXG4gICAqIEByZXR1cm4ge2FueX0gVGhlIHByb3BlcnRpZXMgb2YgdGhlIHByaW1hcnkga2V5XG4gICAqL1xuICBwcm90ZWN0ZWQgZ2V0IHBrUHJvcHMoKTogYW55IHtcbiAgICBpZiAoIXRoaXMuX3BrUHJvcHMpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICAgIGNvbnN0IHBrID0gdGhpcy5waztcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX3BrUHJvcHM7XG4gIH1cblxuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IoY2xheno/OiBDb25zdHJ1Y3RvcjxNPikge1xuICAgIGlmIChjbGF6eikgdGhpcy5fY2xhc3MgPSBjbGF6ejtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXRoaXMtYWxpYXNcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICBbdGhpcy5jcmVhdGUsIHRoaXMucmVhZCwgdGhpcy51cGRhdGUsIHRoaXMuZGVsZXRlXS5mb3JFYWNoKChtKSA9PiB7XG4gICAgICBjb25zdCBuYW1lID0gbS5uYW1lO1xuICAgICAgd3JhcE1ldGhvZFdpdGhDb250ZXh0KFxuICAgICAgICBzZWxmLFxuICAgICAgICAoc2VsZiBhcyBhbnkpW25hbWUgKyBcIlByZWZpeFwiXSxcbiAgICAgICAgbSxcbiAgICAgICAgKHNlbGYgYXMgYW55KVtuYW1lICsgXCJTdWZmaXhcIl1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgbW9kZWwgaW5zdGFuY2UgaW4gdGhlIHJlcG9zaXRvcnkuXG4gICAqIEBzdW1tYXJ5IFBlcnNpc3RzIGEgbmV3IG1vZGVsIGluc3RhbmNlIHRvIHRoZSB1bmRlcmx5aW5nIGRhdGEgc3RvcmUuXG4gICAqIFRoaXMgbWV0aG9kIG11c3QgYmUgaW1wbGVtZW50ZWQgYnkgY29uY3JldGUgcmVwb3NpdG9yeSBjbGFzc2VzLlxuICAgKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIHRvIGNyZWF0ZVxuICAgKiBAcGFyYW0ge2FueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIHRoZSBjcmVhdGUgb3BlcmF0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBjcmVhdGVkIG1vZGVsIGluc3RhbmNlXG4gICAqL1xuICBhYnN0cmFjdCBjcmVhdGUobW9kZWw6IE0sIC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTxNPjtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgbXVsdGlwbGUgbW9kZWwgaW5zdGFuY2VzIGluIHRoZSByZXBvc2l0b3J5LlxuICAgKiBAc3VtbWFyeSBQZXJzaXN0cyBtdWx0aXBsZSBtb2RlbCBpbnN0YW5jZXMgdG8gdGhlIHVuZGVybHlpbmcgZGF0YSBzdG9yZSBieSBjYWxsaW5nXG4gICAqIHRoZSBjcmVhdGUgbWV0aG9kIGZvciBlYWNoIG1vZGVsIGluIHRoZSBhcnJheS5cbiAgICogQHBhcmFtIHtNW119IG1vZGVscyAtIFRoZSBhcnJheSBvZiBtb2RlbCBpbnN0YW5jZXMgdG8gY3JlYXRlXG4gICAqIEBwYXJhbSB7YW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgdGhlIGNyZWF0ZSBvcGVyYXRpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTxNW10+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheSBvZiBjcmVhdGVkIG1vZGVsIGluc3RhbmNlc1xuICAgKi9cbiAgYXN5bmMgY3JlYXRlQWxsKG1vZGVsczogTVtdLCAuLi5hcmdzOiBhbnlbXSk6IFByb21pc2U8TVtdPiB7XG4gICAgcmV0dXJuIFByb21pc2UuYWxsKG1vZGVscy5tYXAoKG0pID0+IHRoaXMuY3JlYXRlKG0sIC4uLmFyZ3MpKSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIGEgbW9kZWwgZm9yIGNyZWF0aW9uIGFuZCBleGVjdXRlcyBwcmUtY3JlYXRpb24gb3BlcmF0aW9ucy5cbiAgICogQHN1bW1hcnkgUHJvY2Vzc2VzIGEgbW9kZWwgYmVmb3JlIGl0IGlzIGNyZWF0ZWQgaW4gdGhlIGRhdGEgc3RvcmUuIFRoaXMgaW5jbHVkZXNcbiAgICogY3JlYXRpbmcgYSBjb250ZXh0LCBpbnN0YW50aWF0aW5nIGEgbmV3IG1vZGVsIGluc3RhbmNlLCBhbmQgZW5mb3JjaW5nIGFueSBkZWNvcmF0b3JzXG4gICAqIHRoYXQgc2hvdWxkIGJlIGFwcGxpZWQgYmVmb3JlIGNyZWF0aW9uLlxuICAgKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIHRvIHByZXBhcmUgZm9yIGNyZWF0aW9uXG4gICAqIEBwYXJhbSB7YW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgdGhlIGNyZWF0ZSBvcGVyYXRpb25cbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheSBjb250YWluaW5nIHRoZSBwcmVwYXJlZCBtb2RlbCBhbmQgY29udGV4dCBhcmd1bWVudHNcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBjcmVhdGVQcmVmaXgobW9kZWw6IE0sIC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3M8TSwgQywgRj4oXG4gICAgICBPcGVyYXRpb25LZXlzLkNSRUFURSxcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBhcmdzXG4gICAgKTtcbiAgICBtb2RlbCA9IG5ldyB0aGlzLmNsYXNzKG1vZGVsKTtcbiAgICBhd2FpdCBlbmZvcmNlREJEZWNvcmF0b3JzPE0sIHR5cGVvZiB0aGlzLCBhbnksIEYsIEM+KFxuICAgICAgdGhpcyxcbiAgICAgIGNvbnRleHRBcmdzLmNvbnRleHQsXG4gICAgICBtb2RlbCxcbiAgICAgIE9wZXJhdGlvbktleXMuQ1JFQVRFLFxuICAgICAgT3BlcmF0aW9uS2V5cy5PTlxuICAgICk7XG4gICAgcmV0dXJuIFttb2RlbCwgLi4uY29udGV4dEFyZ3MuYXJnc107XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByb2Nlc3NlcyBhIG1vZGVsIGFmdGVyIGNyZWF0aW9uIGFuZCBleGVjdXRlcyBwb3N0LWNyZWF0aW9uIG9wZXJhdGlvbnMuXG4gICAqIEBzdW1tYXJ5IEZpbmFsaXplcyBhIG1vZGVsIGFmdGVyIGl0IGhhcyBiZWVuIGNyZWF0ZWQgaW4gdGhlIGRhdGEgc3RvcmUuIFRoaXMgaW5jbHVkZXNcbiAgICogZW5mb3JjaW5nIGFueSBkZWNvcmF0b3JzIHRoYXQgc2hvdWxkIGJlIGFwcGxpZWQgYWZ0ZXIgY3JlYXRpb24uXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2UgdGhhdCB3YXMgY3JlYXRlZFxuICAgKiBAcGFyYW0ge0N9IGNvbnRleHQgLSBUaGUgY29udGV4dCBmb3IgdGhlIG9wZXJhdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE0+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcHJvY2Vzc2VkIG1vZGVsIGluc3RhbmNlXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgY3JlYXRlU3VmZml4KG1vZGVsOiBNLCBjb250ZXh0OiBDKSB7XG4gICAgYXdhaXQgZW5mb3JjZURCRGVjb3JhdG9yczxNLCB0eXBlb2YgdGhpcywgYW55LCBGLCBDPihcbiAgICAgIHRoaXMsXG4gICAgICBjb250ZXh0LFxuICAgICAgbW9kZWwsXG4gICAgICBPcGVyYXRpb25LZXlzLkNSRUFURSxcbiAgICAgIE9wZXJhdGlvbktleXMuQUZURVJcbiAgICApO1xuICAgIHJldHVybiBtb2RlbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJlcGFyZXMgbXVsdGlwbGUgbW9kZWxzIGZvciBjcmVhdGlvbiBhbmQgZXhlY3V0ZXMgcHJlLWNyZWF0aW9uIG9wZXJhdGlvbnMuXG4gICAqIEBzdW1tYXJ5IFByb2Nlc3NlcyBtdWx0aXBsZSBtb2RlbHMgYmVmb3JlIHRoZXkgYXJlIGNyZWF0ZWQgaW4gdGhlIGRhdGEgc3RvcmUuIFRoaXMgaW5jbHVkZXNcbiAgICogY3JlYXRpbmcgYSBjb250ZXh0LCBpbnN0YW50aWF0aW5nIG5ldyBtb2RlbCBpbnN0YW5jZXMsIGFuZCBlbmZvcmNpbmcgYW55IGRlY29yYXRvcnNcbiAgICogdGhhdCBzaG91bGQgYmUgYXBwbGllZCBiZWZvcmUgY3JlYXRpb24gZm9yIGVhY2ggbW9kZWwuXG4gICAqIEBwYXJhbSB7TVtdfSBtb2RlbHMgLSBUaGUgYXJyYXkgb2YgbW9kZWwgaW5zdGFuY2VzIHRvIHByZXBhcmUgZm9yIGNyZWF0aW9uXG4gICAqIEBwYXJhbSB7YW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgdGhlIGNyZWF0ZSBvcGVyYXRpb25cbiAgICogQHJldHVybiAgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXkgY29udGFpbmluZyB0aGUgcHJlcGFyZWQgbW9kZWxzIGFuZCBjb250ZXh0IGFyZ3VtZW50c1xuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGNyZWF0ZUFsbFByZWZpeChtb2RlbHM6IE1bXSwgLi4uYXJnczogYW55W10pIHtcbiAgICBjb25zdCBjb250ZXh0QXJncyA9IGF3YWl0IENvbnRleHQuYXJnczxNLCBDLCBGPihcbiAgICAgIE9wZXJhdGlvbktleXMuQ1JFQVRFLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIGFyZ3NcbiAgICApO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgbW9kZWxzLm1hcChhc3luYyAobSkgPT4ge1xuICAgICAgICBtID0gbmV3IHRoaXMuY2xhc3MobSk7XG4gICAgICAgIGF3YWl0IGVuZm9yY2VEQkRlY29yYXRvcnM8TSwgdHlwZW9mIHRoaXMsIGFueSwgRiwgQz4oXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICBjb250ZXh0QXJncy5jb250ZXh0LFxuICAgICAgICAgIG0sXG4gICAgICAgICAgT3BlcmF0aW9uS2V5cy5DUkVBVEUsXG4gICAgICAgICAgT3BlcmF0aW9uS2V5cy5PTlxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gbTtcbiAgICAgIH0pXG4gICAgKTtcbiAgICByZXR1cm4gW21vZGVscywgLi4uY29udGV4dEFyZ3MuYXJnc107XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByb2Nlc3NlcyBtdWx0aXBsZSBtb2RlbHMgYWZ0ZXIgY3JlYXRpb24gYW5kIGV4ZWN1dGVzIHBvc3QtY3JlYXRpb24gb3BlcmF0aW9ucy5cbiAgICogQHN1bW1hcnkgRmluYWxpemVzIG11bHRpcGxlIG1vZGVscyBhZnRlciB0aGV5IGhhdmUgYmVlbiBjcmVhdGVkIGluIHRoZSBkYXRhIHN0b3JlLiBUaGlzIGluY2x1ZGVzXG4gICAqIGVuZm9yY2luZyBhbnkgZGVjb3JhdG9ycyB0aGF0IHNob3VsZCBiZSBhcHBsaWVkIGFmdGVyIGNyZWF0aW9uIGZvciBlYWNoIG1vZGVsLlxuICAgKiBAcGFyYW0ge01bXX0gbW9kZWxzIC0gVGhlIGFycmF5IG9mIG1vZGVsIGluc3RhbmNlcyB0aGF0IHdlcmUgY3JlYXRlZFxuICAgKiBAcGFyYW0ge0N9IGNvbnRleHQgLSBUaGUgY29udGV4dCBmb3IgdGhlIG9wZXJhdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1bXT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBhcnJheSBvZiBwcm9jZXNzZWQgbW9kZWwgaW5zdGFuY2VzXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgY3JlYXRlQWxsU3VmZml4KG1vZGVsczogTVtdLCBjb250ZXh0OiBDKSB7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBtb2RlbHMubWFwKChtKSA9PlxuICAgICAgICBlbmZvcmNlREJEZWNvcmF0b3JzPE0sIHR5cGVvZiB0aGlzLCBhbnksIEYsIEM+KFxuICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgY29udGV4dCxcbiAgICAgICAgICBtLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuQ1JFQVRFLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuQUZURVJcbiAgICAgICAgKVxuICAgICAgKVxuICAgICk7XG4gICAgcmV0dXJuIG1vZGVscztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmV0cmlldmVzIGEgbW9kZWwgaW5zdGFuY2UgZnJvbSB0aGUgcmVwb3NpdG9yeSBieSBpdHMgcHJpbWFyeSBrZXkuXG4gICAqIEBzdW1tYXJ5IEZldGNoZXMgYSBtb2RlbCBpbnN0YW5jZSBmcm9tIHRoZSB1bmRlcmx5aW5nIGRhdGEgc3RvcmUgdXNpbmcgaXRzIHByaW1hcnkga2V5LlxuICAgKiBUaGlzIG1ldGhvZCBtdXN0IGJlIGltcGxlbWVudGVkIGJ5IGNvbmNyZXRlIHJlcG9zaXRvcnkgY2xhc3Nlcy5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCBudW1iZXJ9IGtleSAtIFRoZSBwcmltYXJ5IGtleSBvZiB0aGUgbW9kZWwgdG8gcmV0cmlldmVcbiAgICogQHBhcmFtIHthbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciB0aGUgcmVhZCBvcGVyYXRpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTxNPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJldHJpZXZlZCBtb2RlbCBpbnN0YW5jZVxuICAgKi9cbiAgYWJzdHJhY3QgcmVhZChrZXk6IHN0cmluZyB8IG51bWJlciwgLi4uYXJnczogYW55W10pOiBQcm9taXNlPE0+O1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmV0cmlldmVzIG11bHRpcGxlIG1vZGVsIGluc3RhbmNlcyBmcm9tIHRoZSByZXBvc2l0b3J5IGJ5IHRoZWlyIHByaW1hcnkga2V5cy5cbiAgICogQHN1bW1hcnkgRmV0Y2hlcyBtdWx0aXBsZSBtb2RlbCBpbnN0YW5jZXMgZnJvbSB0aGUgdW5kZXJseWluZyBkYXRhIHN0b3JlIHVzaW5nIHRoZWlyIHByaW1hcnkga2V5c1xuICAgKiBieSBjYWxsaW5nIHRoZSByZWFkIG1ldGhvZCBmb3IgZWFjaCBrZXkgaW4gdGhlIGFycmF5LlxuICAgKiBAcGFyYW0ge3N0cmluZ1tdIHwgbnVtYmVyW119IGtleXMgLSBUaGUgYXJyYXkgb2YgcHJpbWFyeSBrZXlzIG9mIHRoZSBtb2RlbHMgdG8gcmV0cmlldmVcbiAgICogQHBhcmFtIHthbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciB0aGUgcmVhZCBvcGVyYXRpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTxNW10+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheSBvZiByZXRyaWV2ZWQgbW9kZWwgaW5zdGFuY2VzXG4gICAqL1xuICBhc3luYyByZWFkQWxsKGtleXM6IHN0cmluZ1tdIHwgbnVtYmVyW10sIC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTxNW10+IHtcbiAgICByZXR1cm4gYXdhaXQgUHJvbWlzZS5hbGwoa2V5cy5tYXAoKGlkKSA9PiB0aGlzLnJlYWQoaWQsIC4uLmFyZ3MpKSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByb2Nlc3NlcyBhIG1vZGVsIGFmdGVyIHJldHJpZXZhbCBhbmQgZXhlY3V0ZXMgcG9zdC1yZWFkIG9wZXJhdGlvbnMuXG4gICAqIEBzdW1tYXJ5IEZpbmFsaXplcyBhIG1vZGVsIGFmdGVyIGl0IGhhcyBiZWVuIHJldHJpZXZlZCBmcm9tIHRoZSBkYXRhIHN0b3JlLiBUaGlzIGluY2x1ZGVzXG4gICAqIGVuZm9yY2luZyBhbnkgZGVjb3JhdG9ycyB0aGF0IHNob3VsZCBiZSBhcHBsaWVkIGFmdGVyIHJlYWRpbmcuXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2UgdGhhdCB3YXMgcmV0cmlldmVkXG4gICAqIEBwYXJhbSB7Q30gY29udGV4dCAtIFRoZSBjb250ZXh0IGZvciB0aGUgb3BlcmF0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBwcm9jZXNzZWQgbW9kZWwgaW5zdGFuY2VcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyByZWFkU3VmZml4KG1vZGVsOiBNLCBjb250ZXh0OiBDKSB7XG4gICAgYXdhaXQgZW5mb3JjZURCRGVjb3JhdG9yczxNLCB0eXBlb2YgdGhpcywgYW55LCBGLCBDPihcbiAgICAgIHRoaXMsXG4gICAgICBjb250ZXh0LFxuICAgICAgbW9kZWwsXG4gICAgICBPcGVyYXRpb25LZXlzLlJFQUQsXG4gICAgICBPcGVyYXRpb25LZXlzLkFGVEVSXG4gICAgKTtcbiAgICByZXR1cm4gbW9kZWw7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIGZvciByZWFkaW5nIGEgbW9kZWwgYW5kIGV4ZWN1dGVzIHByZS1yZWFkIG9wZXJhdGlvbnMuXG4gICAqIEBzdW1tYXJ5IFByb2Nlc3NlcyBhIGtleSBiZWZvcmUgYSBtb2RlbCBpcyByZWFkIGZyb20gdGhlIGRhdGEgc3RvcmUuIFRoaXMgaW5jbHVkZXNcbiAgICogY3JlYXRpbmcgYSBjb250ZXh0LCBpbnN0YW50aWF0aW5nIGEgbmV3IG1vZGVsIGluc3RhbmNlIHdpdGggdGhlIGtleSwgYW5kIGVuZm9yY2luZyBhbnkgZGVjb3JhdG9yc1xuICAgKiB0aGF0IHNob3VsZCBiZSBhcHBsaWVkIGJlZm9yZSByZWFkaW5nLlxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IC0gVGhlIHByaW1hcnkga2V5IG9mIHRoZSBtb2RlbCB0byByZWFkXG4gICAqIEBwYXJhbSB7YW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgdGhlIHJlYWQgb3BlcmF0aW9uXG4gICAqIEByZXR1cm4gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXkgY29udGFpbmluZyB0aGUga2V5IGFuZCBjb250ZXh0IGFyZ3VtZW50c1xuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIHJlYWRQcmVmaXgoa2V5OiBzdHJpbmcsIC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3M8TSwgQywgRj4oXG4gICAgICBPcGVyYXRpb25LZXlzLlJFQUQsXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgYXJnc1xuICAgICk7XG4gICAgY29uc3QgbW9kZWw6IE0gPSBuZXcgdGhpcy5jbGFzcygpO1xuICAgIG1vZGVsW3RoaXMucGtdID0ga2V5IGFzIGFueTtcbiAgICBhd2FpdCBlbmZvcmNlREJEZWNvcmF0b3JzPE0sIHR5cGVvZiB0aGlzLCBhbnksIEYsIEM+KFxuICAgICAgdGhpcyxcbiAgICAgIGNvbnRleHRBcmdzLmNvbnRleHQsXG4gICAgICBtb2RlbCxcbiAgICAgIE9wZXJhdGlvbktleXMuUkVBRCxcbiAgICAgIE9wZXJhdGlvbktleXMuT05cbiAgICApO1xuICAgIHJldHVybiBba2V5LCAuLi5jb250ZXh0QXJncy5hcmdzXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJlcGFyZXMgZm9yIHJlYWRpbmcgbXVsdGlwbGUgbW9kZWxzIGFuZCBleGVjdXRlcyBwcmUtcmVhZCBvcGVyYXRpb25zLlxuICAgKiBAc3VtbWFyeSBQcm9jZXNzZXMgbXVsdGlwbGUga2V5cyBiZWZvcmUgbW9kZWxzIGFyZSByZWFkIGZyb20gdGhlIGRhdGEgc3RvcmUuIFRoaXMgaW5jbHVkZXNcbiAgICogY3JlYXRpbmcgYSBjb250ZXh0LCBpbnN0YW50aWF0aW5nIG5ldyBtb2RlbCBpbnN0YW5jZXMgd2l0aCB0aGUga2V5cywgYW5kIGVuZm9yY2luZyBhbnkgZGVjb3JhdG9yc1xuICAgKiB0aGF0IHNob3VsZCBiZSBhcHBsaWVkIGJlZm9yZSByZWFkaW5nIGZvciBlYWNoIGtleS5cbiAgICogQHBhcmFtIHtzdHJpbmdbXSB8IG51bWJlcltdfSBrZXlzIC0gVGhlIGFycmF5IG9mIHByaW1hcnkga2V5cyBvZiB0aGUgbW9kZWxzIHRvIHJlYWRcbiAgICogQHBhcmFtIHthbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciB0aGUgcmVhZCBvcGVyYXRpb25cbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheSBjb250YWluaW5nIHRoZSBrZXlzIGFuZCBjb250ZXh0IGFyZ3VtZW50c1xuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIHJlYWRBbGxQcmVmaXgoa2V5czogc3RyaW5nW10gfCBudW1iZXJbXSwgLi4uYXJnczogYW55W10pIHtcbiAgICBjb25zdCBjb250ZXh0QXJncyA9IGF3YWl0IENvbnRleHQuYXJnczxNLCBDLCBGPihcbiAgICAgIE9wZXJhdGlvbktleXMuUkVBRCxcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBhcmdzXG4gICAgKTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIGtleXMubWFwKGFzeW5jIChrKSA9PiB7XG4gICAgICAgIGNvbnN0IG0gPSBuZXcgdGhpcy5jbGFzcygpO1xuICAgICAgICBtW3RoaXMucGtdID0gayBhcyBhbnk7XG4gICAgICAgIHJldHVybiBlbmZvcmNlREJEZWNvcmF0b3JzPE0sIHR5cGVvZiB0aGlzLCBhbnksIEYsIEM+KFxuICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgY29udGV4dEFyZ3MuY29udGV4dCxcbiAgICAgICAgICBtLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuUkVBRCxcbiAgICAgICAgICBPcGVyYXRpb25LZXlzLk9OXG4gICAgICAgICk7XG4gICAgICB9KVxuICAgICk7XG4gICAgcmV0dXJuIFtrZXlzLCAuLi5jb250ZXh0QXJncy5hcmdzXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJvY2Vzc2VzIG11bHRpcGxlIG1vZGVscyBhZnRlciByZXRyaWV2YWwgYW5kIGV4ZWN1dGVzIHBvc3QtcmVhZCBvcGVyYXRpb25zLlxuICAgKiBAc3VtbWFyeSBGaW5hbGl6ZXMgbXVsdGlwbGUgbW9kZWxzIGFmdGVyIHRoZXkgaGF2ZSBiZWVuIHJldHJpZXZlZCBmcm9tIHRoZSBkYXRhIHN0b3JlLiBUaGlzIGluY2x1ZGVzXG4gICAqIGVuZm9yY2luZyBhbnkgZGVjb3JhdG9ycyB0aGF0IHNob3VsZCBiZSBhcHBsaWVkIGFmdGVyIHJlYWRpbmcgZm9yIGVhY2ggbW9kZWwuXG4gICAqIEBwYXJhbSB7TVtdfSBtb2RlbHMgLSBUaGUgYXJyYXkgb2YgbW9kZWwgaW5zdGFuY2VzIHRoYXQgd2VyZSByZXRyaWV2ZWRcbiAgICogQHBhcmFtIHtDfSBjb250ZXh0IC0gVGhlIGNvbnRleHQgZm9yIHRoZSBvcGVyYXRpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTxNW10+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgYXJyYXkgb2YgcHJvY2Vzc2VkIG1vZGVsIGluc3RhbmNlc1xuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIHJlYWRBbGxTdWZmaXgobW9kZWxzOiBNW10sIGNvbnRleHQ6IEMpIHtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIG1vZGVscy5tYXAoKG0pID0+XG4gICAgICAgIGVuZm9yY2VEQkRlY29yYXRvcnM8TSwgdHlwZW9mIHRoaXMsIGFueSwgRiwgQz4oXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICBjb250ZXh0LFxuICAgICAgICAgIG0sXG4gICAgICAgICAgT3BlcmF0aW9uS2V5cy5SRUFELFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuQUZURVJcbiAgICAgICAgKVxuICAgICAgKVxuICAgICk7XG4gICAgcmV0dXJuIG1vZGVscztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVXBkYXRlcyBhbiBleGlzdGluZyBtb2RlbCBpbnN0YW5jZSBpbiB0aGUgcmVwb3NpdG9yeS5cbiAgICogQHN1bW1hcnkgVXBkYXRlcyBhbiBleGlzdGluZyBtb2RlbCBpbnN0YW5jZSBpbiB0aGUgdW5kZXJseWluZyBkYXRhIHN0b3JlLlxuICAgKiBUaGlzIG1ldGhvZCBtdXN0IGJlIGltcGxlbWVudGVkIGJ5IGNvbmNyZXRlIHJlcG9zaXRvcnkgY2xhc3Nlcy5cbiAgICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZSB0byB1cGRhdGVcbiAgICogQHBhcmFtIHthbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciB0aGUgdXBkYXRlIG9wZXJhdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE0+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgdXBkYXRlZCBtb2RlbCBpbnN0YW5jZVxuICAgKi9cbiAgYWJzdHJhY3QgdXBkYXRlKG1vZGVsOiBNLCAuLi5hcmdzOiBhbnlbXSk6IFByb21pc2U8TT47XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIG11bHRpcGxlIG1vZGVsIGluc3RhbmNlcyBpbiB0aGUgcmVwb3NpdG9yeS5cbiAgICogQHN1bW1hcnkgVXBkYXRlcyBtdWx0aXBsZSBtb2RlbCBpbnN0YW5jZXMgaW4gdGhlIHVuZGVybHlpbmcgZGF0YSBzdG9yZSBieSBjYWxsaW5nXG4gICAqIHRoZSB1cGRhdGUgbWV0aG9kIGZvciBlYWNoIG1vZGVsIGluIHRoZSBhcnJheS5cbiAgICogQHBhcmFtIHtNW119IG1vZGVscyAtIFRoZSBhcnJheSBvZiBtb2RlbCBpbnN0YW5jZXMgdG8gdXBkYXRlXG4gICAqIEBwYXJhbSB7YW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgdGhlIHVwZGF0ZSBvcGVyYXRpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTxNW10+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheSBvZiB1cGRhdGVkIG1vZGVsIGluc3RhbmNlc1xuICAgKi9cbiAgYXN5bmMgdXBkYXRlQWxsKG1vZGVsczogTVtdLCAuLi5hcmdzOiBhbnkpOiBQcm9taXNlPE1bXT4ge1xuICAgIHJldHVybiBQcm9taXNlLmFsbChtb2RlbHMubWFwKChtKSA9PiB0aGlzLnVwZGF0ZShtLCAuLi5hcmdzKSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcm9jZXNzZXMgYSBtb2RlbCBhZnRlciB1cGRhdGUgYW5kIGV4ZWN1dGVzIHBvc3QtdXBkYXRlIG9wZXJhdGlvbnMuXG4gICAqIEBzdW1tYXJ5IEZpbmFsaXplcyBhIG1vZGVsIGFmdGVyIGl0IGhhcyBiZWVuIHVwZGF0ZWQgaW4gdGhlIGRhdGEgc3RvcmUuIFRoaXMgaW5jbHVkZXNcbiAgICogZW5mb3JjaW5nIGFueSBkZWNvcmF0b3JzIHRoYXQgc2hvdWxkIGJlIGFwcGxpZWQgYWZ0ZXIgdXBkYXRpbmcuXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2UgdGhhdCB3YXMgdXBkYXRlZFxuICAgKiBAcGFyYW0ge0N9IGNvbnRleHQgLSBUaGUgY29udGV4dCBmb3IgdGhlIG9wZXJhdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE0+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcHJvY2Vzc2VkIG1vZGVsIGluc3RhbmNlXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgdXBkYXRlU3VmZml4KG1vZGVsOiBNLCBjb250ZXh0OiBDKSB7XG4gICAgYXdhaXQgZW5mb3JjZURCRGVjb3JhdG9yczxNLCB0eXBlb2YgdGhpcywgYW55LCBGLCBDPihcbiAgICAgIHRoaXMsXG4gICAgICBjb250ZXh0LFxuICAgICAgbW9kZWwsXG4gICAgICBPcGVyYXRpb25LZXlzLlVQREFURSxcbiAgICAgIE9wZXJhdGlvbktleXMuQUZURVJcbiAgICApO1xuICAgIHJldHVybiBtb2RlbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJlcGFyZXMgYSBtb2RlbCBmb3IgdXBkYXRlIGFuZCBleGVjdXRlcyBwcmUtdXBkYXRlIG9wZXJhdGlvbnMuXG4gICAqIEBzdW1tYXJ5IFByb2Nlc3NlcyBhIG1vZGVsIGJlZm9yZSBpdCBpcyB1cGRhdGVkIGluIHRoZSBkYXRhIHN0b3JlLiBUaGlzIGluY2x1ZGVzXG4gICAqIGNyZWF0aW5nIGEgY29udGV4dCwgdmFsaWRhdGluZyB0aGUgcHJpbWFyeSBrZXksIHJldHJpZXZpbmcgdGhlIGV4aXN0aW5nIG1vZGVsLFxuICAgKiBhbmQgZW5mb3JjaW5nIGFueSBkZWNvcmF0b3JzIHRoYXQgc2hvdWxkIGJlIGFwcGxpZWQgYmVmb3JlIHVwZGF0aW5nLlxuICAgKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIHRvIHByZXBhcmUgZm9yIHVwZGF0ZVxuICAgKiBAcGFyYW0ge2FueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIHRoZSB1cGRhdGUgb3BlcmF0aW9uXG4gICAqIEByZXR1cm4gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXkgY29udGFpbmluZyB0aGUgcHJlcGFyZWQgbW9kZWwgYW5kIGNvbnRleHQgYXJndW1lbnRzXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgdXBkYXRlUHJlZml4KG1vZGVsOiBNLCAuLi5hcmdzOiBhbnlbXSkge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzPE0sIEMsIEY+KFxuICAgICAgT3BlcmF0aW9uS2V5cy5VUERBVEUsXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgYXJnc1xuICAgICk7XG4gICAgY29uc3QgaWQgPSBtb2RlbFt0aGlzLnBrXTtcbiAgICBpZiAoIWlkKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBObyB2YWx1ZSBmb3IgdGhlIElkIGlzIGRlZmluZWQgdW5kZXIgdGhlIHByb3BlcnR5ICR7dGhpcy5wayBhcyBzdHJpbmd9YFxuICAgICAgKTtcbiAgICBjb25zdCBvbGRNb2RlbCA9IGF3YWl0IHRoaXMucmVhZChpZCBhcyBzdHJpbmcpO1xuICAgIGF3YWl0IGVuZm9yY2VEQkRlY29yYXRvcnM8TSwgdHlwZW9mIHRoaXMsIGFueSwgRiwgQz4oXG4gICAgICB0aGlzLFxuICAgICAgY29udGV4dEFyZ3MuY29udGV4dCxcbiAgICAgIG1vZGVsLFxuICAgICAgT3BlcmF0aW9uS2V5cy5VUERBVEUsXG4gICAgICBPcGVyYXRpb25LZXlzLk9OLFxuICAgICAgb2xkTW9kZWxcbiAgICApO1xuICAgIHJldHVybiBbbW9kZWwsIC4uLmNvbnRleHRBcmdzLmFyZ3NdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcmVwYXJlcyBtdWx0aXBsZSBtb2RlbHMgZm9yIHVwZGF0ZSBhbmQgZXhlY3V0ZXMgcHJlLXVwZGF0ZSBvcGVyYXRpb25zLlxuICAgKiBAc3VtbWFyeSBQcm9jZXNzZXMgbXVsdGlwbGUgbW9kZWxzIGJlZm9yZSB0aGV5IGFyZSB1cGRhdGVkIGluIHRoZSBkYXRhIHN0b3JlLiBUaGlzIGluY2x1ZGVzXG4gICAqIGNyZWF0aW5nIGEgY29udGV4dCwgaW5zdGFudGlhdGluZyBuZXcgbW9kZWwgaW5zdGFuY2VzLCBhbmQgZW5mb3JjaW5nIGFueSBkZWNvcmF0b3JzXG4gICAqIHRoYXQgc2hvdWxkIGJlIGFwcGxpZWQgYmVmb3JlIHVwZGF0aW5nIGZvciBlYWNoIG1vZGVsLlxuICAgKiBAcGFyYW0ge01bXX0gbW9kZWxzIC0gVGhlIGFycmF5IG9mIG1vZGVsIGluc3RhbmNlcyB0byBwcmVwYXJlIGZvciB1cGRhdGVcbiAgICogQHBhcmFtIHthbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciB0aGUgdXBkYXRlIG9wZXJhdGlvblxuICAgKiBAcmV0dXJuIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIHByZXBhcmVkIG1vZGVscyBhbmQgY29udGV4dCBhcmd1bWVudHNcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyB1cGRhdGVBbGxQcmVmaXgobW9kZWxzOiBNW10sIC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3M8TSwgQywgRj4oXG4gICAgICBPcGVyYXRpb25LZXlzLlVQREFURSxcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBhcmdzXG4gICAgKTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIG1vZGVscy5tYXAoKG0pID0+IHtcbiAgICAgICAgbSA9IG5ldyB0aGlzLmNsYXNzKG0pO1xuICAgICAgICBlbmZvcmNlREJEZWNvcmF0b3JzPE0sIHR5cGVvZiB0aGlzLCBhbnksIEYsIEM+KFxuICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgY29udGV4dEFyZ3MuY29udGV4dCxcbiAgICAgICAgICBtLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuVVBEQVRFLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuT05cbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgICB9KVxuICAgICk7XG4gICAgcmV0dXJuIFttb2RlbHMsIC4uLmNvbnRleHRBcmdzLmFyZ3NdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcm9jZXNzZXMgbXVsdGlwbGUgbW9kZWxzIGFmdGVyIHVwZGF0ZSBhbmQgZXhlY3V0ZXMgcG9zdC11cGRhdGUgb3BlcmF0aW9ucy5cbiAgICogQHN1bW1hcnkgRmluYWxpemVzIG11bHRpcGxlIG1vZGVscyBhZnRlciB0aGV5IGhhdmUgYmVlbiB1cGRhdGVkIGluIHRoZSBkYXRhIHN0b3JlLiBUaGlzIGluY2x1ZGVzXG4gICAqIGVuZm9yY2luZyBhbnkgZGVjb3JhdG9ycyB0aGF0IHNob3VsZCBiZSBhcHBsaWVkIGFmdGVyIHVwZGF0aW5nIGZvciBlYWNoIG1vZGVsLlxuICAgKiBAcGFyYW0ge01bXX0gbW9kZWxzIC0gVGhlIGFycmF5IG9mIG1vZGVsIGluc3RhbmNlcyB0aGF0IHdlcmUgdXBkYXRlZFxuICAgKiBAcGFyYW0ge0N9IGNvbnRleHQgLSBUaGUgY29udGV4dCBmb3IgdGhlIG9wZXJhdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1bXT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBhcnJheSBvZiBwcm9jZXNzZWQgbW9kZWwgaW5zdGFuY2VzXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgdXBkYXRlQWxsU3VmZml4KG1vZGVsczogTVtdLCBjb250ZXh0OiBDKSB7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBtb2RlbHMubWFwKChtKSA9PlxuICAgICAgICBlbmZvcmNlREJEZWNvcmF0b3JzPE0sIHR5cGVvZiB0aGlzLCBhbnksIEYsIEM+KFxuICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgY29udGV4dCxcbiAgICAgICAgICBtLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuVVBEQVRFLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuQUZURVJcbiAgICAgICAgKVxuICAgICAgKVxuICAgICk7XG4gICAgcmV0dXJuIG1vZGVscztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVsZXRlcyBhIG1vZGVsIGluc3RhbmNlIGZyb20gdGhlIHJlcG9zaXRvcnkgYnkgaXRzIHByaW1hcnkga2V5LlxuICAgKiBAc3VtbWFyeSBSZW1vdmVzIGEgbW9kZWwgaW5zdGFuY2UgZnJvbSB0aGUgdW5kZXJseWluZyBkYXRhIHN0b3JlIHVzaW5nIGl0cyBwcmltYXJ5IGtleS5cbiAgICogVGhpcyBtZXRob2QgbXVzdCBiZSBpbXBsZW1lbnRlZCBieSBjb25jcmV0ZSByZXBvc2l0b3J5IGNsYXNzZXMuXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgbnVtYmVyfSBrZXkgLSBUaGUgcHJpbWFyeSBrZXkgb2YgdGhlIG1vZGVsIHRvIGRlbGV0ZVxuICAgKiBAcGFyYW0ge2FueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIHRoZSBkZWxldGUgb3BlcmF0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBkZWxldGVkIG1vZGVsIGluc3RhbmNlXG4gICAqL1xuICBhYnN0cmFjdCBkZWxldGUoa2V5OiBzdHJpbmcgfCBudW1iZXIsIC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTxNPjtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIERlbGV0ZXMgbXVsdGlwbGUgbW9kZWwgaW5zdGFuY2VzIGZyb20gdGhlIHJlcG9zaXRvcnkgYnkgdGhlaXIgcHJpbWFyeSBrZXlzLlxuICAgKiBAc3VtbWFyeSBSZW1vdmVzIG11bHRpcGxlIG1vZGVsIGluc3RhbmNlcyBmcm9tIHRoZSB1bmRlcmx5aW5nIGRhdGEgc3RvcmUgdXNpbmcgdGhlaXIgcHJpbWFyeSBrZXlzXG4gICAqIGJ5IGNhbGxpbmcgdGhlIGRlbGV0ZSBtZXRob2QgZm9yIGVhY2gga2V5IGluIHRoZSBhcnJheS5cbiAgICogQHBhcmFtIHtzdHJpbmdbXSB8IG51bWJlcltdfSBrZXlzIC0gVGhlIGFycmF5IG9mIHByaW1hcnkga2V5cyBvZiB0aGUgbW9kZWxzIHRvIGRlbGV0ZVxuICAgKiBAcGFyYW0ge2FueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIHRoZSBkZWxldGUgb3BlcmF0aW9uXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TVtdPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXkgb2YgZGVsZXRlZCBtb2RlbCBpbnN0YW5jZXNcbiAgICovXG4gIGFzeW5jIGRlbGV0ZUFsbChrZXlzOiBzdHJpbmdbXSB8IG51bWJlcltdLCAuLi5hcmdzOiBhbnlbXSk6IFByb21pc2U8TVtdPiB7XG4gICAgcmV0dXJuIFByb21pc2UuYWxsKGtleXMubWFwKChrKSA9PiB0aGlzLmRlbGV0ZShrLCAuLi5hcmdzKSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcm9jZXNzZXMgYSBtb2RlbCBhZnRlciBkZWxldGlvbiBhbmQgZXhlY3V0ZXMgcG9zdC1kZWxldGUgb3BlcmF0aW9ucy5cbiAgICogQHN1bW1hcnkgRmluYWxpemVzIGEgbW9kZWwgYWZ0ZXIgaXQgaGFzIGJlZW4gZGVsZXRlZCBmcm9tIHRoZSBkYXRhIHN0b3JlLiBUaGlzIGluY2x1ZGVzXG4gICAqIGVuZm9yY2luZyBhbnkgZGVjb3JhdG9ycyB0aGF0IHNob3VsZCBiZSBhcHBsaWVkIGFmdGVyIGRlbGV0aW9uLlxuICAgKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIHRoYXQgd2FzIGRlbGV0ZWRcbiAgICogQHBhcmFtIHtDfSBjb250ZXh0IC0gVGhlIGNvbnRleHQgZm9yIHRoZSBvcGVyYXRpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTxNPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHByb2Nlc3NlZCBtb2RlbCBpbnN0YW5jZVxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGRlbGV0ZVN1ZmZpeChtb2RlbDogTSwgY29udGV4dDogQykge1xuICAgIGF3YWl0IGVuZm9yY2VEQkRlY29yYXRvcnM8TSwgdHlwZW9mIHRoaXMsIGFueSwgRiwgQz4oXG4gICAgICB0aGlzLFxuICAgICAgY29udGV4dCxcbiAgICAgIG1vZGVsLFxuICAgICAgT3BlcmF0aW9uS2V5cy5ERUxFVEUsXG4gICAgICBPcGVyYXRpb25LZXlzLkFGVEVSXG4gICAgKTtcbiAgICByZXR1cm4gbW9kZWw7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIGZvciBkZWxldGluZyBhIG1vZGVsIGFuZCBleGVjdXRlcyBwcmUtZGVsZXRlIG9wZXJhdGlvbnMuXG4gICAqIEBzdW1tYXJ5IFByb2Nlc3NlcyBhIGtleSBiZWZvcmUgYSBtb2RlbCBpcyBkZWxldGVkIGZyb20gdGhlIGRhdGEgc3RvcmUuIFRoaXMgaW5jbHVkZXNcbiAgICogY3JlYXRpbmcgYSBjb250ZXh0LCByZXRyaWV2aW5nIHRoZSBtb2RlbCB0byBiZSBkZWxldGVkLCBhbmQgZW5mb3JjaW5nIGFueSBkZWNvcmF0b3JzXG4gICAqIHRoYXQgc2hvdWxkIGJlIGFwcGxpZWQgYmVmb3JlIGRlbGV0aW9uLlxuICAgKiBAcGFyYW0ge2FueX0ga2V5IC0gVGhlIHByaW1hcnkga2V5IG9mIHRoZSBtb2RlbCB0byBkZWxldGVcbiAgICogQHBhcmFtIHthbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciB0aGUgZGVsZXRlIG9wZXJhdGlvblxuICAgKiBAcmV0dXJuIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIGtleSBhbmQgY29udGV4dCBhcmd1bWVudHNcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBkZWxldGVQcmVmaXgoa2V5OiBhbnksIC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3M8TSwgQywgRj4oXG4gICAgICBPcGVyYXRpb25LZXlzLkRFTEVURSxcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBhcmdzXG4gICAgKTtcbiAgICBjb25zdCBtb2RlbCA9IGF3YWl0IHRoaXMucmVhZChrZXksIC4uLmNvbnRleHRBcmdzLmFyZ3MpO1xuICAgIGF3YWl0IGVuZm9yY2VEQkRlY29yYXRvcnM8TSwgdHlwZW9mIHRoaXMsIGFueSwgRiwgQz4oXG4gICAgICB0aGlzLFxuICAgICAgY29udGV4dEFyZ3MuY29udGV4dCxcbiAgICAgIG1vZGVsLFxuICAgICAgT3BlcmF0aW9uS2V5cy5ERUxFVEUsXG4gICAgICBPcGVyYXRpb25LZXlzLk9OXG4gICAgKTtcbiAgICByZXR1cm4gW2tleSwgLi4uY29udGV4dEFyZ3MuYXJnc107XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIGZvciBkZWxldGluZyBtdWx0aXBsZSBtb2RlbHMgYW5kIGV4ZWN1dGVzIHByZS1kZWxldGUgb3BlcmF0aW9ucy5cbiAgICogQHN1bW1hcnkgUHJvY2Vzc2VzIG11bHRpcGxlIGtleXMgYmVmb3JlIG1vZGVscyBhcmUgZGVsZXRlZCBmcm9tIHRoZSBkYXRhIHN0b3JlLiBUaGlzIGluY2x1ZGVzXG4gICAqIGNyZWF0aW5nIGEgY29udGV4dCwgcmV0cmlldmluZyB0aGUgbW9kZWxzIHRvIGJlIGRlbGV0ZWQsIGFuZCBlbmZvcmNpbmcgYW55IGRlY29yYXRvcnNcbiAgICogdGhhdCBzaG91bGQgYmUgYXBwbGllZCBiZWZvcmUgZGVsZXRpb24gZm9yIGVhY2ggbW9kZWwuXG4gICAqIEBwYXJhbSB7c3RyaW5nW10gfCBudW1iZXJbXX0ga2V5cyAtIFRoZSBhcnJheSBvZiBwcmltYXJ5IGtleXMgb2YgdGhlIG1vZGVscyB0byBkZWxldGVcbiAgICogQHBhcmFtIHthbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciB0aGUgZGVsZXRlIG9wZXJhdGlvblxuICAgKiBAcmV0dXJuIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIGtleXMgYW5kIGNvbnRleHQgYXJndW1lbnRzXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZGVsZXRlQWxsUHJlZml4KGtleXM6IHN0cmluZ1tdIHwgbnVtYmVyW10sIC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3M8TSwgQywgRj4oXG4gICAgICBPcGVyYXRpb25LZXlzLkRFTEVURSxcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBhcmdzXG4gICAgKTtcbiAgICBjb25zdCBtb2RlbHMgPSBhd2FpdCB0aGlzLnJlYWRBbGwoa2V5cywgLi4uY29udGV4dEFyZ3MuYXJncyk7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICBtb2RlbHMubWFwKGFzeW5jIChtKSA9PiB7XG4gICAgICAgIHJldHVybiBlbmZvcmNlREJEZWNvcmF0b3JzPE0sIHR5cGVvZiB0aGlzLCBhbnksIEYsIEM+KFxuICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgY29udGV4dEFyZ3MuY29udGV4dCxcbiAgICAgICAgICBtLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuREVMRVRFLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuT05cbiAgICAgICAgKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgICByZXR1cm4gW2tleXMsIC4uLmNvbnRleHRBcmdzLmFyZ3NdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcm9jZXNzZXMgbXVsdGlwbGUgbW9kZWxzIGFmdGVyIGRlbGV0aW9uIGFuZCBleGVjdXRlcyBwb3N0LWRlbGV0ZSBvcGVyYXRpb25zLlxuICAgKiBAc3VtbWFyeSBGaW5hbGl6ZXMgbXVsdGlwbGUgbW9kZWxzIGFmdGVyIHRoZXkgaGF2ZSBiZWVuIGRlbGV0ZWQgZnJvbSB0aGUgZGF0YSBzdG9yZS4gVGhpcyBpbmNsdWRlc1xuICAgKiBlbmZvcmNpbmcgYW55IGRlY29yYXRvcnMgdGhhdCBzaG91bGQgYmUgYXBwbGllZCBhZnRlciBkZWxldGlvbiBmb3IgZWFjaCBtb2RlbC5cbiAgICogQHBhcmFtIHtNW119IG1vZGVscyAtIFRoZSBhcnJheSBvZiBtb2RlbCBpbnN0YW5jZXMgdGhhdCB3ZXJlIGRlbGV0ZWRcbiAgICogQHBhcmFtIHtDfSBjb250ZXh0IC0gVGhlIGNvbnRleHQgZm9yIHRoZSBvcGVyYXRpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTxNW10+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgYXJyYXkgb2YgcHJvY2Vzc2VkIG1vZGVsIGluc3RhbmNlc1xuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGRlbGV0ZUFsbFN1ZmZpeChtb2RlbHM6IE1bXSwgY29udGV4dDogQykge1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgbW9kZWxzLm1hcCgobSkgPT5cbiAgICAgICAgZW5mb3JjZURCRGVjb3JhdG9yczxNLCB0eXBlb2YgdGhpcywgYW55LCBGLCBDPihcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgIGNvbnRleHQsXG4gICAgICAgICAgbSxcbiAgICAgICAgICBPcGVyYXRpb25LZXlzLkRFTEVURSxcbiAgICAgICAgICBPcGVyYXRpb25LZXlzLkFGVEVSXG4gICAgICAgIClcbiAgICAgIClcbiAgICApO1xuICAgIHJldHVybiBtb2RlbHM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIE1lcmdlcyB0d28gbW9kZWwgaW5zdGFuY2VzIGludG8gYSBuZXcgaW5zdGFuY2UuXG4gICAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBuZXcgbW9kZWwgaW5zdGFuY2UgYnkgY29tYmluaW5nIHByb3BlcnRpZXMgZnJvbSBhbiBvbGQgbW9kZWwgYW5kIGEgbmV3IG1vZGVsLlxuICAgKiBQcm9wZXJ0aWVzIGZyb20gdGhlIG5ldyBtb2RlbCBvdmVycmlkZSBwcm9wZXJ0aWVzIGZyb20gdGhlIG9sZCBtb2RlbCBpZiB0aGV5IGFyZSBkZWZpbmVkLlxuICAgKiBAcGFyYW0ge019IG9sZE1vZGVsIC0gVGhlIG9yaWdpbmFsIG1vZGVsIGluc3RhbmNlXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbmV3IG1vZGVsIGluc3RhbmNlIHdpdGggdXBkYXRlZCBwcm9wZXJ0aWVzXG4gICAqIEByZXR1cm4ge019IEEgbmV3IG1vZGVsIGluc3RhbmNlIHdpdGggbWVyZ2VkIHByb3BlcnRpZXNcbiAgICovXG4gIHByb3RlY3RlZCBtZXJnZShvbGRNb2RlbDogTSwgbW9kZWw6IE0pOiBNIHtcbiAgICBjb25zdCBleHRyYWN0ID0gKG1vZGVsOiBNKSA9PlxuICAgICAgT2JqZWN0LmVudHJpZXMobW9kZWwpLnJlZHVjZSgoYWNjdW06IFJlY29yZDxzdHJpbmcsIGFueT4sIFtrZXksIHZhbF0pID0+IHtcbiAgICAgICAgaWYgKHR5cGVvZiB2YWwgIT09IFwidW5kZWZpbmVkXCIpIGFjY3VtW2tleV0gPSB2YWw7XG4gICAgICAgIHJldHVybiBhY2N1bTtcbiAgICAgIH0sIHt9KTtcblxuICAgIHJldHVybiBuZXcgdGhpcy5jbGFzcyhPYmplY3QuYXNzaWduKHt9LCBleHRyYWN0KG9sZE1vZGVsKSwgZXh0cmFjdChtb2RlbCkpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmV0dXJucyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgcmVwb3NpdG9yeS5cbiAgICogQHN1bW1hcnkgQ3JlYXRlcyBhIHN0cmluZyB0aGF0IGlkZW50aWZpZXMgdGhpcyByZXBvc2l0b3J5IGJ5IHRoZSBuYW1lIG9mIGl0cyBtb2RlbCBjbGFzcy5cbiAgICogQHJldHVybiB7c3RyaW5nfSBBIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgcmVwb3NpdG9yeVxuICAgKi9cbiAgdG9TdHJpbmcoKSB7XG4gICAgcmV0dXJuIGAke3RoaXMuY2xhc3MubmFtZX0gUmVwb3NpdG9yeWA7XG4gIH1cbn1cbiIsImltcG9ydCB7IGVuZm9yY2VEQkRlY29yYXRvcnMgfSBmcm9tIFwiLi91dGlsc1wiO1xuaW1wb3J0IHsgT3BlcmF0aW9uS2V5cyB9IGZyb20gXCIuLi9vcGVyYXRpb25zL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgSW50ZXJuYWxFcnJvciwgVmFsaWRhdGlvbkVycm9yIH0gZnJvbSBcIi4vZXJyb3JzXCI7XG5pbXBvcnQgeyBCYXNlUmVwb3NpdG9yeSB9IGZyb20gXCIuL0Jhc2VSZXBvc2l0b3J5XCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBEQktleXMgfSBmcm9tIFwiLi4vbW9kZWwvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBDb250ZXh0IH0gZnJvbSBcIi4vQ29udGV4dFwiO1xuaW1wb3J0IHsgUmVwb3NpdG9yeUZsYWdzIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ29uY3JldGUgcmVwb3NpdG9yeSBpbXBsZW1lbnRhdGlvbiB3aXRoIHZhbGlkYXRpb24gc3VwcG9ydC5cbiAqIEBzdW1tYXJ5IFRoZSBSZXBvc2l0b3J5IGNsYXNzIGV4dGVuZHMgQmFzZVJlcG9zaXRvcnkgdG8gcHJvdmlkZSBhZGRpdGlvbmFsIHZhbGlkYXRpb25cbiAqIGZ1bmN0aW9uYWxpdHkuIEl0IG92ZXJyaWRlcyBwcmVmaXggbWV0aG9kcyB0byBwZXJmb3JtIG1vZGVsIHZhbGlkYXRpb24gYmVmb3JlIGRhdGFiYXNlXG4gKiBvcGVyYXRpb25zIGFuZCB0aHJvd3MgVmFsaWRhdGlvbkVycm9yIHdoZW4gdmFsaWRhdGlvbiBmYWlscy5cbiAqIEB0ZW1wbGF0ZSBNIC0gVGhlIG1vZGVsIHR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgRiAtIFRoZSByZXBvc2l0b3J5IGZsYWdzIHR5cGUsIGRlZmF1bHRzIHRvIFJlcG9zaXRvcnlGbGFnc1xuICogQHRlbXBsYXRlIEMgLSBUaGUgY29udGV4dCB0eXBlLCBkZWZhdWx0cyB0byBDb250ZXh0PEY+XG4gKiBAY2xhc3MgUmVwb3NpdG9yeVxuICogQGV4YW1wbGVcbiAqIGNsYXNzIFVzZXJNb2RlbCBleHRlbmRzIE1vZGVsIHtcbiAqICAgQGlkKClcbiAqICAgaWQ6IHN0cmluZztcbiAqXG4gKiAgIEByZXF1aXJlZCgpXG4gKiAgIEBtaW5MZW5ndGgoMylcbiAqICAgbmFtZTogc3RyaW5nO1xuICogfVxuICpcbiAqIGNsYXNzIFVzZXJSZXBvc2l0b3J5IGV4dGVuZHMgUmVwb3NpdG9yeTxVc2VyTW9kZWw+IHtcbiAqICAgY29uc3RydWN0b3IoKSB7XG4gKiAgICAgc3VwZXIoVXNlck1vZGVsKTtcbiAqICAgfVxuICpcbiAqICAgYXN5bmMgY3JlYXRlKG1vZGVsOiBVc2VyTW9kZWwpOiBQcm9taXNlPFVzZXJNb2RlbD4ge1xuICogICAgIC8vIEltcGxlbWVudGF0aW9uIHdpdGggYXV0b21hdGljIHZhbGlkYXRpb25cbiAqICAgICByZXR1cm4gbW9kZWw7XG4gKiAgIH1cbiAqIH1cbiAqXG4gKiAvLyBVc2luZyB0aGUgcmVwb3NpdG9yeVxuICogY29uc3QgcmVwbyA9IG5ldyBVc2VyUmVwb3NpdG9yeSgpO1xuICogdHJ5IHtcbiAqICAgY29uc3QgdXNlciA9IGF3YWl0IHJlcG8uY3JlYXRlKHsgbmFtZTogJ0pvJyB9KTsgLy8gV2lsbCB0aHJvdyBWYWxpZGF0aW9uRXJyb3JcbiAqIH0gY2F0Y2ggKGVycm9yKSB7XG4gKiAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpOyAvLyBWYWxpZGF0aW9uRXJyb3I6IG5hbWUgbXVzdCBiZSBhdCBsZWFzdCAzIGNoYXJhY3RlcnNcbiAqIH1cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFJlcG9zaXRvcnk8XG4gIE0gZXh0ZW5kcyBNb2RlbDxib29sZWFuPixcbiAgRiBleHRlbmRzIFJlcG9zaXRvcnlGbGFncyA9IFJlcG9zaXRvcnlGbGFncyxcbiAgQyBleHRlbmRzIENvbnRleHQ8Rj4gPSBDb250ZXh0PEY+LFxuPiBleHRlbmRzIEJhc2VSZXBvc2l0b3J5PE0sIEYsIEM+IHtcbiAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKGNsYXp6PzogQ29uc3RydWN0b3I8TT4pIHtcbiAgICBzdXBlcihjbGF6eik7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIGEgbW9kZWwgZm9yIGNyZWF0aW9uIHdpdGggdmFsaWRhdGlvbi5cbiAgICogQHN1bW1hcnkgT3ZlcnJpZGVzIHRoZSBiYXNlIGNyZWF0ZVByZWZpeCBtZXRob2QgdG8gYWRkIHZhbGlkYXRpb24gY2hlY2tzLlxuICAgKiBDcmVhdGVzIGEgY29udGV4dCwgaW5zdGFudGlhdGVzIGEgbmV3IG1vZGVsLCBlbmZvcmNlcyBkZWNvcmF0b3JzLCBhbmQgdmFsaWRhdGVzXG4gICAqIHRoZSBtb2RlbCBiZWZvcmUgYWxsb3dpbmcgY3JlYXRpb24gdG8gcHJvY2VlZC5cbiAgICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZSB0byBwcmVwYXJlIGZvciBjcmVhdGlvblxuICAgKiBAcGFyYW0ge2FueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIHRoZSBjcmVhdGUgb3BlcmF0aW9uXG4gICAqIEByZXR1cm4gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXkgY29udGFpbmluZyB0aGUgdmFsaWRhdGVkIG1vZGVsIGFuZCBjb250ZXh0IGFyZ3VtZW50c1xuICAgKiBAdGhyb3dzIHtWYWxpZGF0aW9uRXJyb3J9IElmIHRoZSBtb2RlbCBmYWlscyB2YWxpZGF0aW9uXG4gICAqL1xuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlUHJlZml4KFxuICAgIG1vZGVsOiBNLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8W00sIC4uLmFueVtdXT4ge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzKFxuICAgICAgT3BlcmF0aW9uS2V5cy5DUkVBVEUsXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgYXJnc1xuICAgICk7XG4gICAgbW9kZWwgPSBuZXcgdGhpcy5jbGFzcyhtb2RlbCk7XG4gICAgYXdhaXQgZW5mb3JjZURCRGVjb3JhdG9ycyhcbiAgICAgIHRoaXMsXG4gICAgICBjb250ZXh0QXJncy5jb250ZXh0LFxuICAgICAgbW9kZWwsXG4gICAgICBPcGVyYXRpb25LZXlzLkNSRUFURSxcbiAgICAgIE9wZXJhdGlvbktleXMuT05cbiAgICApO1xuXG4gICAgY29uc3QgZXJyb3JzID0gYXdhaXQgUHJvbWlzZS5yZXNvbHZlKG1vZGVsLmhhc0Vycm9ycygpKTtcbiAgICBpZiAoZXJyb3JzKSB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKGVycm9ycy50b1N0cmluZygpKTtcblxuICAgIHJldHVybiBbbW9kZWwsIC4uLmNvbnRleHRBcmdzLmFyZ3NdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcmVwYXJlcyBtdWx0aXBsZSBtb2RlbHMgZm9yIGNyZWF0aW9uIHdpdGggdmFsaWRhdGlvbi5cbiAgICogQHN1bW1hcnkgT3ZlcnJpZGVzIHRoZSBiYXNlIGNyZWF0ZUFsbFByZWZpeCBtZXRob2QgdG8gYWRkIHZhbGlkYXRpb24gY2hlY2tzIGZvciBtdWx0aXBsZSBtb2RlbHMuXG4gICAqIENyZWF0ZXMgYSBjb250ZXh0LCBpbnN0YW50aWF0ZXMgbmV3IG1vZGVscywgZW5mb3JjZXMgZGVjb3JhdG9ycywgYW5kIHZhbGlkYXRlc1xuICAgKiBlYWNoIG1vZGVsIGJlZm9yZSBhbGxvd2luZyBjcmVhdGlvbiB0byBwcm9jZWVkLiBDb2xsZWN0cyB2YWxpZGF0aW9uIGVycm9ycyBmcm9tIGFsbCBtb2RlbHMuXG4gICAqIEBwYXJhbSB7TVtdfSBtb2RlbHMgLSBUaGUgYXJyYXkgb2YgbW9kZWwgaW5zdGFuY2VzIHRvIHByZXBhcmUgZm9yIGNyZWF0aW9uXG4gICAqIEBwYXJhbSB7YW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgdGhlIGNyZWF0ZSBvcGVyYXRpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTxhbnlbXT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIHZhbGlkYXRlZCBtb2RlbHMgYW5kIGNvbnRleHQgYXJndW1lbnRzXG4gICAqIEB0aHJvd3Mge1ZhbGlkYXRpb25FcnJvcn0gSWYgYW55IG1vZGVsIGZhaWxzIHZhbGlkYXRpb24sIHdpdGggZGV0YWlscyBhYm91dCB3aGljaCBtb2RlbHMgZmFpbGVkXG4gICAqL1xuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlQWxsUHJlZml4KFxuICAgIG1vZGVsczogTVtdLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8YW55W10+IHtcbiAgICBjb25zdCBjb250ZXh0QXJncyA9IGF3YWl0IENvbnRleHQuYXJncyhcbiAgICAgIE9wZXJhdGlvbktleXMuQ1JFQVRFLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIGFyZ3NcbiAgICApO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgbW9kZWxzLm1hcChhc3luYyAobSkgPT4ge1xuICAgICAgICBtID0gbmV3IHRoaXMuY2xhc3MobSk7XG4gICAgICAgIGF3YWl0IGVuZm9yY2VEQkRlY29yYXRvcnMoXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICBjb250ZXh0QXJncy5jb250ZXh0LFxuICAgICAgICAgIG0sXG4gICAgICAgICAgT3BlcmF0aW9uS2V5cy5DUkVBVEUsXG4gICAgICAgICAgT3BlcmF0aW9uS2V5cy5PTlxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gbTtcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIGNvbnN0IG1vZGVsc1ZhbGlkYXRpb24gPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIG1vZGVscy5tYXAoKG0pID0+IFByb21pc2UucmVzb2x2ZShtLmhhc0Vycm9ycygpKSlcbiAgICApO1xuXG4gICAgY29uc3QgZXJyb3JzID0gbW9kZWxzVmFsaWRhdGlvbi5yZWR1Y2UoXG4gICAgICAoYWNjdW06IHN0cmluZyB8IHVuZGVmaW5lZCwgZSwgaSkgPT4ge1xuICAgICAgICBpZiAoZSlcbiAgICAgICAgICBhY2N1bSA9XG4gICAgICAgICAgICB0eXBlb2YgYWNjdW0gPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgICAgPyBhY2N1bSArIGBcXG4gLSAke2l9OiAke2UudG9TdHJpbmcoKX1gXG4gICAgICAgICAgICAgIDogYCAtICR7aX06ICR7ZS50b1N0cmluZygpfWA7XG4gICAgICAgIHJldHVybiBhY2N1bTtcbiAgICAgIH0sXG4gICAgICB1bmRlZmluZWRcbiAgICApO1xuXG4gICAgaWYgKGVycm9ycykgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihlcnJvcnMpO1xuICAgIHJldHVybiBbbW9kZWxzLCAuLi5jb250ZXh0QXJncy5hcmdzXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUHJlcGFyZXMgYSBtb2RlbCBmb3IgdXBkYXRlIHdpdGggdmFsaWRhdGlvbi5cbiAgICogQHN1bW1hcnkgT3ZlcnJpZGVzIHRoZSBiYXNlIHVwZGF0ZVByZWZpeCBtZXRob2QgdG8gYWRkIHZhbGlkYXRpb24gY2hlY2tzLlxuICAgKiBDcmVhdGVzIGEgY29udGV4dCwgdmFsaWRhdGVzIHRoZSBwcmltYXJ5IGtleSwgcmV0cmlldmVzIHRoZSBleGlzdGluZyBtb2RlbCxcbiAgICogbWVyZ2VzIHRoZSBvbGQgYW5kIG5ldyBtb2RlbHMsIGVuZm9yY2VzIGRlY29yYXRvcnMsIGFuZCB2YWxpZGF0ZXMgdGhlIG1vZGVsXG4gICAqIGJlZm9yZSBhbGxvd2luZyB0aGUgdXBkYXRlIHRvIHByb2NlZWQuXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2UgdG8gcHJlcGFyZSBmb3IgdXBkYXRlXG4gICAqIEBwYXJhbSB7YW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgdGhlIHVwZGF0ZSBvcGVyYXRpb25cbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheSBjb250YWluaW5nIHRoZSB2YWxpZGF0ZWQgbW9kZWwgYW5kIGNvbnRleHQgYXJndW1lbnRzXG4gICAqIEB0aHJvd3Mge0ludGVybmFsRXJyb3J9IElmIHRoZSBtb2RlbCBkb2Vzbid0IGhhdmUgYSBwcmltYXJ5IGtleSB2YWx1ZVxuICAgKiBAdGhyb3dzIHtWYWxpZGF0aW9uRXJyb3J9IElmIHRoZSBtb2RlbCBmYWlscyB2YWxpZGF0aW9uXG4gICAqL1xuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgdXBkYXRlUHJlZml4KFxuICAgIG1vZGVsOiBNLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8W00sIC4uLmFyZ3M6IGFueVtdXT4ge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzKFxuICAgICAgT3BlcmF0aW9uS2V5cy5VUERBVEUsXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgYXJnc1xuICAgICk7XG4gICAgY29uc3QgcGsgPSAobW9kZWwgYXMgYW55KVt0aGlzLnBrXTtcbiAgICBpZiAoIXBrKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBObyB2YWx1ZSBmb3IgdGhlIElkIGlzIGRlZmluZWQgdW5kZXIgdGhlIHByb3BlcnR5ICR7dGhpcy5wayBhcyBzdHJpbmd9YFxuICAgICAgKTtcblxuICAgIGNvbnN0IG9sZE1vZGVsOiBNID0gYXdhaXQgdGhpcy5yZWFkKHBrKTtcblxuICAgIG1vZGVsID0gdGhpcy5tZXJnZShvbGRNb2RlbCwgbW9kZWwpO1xuXG4gICAgYXdhaXQgZW5mb3JjZURCRGVjb3JhdG9ycyhcbiAgICAgIHRoaXMsXG4gICAgICBjb250ZXh0QXJncy5jb250ZXh0LFxuICAgICAgbW9kZWwsXG4gICAgICBPcGVyYXRpb25LZXlzLlVQREFURSxcbiAgICAgIE9wZXJhdGlvbktleXMuT04sXG4gICAgICBvbGRNb2RlbFxuICAgICk7XG5cbiAgICBjb25zdCBlcnJvcnMgPSBhd2FpdCBQcm9taXNlLnJlc29sdmUobW9kZWwuaGFzRXJyb3JzKG9sZE1vZGVsIGFzIGFueSkpO1xuICAgIGlmIChlcnJvcnMpIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoZXJyb3JzLnRvU3RyaW5nKCkpO1xuICAgIHJldHVybiBbbW9kZWwsIC4uLmNvbnRleHRBcmdzLmFyZ3NdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcmVwYXJlcyBtdWx0aXBsZSBtb2RlbHMgZm9yIHVwZGF0ZSB3aXRoIHZhbGlkYXRpb24uXG4gICAqIEBzdW1tYXJ5IE92ZXJyaWRlcyB0aGUgYmFzZSB1cGRhdGVBbGxQcmVmaXggbWV0aG9kIHRvIGFkZCB2YWxpZGF0aW9uIGNoZWNrcyBmb3IgbXVsdGlwbGUgbW9kZWxzLlxuICAgKiBDcmVhdGVzIGEgY29udGV4dCwgdmFsaWRhdGVzIHByaW1hcnkga2V5cywgcmV0cmlldmVzIGV4aXN0aW5nIG1vZGVscywgbWVyZ2VzIG9sZCBhbmQgbmV3IG1vZGVscyxcbiAgICogZW5mb3JjZXMgZGVjb3JhdG9ycywgYW5kIHZhbGlkYXRlcyBlYWNoIG1vZGVsIGJlZm9yZSBhbGxvd2luZyB1cGRhdGVzIHRvIHByb2NlZWQuXG4gICAqIENvbGxlY3RzIHZhbGlkYXRpb24gZXJyb3JzIGZyb20gYWxsIG1vZGVscy5cbiAgICogQHBhcmFtIHtNW119IG1vZGVscyAtIFRoZSBhcnJheSBvZiBtb2RlbCBpbnN0YW5jZXMgdG8gcHJlcGFyZSBmb3IgdXBkYXRlXG4gICAqIEBwYXJhbSB7YW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgdGhlIHVwZGF0ZSBvcGVyYXRpb25cbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheSBjb250YWluaW5nIHRoZSB2YWxpZGF0ZWQgbW9kZWxzIGFuZCBjb250ZXh0IGFyZ3VtZW50c1xuICAgKiBAdGhyb3dzIHtJbnRlcm5hbEVycm9yfSBJZiBhbnkgbW9kZWwgZG9lc24ndCBoYXZlIGEgcHJpbWFyeSBrZXkgdmFsdWVcbiAgICogQHRocm93cyB7VmFsaWRhdGlvbkVycm9yfSBJZiBhbnkgbW9kZWwgZmFpbHMgdmFsaWRhdGlvbiwgd2l0aCBkZXRhaWxzIGFib3V0IHdoaWNoIG1vZGVscyBmYWlsZWRcbiAgICovXG4gIHByb3RlY3RlZCBvdmVycmlkZSBhc3luYyB1cGRhdGVBbGxQcmVmaXgobW9kZWxzOiBNW10sIC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgY29uc3QgY29udGV4dEFyZ3MgPSBhd2FpdCBDb250ZXh0LmFyZ3MoXG4gICAgICBPcGVyYXRpb25LZXlzLlVQREFURSxcbiAgICAgIHRoaXMuY2xhc3MsXG4gICAgICBhcmdzXG4gICAgKTtcbiAgICBjb25zdCBpZHMgPSBtb2RlbHMubWFwKChtKSA9PiB7XG4gICAgICBjb25zdCBpZCA9IG1bdGhpcy5wa107XG4gICAgICBpZiAodHlwZW9mIGlkID09PSBcInVuZGVmaW5lZFwiKVxuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICBgTm8gdmFsdWUgZm9yIHRoZSBJZCBpcyBkZWZpbmVkIHVuZGVyIHRoZSBwcm9wZXJ0eSAke3RoaXMucGsgYXMgc3RyaW5nfWBcbiAgICAgICAgKTtcbiAgICAgIHJldHVybiBpZCBhcyBzdHJpbmc7XG4gICAgfSk7XG4gICAgY29uc3Qgb2xkTW9kZWxzOiBNW10gPSBhd2FpdCB0aGlzLnJlYWRBbGwoaWRzLCAuLi5jb250ZXh0QXJncy5hcmdzKTtcbiAgICBtb2RlbHMgPSBtb2RlbHMubWFwKChtLCBpKSA9PiB0aGlzLm1lcmdlKG9sZE1vZGVsc1tpXSwgbSkpO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgbW9kZWxzLm1hcCgobSwgaSkgPT5cbiAgICAgICAgZW5mb3JjZURCRGVjb3JhdG9ycyhcbiAgICAgICAgICB0aGlzLFxuICAgICAgICAgIGNvbnRleHRBcmdzLmNvbnRleHQsXG4gICAgICAgICAgbSxcbiAgICAgICAgICBPcGVyYXRpb25LZXlzLlVQREFURSxcbiAgICAgICAgICBPcGVyYXRpb25LZXlzLk9OLFxuICAgICAgICAgIG9sZE1vZGVsc1tpXVxuICAgICAgICApXG4gICAgICApXG4gICAgKTtcblxuICAgIGNvbnN0IG1vZGVsc1ZhbGlkYXRpb24gPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIG1vZGVscy5tYXAoKG0sIGkpID0+IFByb21pc2UucmVzb2x2ZShtLmhhc0Vycm9ycyhvbGRNb2RlbHNbaV0gYXMgYW55KSkpXG4gICAgKTtcblxuICAgIGNvbnN0IGVycm9ycyA9IG1vZGVsc1ZhbGlkYXRpb24ucmVkdWNlKFxuICAgICAgKGFjY3VtOiBzdHJpbmcgfCB1bmRlZmluZWQsIGUsIGkpID0+IHtcbiAgICAgICAgaWYgKGUpXG4gICAgICAgICAgYWNjdW0gPVxuICAgICAgICAgICAgdHlwZW9mIGFjY3VtID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAgID8gYWNjdW0gKyBgXFxuIC0gJHtpfTogJHtlLnRvU3RyaW5nKCl9YFxuICAgICAgICAgICAgICA6IGAgLSAke2l9OiAke2UudG9TdHJpbmcoKX1gO1xuICAgICAgICByZXR1cm4gYWNjdW07XG4gICAgICB9LFxuICAgICAgdW5kZWZpbmVkXG4gICAgKTtcblxuICAgIGlmIChlcnJvcnMpIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoZXJyb3JzKTtcbiAgICByZXR1cm4gW21vZGVscywgLi4uY29udGV4dEFyZ3MuYXJnc107XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSByZWZsZWN0aW9uIGtleSBmb3IgZGF0YWJhc2Ugb3BlcmF0aW9ucy5cbiAgICogQHN1bW1hcnkgR2VuZXJhdGVzIGEga2V5IGZvciBzdG9yaW5nIG1ldGFkYXRhIGluIHRoZSByZWZsZWN0aW9uIHN5c3RlbSBieSBwcmVmaXhpbmdcbiAgICogdGhlIHByb3ZpZGVkIGtleSB3aXRoIHRoZSBkYXRhYmFzZSByZWZsZWN0aW9uIHByZWZpeC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleSAtIFRoZSBiYXNlIGtleSB0byBwcmVmaXhcbiAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgcHJlZml4ZWQgcmVmbGVjdGlvbiBrZXlcbiAgICovXG4gIHN0YXRpYyBrZXkoa2V5OiBzdHJpbmcpIHtcbiAgICByZXR1cm4gREJLZXlzLlJFRkxFQ1QgKyBrZXk7XG4gIH1cbn1cbiIsImltcG9ydCBcIi4vdmFsaWRhdGlvblwiO1xuaW1wb3J0IHtcbiAgZGF0ZSxcbiAgRGVjb3JhdGlvbixcbiAgTW9kZWwsXG4gIHByb3BNZXRhZGF0YSxcbiAgcmVxdWlyZWQsXG4gIHR5cGUsXG4gIFZhbGlkYXRpb24sXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IERCS2V5cywgREVGQVVMVF9USU1FU1RBTVBfRk9STUFUIH0gZnJvbSBcIi4uL21vZGVsL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgREVGQVVMVF9FUlJPUl9NRVNTQUdFUyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgREJPcGVyYXRpb25zLCBPcGVyYXRpb25LZXlzIH0gZnJvbSBcIi4uL29wZXJhdGlvbnMvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBhZnRlciwgb24sIG9uQ3JlYXRlVXBkYXRlIH0gZnJvbSBcIi4uL29wZXJhdGlvbnMvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgSVJlcG9zaXRvcnkgfSBmcm9tIFwiLi4vaW50ZXJmYWNlcy9JUmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgU2VyaWFsaXphdGlvbkVycm9yIH0gZnJvbSBcIi4uL3JlcG9zaXRvcnkvZXJyb3JzXCI7XG5pbXBvcnQgeyBhcHBseSwgbWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL3JlZmxlY3Rpb25cIjtcbmltcG9ydCB7IFJlcG9zaXRvcnkgfSBmcm9tIFwiLi4vcmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgQ29udGV4dCB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L0NvbnRleHRcIjtcbmltcG9ydCB7IFJlcG9zaXRvcnlGbGFncyB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFByZXZlbnRzIGEgcHJvcGVydHkgZnJvbSBiZWluZyBtb2RpZmllZCBhZnRlciBpbml0aWFsIGNyZWF0aW9uLlxuICogQHN1bW1hcnkgTWFya3MgdGhlIHByb3BlcnR5IGFzIHJlYWRvbmx5LCBjYXVzaW5nIHZhbGlkYXRpb24gZXJyb3JzIGlmIGF0dGVtcHRzIGFyZSBtYWRlIHRvIG1vZGlmeSBpdCBkdXJpbmcgdXBkYXRlcy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbbWVzc2FnZV0gLSBUaGUgZXJyb3IgbWVzc2FnZSB0byBkaXNwbGF5IHdoZW4gdmFsaWRhdGlvbiBmYWlscy4gRGVmYXVsdHMgdG8ge0BsaW5rIERFRkFVTFRfRVJST1JfTUVTU0FHRVMuUkVBRE9OTFkuSU5WQUxJRH1cbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciBmdW5jdGlvbiB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGNsYXNzIHByb3BlcnRpZXNcbiAqIEBmdW5jdGlvbiByZWFkb25seVxuICogQGNhdGVnb3J5IFByb3BlcnR5IERlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlYWRvbmx5KFxuICBtZXNzYWdlOiBzdHJpbmcgPSBERUZBVUxUX0VSUk9SX01FU1NBR0VTLlJFQURPTkxZLklOVkFMSURcbikge1xuICBjb25zdCBrZXkgPSBWYWxpZGF0aW9uLnVwZGF0ZUtleShEQktleXMuUkVBRE9OTFkpO1xuICByZXR1cm4gRGVjb3JhdGlvbi5mb3Ioa2V5KVxuICAgIC5kZWZpbmUoXG4gICAgICBwcm9wTWV0YWRhdGEoa2V5LCB7XG4gICAgICAgIG1lc3NhZ2U6IG1lc3NhZ2UsXG4gICAgICB9KVxuICAgIClcbiAgICAuYXBwbHkoKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gSGFuZGxlciBmdW5jdGlvbiB0aGF0IHNldHMgYSB0aW1lc3RhbXAgcHJvcGVydHkgdG8gdGhlIGN1cnJlbnQgdGltZXN0YW1wLlxuICogQHN1bW1hcnkgVXBkYXRlcyBhIG1vZGVsIHByb3BlcnR5IHdpdGggdGhlIGN1cnJlbnQgdGltZXN0YW1wIGZyb20gdGhlIHJlcG9zaXRvcnkgY29udGV4dC5cbiAqIEB0ZW1wbGF0ZSBNIC0gVGhlIG1vZGVsIHR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgUiAtIFRoZSByZXBvc2l0b3J5IHR5cGUgZXh0ZW5kaW5nIElSZXBvc2l0b3J5XG4gKiBAdGVtcGxhdGUgViAtIFRoZSBkYXRhIHR5cGUgZm9yIHRoZSBvcGVyYXRpb25cbiAqIEB0ZW1wbGF0ZSBGIC0gVGhlIHJlcG9zaXRvcnkgZmxhZ3MgdHlwZVxuICogQHRlbXBsYXRlIEMgLSBUaGUgY29udGV4dCB0eXBlXG4gKiBAcGFyYW0ge0N9IGNvbnRleHQgLSBUaGUgcmVwb3NpdG9yeSBjb250ZXh0IGNvbnRhaW5pbmcgdGhlIGN1cnJlbnQgdGltZXN0YW1wXG4gKiBAcGFyYW0ge1Z9IGRhdGEgLSBUaGUgZGF0YSBiZWluZyBwcm9jZXNzZWRcbiAqIEBwYXJhbSBrZXkgLSBUaGUgcHJvcGVydHkga2V5IHRvIHVwZGF0ZVxuICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZSBiZWluZyB1cGRhdGVkXG4gKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSB0aW1lc3RhbXAgaGFzIGJlZW4gc2V0XG4gKiBAZnVuY3Rpb24gdGltZXN0YW1wSGFuZGxlclxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdGltZXN0YW1wSGFuZGxlcjxcbiAgTSBleHRlbmRzIE1vZGVsLFxuICBSIGV4dGVuZHMgSVJlcG9zaXRvcnk8TSwgRiwgQz4sXG4gIFYsXG4gIEYgZXh0ZW5kcyBSZXBvc2l0b3J5RmxhZ3MgPSBSZXBvc2l0b3J5RmxhZ3MsXG4gIEMgZXh0ZW5kcyBDb250ZXh0PEY+ID0gQ29udGV4dDxGPixcbj4odGhpczogUiwgY29udGV4dDogQywgZGF0YTogViwga2V5OiBrZXlvZiBNLCBtb2RlbDogTSk6IFByb21pc2U8dm9pZD4ge1xuICAobW9kZWwgYXMgYW55KVtrZXldID0gY29udGV4dC50aW1lc3RhbXA7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEF1dG9tYXRpY2FsbHkgbWFuYWdlcyB0aW1lc3RhbXAgcHJvcGVydGllcyBmb3IgdHJhY2tpbmcgY3JlYXRpb24gYW5kIHVwZGF0ZSB0aW1lcy5cbiAqIEBzdW1tYXJ5IE1hcmtzIHRoZSBwcm9wZXJ0eSBhcyBhIHRpbWVzdGFtcCwgbWFraW5nIGl0IHJlcXVpcmVkIGFuZCBlbnN1cmluZyBpdCdzIGEgdmFsaWQgZGF0ZS4gVGhlIHByb3BlcnR5IHdpbGwgYmUgYXV0b21hdGljYWxseSB1cGRhdGVkIHdpdGggdGhlIGN1cnJlbnQgdGltZXN0YW1wIGR1cmluZyBzcGVjaWZpZWQgb3BlcmF0aW9ucy5cbiAqXG4gKiBEYXRlIEZvcm1hdDpcbiAqXG4gKiA8cHJlPlxuICogICAgICBVc2luZyBzaW1pbGFyIGZvcm1hdHRpbmcgYXMgTW9tZW50LmpzLCBDbGFzcyBEYXRlVGltZUZvcm1hdHRlciAoSmF2YSksIGFuZCBDbGFzcyBTaW1wbGVEYXRlRm9ybWF0IChKYXZhKSxcbiAqICAgICAgSSBpbXBsZW1lbnRlZCBhIGNvbXByZWhlbnNpdmUgc29sdXRpb24gZm9ybWF0RGF0ZShkYXRlLCBwYXR0ZXJuU3RyKSB3aGVyZSB0aGUgY29kZSBpcyBlYXN5IHRvIHJlYWQgYW5kIG1vZGlmeS5cbiAqICAgICAgWW91IGNhbiBkaXNwbGF5IGRhdGUsIHRpbWUsIEFNL1BNLCBldGMuXG4gKlxuICogICAgICBEYXRlIGFuZCBUaW1lIFBhdHRlcm5zXG4gKiAgICAgIHl5ID0gMi1kaWdpdCB5ZWFyOyB5eXl5ID0gZnVsbCB5ZWFyXG4gKiAgICAgIE0gPSBkaWdpdCBtb250aDsgTU0gPSAyLWRpZ2l0IG1vbnRoOyBNTU0gPSBzaG9ydCBtb250aCBuYW1lOyBNTU1NID0gZnVsbCBtb250aCBuYW1lXG4gKiAgICAgIEVFRUUgPSBmdWxsIHdlZWtkYXkgbmFtZTsgRUVFID0gc2hvcnQgd2Vla2RheSBuYW1lXG4gKiAgICAgIGQgPSBkaWdpdCBkYXk7IGRkID0gMi1kaWdpdCBkYXlcbiAqICAgICAgaCA9IGhvdXJzIGFtL3BtOyBoaCA9IDItZGlnaXQgaG91cnMgYW0vcG07IEggPSBob3VyczsgSEggPSAyLWRpZ2l0IGhvdXJzXG4gKiAgICAgIG0gPSBtaW51dGVzOyBtbSA9IDItZGlnaXQgbWludXRlczsgYWFhID0gQU0vUE1cbiAqICAgICAgcyA9IHNlY29uZHM7IHNzID0gMi1kaWdpdCBzZWNvbmRzXG4gKiAgICAgIFMgPSBtaWxpc2Vjb25kc1xuICogPC9wcmU+XG4gKlxuICogQHBhcmFtIHtPcGVyYXRpb25LZXlzW119IG9wZXJhdGlvbiAtIFRoZSBvcGVyYXRpb25zIHRvIGFjdCBvbi4gRGVmYXVsdHMgdG8ge0BsaW5rIERCT3BlcmF0aW9ucy5DUkVBVEVfVVBEQVRFfVxuICogQHBhcmFtIHtzdHJpbmd9IFtmb3JtYXRdIC0gVGhlIHRpbWVzdGFtcCBmb3JtYXQuIERlZmF1bHRzIHRvIHtAbGluayBERUZBVUxUX1RJTUVTVEFNUF9GT1JNQVR9XG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgZnVuY3Rpb24gdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gdGltZXN0YW1wXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDIGFzIENsaWVudFxuICogICBwYXJ0aWNpcGFudCBNIGFzIE1vZGVsXG4gKiAgIHBhcnRpY2lwYW50IFQgYXMgVGltZXN0YW1wRGVjb3JhdG9yXG4gKiAgIHBhcnRpY2lwYW50IFYgYXMgVmFsaWRhdG9yXG4gKlxuICogICBDLT4+TTogQ3JlYXRlL1VwZGF0ZSBtb2RlbFxuICogICBNLT4+VDogUHJvY2VzcyB0aW1lc3RhbXAgcHJvcGVydHlcbiAqICAgVC0+Pk06IEFwcGx5IHJlcXVpcmVkIHZhbGlkYXRpb25cbiAqICAgVC0+Pk06IEFwcGx5IGRhdGUgZm9ybWF0IHZhbGlkYXRpb25cbiAqXG4gKiAgIGFsdCBVcGRhdGUgb3BlcmF0aW9uXG4gKiAgICAgVC0+PlY6IFJlZ2lzdGVyIHRpbWVzdGFtcCB2YWxpZGF0b3JcbiAqICAgICBWLT4+TTogVmFsaWRhdGUgdGltZXN0YW1wIGlzIG5ld2VyXG4gKiAgIGVuZFxuICpcbiAqICAgVC0+Pk06IFNldCBjdXJyZW50IHRpbWVzdGFtcFxuICogICBNLT4+QzogUmV0dXJuIHVwZGF0ZWQgbW9kZWxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRpbWVzdGFtcChcbiAgb3BlcmF0aW9uOiBPcGVyYXRpb25LZXlzW10gPSBEQk9wZXJhdGlvbnMuQ1JFQVRFX1VQREFURSBhcyB1bmtub3duIGFzIE9wZXJhdGlvbktleXNbXSxcbiAgZm9ybWF0OiBzdHJpbmcgPSBERUZBVUxUX1RJTUVTVEFNUF9GT1JNQVRcbikge1xuICBjb25zdCBrZXkgPSBWYWxpZGF0aW9uLnVwZGF0ZUtleShEQktleXMuVElNRVNUQU1QKTtcblxuICBmdW5jdGlvbiB0cyhvcGVyYXRpb246IE9wZXJhdGlvbktleXNbXSwgZm9ybWF0OiBzdHJpbmcpIHtcbiAgICBjb25zdCBkZWNvcmF0b3JzOiBhbnlbXSA9IFtcbiAgICAgIGRhdGUoZm9ybWF0LCBERUZBVUxUX0VSUk9SX01FU1NBR0VTLlRJTUVTVEFNUC5EQVRFKSxcbiAgICAgIHJlcXVpcmVkKERFRkFVTFRfRVJST1JfTUVTU0FHRVMuVElNRVNUQU1QLlJFUVVJUkVEKSxcbiAgICAgIHByb3BNZXRhZGF0YShWYWxpZGF0aW9uLmtleShEQktleXMuVElNRVNUQU1QKSwge1xuICAgICAgICBvcGVyYXRpb246IG9wZXJhdGlvbixcbiAgICAgICAgZm9ybWF0OiBmb3JtYXQsXG4gICAgICB9KSxcbiAgICAgIG9uKG9wZXJhdGlvbiwgdGltZXN0YW1wSGFuZGxlciksXG4gICAgXTtcbiAgICBpZiAob3BlcmF0aW9uLmluZGV4T2YoT3BlcmF0aW9uS2V5cy5VUERBVEUpICE9PSAtMSlcbiAgICAgIGRlY29yYXRvcnMucHVzaChcbiAgICAgICAgcHJvcE1ldGFkYXRhKGtleSwge1xuICAgICAgICAgIG1lc3NhZ2U6IERFRkFVTFRfRVJST1JfTUVTU0FHRVMuVElNRVNUQU1QLklOVkFMSUQsXG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIGVsc2UgZGVjb3JhdG9ycy5wdXNoKHJlYWRvbmx5KCkpO1xuICAgIHJldHVybiBhcHBseSguLi5kZWNvcmF0b3JzKTtcbiAgfVxuICByZXR1cm4gRGVjb3JhdGlvbi5mb3Ioa2V5KVxuICAgIC5kZWZpbmUoe1xuICAgICAgZGVjb3JhdG9yOiB0cyxcbiAgICAgIGFyZ3M6IFtvcGVyYXRpb24sIGZvcm1hdF0sXG4gICAgfSlcbiAgICAuYXBwbHkoKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gSGFuZGxlciBmdW5jdGlvbiB0aGF0IHNlcmlhbGl6ZXMgYSBwcm9wZXJ0eSB0byBKU09OIHN0cmluZyBkdXJpbmcgY3JlYXRlIGFuZCB1cGRhdGUgb3BlcmF0aW9ucy5cbiAqIEBzdW1tYXJ5IENvbnZlcnRzIGEgY29tcGxleCBvYmplY3QgcHJvcGVydHkgdG8gYSBKU09OIHN0cmluZyBiZWZvcmUgc3RvcmluZyBpdCBpbiB0aGUgZGF0YWJhc2UuXG4gKiBAdGVtcGxhdGUgTSAtIFRoZSBtb2RlbCB0eXBlIGV4dGVuZGluZyBNb2RlbFxuICogQHRlbXBsYXRlIFIgLSBUaGUgcmVwb3NpdG9yeSB0eXBlIGV4dGVuZGluZyBJUmVwb3NpdG9yeVxuICogQHRlbXBsYXRlIFYgLSBUaGUgZGF0YSB0eXBlIGZvciB0aGUgb3BlcmF0aW9uXG4gKiBAdGVtcGxhdGUgRiAtIFRoZSByZXBvc2l0b3J5IGZsYWdzIHR5cGVcbiAqIEB0ZW1wbGF0ZSBDIC0gVGhlIGNvbnRleHQgdHlwZVxuICogQHBhcmFtIHtDfSBjb250ZXh0IC0gVGhlIHJlcG9zaXRvcnkgY29udGV4dFxuICogQHBhcmFtIHtWfSBkYXRhIC0gVGhlIGRhdGEgYmVpbmcgcHJvY2Vzc2VkXG4gKiBAcGFyYW0ga2V5IC0gVGhlIHByb3BlcnR5IGtleSB0byBzZXJpYWxpemVcbiAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2UgYmVpbmcgcHJvY2Vzc2VkXG4gKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBwcm9wZXJ0eSBoYXMgYmVlbiBzZXJpYWxpemVkXG4gKiBAZnVuY3Rpb24gc2VyaWFsaXplT25DcmVhdGVVcGRhdGVcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlcmlhbGl6ZU9uQ3JlYXRlVXBkYXRlPFxuICBNIGV4dGVuZHMgTW9kZWwsXG4gIFIgZXh0ZW5kcyBJUmVwb3NpdG9yeTxNLCBGLCBDPixcbiAgVixcbiAgRiBleHRlbmRzIFJlcG9zaXRvcnlGbGFncyA9IFJlcG9zaXRvcnlGbGFncyxcbiAgQyBleHRlbmRzIENvbnRleHQ8Rj4gPSBDb250ZXh0PEY+LFxuPih0aGlzOiBSLCBjb250ZXh0OiBDLCBkYXRhOiBWLCBrZXk6IGtleW9mIE0sIG1vZGVsOiBNKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmICghbW9kZWxba2V5XSkgcmV0dXJuO1xuICB0cnkge1xuICAgIG1vZGVsW2tleV0gPSBKU09OLnN0cmluZ2lmeShtb2RlbFtrZXldKSBhcyBNW2tleW9mIE1dO1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoXG4gICAgICBgRmFpbGVkIHRvIHNlcmlhbGl6ZSAke2tleS50b1N0cmluZygpfSBwcm9wZXJ0eSBvZiBtb2RlbCAke21vZGVsLmNvbnN0cnVjdG9yLm5hbWV9OiBlYFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gSGFuZGxlciBmdW5jdGlvbiB0aGF0IGRlc2VyaWFsaXplcyBhIHByb3BlcnR5IGZyb20gSlNPTiBzdHJpbmcgYWZ0ZXIgZGF0YWJhc2Ugb3BlcmF0aW9ucy5cbiAqIEBzdW1tYXJ5IENvbnZlcnRzIGEgSlNPTiBzdHJpbmcgcHJvcGVydHkgYmFjayB0byBpdHMgb3JpZ2luYWwgY29tcGxleCBvYmplY3QgZm9ybSBhZnRlciByZXRyaWV2aW5nIGl0IGZyb20gdGhlIGRhdGFiYXNlLlxuICogQHRlbXBsYXRlIE0gLSBUaGUgbW9kZWwgdHlwZSBleHRlbmRpbmcgTW9kZWxcbiAqIEB0ZW1wbGF0ZSBSIC0gVGhlIHJlcG9zaXRvcnkgdHlwZSBleHRlbmRpbmcgSVJlcG9zaXRvcnlcbiAqIEB0ZW1wbGF0ZSBWIC0gVGhlIGRhdGEgdHlwZSBmb3IgdGhlIG9wZXJhdGlvblxuICogQHRlbXBsYXRlIEYgLSBUaGUgcmVwb3NpdG9yeSBmbGFncyB0eXBlXG4gKiBAdGVtcGxhdGUgQyAtIFRoZSBjb250ZXh0IHR5cGVcbiAqIEBwYXJhbSB7Q30gY29udGV4dCAtIFRoZSByZXBvc2l0b3J5IGNvbnRleHRcbiAqIEBwYXJhbSB7Vn0gZGF0YSAtIFRoZSBkYXRhIGJlaW5nIHByb2Nlc3NlZFxuICogQHBhcmFtIGtleSAtIFRoZSBwcm9wZXJ0eSBrZXkgdG8gZGVzZXJpYWxpemVcbiAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgaW5zdGFuY2UgYmVpbmcgcHJvY2Vzc2VkXG4gKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBwcm9wZXJ0eSBoYXMgYmVlbiBkZXNlcmlhbGl6ZWRcbiAqIEBmdW5jdGlvbiBzZXJpYWxpemVBZnRlckFsbFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2VyaWFsaXplQWZ0ZXJBbGw8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIElSZXBvc2l0b3J5PE0sIEYsIEM+LFxuICBWLFxuICBGIGV4dGVuZHMgUmVwb3NpdG9yeUZsYWdzID0gUmVwb3NpdG9yeUZsYWdzLFxuICBDIGV4dGVuZHMgQ29udGV4dDxGPiA9IENvbnRleHQ8Rj4sXG4+KHRoaXM6IFIsIGNvbnRleHQ6IEMsIGRhdGE6IFYsIGtleToga2V5b2YgTSwgbW9kZWw6IE0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKCFtb2RlbFtrZXldKSByZXR1cm47XG4gIGlmICh0eXBlb2YgbW9kZWxba2V5XSAhPT0gXCJzdHJpbmdcIikgcmV0dXJuO1xuXG4gIHRyeSB7XG4gICAgbW9kZWxba2V5XSA9IEpTT04ucGFyc2UobW9kZWxba2V5XSk7XG4gIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICB0aHJvdyBuZXcgU2VyaWFsaXphdGlvbkVycm9yKFxuICAgICAgYEZhaWxlZCB0byBkZXNlcmlhbGl6ZSAke2tleS50b1N0cmluZygpfSBwcm9wZXJ0eSBvZiBtb2RlbCAke21vZGVsLmNvbnN0cnVjdG9yLm5hbWV9OiAke2V9YFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gRW5hYmxlcyBhdXRvbWF0aWMgSlNPTiBzZXJpYWxpemF0aW9uIGFuZCBkZXNlcmlhbGl6YXRpb24gZm9yIGNvbXBsZXggb2JqZWN0IHByb3BlcnRpZXMuXG4gKiBAc3VtbWFyeSBEZWNvcmF0b3IgdGhhdCBhdXRvbWF0aWNhbGx5IGNvbnZlcnRzIGNvbXBsZXggb2JqZWN0cyB0byBKU09OIHN0cmluZ3MgYmVmb3JlIHN0b3JpbmcgaW4gdGhlIGRhdGFiYXNlIGFuZCBiYWNrIHRvIG9iamVjdHMgd2hlbiByZXRyaWV2aW5nIHRoZW0uXG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgZnVuY3Rpb24gdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gc2VyaWFsaXplXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHkgRGVjb3JhdG9yc1xuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDIGFzIENsaWVudFxuICogICBwYXJ0aWNpcGFudCBNIGFzIE1vZGVsXG4gKiAgIHBhcnRpY2lwYW50IFMgYXMgU2VyaWFsaXplRGVjb3JhdG9yXG4gKiAgIHBhcnRpY2lwYW50IERCIGFzIERhdGFiYXNlXG4gKlxuICogICBOb3RlIG92ZXIgQyxEQjogQ3JlYXRlL1VwZGF0ZSBGbG93XG4gKiAgIEMtPj5NOiBTZXQgY29tcGxleCBvYmplY3QgcHJvcGVydHlcbiAqICAgTS0+PlM6IFByb2Nlc3MgcHJvcGVydHkgKGNyZWF0ZS91cGRhdGUpXG4gKiAgIFMtPj5NOiBDb252ZXJ0IHRvIEpTT04gc3RyaW5nXG4gKiAgIE0tPj5EQjogU3RvcmUgc2VyaWFsaXplZCBkYXRhXG4gKlxuICogICBOb3RlIG92ZXIgQyxEQjogUmV0cmlldmFsIEZsb3dcbiAqICAgQy0+Pk06IFJlcXVlc3QgbW9kZWxcbiAqICAgTS0+PkRCOiBGZXRjaCBkYXRhXG4gKiAgIERCLT4+TTogUmV0dXJuIHdpdGggc2VyaWFsaXplZCBwcm9wZXJ0eVxuICogICBNLT4+UzogUHJvY2VzcyBwcm9wZXJ0eSAoYWZ0ZXIgYWxsIG9wcylcbiAqICAgUy0+Pk06IFBhcnNlIEpTT04gYmFjayB0byBvYmplY3RcbiAqICAgTS0+PkM6IFJldHVybiBtb2RlbCB3aXRoIGRlc2VyaWFsaXplZCBwcm9wZXJ0eVxuICovXG5leHBvcnQgZnVuY3Rpb24gc2VyaWFsaXplKCkge1xuICByZXR1cm4gYXBwbHkoXG4gICAgb25DcmVhdGVVcGRhdGUoc2VyaWFsaXplT25DcmVhdGVVcGRhdGUpLFxuICAgIGFmdGVyKERCT3BlcmF0aW9ucy5BTEwsIHNlcmlhbGl6ZUFmdGVyQWxsKSxcbiAgICB0eXBlKFtTdHJpbmcubmFtZSwgT2JqZWN0Lm5hbWVdKSxcbiAgICBtZXRhZGF0YShSZXBvc2l0b3J5LmtleShEQktleXMuU0VSSUFMSVpFKSwge30pXG4gICk7XG59XG4iLCJpbXBvcnQgeyBwcm9wTWV0YWRhdGEsIHJlcXVpcmVkIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgcmVhZG9ubHkgfSBmcm9tIFwiLi4vdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgREJLZXlzIH0gZnJvbSBcIi4uL21vZGVsL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgUmVwb3NpdG9yeSB9IGZyb20gXCIuLi9yZXBvc2l0b3J5XCI7XG5pbXBvcnQgeyBhcHBseSB9IGZyb20gXCJAZGVjYWYtdHMvcmVmbGVjdGlvblwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBEZWNvcmF0b3IgdGhhdCBtYXJrcyBhIHByb3BlcnR5IGFzIGFuIElEIGZpZWxkXG4gKiBAc3VtbWFyeSBDcmVhdGVzIGEgY29tcG9zaXRlIGRlY29yYXRvciB0aGF0IG1hcmtzIGEgcHJvcGVydHkgYXMgcmVxdWlyZWQsIHJlYWRvbmx5LCBhbmQgYXMgdGhlIElEIGZpZWxkIGZvciBkYXRhYmFzZSBvcGVyYXRpb25zXG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gaWRcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eSBEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpZCgpIHtcbiAgcmV0dXJuIGFwcGx5KFxuICAgIHJlcXVpcmVkKCksXG4gICAgcmVhZG9ubHkoKSxcbiAgICBwcm9wTWV0YWRhdGEoUmVwb3NpdG9yeS5rZXkoREJLZXlzLklEKSwge30pXG4gICk7XG59XG4iLCJpbXBvcnQge1xuICBDb25kaXRpb25hbEFzeW5jLFxuICBEZWNvcmF0b3JNZXRhZGF0YUFzeW5jLFxuICBnZXRWYWxpZGF0aW9uRGVjb3JhdG9ycyxcbiAgTW9kZWwsXG4gIE1vZGVsQ29uZGl0aW9uYWxBc3luYyxcbiAgTW9kZWxFcnJvckRlZmluaXRpb24sXG4gIE1vZGVsRXJyb3JzLFxuICBNb2RlbEtleXMsXG4gIHRvQ29uZGl0aW9uYWxQcm9taXNlLFxuICBWYWxpZGF0aW9uLFxuICBWYWxpZGF0aW9uS2V5cyxcbiAgVmFsaWRhdGlvblByb3BlcnR5RGVjb3JhdG9yRGVmaW5pdGlvbixcbn0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgUmVmbGVjdGlvbiB9IGZyb20gXCJAZGVjYWYtdHMvcmVmbGVjdGlvblwiO1xuaW1wb3J0IHsgVXBkYXRlVmFsaWRhdGlvbktleXMsIFVwZGF0ZVZhbGlkYXRvciB9IGZyb20gXCIuLi92YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBmaW5kTW9kZWxJZCB9IGZyb20gXCIuLi9pZGVudGl0eVwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvblxuICogUmV0cmlldmVzIHZhbGlkYXRpb24gZGVjb3JhdG9yIGRlZmluaXRpb25zIGZyb20gYSBtb2RlbCBmb3IgdXBkYXRlIG9wZXJhdGlvbnMsIGluY2x1ZGluZ1xuICogc3VwcG9ydCBmb3Igc3BlY2lhbCBoYW5kbGluZyBvZiBsaXN0IGRlY29yYXRvcnMuXG4gKlxuICogQHN1bW1hcnlcbiAqIEl0ZXJhdGVzIG92ZXIgdGhlIG1vZGVsJ3Mgb3duIGVudW1lcmFibGUgcHJvcGVydGllcyBhbmQgZmlsdGVycyBvdXQgdGhvc2Ugc3BlY2lmaWVkIGluIHRoZVxuICogYHByb3BzVG9JZ25vcmVgIGFycmF5LiBGb3IgZWFjaCByZW1haW5pbmcgcHJvcGVydHksIHJldHJpZXZlcyB2YWxpZGF0aW9uIGRlY29yYXRvcnMgc3BlY2lmaWNcbiAqIHRvIHVwZGF0ZSBvcGVyYXRpb25zIHVzaW5nIHRoZSBgVXBkYXRlVmFsaWRhdGlvbktleXMuUkVGTEVDVGAga2V5LiBBZGRpdGlvbmFsbHksIGl0IGV4cGxpY2l0bHlcbiAqIGNoZWNrcyBmb3IgYW5kIGFwcGVuZHMgYW55IGBMSVNUYCB0eXBlIGRlY29yYXRvcnMgdG8gZW5zdXJlIHByb3BlciB2YWxpZGF0aW9uIG9mIGNvbGxlY3Rpb24gdHlwZXMuXG4gKlxuICogQHRlbXBsYXRlIE0gLSBBIGdlbmVyaWMgcGFyYW1ldGVyIGV4dGVuZGluZyB0aGUgYE1vZGVsYCBjbGFzcywgcmVwcmVzZW50aW5nIHRoZSBtb2RlbCB0eXBlIGJlaW5nIGluc3BlY3RlZC5cbiAqXG4gKiBAcGFyYW0ge019IG1vZGVsIC0gVGhlIG1vZGVsIGluc3RhbmNlIHdob3NlIHByb3BlcnRpZXMgYXJlIGJlaW5nIGluc3BlY3RlZCBmb3IgdXBkYXRlLXJlbGF0ZWQgdmFsaWRhdGlvbnMuXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBwcm9wc1RvSWdub3JlIC0gQSBsaXN0IG9mIHByb3BlcnR5IG5hbWVzIHRvIGV4Y2x1ZGUgZnJvbSB0aGUgdmFsaWRhdGlvbiBkZWNvcmF0b3IgcmV0cmlldmFsIHByb2Nlc3MuXG4gKlxuICogQHJldHVybiB7VmFsaWRhdGlvblByb3BlcnR5RGVjb3JhdG9yRGVmaW5pdGlvbltdfSBBbiBhcnJheSBvZiB2YWxpZGF0aW9uIGRlY29yYXRvciBkZWZpbml0aW9ucywgaW5jbHVkaW5nIGJvdGhcbiAqIHVwZGF0ZS1zcGVjaWZpYyBhbmQgbGlzdC10eXBlIGRlY29yYXRvcnMsIGV4Y2x1ZGluZyB0aG9zZSBmb3IgaWdub3JlZCBwcm9wZXJ0aWVzLlxuICpcbiAqIEBmdW5jdGlvbiBnZXRWYWxpZGF0YWJsZVVwZGF0ZVByb3BzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRWYWxpZGF0YWJsZVVwZGF0ZVByb3BzPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNLFxuICBwcm9wc1RvSWdub3JlOiBzdHJpbmdbXVxuKTogVmFsaWRhdGlvblByb3BlcnR5RGVjb3JhdG9yRGVmaW5pdGlvbltdIHtcbiAgY29uc3QgZGVjb3JhdGVkUHJvcGVydGllczogVmFsaWRhdGlvblByb3BlcnR5RGVjb3JhdG9yRGVmaW5pdGlvbltdID0gW107XG4gIGZvciAoY29uc3QgcHJvcCBpbiBtb2RlbCkge1xuICAgIGlmIChcbiAgICAgIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChtb2RlbCwgcHJvcCkgJiZcbiAgICAgICFwcm9wc1RvSWdub3JlLmluY2x1ZGVzKHByb3ApXG4gICAgKSB7XG4gICAgICBjb25zdCB2YWxpZGF0aW9uUHJvcGVydHlEZWZpbml0aW9uID0gZ2V0VmFsaWRhdGlvbkRlY29yYXRvcnMoXG4gICAgICAgIG1vZGVsLFxuICAgICAgICBwcm9wLFxuICAgICAgICBVcGRhdGVWYWxpZGF0aW9uS2V5cy5SRUZMRUNUXG4gICAgICApO1xuXG4gICAgICBjb25zdCBsaXN0RGVjb3JhdG9yID0gZ2V0VmFsaWRhdGlvbkRlY29yYXRvcnMoXG4gICAgICAgIG1vZGVsLFxuICAgICAgICBwcm9wXG4gICAgICApLmRlY29yYXRvcnMuZmluZCgoeyBrZXkgfSkgPT4ga2V5ID09PSBWYWxpZGF0aW9uS2V5cy5MSVNUKTtcblxuICAgICAgaWYgKGxpc3REZWNvcmF0b3IpXG4gICAgICAgIHZhbGlkYXRpb25Qcm9wZXJ0eURlZmluaXRpb24uZGVjb3JhdG9ycy5wdXNoKGxpc3REZWNvcmF0b3IpO1xuXG4gICAgICBkZWNvcmF0ZWRQcm9wZXJ0aWVzLnB1c2godmFsaWRhdGlvblByb3BlcnR5RGVmaW5pdGlvbik7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGRlY29yYXRlZFByb3BlcnRpZXM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZURlY29yYXRvcjxcbiAgTSBleHRlbmRzIE1vZGVsLFxuICBBc3luYyBleHRlbmRzIGJvb2xlYW4gPSBmYWxzZSxcbj4oXG4gIG5ld01vZGVsOiBNLFxuICBvbGRNb2RlbDogTSxcbiAgcHJvcDogc3RyaW5nLFxuICBkZWNvcmF0b3I6IERlY29yYXRvck1ldGFkYXRhQXN5bmMsXG4gIGFzeW5jPzogQXN5bmNcbik6IENvbmRpdGlvbmFsQXN5bmM8QXN5bmMsIHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICBjb25zdCB2YWxpZGF0b3I6IFVwZGF0ZVZhbGlkYXRvciA9IFZhbGlkYXRpb24uZ2V0KFxuICAgIGRlY29yYXRvci5rZXlcbiAgKSBhcyBVcGRhdGVWYWxpZGF0b3I7XG5cbiAgaWYgKCF2YWxpZGF0b3IpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYE1pc3NpbmcgdmFsaWRhdG9yIGZvciAke2RlY29yYXRvci5rZXl9YCk7XG4gIH1cblxuICAvLyBTa2lwIHZhbGlkYXRvcnMgdGhhdCBhcmVuJ3QgVXBkYXRlVmFsaWRhdG9yc1xuICBpZiAoIXZhbGlkYXRvci51cGRhdGVIYXNFcnJvcnMpIHJldHVybiB0b0NvbmRpdGlvbmFsUHJvbWlzZSh1bmRlZmluZWQsIGFzeW5jKTtcblxuICAvLyBza2lwIGFzeW5jIGRlY29yYXRvcnMgaWYgdmFsaWRhdGVEZWNvcmF0b3JzIGlzIGNhbGxlZCBzeW5jaHJvbm91c2x5IChhc3luYyA9IGZhbHNlKVxuICBpZiAoIWFzeW5jICYmIGRlY29yYXRvci5wcm9wcy5hc3luYylcbiAgICByZXR1cm4gdG9Db25kaXRpb25hbFByb21pc2UodW5kZWZpbmVkLCBhc3luYyk7XG5cbiAgY29uc3QgZGVjb3JhdG9yUHJvcHMgPSBPYmplY3QudmFsdWVzKGRlY29yYXRvci5wcm9wcykgfHwge307XG5cbiAgLy8gY29uc3QgY29udGV4dCA9IFBhdGhQcm94eUVuZ2luZS5jcmVhdGUob2JqLCB7XG4gIC8vICAgaWdub3JlVW5kZWZpbmVkOiB0cnVlLFxuICAvLyAgIGlnbm9yZU51bGw6IHRydWUsXG4gIC8vIH0pO1xuXG4gIGNvbnN0IG1heWJlRXJyb3IgPSB2YWxpZGF0b3IudXBkYXRlSGFzRXJyb3JzKFxuICAgIChuZXdNb2RlbCBhcyBhbnkpW3Byb3BdLFxuICAgIChvbGRNb2RlbCBhcyBhbnkpW3Byb3BdLFxuICAgIC4uLmRlY29yYXRvclByb3BzXG4gICk7XG5cbiAgcmV0dXJuIHRvQ29uZGl0aW9uYWxQcm9taXNlKG1heWJlRXJyb3IsIGFzeW5jKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlRGVjb3JhdG9yczxcbiAgTSBleHRlbmRzIE1vZGVsLFxuICBBc3luYyBleHRlbmRzIGJvb2xlYW4gPSBmYWxzZSxcbj4oXG4gIG5ld01vZGVsOiBNLFxuICBvbGRNb2RlbDogTSxcbiAgcHJvcDogc3RyaW5nLFxuICBkZWNvcmF0b3JzOiBEZWNvcmF0b3JNZXRhZGF0YUFzeW5jW10sXG4gIGFzeW5jPzogQXN5bmNcbik6IENvbmRpdGlvbmFsQXN5bmM8QXN5bmMsIFJlY29yZDxzdHJpbmcsIHN0cmluZz4+IHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBQcm9taXNlPHN0cmluZz4+ID0ge307XG5cbiAgZm9yIChjb25zdCBkZWNvcmF0b3Igb2YgZGVjb3JhdG9ycykge1xuICAgIC8vIHNraXAgYXN5bmMgZGVjb3JhdG9ycyBpZiB2YWxpZGF0ZURlY29yYXRvcnMgaXMgY2FsbGVkIHN5bmNocm9ub3VzbHkgKGFzeW5jID0gZmFsc2UpXG4gICAgaWYgKCFhc3luYyAmJiBkZWNvcmF0b3IucHJvcHMuYXN5bmMpIGNvbnRpbnVlO1xuXG4gICAgbGV0IHZhbGlkYXRpb25FcnJvcnMgPSB2YWxpZGF0ZURlY29yYXRvcihcbiAgICAgIG5ld01vZGVsLFxuICAgICAgb2xkTW9kZWwsXG4gICAgICBwcm9wLFxuICAgICAgZGVjb3JhdG9yLFxuICAgICAgYXN5bmNcbiAgICApO1xuXG4gICAgLypcbiAgICBJZiB0aGUgZGVjb3JhdG9yIGlzIGEgbGlzdCwgZWFjaCBlbGVtZW50IG11c3QgYmUgY2hlY2tlZC5cbiAgICBXaGVuICdhc3luYycgaXMgdHJ1ZSwgdGhlICdlcnInIHdpbGwgYWx3YXlzIGJlIGEgcGVuZGluZyBwcm9taXNlIGluaXRpYWxseSxcbiAgICBzbyB0aGUgJyFlcnInIGNoZWNrIHdpbGwgZXZhbHVhdGUgdG8gZmFsc2UgKGV2ZW4gaWYgdGhlIHByb21pc2UgbGF0ZXIgcmVzb2x2ZXMgd2l0aCBubyBlcnJvcnMpXG4gICAgKi9cbiAgICBpZiAoZGVjb3JhdG9yLmtleSA9PT0gVmFsaWRhdGlvbktleXMuTElTVCAmJiAoIXZhbGlkYXRpb25FcnJvcnMgfHwgYXN5bmMpKSB7XG4gICAgICBjb25zdCBuZXdQcm9wVmFsdWUgPSAobmV3TW9kZWwgYXMgYW55KVtwcm9wXTtcbiAgICAgIGNvbnN0IG9sZFByb3BWYWx1ZSA9IChvbGRNb2RlbCBhcyBhbnkpW3Byb3BdO1xuXG4gICAgICBjb25zdCBuZXdWYWx1ZXMgPVxuICAgICAgICBuZXdQcm9wVmFsdWUgaW5zdGFuY2VvZiBTZXQgPyBbLi4ubmV3UHJvcFZhbHVlXSA6IG5ld1Byb3BWYWx1ZTtcbiAgICAgIGNvbnN0IG9sZFZhbHVlcyA9XG4gICAgICAgIG9sZFByb3BWYWx1ZSBpbnN0YW5jZW9mIFNldCA/IFsuLi5vbGRQcm9wVmFsdWVdIDogb2xkUHJvcFZhbHVlO1xuXG4gICAgICBpZiAobmV3VmFsdWVzICYmIG5ld1ZhbHVlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IHR5cGVzID1cbiAgICAgICAgICBkZWNvcmF0b3IucHJvcHMuY2xhc3MgfHxcbiAgICAgICAgICBkZWNvcmF0b3IucHJvcHMuY2xhenogfHxcbiAgICAgICAgICBkZWNvcmF0b3IucHJvcHMuY3VzdG9tVHlwZXM7XG5cbiAgICAgICAgY29uc3QgYWxsb3dlZFR5cGVzID0gW3R5cGVzXS5mbGF0KCkubWFwKCh0KSA9PiB7XG4gICAgICAgICAgdCA9IHR5cGVvZiB0ID09PSBcImZ1bmN0aW9uXCIgJiYgIXQubmFtZSA/IHQoKSA6IHQ7XG4gICAgICAgICAgdCA9ICh0IGFzIGFueSkubmFtZSA/ICh0IGFzIGFueSkubmFtZSA6IHQ7XG4gICAgICAgICAgcmV0dXJuIFN0cmluZyh0KS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBlcnJzID0gbmV3VmFsdWVzLm1hcCgoY2hpbGRWYWx1ZTogYW55KSA9PiB7XG4gICAgICAgICAgLy8gZmluZCBieSBpZCBzbyB0aGUgbGlzdCBlbGVtZW50cyBvcmRlciBkb2Vzbid0IG1hdHRlclxuICAgICAgICAgIGNvbnN0IGlkID0gZmluZE1vZGVsSWQoY2hpbGRWYWx1ZSBhcyBhbnksIHRydWUpO1xuICAgICAgICAgIGlmICghaWQpIHJldHVybiBcIkZhaWxlZCB0byBmaW5kIG1vZGVsIGlkXCI7XG5cbiAgICAgICAgICBjb25zdCBvbGRNb2RlbCA9IG9sZFZhbHVlcy5maW5kKFxuICAgICAgICAgICAgKGVsOiBhbnkpID0+IGlkID09PSBmaW5kTW9kZWxJZChlbCwgdHJ1ZSlcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgaWYgKE1vZGVsLmlzTW9kZWwoY2hpbGRWYWx1ZSkpIHtcbiAgICAgICAgICAgIHJldHVybiBjaGlsZFZhbHVlLmhhc0Vycm9ycyhvbGRNb2RlbCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIGFsbG93ZWRUeXBlcy5pbmNsdWRlcyh0eXBlb2YgY2hpbGRWYWx1ZSlcbiAgICAgICAgICAgID8gdW5kZWZpbmVkXG4gICAgICAgICAgICA6IFwiVmFsdWUgaGFzIG5vIHZhbGlkYXRhYmxlIHR5cGVcIjtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKGFzeW5jKSB7XG4gICAgICAgICAgdmFsaWRhdGlvbkVycm9ycyA9IFByb21pc2UuYWxsKGVycnMpLnRoZW4oKHJlc3VsdCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgYWxsRW1wdHkgPSByZXN1bHQuZXZlcnkoKHIpID0+ICFyKTtcbiAgICAgICAgICAgIHJldHVybiBhbGxFbXB0eSA/IHVuZGVmaW5lZCA6IHJlc3VsdDtcbiAgICAgICAgICB9KSBhcyBhbnk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgYWxsRW1wdHkgPSBlcnJzLmV2ZXJ5KChyOiBzdHJpbmcgfCB1bmRlZmluZWQpID0+ICFyKTtcbiAgICAgICAgICB2YWxpZGF0aW9uRXJyb3JzID0gZXJycy5sZW5ndGggPiAwICYmICFhbGxFbXB0eSA/IGVycnMgOiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodmFsaWRhdGlvbkVycm9ycykgKHJlc3VsdCBhcyBhbnkpW2RlY29yYXRvci5rZXldID0gdmFsaWRhdGlvbkVycm9ycztcbiAgfVxuXG4gIGlmICghYXN5bmMpXG4gICAgcmV0dXJuIE9iamVjdC5rZXlzKHJlc3VsdCkubGVuZ3RoID4gMCA/IChyZXN1bHQgYXMgYW55KSA6IHVuZGVmaW5lZDtcblxuICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMocmVzdWx0KTtcbiAgY29uc3QgcHJvbWlzZXMgPSBPYmplY3QudmFsdWVzKHJlc3VsdCkgYXMgUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+W107XG4gIHJldHVybiBQcm9taXNlLmFsbChwcm9taXNlcykudGhlbigocmVzb2x2ZWRWYWx1ZXMpID0+IHtcbiAgICBjb25zdCByZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJlc29sdmVkVmFsdWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCB2YWwgPSByZXNvbHZlZFZhbHVlc1tpXTtcbiAgICAgIGlmICh2YWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXNba2V5c1tpXV0gPSB2YWw7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBPYmplY3Qua2V5cyhyZXMpLmxlbmd0aCA+IDAgPyByZXMgOiB1bmRlZmluZWQ7XG4gIH0pIGFzIGFueTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gVmFsaWRhdGVzIGNoYW5nZXMgYmV0d2VlbiB0d28gbW9kZWwgdmVyc2lvbnNcbiAqIEBzdW1tYXJ5IENvbXBhcmVzIGFuIG9sZCBhbmQgbmV3IG1vZGVsIHZlcnNpb24gdG8gdmFsaWRhdGUgdXBkYXRlIG9wZXJhdGlvbnNcbiAqIEB0ZW1wbGF0ZSBNIC0gVHlwZSBleHRlbmRpbmcgTW9kZWxcbiAqIEBwYXJhbSB7TX0gb2xkTW9kZWwgLSBUaGUgb3JpZ2luYWwgbW9kZWwgdmVyc2lvblxuICogQHBhcmFtIHtNfSBuZXdNb2RlbCAtIFRoZSB1cGRhdGVkIG1vZGVsIHZlcnNpb25cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYXN5bmMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIHZhbGlkYXRpb24gc2hvdWxkIGJlIGFzeW5jaHJvbm91cy5cbiAqIEBwYXJhbSB7Li4uc3RyaW5nW119IGV4Y2VwdGlvbnMgLSBQcm9wZXJ0aWVzIHRvIGV4Y2x1ZGUgZnJvbSB2YWxpZGF0aW9uXG4gKiBAcmV0dXJuIHtNb2RlbEVycm9yRGVmaW5pdGlvbnx1bmRlZmluZWR9IEVycm9yIGRlZmluaXRpb24gaWYgdmFsaWRhdGlvbiBmYWlscywgdW5kZWZpbmVkIG90aGVyd2lzZVxuICogQGZ1bmN0aW9uIHZhbGlkYXRlQ29tcGFyZVxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCB2YWxpZGF0ZUNvbXBhcmVcbiAqICAgcGFydGljaXBhbnQgUmVmbGVjdGlvblxuICogICBwYXJ0aWNpcGFudCBWYWxpZGF0aW9uXG4gKlxuICogICBDYWxsZXItPj52YWxpZGF0ZUNvbXBhcmU6IG9sZE1vZGVsLCBuZXdNb2RlbCwgZXhjZXB0aW9uc1xuICogICB2YWxpZGF0ZUNvbXBhcmUtPj5SZWZsZWN0aW9uOiBnZXQgZGVjb3JhdGVkIHByb3BlcnRpZXNcbiAqICAgUmVmbGVjdGlvbi0tPj52YWxpZGF0ZUNvbXBhcmU6IHByb3BlcnR5IGRlY29yYXRvcnNcbiAqICAgbG9vcCBGb3IgZWFjaCBkZWNvcmF0ZWQgcHJvcGVydHlcbiAqICAgICB2YWxpZGF0ZUNvbXBhcmUtPj5WYWxpZGF0aW9uOiBnZXQgdmFsaWRhdG9yXG4gKiAgICAgVmFsaWRhdGlvbi0tPj52YWxpZGF0ZUNvbXBhcmU6IHZhbGlkYXRvclxuICogICAgIHZhbGlkYXRlQ29tcGFyZS0+PnZhbGlkYXRlQ29tcGFyZTogdmFsaWRhdGUgcHJvcGVydHkgdXBkYXRlXG4gKiAgIGVuZFxuICogICBsb29wIEZvciBuZXN0ZWQgbW9kZWxzXG4gKiAgICAgdmFsaWRhdGVDb21wYXJlLT4+dmFsaWRhdGVDb21wYXJlOiB2YWxpZGF0ZSBuZXN0ZWQgbW9kZWxzXG4gKiAgIGVuZFxuICogICB2YWxpZGF0ZUNvbXBhcmUtLT4+Q2FsbGVyOiB2YWxpZGF0aW9uIGVycm9ycyBvciB1bmRlZmluZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlQ29tcGFyZTxNIGV4dGVuZHMgTW9kZWw8YW55Pj4oXG4gIG9sZE1vZGVsOiBNLFxuICBuZXdNb2RlbDogTSxcbiAgYXN5bmM6IGJvb2xlYW4sXG4gIC4uLmV4Y2VwdGlvbnM6IHN0cmluZ1tdXG4pOiBNb2RlbENvbmRpdGlvbmFsQXN5bmM8TT4ge1xuICBjb25zdCBkZWNvcmF0ZWRQcm9wZXJ0aWVzOiBWYWxpZGF0aW9uUHJvcGVydHlEZWNvcmF0b3JEZWZpbml0aW9uW10gPVxuICAgIGdldFZhbGlkYXRhYmxlVXBkYXRlUHJvcHMobmV3TW9kZWwsIGV4Y2VwdGlvbnMpO1xuXG4gIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuXG4gIGNvbnN0IG5lc3RlZEVycm9yczogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICBmb3IgKGNvbnN0IHsgcHJvcCwgZGVjb3JhdG9ycyB9IG9mIGRlY29yYXRlZFByb3BlcnRpZXMpIHtcbiAgICBjb25zdCBwcm9wS2V5ID0gU3RyaW5nKHByb3ApO1xuICAgIGxldCBwcm9wVmFsdWUgPSAobmV3TW9kZWwgYXMgYW55KVtwcm9wXTtcblxuICAgIGlmICghZGVjb3JhdG9ycz8ubGVuZ3RoKSBjb250aW51ZTtcblxuICAgIC8vIEdldCB0aGUgZGVmYXVsdCB0eXBlIHZhbGlkYXRvclxuICAgIGNvbnN0IGRlc2lnblR5cGVEZWMgPSBkZWNvcmF0b3JzLmZpbmQoKGQpID0+XG4gICAgICBbTW9kZWxLZXlzLlRZUEUsIFZhbGlkYXRpb25LZXlzLlRZUEVdLmluY2x1ZGVzKGQua2V5IGFzIGFueSlcbiAgICApO1xuICAgIGlmICghZGVzaWduVHlwZURlYykgY29udGludWU7XG5cbiAgICBjb25zdCBkZXNpZ25UeXBlID0gZGVzaWduVHlwZURlYy5wcm9wcy5uYW1lO1xuXG4gICAgLy8gSGFuZGxlIGFycmF5IG9yIFNldCB0eXBlcyBhbmQgZW5mb3JjZSB0aGUgcHJlc2VuY2Ugb2YgQGxpc3QgZGVjb3JhdG9yXG4gICAgaWYgKFtBcnJheS5uYW1lLCBTZXQubmFtZV0uaW5jbHVkZXMoZGVzaWduVHlwZSkpIHtcbiAgICAgIGNvbnN0IHsgZGVjb3JhdG9ycyB9ID0gUmVmbGVjdGlvbi5nZXRQcm9wZXJ0eURlY29yYXRvcnMoXG4gICAgICAgIFZhbGlkYXRpb25LZXlzLlJFRkxFQ1QsXG4gICAgICAgIG5ld01vZGVsLFxuICAgICAgICBwcm9wS2V5XG4gICAgICApIGFzIHVua25vd24gYXMgVmFsaWRhdGlvblByb3BlcnR5RGVjb3JhdG9yRGVmaW5pdGlvbjtcblxuICAgICAgaWYgKCFkZWNvcmF0b3JzLnNvbWUoKGQpID0+IGQua2V5ID09PSBWYWxpZGF0aW9uS2V5cy5MSVNUKSkge1xuICAgICAgICByZXN1bHRbcHJvcEtleV0gPSB7XG4gICAgICAgICAgW1ZhbGlkYXRpb25LZXlzLlRZUEVdOiBgQXJyYXkgb3IgU2V0IHByb3BlcnR5ICcke3Byb3BLZXl9JyByZXF1aXJlcyBhIEBsaXN0IGRlY29yYXRvcmAsXG4gICAgICAgIH07XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAoXG4gICAgICAgIHByb3BWYWx1ZSAmJlxuICAgICAgICAhKEFycmF5LmlzQXJyYXkocHJvcFZhbHVlKSB8fCBwcm9wVmFsdWUgaW5zdGFuY2VvZiBTZXQpXG4gICAgICApIHtcbiAgICAgICAgcmVzdWx0W3Byb3BLZXldID0ge1xuICAgICAgICAgIFtWYWxpZGF0aW9uS2V5cy5UWVBFXTogYFByb3BlcnR5ICcke1N0cmluZyhwcm9wKX0nIG11c3QgYmUgZWl0aGVyIGFuIGFycmF5IG9yIGEgU2V0YCxcbiAgICAgICAgfTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIC8vIFJlbW92ZSBkZXNpZ246dHlwZSBkZWNvcmF0b3IsIHNpbmNlIEBsaXN0IGRlY29yYXRvciBhbHJlYWR5IGVuc3VyZXMgdHlwZVxuICAgICAgZm9yIChsZXQgaSA9IGRlY29yYXRvcnMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgICAgaWYgKGRlY29yYXRvcnNbaV0ua2V5ID09PSBNb2RlbEtleXMuVFlQRSkge1xuICAgICAgICAgIGRlY29yYXRvcnMuc3BsaWNlKGksIDEpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBwcm9wVmFsdWUgPSBwcm9wVmFsdWUgaW5zdGFuY2VvZiBTZXQgPyBbLi4ucHJvcFZhbHVlXSA6IHByb3BWYWx1ZTtcbiAgICB9XG5cbiAgICBjb25zdCBwcm9wRXJyb3JzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID1cbiAgICAgIHZhbGlkYXRlRGVjb3JhdG9ycyhuZXdNb2RlbCwgb2xkTW9kZWwsIHByb3BLZXksIGRlY29yYXRvcnMsIGFzeW5jKSB8fCB7fTtcblxuICAgIC8vIENoZWNrIGZvciBuZXN0ZWQgcHJvcGVydGllcy5cbiAgICAvLyBUbyBwcmV2ZW50IHVubmVjZXNzYXJ5IHByb2Nlc3NpbmcsIFwicHJvcFZhbHVlXCIgbXVzdCBiZSBkZWZpbmVkIGFuZCB2YWxpZGF0YWJsZVxuICAgIGNvbnN0IGlzQ29uc3RyID0gTW9kZWwuaXNQcm9wZXJ0eU1vZGVsKG5ld01vZGVsLCBwcm9wS2V5KTtcbiAgICAvLyBpZiBwcm9wVmFsdWUgIT09IHVuZGVmaW5lZCwgbnVsbFxuICAgIGlmIChwcm9wVmFsdWUgJiYgaXNDb25zdHIpIHtcbiAgICAgIGNvbnN0IGluc3RhbmNlOiBNb2RlbCA9IHByb3BWYWx1ZTtcbiAgICAgIGNvbnN0IGlzSW52YWxpZE1vZGVsID1cbiAgICAgICAgdHlwZW9mIGluc3RhbmNlICE9PSBcIm9iamVjdFwiIHx8XG4gICAgICAgICFpbnN0YW5jZS5oYXNFcnJvcnMgfHxcbiAgICAgICAgdHlwZW9mIGluc3RhbmNlLmhhc0Vycm9ycyAhPT0gXCJmdW5jdGlvblwiO1xuXG4gICAgICBpZiAoaXNJbnZhbGlkTW9kZWwpIHtcbiAgICAgICAgLy8gcHJvcEVycm9yc1tWYWxpZGF0aW9uS2V5cy5UWVBFXSA9XG4gICAgICAgIC8vICAgXCJNb2RlbCBzaG91bGQgYmUgdmFsaWRhdGFibGUgYnV0IGl0J3Mgbm90LlwiO1xuICAgICAgICBjb25zb2xlLndhcm4oXCJNb2RlbCBzaG91bGQgYmUgdmFsaWRhdGFibGUgYnV0IGl0J3Mgbm90LlwiKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG5lc3RlZEVycm9yc1twcm9wS2V5XSA9IGluc3RhbmNlLmhhc0Vycm9ycygob2xkTW9kZWwgYXMgYW55KVtwcm9wXSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQWRkIHRvIHRoZSByZXN1bHQgaWYgd2UgaGF2ZSBhbnkgZXJyb3JzXG4gICAgLy8gQXN5bmMgbW9kZSByZXR1cm5zIGEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHVuZGVmaW5lZCB3aGVuIG5vIGVycm9ycyBleGlzdFxuICAgIGlmIChPYmplY3Qua2V5cyhwcm9wRXJyb3JzKS5sZW5ndGggPiAwIHx8IGFzeW5jKVxuICAgICAgcmVzdWx0W3Byb3BLZXldID0gcHJvcEVycm9ycztcblxuICAgIC8vIFRoZW4gbWVyZ2UgYW55IG5lc3RlZCBlcnJvcnNcbiAgICBpZiAoIWFzeW5jKSB7XG4gICAgICBPYmplY3QuZW50cmllcyhuZXN0ZWRFcnJvcnNbcHJvcEtleV0gfHwge30pLmZvckVhY2goKFtrZXksIGVycm9yXSkgPT4ge1xuICAgICAgICBpZiAoZXJyb3IgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHJlc3VsdFtgJHtwcm9wS2V5fS4ke2tleX1gXSA9IGVycm9yO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICAvLyBTeW5jaHJvbm91cyByZXR1cm5cbiAgaWYgKCFhc3luYykge1xuICAgIHJldHVybiAoXG4gICAgICBPYmplY3Qua2V5cyhyZXN1bHQpLmxlbmd0aCA+IDBcbiAgICAgICAgPyBuZXcgTW9kZWxFcnJvckRlZmluaXRpb24ocmVzdWx0KVxuICAgICAgICA6IHVuZGVmaW5lZFxuICAgICkgYXMgYW55O1xuICB9XG5cbiAgY29uc3QgbWVyZ2VkOiBhbnkgPSByZXN1bHQ7IC8vIFRPRE86IGFwcGx5IGZpbHRlcmluZ1xuXG4gIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhtZXJnZWQpO1xuICBjb25zdCBwcm9taXNlcyA9IE9iamVjdC52YWx1ZXMobWVyZ2VkKTtcbiAgcmV0dXJuIFByb21pc2UuYWxsU2V0dGxlZChwcm9taXNlcykudGhlbihhc3luYyAocmVzdWx0cykgPT4ge1xuICAgIGNvbnN0IHJlc3VsdDogTW9kZWxFcnJvcnMgPSB7fTtcblxuICAgIGZvciAoY29uc3QgW3BhcmVudFByb3AsIG5lc3RlZEVyclByb21pc2VdIG9mIE9iamVjdC5lbnRyaWVzKG5lc3RlZEVycm9ycykpIHtcbiAgICAgIGNvbnN0IG5lc3RlZFByb3BEZWNFcnJvcnMgPSAoYXdhaXQgbmVzdGVkRXJyUHJvbWlzZSkgYXMgUmVjb3JkPFxuICAgICAgICBzdHJpbmcsXG4gICAgICAgIGFueVxuICAgICAgPjtcblxuICAgICAgaWYgKG5lc3RlZFByb3BEZWNFcnJvcnMpXG4gICAgICAgIE9iamVjdC5lbnRyaWVzKG5lc3RlZFByb3BEZWNFcnJvcnMpLmZvckVhY2goXG4gICAgICAgICAgKFtuZXN0ZWRQcm9wLCBuZXN0ZWRQcm9wRGVjRXJyb3JdKSA9PiB7XG4gICAgICAgICAgICBpZiAobmVzdGVkUHJvcERlY0Vycm9yICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgY29uc3QgbmVzdGVkS2V5ID0gW3BhcmVudFByb3AsIG5lc3RlZFByb3BdLmpvaW4oXCIuXCIpO1xuICAgICAgICAgICAgICByZXN1bHRbbmVzdGVkS2V5XSA9IG5lc3RlZFByb3BEZWNFcnJvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXN1bHRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBrZXkgPSBrZXlzW2ldO1xuICAgICAgY29uc3QgcmVzID0gcmVzdWx0c1tpXTtcblxuICAgICAgaWYgKHJlcy5zdGF0dXMgPT09IFwiZnVsZmlsbGVkXCIgJiYgcmVzLnZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgKHJlc3VsdCBhcyBhbnkpW2tleV0gPSByZXMudmFsdWU7XG4gICAgICB9IGVsc2UgaWYgKHJlcy5zdGF0dXMgPT09IFwicmVqZWN0ZWRcIikge1xuICAgICAgICAocmVzdWx0IGFzIGFueSlba2V5XSA9XG4gICAgICAgICAgcmVzLnJlYXNvbiBpbnN0YW5jZW9mIEVycm9yXG4gICAgICAgICAgICA/IHJlcy5yZWFzb24ubWVzc2FnZVxuICAgICAgICAgICAgOiBTdHJpbmcocmVzLnJlYXNvbiB8fCBcIlZhbGlkYXRpb24gZmFpbGVkXCIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBPYmplY3Qua2V5cyhyZXN1bHQpLmxlbmd0aCA+IDBcbiAgICAgID8gbmV3IE1vZGVsRXJyb3JEZWZpbml0aW9uKHJlc3VsdClcbiAgICAgIDogdW5kZWZpbmVkO1xuICB9KSBhcyBhbnk7XG59XG4iLCJpbXBvcnQgeyBEQktleXMsIERlZmF1bHRTZXBhcmF0b3IgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGFwcGx5IH0gZnJvbSBcIkBkZWNhZi10cy9yZWZsZWN0aW9uXCI7XG5pbXBvcnQge1xuICBEZWNvcmF0aW9uLFxuICBIYXNoaW5nLFxuICBNb2RlbCxcbiAgcHJvcE1ldGFkYXRhLFxuICB0eXBlLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBvbkNyZWF0ZSwgb25DcmVhdGVVcGRhdGUsIG9uVXBkYXRlIH0gZnJvbSBcIi4uL29wZXJhdGlvbnMvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgSVJlcG9zaXRvcnkgfSBmcm9tIFwiLi4vaW50ZXJmYWNlcy9JUmVwb3NpdG9yeVwiO1xuaW1wb3J0IHsgSW50ZXJuYWxFcnJvciB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L2Vycm9yc1wiO1xuaW1wb3J0IHsgUmVwb3NpdG9yeSB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L1JlcG9zaXRvcnlcIjtcbmltcG9ydCB7IENvbnRleHQgfSBmcm9tIFwiLi4vcmVwb3NpdG9yeS9Db250ZXh0XCI7XG5pbXBvcnQgeyBDcnVkT3BlcmF0aW9ucywgR3JvdXBTb3J0LCBPcGVyYXRpb25LZXlzIH0gZnJvbSBcIi4uL29wZXJhdGlvbnNcIjtcbmltcG9ydCB7IFJlcG9zaXRvcnlGbGFncyB9IGZyb20gXCIuLi9yZXBvc2l0b3J5L3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEhhc2hlcyBhIHByb3BlcnR5IHZhbHVlIGR1cmluZyBjcmVhdGUgb3IgdXBkYXRlIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IENhbGxiYWNrIGZ1bmN0aW9uIHVzZWQgYnkgdGhlIGhhc2ggZGVjb3JhdG9yIHRvIGFwcGx5IGhhc2hpbmcgdG8gYSBwcm9wZXJ0eSB2YWx1ZVxuICogQHRlbXBsYXRlIE0gLSBUeXBlIGV4dGVuZGluZyBNb2RlbFxuICogQHRlbXBsYXRlIFIgLSBUeXBlIGV4dGVuZGluZyBJUmVwb3NpdG9yeVxuICogQHRlbXBsYXRlIFYgLSBUeXBlIGZvciBtZXRhZGF0YVxuICogQHRlbXBsYXRlIEYgLSBUeXBlIGV4dGVuZGluZyBSZXBvc2l0b3J5RmxhZ3NcbiAqIEB0ZW1wbGF0ZSBDIC0gVHlwZSBleHRlbmRpbmcgQ29udGV4dFxuICogQHBhcmFtIHtDfSBjb250ZXh0IC0gVGhlIG9wZXJhdGlvbiBjb250ZXh0XG4gKiBAcGFyYW0ge1Z9IGRhdGEgLSBNZXRhZGF0YSBmb3IgdGhlIG9wZXJhdGlvblxuICogQHBhcmFtIGtleSAtIFRoZSBwcm9wZXJ0eSBrZXkgdG8gaGFzaFxuICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBiZWluZyBwcm9jZXNzZWRcbiAqIEBwYXJhbSB7TX0gW29sZE1vZGVsXSAtIFRoZSBwcmV2aW91cyBtb2RlbCBzdGF0ZSAoZm9yIHVwZGF0ZXMpXG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGZ1bmN0aW9uIGhhc2hPbkNyZWF0ZVVwZGF0ZVxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNoT25DcmVhdGVVcGRhdGU8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIElSZXBvc2l0b3J5PE0sIEYsIEM+LFxuICBWIGV4dGVuZHMgb2JqZWN0LFxuICBGIGV4dGVuZHMgUmVwb3NpdG9yeUZsYWdzID0gUmVwb3NpdG9yeUZsYWdzLFxuICBDIGV4dGVuZHMgQ29udGV4dDxGPiA9IENvbnRleHQ8Rj4sXG4+KHRoaXM6IFIsIGNvbnRleHQ6IEMsIGRhdGE6IFYsIGtleToga2V5b2YgTSwgbW9kZWw6IE0sIG9sZE1vZGVsPzogTSk6IHZvaWQge1xuICBpZiAodHlwZW9mIG1vZGVsW2tleV0gPT09IFwidW5kZWZpbmVkXCIpIHJldHVybjtcbiAgY29uc3QgaGFzaCA9IEhhc2hpbmcuaGFzaCgobW9kZWwgYXMgYW55KVtrZXldKTtcbiAgaWYgKG9sZE1vZGVsICYmIChtb2RlbCBhcyBhbnkpW2tleV0gPT09IGhhc2gpIHJldHVybjtcbiAgbW9kZWxba2V5XSA9IGhhc2g7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBkZWNvcmF0b3IgdGhhdCBoYXNoZXMgYSBwcm9wZXJ0eSB2YWx1ZVxuICogQHN1bW1hcnkgRGVjb3JhdG9yIHRoYXQgYXV0b21hdGljYWxseSBoYXNoZXMgYSBwcm9wZXJ0eSB2YWx1ZSBkdXJpbmcgY3JlYXRlIGFuZCB1cGRhdGUgb3BlcmF0aW9uc1xuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgZGVjb3JhdG9yIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gY2xhc3MgcHJvcGVydGllc1xuICogQGZ1bmN0aW9uIGhhc2hcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eSBEZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNoKCkge1xuICByZXR1cm4gYXBwbHkoXG4gICAgb25DcmVhdGVVcGRhdGUoaGFzaE9uQ3JlYXRlVXBkYXRlKSxcbiAgICBwcm9wTWV0YWRhdGEoUmVwb3NpdG9yeS5rZXkoREJLZXlzLkhBU0gpLCB7fSlcbiAgKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gTWV0YWRhdGEgZm9yIGNvbXBvc2VkIHByb3BlcnR5IGRlY29yYXRvcnNcbiAqIEBzdW1tYXJ5IENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgcHJvcGVydHkgY29tcG9zaXRpb24gZnJvbSBvdGhlciBwcm9wZXJ0aWVzXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBDb21wb3NlZEZyb21NZXRhZGF0YVxuICogQHByb3BlcnR5IHtzdHJpbmdbXX0gYXJncyAtIFByb3BlcnR5IG5hbWVzIHRvIGNvbXBvc2UgZnJvbVxuICogQHByb3BlcnR5IHtzdHJpbmd9IHNlcGFyYXRvciAtIENoYXJhY3RlciB1c2VkIHRvIGpvaW4gdGhlIGNvbXBvc2VkIHZhbHVlc1xuICogQHByb3BlcnR5IHtib29sZWFufSBoYXNoUmVzdWx0IC0gV2hldGhlciB0byBoYXNoIHRoZSBjb21wb3NlZCByZXN1bHRcbiAqIEBwcm9wZXJ0eSB7XCJrZXlzXCJ8XCJ2YWx1ZXNcIn0gdHlwZSAtIFdoZXRoZXIgdG8gdXNlIHByb3BlcnR5IGtleXMgb3IgdmFsdWVzXG4gKiBAcHJvcGVydHkge3N0cmluZ30gW3ByZWZpeF0gLSBPcHRpb25hbCBwcmVmaXggdG8gYWRkIHRvIHRoZSBjb21wb3NlZCB2YWx1ZVxuICogQHByb3BlcnR5IHtzdHJpbmd9IFtzdWZmaXhdIC0gT3B0aW9uYWwgc3VmZml4IHRvIGFkZCB0byB0aGUgY29tcG9zZWQgdmFsdWVcbiAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9yc1xuICovXG5leHBvcnQgdHlwZSBDb21wb3NlZEZyb21NZXRhZGF0YSA9IHtcbiAgYXJnczogc3RyaW5nW107XG4gIHNlcGFyYXRvcjogc3RyaW5nO1xuICBoYXNoUmVzdWx0OiBib29sZWFuO1xuICB0eXBlOiBcImtleXNcIiB8IFwidmFsdWVzXCI7XG4gIHByZWZpeD86IHN0cmluZztcbiAgc3VmZml4Pzogc3RyaW5nO1xufTtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ29tcG9zZXMgYSBwcm9wZXJ0eSB2YWx1ZSBmcm9tIG90aGVyIHByb3BlcnRpZXMgZHVyaW5nIGNyZWF0ZSBvciB1cGRhdGUgb3BlcmF0aW9uc1xuICogQHN1bW1hcnkgQ2FsbGJhY2sgZnVuY3Rpb24gdXNlZCBieSBjb21wb3NlZCBkZWNvcmF0b3JzIHRvIGdlbmVyYXRlIGEgcHJvcGVydHkgdmFsdWUgZnJvbSBvdGhlciBwcm9wZXJ0aWVzXG4gKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgUiAtIFR5cGUgZXh0ZW5kaW5nIElSZXBvc2l0b3J5XG4gKiBAdGVtcGxhdGUgViAtIFR5cGUgZXh0ZW5kaW5nIENvbXBvc2VkRnJvbU1ldGFkYXRhXG4gKiBAdGVtcGxhdGUgRiAtIFR5cGUgZXh0ZW5kaW5nIFJlcG9zaXRvcnlGbGFnc1xuICogQHRlbXBsYXRlIEMgLSBUeXBlIGV4dGVuZGluZyBDb250ZXh0XG4gKiBAcGFyYW0ge0N9IGNvbnRleHQgLSBUaGUgb3BlcmF0aW9uIGNvbnRleHRcbiAqIEBwYXJhbSB7Vn0gZGF0YSAtIE1ldGFkYXRhIGZvciB0aGUgY29tcG9zaXRpb25cbiAqIEBwYXJhbSBrZXkgLSBUaGUgcHJvcGVydHkga2V5IHRvIHNldCB0aGUgY29tcG9zZWQgdmFsdWUgb25cbiAqIEBwYXJhbSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgYmVpbmcgcHJvY2Vzc2VkXG4gKiBAcmV0dXJuIHt2b2lkfVxuICogQGZ1bmN0aW9uIGNvbXBvc2VkRnJvbUNyZWF0ZVVwZGF0ZVxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wb3NlZEZyb21DcmVhdGVVcGRhdGU8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIElSZXBvc2l0b3J5PE0sIEYsIEM+LFxuICBWIGV4dGVuZHMgQ29tcG9zZWRGcm9tTWV0YWRhdGEsXG4gIEYgZXh0ZW5kcyBSZXBvc2l0b3J5RmxhZ3MgPSBSZXBvc2l0b3J5RmxhZ3MsXG4gIEMgZXh0ZW5kcyBDb250ZXh0PEY+ID0gQ29udGV4dDxGPixcbj4odGhpczogUiwgY29udGV4dDogQywgZGF0YTogViwga2V5OiBrZXlvZiBNLCBtb2RlbDogTSkge1xuICB0cnkge1xuICAgIGNvbnN0IHsgYXJncywgdHlwZSwgcHJlZml4LCBzdWZmaXgsIHNlcGFyYXRvciB9ID0gZGF0YTtcbiAgICBjb25zdCBjb21wb3NlZCA9IGFyZ3MubWFwKChhcmc6IHN0cmluZykgPT4ge1xuICAgICAgaWYgKCEoYXJnIGluIG1vZGVsKSlcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYFByb3BlcnR5ICR7YXJnfSBub3QgZm91bmQgdG8gY29tcG9zZSBmcm9tYCk7XG4gICAgICBpZiAodHlwZSA9PT0gXCJrZXlzXCIpIHJldHVybiBhcmc7XG4gICAgICBpZiAodHlwZW9mIChtb2RlbCBhcyBhbnkpW2FyZ10gPT09IFwidW5kZWZpbmVkXCIpXG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgIGBQcm9wZXJ0eSAke2FyZ3N9IGRvZXMgbm90IGNvbnRhaW4gYSB2YWx1ZSB0byBjb21wb3NlIGZyb21gXG4gICAgICAgICk7XG4gICAgICByZXR1cm4gKChtb2RlbCBhcyBhbnkpW2FyZ10gYXMgYW55KS50b1N0cmluZygpO1xuICAgIH0pO1xuXG4gICAgaWYgKHByZWZpeCkgY29tcG9zZWQudW5zaGlmdChwcmVmaXgpO1xuICAgIGlmIChzdWZmaXgpIGNvbXBvc2VkLnB1c2goc3VmZml4KTtcblxuICAgIChtb2RlbCBhcyBhbnkpW2tleV0gPSBjb21wb3NlZC5qb2luKHNlcGFyYXRvcik7XG4gIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBGYWlsZWQgdG8gY29tcG9zZSB2YWx1ZTogJHtlfWApO1xuICB9XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBkZWNvcmF0b3IgdGhhdCBjb21wb3NlcyBhIHByb3BlcnR5IHZhbHVlIGZyb20gb3RoZXIgcHJvcGVydGllc1xuICogQHN1bW1hcnkgQmFzZSBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgcHJvcGVydHkgY29tcG9zaXRpb24gZGVjb3JhdG9yc1xuICogQHBhcmFtIHtzdHJpbmdbXX0gYXJncyAtIFByb3BlcnR5IG5hbWVzIHRvIGNvbXBvc2UgZnJvbVxuICogQHBhcmFtIHtib29sZWFufSBbaGFzaFJlc3VsdD1mYWxzZV0gLSBXaGV0aGVyIHRvIGhhc2ggdGhlIGNvbXBvc2VkIHJlc3VsdFxuICogQHBhcmFtIHtzdHJpbmd9IFtzZXBhcmF0b3I9RGVmYXVsdFNlcGFyYXRvcl0gLSBDaGFyYWN0ZXIgdXNlZCB0byBqb2luIHRoZSBjb21wb3NlZCB2YWx1ZXNcbiAqIEBwYXJhbSB7XCJrZXlzXCJ8XCJ2YWx1ZXNcIn0gW3R5cGU9XCJ2YWx1ZXNcIl0gLSBXaGV0aGVyIHRvIHVzZSBwcm9wZXJ0eSBrZXlzIG9yIHZhbHVlc1xuICogQHBhcmFtIHtzdHJpbmd9IFtwcmVmaXg9XCJcIl0gLSBPcHRpb25hbCBwcmVmaXggdG8gYWRkIHRvIHRoZSBjb21wb3NlZCB2YWx1ZVxuICogQHBhcmFtIHtzdHJpbmd9IFtzdWZmaXg9XCJcIl0gLSBPcHRpb25hbCBzdWZmaXggdG8gYWRkIHRvIHRoZSBjb21wb3NlZCB2YWx1ZVxuICogQHBhcmFtIHtHcm91cFNvcnR9IGdyb3Vwc29ydCAtIEdyb3VwU29ydCBjb25maWd1cmF0aW9uXG4gKiBAcmV0dXJuIHtQcm9wZXJ0eURlY29yYXRvcn0gQSBkZWNvcmF0b3IgdGhhdCBjYW4gYmUgYXBwbGllZCB0byBjbGFzcyBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gY29tcG9zZWRGcm9tXG4gKiBAY2F0ZWdvcnkgUHJvcGVydHlEZWNvcmF0b3JzXG4gKi9cbmZ1bmN0aW9uIGNvbXBvc2VkRnJvbShcbiAgYXJnczogc3RyaW5nW10sXG4gIGhhc2hSZXN1bHQ6IGJvb2xlYW4gPSBmYWxzZSxcbiAgc2VwYXJhdG9yOiBzdHJpbmcgPSBEZWZhdWx0U2VwYXJhdG9yLFxuICB0eXBlOiBcImtleXNcIiB8IFwidmFsdWVzXCIgPSBcInZhbHVlc1wiLFxuICBwcmVmaXggPSBcIlwiLFxuICBzdWZmaXggPSBcIlwiLFxuICBncm91cHNvcnQ6IEdyb3VwU29ydCA9IHsgcHJpb3JpdHk6IDU1IH1cbikge1xuICBjb25zdCBkYXRhOiBDb21wb3NlZEZyb21NZXRhZGF0YSA9IHtcbiAgICBhcmdzOiBhcmdzLFxuICAgIGhhc2hSZXN1bHQ6IGhhc2hSZXN1bHQsXG4gICAgc2VwYXJhdG9yOiBzZXBhcmF0b3IsXG4gICAgdHlwZTogdHlwZSxcbiAgICBwcmVmaXg6IHByZWZpeCxcbiAgICBzdWZmaXg6IHN1ZmZpeCxcbiAgfTtcblxuICBjb25zdCBkZWNvcmF0b3JzID0gW1xuICAgIG9uQ3JlYXRlVXBkYXRlKGNvbXBvc2VkRnJvbUNyZWF0ZVVwZGF0ZSwgZGF0YSwgZ3JvdXBzb3J0KSxcbiAgICBwcm9wTWV0YWRhdGEoUmVwb3NpdG9yeS5rZXkoREJLZXlzLkNPTVBPU0VEKSwgZGF0YSksXG4gIF07XG4gIGlmIChoYXNoUmVzdWx0KSBkZWNvcmF0b3JzLnB1c2goaGFzaCgpKTtcbiAgcmV0dXJuIGFwcGx5KC4uLmRlY29yYXRvcnMpO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgZGVjb3JhdG9yIHRoYXQgY29tcG9zZXMgYSBwcm9wZXJ0eSB2YWx1ZSBmcm9tIHByb3BlcnR5IGtleXNcbiAqIEBzdW1tYXJ5IERlY29yYXRvciB0aGF0IGdlbmVyYXRlcyBhIHByb3BlcnR5IHZhbHVlIGJ5IGpvaW5pbmcgdGhlIG5hbWVzIG9mIG90aGVyIHByb3BlcnRpZXNcbiAqIEBwYXJhbSB7c3RyaW5nW119IGFyZ3MgLSBQcm9wZXJ0eSBuYW1lcyB0byBjb21wb3NlIGZyb21cbiAqIEBwYXJhbSB7c3RyaW5nfSBbc2VwYXJhdG9yPURlZmF1bHRTZXBhcmF0b3JdIC0gQ2hhcmFjdGVyIHVzZWQgdG8gam9pbiB0aGUgcHJvcGVydHkgbmFtZXNcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2hhc2g9ZmFsc2VdIC0gV2hldGhlciB0byBoYXNoIHRoZSBjb21wb3NlZCByZXN1bHRcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcHJlZml4PVwiXCJdIC0gT3B0aW9uYWwgcHJlZml4IHRvIGFkZCB0byB0aGUgY29tcG9zZWQgdmFsdWVcbiAqIEBwYXJhbSB7c3RyaW5nfSBbc3VmZml4PVwiXCJdIC0gT3B0aW9uYWwgc3VmZml4IHRvIGFkZCB0byB0aGUgY29tcG9zZWQgdmFsdWVcbiAqIEBwYXJhbSB7R3JvdXBTb3J0fSBncm91cHNvcnQgLSBHcm91cFNvcnQgY29uZmlndXJhdGlvblxuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgZGVjb3JhdG9yIHRoYXQgY2FuIGJlIGFwcGxpZWQgdG8gY2xhc3MgcHJvcGVydGllc1xuICogQGZ1bmN0aW9uIGNvbXBvc2VkRnJvbUtleXNcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eURlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbXBvc2VkRnJvbUtleXMoXG4gIGFyZ3M6IHN0cmluZ1tdLFxuICBzZXBhcmF0b3I6IHN0cmluZyA9IERlZmF1bHRTZXBhcmF0b3IsXG4gIGhhc2g6IGJvb2xlYW4gPSBmYWxzZSxcbiAgcHJlZml4ID0gXCJcIixcbiAgc3VmZml4ID0gXCJcIixcbiAgZ3JvdXBzb3J0OiBHcm91cFNvcnQgPSB7IHByaW9yaXR5OiA1NSB9XG4pIHtcbiAgcmV0dXJuIGNvbXBvc2VkRnJvbShhcmdzLCBoYXNoLCBzZXBhcmF0b3IsIFwia2V5c1wiLCBwcmVmaXgsIHN1ZmZpeCwgZ3JvdXBzb3J0KTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGRlY29yYXRvciB0aGF0IGNvbXBvc2VzIGEgcHJvcGVydHkgdmFsdWUgZnJvbSBwcm9wZXJ0eSB2YWx1ZXNcbiAqIEBzdW1tYXJ5IERlY29yYXRvciB0aGF0IGdlbmVyYXRlcyBhIHByb3BlcnR5IHZhbHVlIGJ5IGpvaW5pbmcgdGhlIHZhbHVlcyBvZiBvdGhlciBwcm9wZXJ0aWVzXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBhcmdzIC0gUHJvcGVydHkgbmFtZXMgd2hvc2UgdmFsdWVzIHdpbGwgYmUgY29tcG9zZWRcbiAqIEBwYXJhbSB7c3RyaW5nfSBbc2VwYXJhdG9yPURlZmF1bHRTZXBhcmF0b3JdIC0gQ2hhcmFjdGVyIHVzZWQgdG8gam9pbiB0aGUgcHJvcGVydHkgdmFsdWVzXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtoYXNoPWZhbHNlXSAtIFdoZXRoZXIgdG8gaGFzaCB0aGUgY29tcG9zZWQgcmVzdWx0XG4gKiBAcGFyYW0ge3N0cmluZ30gW3ByZWZpeD1cIlwiXSAtIE9wdGlvbmFsIHByZWZpeCB0byBhZGQgdG8gdGhlIGNvbXBvc2VkIHZhbHVlXG4gKiBAcGFyYW0ge3N0cmluZ30gW3N1ZmZpeD1cIlwiXSAtIE9wdGlvbmFsIHN1ZmZpeCB0byBhZGQgdG8gdGhlIGNvbXBvc2VkIHZhbHVlXG4gKiBAcGFyYW0ge0dyb3VwU29ydH0gZ3JvdXBzb3J0IC0gR3JvdXBTb3J0IGNvbmZpZ3VyYXRpb25cbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGNsYXNzIHByb3BlcnRpZXNcbiAqIEBmdW5jdGlvbiBjb21wb3NlZFxuICogQGNhdGVnb3J5IFByb3BlcnR5RGVjb3JhdG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcG9zZWQoXG4gIGFyZ3M6IHN0cmluZ1tdLFxuICBzZXBhcmF0b3I6IHN0cmluZyA9IERlZmF1bHRTZXBhcmF0b3IsXG4gIGhhc2g6IGJvb2xlYW4gPSBmYWxzZSxcbiAgcHJlZml4ID0gXCJcIixcbiAgc3VmZml4ID0gXCJcIixcbiAgZ3JvdXBzb3J0OiBHcm91cFNvcnQgPSB7IHByaW9yaXR5OiA1NSB9XG4pIHtcbiAgcmV0dXJuIGNvbXBvc2VkRnJvbShcbiAgICBhcmdzLFxuICAgIGhhc2gsXG4gICAgc2VwYXJhdG9yLFxuICAgIFwidmFsdWVzXCIsXG4gICAgcHJlZml4LFxuICAgIHN1ZmZpeCxcbiAgICBncm91cHNvcnRcbiAgKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGZ1bmN0aW9uIHRoYXQgdXBkYXRlcyBhIHZlcnNpb24gcHJvcGVydHkgZHVyaW5nIG9wZXJhdGlvbnNcbiAqIEBzdW1tYXJ5IEZhY3RvcnkgZnVuY3Rpb24gdGhhdCBnZW5lcmF0ZXMgYSBjYWxsYmFjayBmb3IgaW5jcmVtZW50aW5nIHZlcnNpb24gbnVtYmVyc1xuICogQHBhcmFtIHtDcnVkT3BlcmF0aW9uc30gb3BlcmF0aW9uIC0gVGhlIHR5cGUgb2Ygb3BlcmF0aW9uIChDUkVBVEUgb3IgVVBEQVRFKVxuICogQHJldHVybiB7RnVuY3Rpb259IEEgY2FsbGJhY2sgZnVuY3Rpb24gdGhhdCB1cGRhdGVzIHRoZSB2ZXJzaW9uIHByb3BlcnR5XG4gKiBAdGVtcGxhdGUgTSAtIFR5cGUgZXh0ZW5kaW5nIE1vZGVsXG4gKiBAdGVtcGxhdGUgUiAtIFR5cGUgZXh0ZW5kaW5nIElSZXBvc2l0b3J5XG4gKiBAdGVtcGxhdGUgViAtIFR5cGUgZm9yIG1ldGFkYXRhXG4gKiBAdGVtcGxhdGUgRiAtIFR5cGUgZXh0ZW5kaW5nIFJlcG9zaXRvcnlGbGFnc1xuICogQHRlbXBsYXRlIEMgLSBUeXBlIGV4dGVuZGluZyBDb250ZXh0XG4gKiBAZnVuY3Rpb24gdmVyc2lvbkNyZWF0ZVVwZGF0ZVxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCB2ZXJzaW9uQ3JlYXRlVXBkYXRlXG4gKlxuICogICBDYWxsZXItPj52ZXJzaW9uQ3JlYXRlVXBkYXRlOiBvcGVyYXRpb25cbiAqICAgdmVyc2lvbkNyZWF0ZVVwZGF0ZS0tPj5DYWxsZXI6IGNhbGxiYWNrIGZ1bmN0aW9uXG4gKiAgIE5vdGUgb3ZlciBDYWxsZXIsdmVyc2lvbkNyZWF0ZVVwZGF0ZTogV2hlbiBjYWxsYmFjayBpcyBleGVjdXRlZDpcbiAqICAgQ2FsbGVyLT4+dmVyc2lvbkNyZWF0ZVVwZGF0ZTogY29udGV4dCwgZGF0YSwga2V5LCBtb2RlbFxuICogICBhbHQgb3BlcmF0aW9uIGlzIENSRUFURVxuICogICAgIHZlcnNpb25DcmVhdGVVcGRhdGUtPj52ZXJzaW9uQ3JlYXRlVXBkYXRlOiBzZXQgdmVyc2lvbiB0byAxXG4gKiAgIGVsc2Ugb3BlcmF0aW9uIGlzIFVQREFURVxuICogICAgIHZlcnNpb25DcmVhdGVVcGRhdGUtPj52ZXJzaW9uQ3JlYXRlVXBkYXRlOiBpbmNyZW1lbnQgdmVyc2lvblxuICogICBlbHNlIGludmFsaWQgb3BlcmF0aW9uXG4gKiAgICAgdmVyc2lvbkNyZWF0ZVVwZGF0ZS0+PnZlcnNpb25DcmVhdGVVcGRhdGU6IHRocm93IGVycm9yXG4gKiAgIGVuZFxuICogICB2ZXJzaW9uQ3JlYXRlVXBkYXRlLS0+PkNhbGxlcjogdm9pZFxuICovXG5leHBvcnQgZnVuY3Rpb24gdmVyc2lvbkNyZWF0ZVVwZGF0ZShvcGVyYXRpb246IENydWRPcGVyYXRpb25zKSB7XG4gIHJldHVybiBmdW5jdGlvbiB2ZXJzaW9uQ3JlYXRlVXBkYXRlPFxuICAgIE0gZXh0ZW5kcyBNb2RlbCxcbiAgICBSIGV4dGVuZHMgSVJlcG9zaXRvcnk8TSwgRiwgQz4sXG4gICAgViBleHRlbmRzIG9iamVjdCxcbiAgICBGIGV4dGVuZHMgUmVwb3NpdG9yeUZsYWdzID0gUmVwb3NpdG9yeUZsYWdzLFxuICAgIEMgZXh0ZW5kcyBDb250ZXh0PEY+ID0gQ29udGV4dDxGPixcbiAgPih0aGlzOiBSLCBjb250ZXh0OiBDLCBkYXRhOiBWLCBrZXk6IGtleW9mIE0sIG1vZGVsOiBNKSB7XG4gICAgdHJ5IHtcbiAgICAgIHN3aXRjaCAob3BlcmF0aW9uKSB7XG4gICAgICAgIGNhc2UgT3BlcmF0aW9uS2V5cy5DUkVBVEU6XG4gICAgICAgICAgKG1vZGVsIGFzIGFueSlba2V5XSA9IDE7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgT3BlcmF0aW9uS2V5cy5VUERBVEU6XG4gICAgICAgICAgKG1vZGVsIGFzIGFueSlba2V5XSsrO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBJbnZhbGlkIG9wZXJhdGlvbjogJHtvcGVyYXRpb259YCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYEZhaWxlZCB0byB1cGRhdGUgdmVyc2lvbjogJHtlfWApO1xuICAgIH1cbiAgfTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGRlY29yYXRvciBmb3IgdmVyc2lvbmluZyBhIHByb3BlcnR5IGluIGEgbW9kZWxcbiAqIEBzdW1tYXJ5IFRoaXMgZGVjb3JhdG9yIGFwcGxpZXMgbXVsdGlwbGUgc3ViLWRlY29yYXRvcnMgdG8gaGFuZGxlIHZlcnNpb24gbWFuYWdlbWVudCBkdXJpbmcgY3JlYXRlIGFuZCB1cGRhdGUgb3BlcmF0aW9uc1xuICogQHJldHVybiB7UHJvcGVydHlEZWNvcmF0b3J9IEEgY29tcG9zaXRlIGRlY29yYXRvciB0aGF0IHNldHMgdGhlIHR5cGUgdG8gTnVtYmVyLCBtYW5hZ2VzIHZlcnNpb24gdXBkYXRlcywgYW5kIGFkZHMgdmVyc2lvbmluZyBtZXRhZGF0YVxuICogQGZ1bmN0aW9uIHZlcnNpb25cbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eURlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZlcnNpb24oKSB7XG4gIGNvbnN0IGtleSA9IFJlcG9zaXRvcnkua2V5KERCS2V5cy5WRVJTSU9OKTtcbiAgcmV0dXJuIERlY29yYXRpb24uZm9yKGtleSlcbiAgICAuZGVmaW5lKFxuICAgICAgdHlwZShOdW1iZXIubmFtZSksXG4gICAgICBvbkNyZWF0ZSh2ZXJzaW9uQ3JlYXRlVXBkYXRlKE9wZXJhdGlvbktleXMuQ1JFQVRFKSksXG4gICAgICBvblVwZGF0ZSh2ZXJzaW9uQ3JlYXRlVXBkYXRlKE9wZXJhdGlvbktleXMuVVBEQVRFKSksXG4gICAgICBwcm9wTWV0YWRhdGEoa2V5LCB0cnVlKVxuICAgIClcbiAgICAuYXBwbHkoKTtcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGRlY29yYXRvciB0aGF0IG1hcmtzIGEgcHJvcGVydHkgYXMgdHJhbnNpZW50XG4gKiBAc3VtbWFyeSBEZWNvcmF0b3IgdGhhdCBpbmRpY2F0ZXMgYSBwcm9wZXJ0eSBzaG91bGQgbm90IGJlIHBlcnNpc3RlZCB0byB0aGUgZGF0YWJhc2VcbiAqIEByZXR1cm4ge1Byb3BlcnR5RGVjb3JhdG9yfSBBIGRlY29yYXRvciB0aGF0IGNhbiBiZSBhcHBsaWVkIHRvIGNsYXNzIHByb3BlcnRpZXNcbiAqIEBmdW5jdGlvbiB0cmFuc2llbnRcbiAqIEBjYXRlZ29yeSBQcm9wZXJ0eURlY29yYXRvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zaWVudCgpIHtcbiAgY29uc3Qga2V5ID0gUmVwb3NpdG9yeS5rZXkoREJLZXlzLlRSQU5TSUVOVCk7XG4gIHJldHVybiBEZWNvcmF0aW9uLmZvcihrZXkpXG4gICAgLmRlZmluZShmdW5jdGlvbiB0cmFuc2llbnQobW9kZWw6IGFueSwgYXR0cmlidXRlOiBhbnkpIHtcbiAgICAgIHByb3BNZXRhZGF0YShSZXBvc2l0b3J5LmtleShEQktleXMuVFJBTlNJRU5UKSwgdHJ1ZSkobW9kZWwsIGF0dHJpYnV0ZSk7XG4gICAgICBwcm9wTWV0YWRhdGEoUmVwb3NpdG9yeS5rZXkoREJLZXlzLlRSQU5TSUVOVCksIHRydWUpKG1vZGVsLmNvbnN0cnVjdG9yKTtcbiAgICB9KVxuICAgIC5hcHBseSgpO1xufVxuIiwiaW1wb3J0IHtcbiAgTW9kZWwsXG4gIE1vZGVsQ29uZGl0aW9uYWxBc3luYyxcbiAgdmFsaWRhdGUsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IHZhbGlkYXRlQ29tcGFyZSB9IGZyb20gXCIuL3ZhbGlkYXRpb25cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gVmFsaWRhdGVzIHRoZSBtb2RlbCBhbmQgY2hlY2tzIGZvciBlcnJvcnNcbiAqIEBzdW1tYXJ5IFZhbGlkYXRlcyB0aGUgY3VycmVudCBtb2RlbCBzdGF0ZSBhbmQgb3B0aW9uYWxseSBjb21wYXJlcyB3aXRoIGEgcHJldmlvdXMgdmVyc2lvblxuICogQHRlbXBsYXRlIE0gLSBUeXBlIGV4dGVuZGluZyBNb2RlbFxuICogQHBhcmFtIHtNfGFueX0gW3ByZXZpb3VzVmVyc2lvbl0gLSBPcHRpb25hbCBwcmV2aW91cyB2ZXJzaW9uIG9mIHRoZSBtb2RlbCBmb3IgY29tcGFyaXNvblxuICogQHBhcmFtIHsuLi5hbnlbXX0gZXhjbHVzaW9ucyAtIFByb3BlcnRpZXMgdG8gZXhjbHVkZSBmcm9tIHZhbGlkYXRpb25cbiAqIEByZXR1cm4ge01vZGVsRXJyb3JEZWZpbml0aW9ufHVuZGVmaW5lZH0gRXJyb3IgZGVmaW5pdGlvbiBpZiB2YWxpZGF0aW9uIGZhaWxzLCB1bmRlZmluZWQgb3RoZXJ3aXNlXG4gKiBAZnVuY3Rpb24gaGFzRXJyb3JzXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmRiLWRlY29yYXRvcnNcbiAqL1xuTW9kZWwucHJvdG90eXBlLmhhc0Vycm9ycyA9IGZ1bmN0aW9uIDxNIGV4dGVuZHMgTW9kZWw8dHJ1ZSB8IGZhbHNlPj4oXG4gIHRoaXM6IE0sXG4gIHByZXZpb3VzVmVyc2lvbj86IE0gfCBhbnksXG4gIC4uLmV4Y2x1c2lvbnM6IGFueVtdXG4pOiBNb2RlbENvbmRpdGlvbmFsQXN5bmM8TT4ge1xuICBpZiAocHJldmlvdXNWZXJzaW9uICYmICEocHJldmlvdXNWZXJzaW9uIGluc3RhbmNlb2YgTW9kZWwpKSB7XG4gICAgZXhjbHVzaW9ucy51bnNoaWZ0KHByZXZpb3VzVmVyc2lvbik7XG4gICAgcHJldmlvdXNWZXJzaW9uID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgY29uc3QgYXN5bmMgPSB0aGlzLmlzQXN5bmMoKTtcbiAgY29uc3QgZXJycyA9IHZhbGlkYXRlKHRoaXMsIGFzeW5jLCAuLi5leGNsdXNpb25zKTtcblxuICBpZiAoYXN5bmMpIHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGVycnMpLnRoZW4oKHJlc29sdmVkRXJycykgPT4ge1xuICAgICAgaWYgKHJlc29sdmVkRXJycyB8fCAhcHJldmlvdXNWZXJzaW9uKSB7XG4gICAgICAgIHJldHVybiByZXNvbHZlZEVycnM7XG4gICAgICB9XG4gICAgICByZXR1cm4gdmFsaWRhdGVDb21wYXJlKHByZXZpb3VzVmVyc2lvbiwgdGhpcywgYXN5bmMsIC4uLmV4Y2x1c2lvbnMpO1xuICAgIH0pIGFzIGFueTtcbiAgfVxuXG4gIGlmIChlcnJzIHx8ICFwcmV2aW91c1ZlcnNpb24pIHJldHVybiBlcnJzIGFzIGFueTtcblxuICAvLyBAdHMtZXhwZWN0LWVycm9yIE92ZXJyaWRpbmcgTW9kZWwgcHJvdG90eXBlIG1ldGhvZCB3aXRoIGR5bmFtaWMgY29uZGl0aW9uYWwgcmV0dXJuIHR5cGUuXG4gIHJldHVybiB2YWxpZGF0ZUNvbXBhcmUocHJldmlvdXNWZXJzaW9uLCB0aGlzLCBhc3luYywgLi4uZXhjbHVzaW9ucyk7XG59O1xuIiwiaW1wb3J0IHtcbiAgZ2V0QWxsUHJvcGVydHlEZWNvcmF0b3JzUmVjdXJzaXZlLFxuICBSZXBvc2l0b3J5LFxuICBTZXJpYWxpemF0aW9uRXJyb3IsXG59IGZyb20gXCIuLi9yZXBvc2l0b3J5XCI7XG5pbXBvcnQgeyBNb2RlbCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IERCS2V5cyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDaGVja3MgaWYgYSBtb2RlbCBpcyBtYXJrZWQgYXMgdHJhbnNpZW50XG4gKiBAc3VtbWFyeSBEZXRlcm1pbmVzIHdoZXRoZXIgYSBtb2RlbCBjbGFzcyBoYXMgYmVlbiBkZWNvcmF0ZWQgd2l0aCB0aGUgdHJhbnNpZW50IGRlY29yYXRvclxuICogQHRlbXBsYXRlIE0gLSBUeXBlIGV4dGVuZGluZyBNb2RlbFxuICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZSB0byBjaGVja1xuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgbW9kZWwgaXMgdHJhbnNpZW50LCBmYWxzZSBvdGhlcndpc2VcbiAqIEBmdW5jdGlvbiBpc1RyYW5zaWVudFxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1RyYW5zaWVudDxNIGV4dGVuZHMgTW9kZWw+KG1vZGVsOiBNKSB7XG4gIHJldHVybiAhIShcbiAgICBSZWZsZWN0LmdldE1ldGFkYXRhKFJlcG9zaXRvcnkua2V5KERCS2V5cy5UUkFOU0lFTlQpLCBtb2RlbC5jb25zdHJ1Y3RvcikgfHxcbiAgICBSZWZsZWN0LmdldE1ldGFkYXRhKFxuICAgICAgUmVwb3NpdG9yeS5rZXkoREJLZXlzLlRSQU5TSUVOVCksXG4gICAgICBNb2RlbC5nZXQobW9kZWwuY29uc3RydWN0b3IubmFtZSkgYXMgYW55XG4gICAgKVxuICApO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBTZXBhcmF0ZXMgdHJhbnNpZW50IHByb3BlcnRpZXMgZnJvbSBhIG1vZGVsXG4gKiBAc3VtbWFyeSBFeHRyYWN0cyBwcm9wZXJ0aWVzIG1hcmtlZCBhcyB0cmFuc2llbnQgaW50byBhIHNlcGFyYXRlIG9iamVjdFxuICogQHRlbXBsYXRlIE0gLSBUeXBlIGV4dGVuZGluZyBNb2RlbFxuICogQHBhcmFtIHtNfSBtb2RlbCAtIFRoZSBtb2RlbCBpbnN0YW5jZSB0byBwcm9jZXNzXG4gKiBAcmV0dXJuIHtPYmplY3R9IE9iamVjdCBjb250YWluaW5nIHRoZSBtb2RlbCB3aXRob3V0IHRyYW5zaWVudCBwcm9wZXJ0aWVzIGFuZCBhIHNlcGFyYXRlIHRyYW5zaWVudCBvYmplY3RcbiAqIEBwcm9wZXJ0eSB7TX0gbW9kZWwgLSBUaGUgbW9kZWwgd2l0aCB0cmFuc2llbnQgcHJvcGVydGllcyByZW1vdmVkXG4gKiBAcHJvcGVydHkge1JlY29yZDxzdHJpbmcsIGFueT59IFt0cmFuc2llbnRdIC0gT2JqZWN0IGNvbnRhaW5pbmcgdGhlIHRyYW5zaWVudCBwcm9wZXJ0aWVzXG4gKiBAZnVuY3Rpb24gbW9kZWxUb1RyYW5zaWVudFxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCBtb2RlbFRvVHJhbnNpZW50XG4gKiAgIHBhcnRpY2lwYW50IGlzVHJhbnNpZW50XG4gKiAgIHBhcnRpY2lwYW50IGdldEFsbFByb3BlcnR5RGVjb3JhdG9yc1JlY3Vyc2l2ZVxuICpcbiAqICAgQ2FsbGVyLT4+bW9kZWxUb1RyYW5zaWVudDogbW9kZWxcbiAqICAgbW9kZWxUb1RyYW5zaWVudC0+PmlzVHJhbnNpZW50OiBjaGVjayBpZiBtb2RlbCBpcyB0cmFuc2llbnRcbiAqICAgaXNUcmFuc2llbnQtLT4+bW9kZWxUb1RyYW5zaWVudDogdHJhbnNpZW50IHN0YXR1c1xuICogICBhbHQgbW9kZWwgaXMgbm90IHRyYW5zaWVudFxuICogICAgIG1vZGVsVG9UcmFuc2llbnQtLT4+Q2FsbGVyOiB7bW9kZWx9XG4gKiAgIGVsc2UgbW9kZWwgaXMgdHJhbnNpZW50XG4gKiAgICAgbW9kZWxUb1RyYW5zaWVudC0+PmdldEFsbFByb3BlcnR5RGVjb3JhdG9yc1JlY3Vyc2l2ZTogZ2V0IHRyYW5zaWVudCBwcm9wZXJ0aWVzXG4gKiAgICAgZ2V0QWxsUHJvcGVydHlEZWNvcmF0b3JzUmVjdXJzaXZlLS0+Pm1vZGVsVG9UcmFuc2llbnQ6IHByb3BlcnR5IGRlY29yYXRvcnNcbiAqICAgICBtb2RlbFRvVHJhbnNpZW50LT4+bW9kZWxUb1RyYW5zaWVudDogc2VwYXJhdGUgcHJvcGVydGllc1xuICogICAgIG1vZGVsVG9UcmFuc2llbnQtPj5Nb2RlbC5idWlsZDogcmVidWlsZCBtb2RlbCB3aXRob3V0IHRyYW5zaWVudCBwcm9wc1xuICogICAgIG1vZGVsVG9UcmFuc2llbnQtLT4+Q2FsbGVyOiB7bW9kZWwsIHRyYW5zaWVudH1cbiAqICAgZW5kXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtb2RlbFRvVHJhbnNpZW50PE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsOiBNXG4pOiB7IG1vZGVsOiBNOyB0cmFuc2llbnQ/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+IH0ge1xuICBpZiAoIWlzVHJhbnNpZW50KG1vZGVsKSkgcmV0dXJuIHsgbW9kZWw6IG1vZGVsIH07XG4gIGNvbnN0IGRlY3M6IFJlY29yZDxzdHJpbmcsIGFueVtdPiA9IGdldEFsbFByb3BlcnR5RGVjb3JhdG9yc1JlY3Vyc2l2ZShcbiAgICBtb2RlbCxcbiAgICB1bmRlZmluZWQsXG4gICAgUmVwb3NpdG9yeS5rZXkoREJLZXlzLlRSQU5TSUVOVClcbiAgKSBhcyBSZWNvcmQ8c3RyaW5nLCBhbnlbXT47XG5cbiAgY29uc3QgcmVzdWx0ID0gT2JqZWN0LmVudHJpZXMoZGVjcykucmVkdWNlKFxuICAgIChcbiAgICAgIGFjY3VtOiB7IG1vZGVsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+OyB0cmFuc2llbnQ/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+IH0sXG4gICAgICBbaywgdmFsXVxuICAgICkgPT4ge1xuICAgICAgY29uc3QgdHJhbnNpZW50ID0gdmFsLmZpbmQoKGVsKSA9PiBlbC5rZXkgPT09IFwiXCIpO1xuICAgICAgaWYgKHRyYW5zaWVudCkge1xuICAgICAgICBhY2N1bS50cmFuc2llbnQgPSBhY2N1bS50cmFuc2llbnQgfHwge307XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYWNjdW0udHJhbnNpZW50W2tdID0gbW9kZWxbayBhcyBrZXlvZiBNXTtcbiAgICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICAgIHRocm93IG5ldyBTZXJpYWxpemF0aW9uRXJyb3IoXG4gICAgICAgICAgICBgRmFpbGVkIHRvIHNlcmlhbGl6ZSB0cmFuc2llbnQgcHJvcGVydHkgJHtrfTogJHtlfWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhY2N1bS5tb2RlbCA9IGFjY3VtLm1vZGVsIHx8IHt9O1xuICAgICAgICBhY2N1bS5tb2RlbFtrXSA9IChtb2RlbCBhcyBSZWNvcmQ8c3RyaW5nLCBhbnk+KVtrXTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBhY2N1bTtcbiAgICB9LFxuICAgIHt9IGFzIHsgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT47IHRyYW5zaWVudD86IFJlY29yZDxzdHJpbmcsIGFueT4gfVxuICApO1xuICByZXN1bHQubW9kZWwgPSBNb2RlbC5idWlsZChyZXN1bHQubW9kZWwsIG1vZGVsLmNvbnN0cnVjdG9yLm5hbWUpO1xuICByZXR1cm4gcmVzdWx0IGFzIHsgbW9kZWw6IE07IHRyYW5zaWVudD86IFJlY29yZDxzdHJpbmcsIGFueT4gfTtcbn1cbiIsImV4cG9ydCAqIGZyb20gXCIuL2lkZW50aXR5XCI7XG5leHBvcnQgKiBmcm9tIFwiLi9pbnRlcmZhY2VzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9tb2RlbFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vb3BlcmF0aW9uc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vcmVwb3NpdG9yeVwiO1xuZXhwb3J0ICogZnJvbSBcIi4vdmFsaWRhdGlvblwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBEYXRhYmFzZSBkZWNvcmF0b3JzIGZvciBUeXBlU2NyaXB0IGFwcGxpY2F0aW9uc1xuICogQHN1bW1hcnkgQSBjb21wcmVoZW5zaXZlIGxpYnJhcnkgcHJvdmlkaW5nIGRlY29yYXRvcnMgYW5kIHV0aWxpdGllcyBmb3IgZGF0YWJhc2Ugb3BlcmF0aW9ucywgbW9kZWwgZGVmaW5pdGlvbnMsIHZhbGlkYXRpb24sIGFuZCByZXBvc2l0b3J5IHBhdHRlcm5zIGluIFR5cGVTY3JpcHQgYXBwbGljYXRpb25zXG4gKiBAbW9kdWxlIGRiLWRlY29yYXRvcnNcbiAqL1xuXG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEN1cnJlbnQgdmVyc2lvbiBvZiB0aGUgcmVmbGVjdGlvbiBwYWNrYWdlXG4gKiBAc3VtbWFyeSBTdG9yZXMgdGhlIHNlbWFudGljIHZlcnNpb24gbnVtYmVyIG9mIHRoZSBwYWNrYWdlXG4gKiBAY29uc3QgVkVSU0lPTlxuICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzXG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gXCIjI1ZFUlNJT04jI1wiO1xuIl0sIm5hbWVzIjpbIkRlY29yYXRvck1lc3NhZ2VzIl0sIm1hcHBpbmdzIjoiOzs7OztBQUVBOzs7OztBQUtHO0FBQ1UsTUFBQSxNQUFNLEdBQUc7QUFDcEIsSUFBQSxPQUFPLEVBQUUsQ0FBQSxFQUFHLFNBQVMsQ0FBQyxPQUFPLENBQWMsWUFBQSxDQUFBO0FBQzNDLElBQUEsVUFBVSxFQUFFLFlBQVk7QUFDeEIsSUFBQSxLQUFLLEVBQUUsUUFBUTtBQUNmLElBQUEsRUFBRSxFQUFFLElBQUk7QUFDUixJQUFBLEtBQUssRUFBRSxPQUFPO0FBQ2QsSUFBQSxNQUFNLEVBQUUsUUFBUTtBQUNoQixJQUFBLFNBQVMsRUFBRSxXQUFXO0FBQ3RCLElBQUEsUUFBUSxFQUFFLFVBQVU7QUFDcEIsSUFBQSxTQUFTLEVBQUUsV0FBVztBQUN0QixJQUFBLFNBQVMsRUFBRSxXQUFXO0FBQ3RCLElBQUEsSUFBSSxFQUFFLE1BQU07QUFDWixJQUFBLFFBQVEsRUFBRSxVQUFVO0FBQ3BCLElBQUEsT0FBTyxFQUFFLFNBQVM7QUFDbEIsSUFBQSxRQUFRLEVBQUUsZUFBZTs7QUFHM0I7Ozs7O0FBS0c7QUFDSSxNQUFNLGdCQUFnQixHQUFHO0FBRWhDOzs7OztBQUtHO0FBQ0ksTUFBTSx3QkFBd0IsR0FBRzs7QUNyQ3hDOzs7Ozs7Ozs7Ozs7Ozs7QUFlRztBQUNVLE1BQUEsc0JBQXNCLEdBQUc7QUFDcEMsSUFBQSxFQUFFLEVBQUU7QUFDRixRQUFBLE9BQU8sRUFBRSxvQkFBb0I7QUFDN0IsUUFBQSxRQUFRLEVBQUUscUJBQXFCO0FBQ2hDLEtBQUE7QUFDRCxJQUFBLFFBQVEsRUFBRTtBQUNSLFFBQUEs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
|