@decaf-ts/for-typeorm 0.0.6
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/LICENSE.md +21 -0
- package/README.md +93 -0
- package/dist/for-typeorm.cjs +2553 -0
- package/dist/for-typeorm.esm.cjs +2538 -0
- package/lib/TypeORMAdapter.cjs +1129 -0
- package/lib/TypeORMAdapter.d.ts +221 -0
- package/lib/TypeORMDispatch.cjs +134 -0
- package/lib/TypeORMDispatch.d.ts +87 -0
- package/lib/TypeORMEventSubscriber.cjs +96 -0
- package/lib/TypeORMEventSubscriber.d.ts +56 -0
- package/lib/TypeORMRepository.cjs +209 -0
- package/lib/TypeORMRepository.d.ts +125 -0
- package/lib/constants.cjs +43 -0
- package/lib/constants.d.ts +39 -0
- package/lib/errors.cjs +28 -0
- package/lib/errors.d.ts +21 -0
- package/lib/esm/TypeORMAdapter.d.ts +221 -0
- package/lib/esm/TypeORMAdapter.js +1124 -0
- package/lib/esm/TypeORMDispatch.d.ts +87 -0
- package/lib/esm/TypeORMDispatch.js +130 -0
- package/lib/esm/TypeORMEventSubscriber.d.ts +56 -0
- package/lib/esm/TypeORMEventSubscriber.js +93 -0
- package/lib/esm/TypeORMRepository.d.ts +125 -0
- package/lib/esm/TypeORMRepository.js +206 -0
- package/lib/esm/constants.d.ts +39 -0
- package/lib/esm/constants.js +40 -0
- package/lib/esm/errors.d.ts +21 -0
- package/lib/esm/errors.js +24 -0
- package/lib/esm/index.d.ts +22 -0
- package/lib/esm/index.js +25 -0
- package/lib/esm/indexes/generator.d.ts +50 -0
- package/lib/esm/indexes/generator.js +95 -0
- package/lib/esm/indexes/index.d.ts +1 -0
- package/lib/esm/indexes/index.js +2 -0
- package/lib/esm/overrides/Column.d.ts +74 -0
- package/lib/esm/overrides/Column.js +70 -0
- package/lib/esm/overrides/CreateDateColumn.d.ts +2 -0
- package/lib/esm/overrides/CreateDateColumn.js +9 -0
- package/lib/esm/overrides/Entity.d.ts +11 -0
- package/lib/esm/overrides/Entity.js +28 -0
- package/lib/esm/overrides/PrimaryColumn.d.ts +20 -0
- package/lib/esm/overrides/PrimaryColumn.js +53 -0
- package/lib/esm/overrides/PrimaryGeneratedColumn.d.ts +24 -0
- package/lib/esm/overrides/PrimaryGeneratedColumn.js +51 -0
- package/lib/esm/overrides/UpdateDateColumn.d.ts +2 -0
- package/lib/esm/overrides/UpdateDateColumn.js +9 -0
- package/lib/esm/overrides/utils.d.ts +2 -0
- package/lib/esm/overrides/utils.js +29 -0
- package/lib/esm/query/Paginator.d.ts +86 -0
- package/lib/esm/query/Paginator.js +124 -0
- package/lib/esm/query/Statement.d.ts +131 -0
- package/lib/esm/query/Statement.js +242 -0
- package/lib/esm/query/constants.d.ts +52 -0
- package/lib/esm/query/constants.js +74 -0
- package/lib/esm/query/index.d.ts +4 -0
- package/lib/esm/query/index.js +5 -0
- package/lib/esm/query/translate.d.ts +34 -0
- package/lib/esm/query/translate.js +42 -0
- package/lib/esm/raw/postgres.d.ts +36 -0
- package/lib/esm/raw/postgres.js +2 -0
- package/lib/esm/sequences/Sequence.d.ts +67 -0
- package/lib/esm/sequences/Sequence.js +117 -0
- package/lib/esm/sequences/index.d.ts +1 -0
- package/lib/esm/sequences/index.js +2 -0
- package/lib/esm/types.d.ts +67 -0
- package/lib/esm/types.js +28 -0
- package/lib/esm/utils.d.ts +16 -0
- package/lib/esm/utils.js +29 -0
- package/lib/index.cjs +42 -0
- package/lib/index.d.ts +22 -0
- package/lib/indexes/generator.cjs +98 -0
- package/lib/indexes/generator.d.ts +50 -0
- package/lib/indexes/index.cjs +18 -0
- package/lib/indexes/index.d.ts +1 -0
- package/lib/overrides/Column.cjs +73 -0
- package/lib/overrides/Column.d.ts +74 -0
- package/lib/overrides/CreateDateColumn.cjs +12 -0
- package/lib/overrides/CreateDateColumn.d.ts +2 -0
- package/lib/overrides/Entity.cjs +31 -0
- package/lib/overrides/Entity.d.ts +11 -0
- package/lib/overrides/PrimaryColumn.cjs +56 -0
- package/lib/overrides/PrimaryColumn.d.ts +20 -0
- package/lib/overrides/PrimaryGeneratedColumn.cjs +54 -0
- package/lib/overrides/PrimaryGeneratedColumn.d.ts +24 -0
- package/lib/overrides/UpdateDateColumn.cjs +12 -0
- package/lib/overrides/UpdateDateColumn.d.ts +2 -0
- package/lib/overrides/utils.cjs +32 -0
- package/lib/overrides/utils.d.ts +2 -0
- package/lib/query/Paginator.cjs +128 -0
- package/lib/query/Paginator.d.ts +86 -0
- package/lib/query/Statement.cjs +246 -0
- package/lib/query/Statement.d.ts +131 -0
- package/lib/query/constants.cjs +77 -0
- package/lib/query/constants.d.ts +52 -0
- package/lib/query/index.cjs +21 -0
- package/lib/query/index.d.ts +4 -0
- package/lib/query/translate.cjs +45 -0
- package/lib/query/translate.d.ts +34 -0
- package/lib/raw/postgres.cjs +3 -0
- package/lib/raw/postgres.d.ts +36 -0
- package/lib/sequences/Sequence.cjs +121 -0
- package/lib/sequences/Sequence.d.ts +67 -0
- package/lib/sequences/index.cjs +18 -0
- package/lib/sequences/index.d.ts +1 -0
- package/lib/types.cjs +31 -0
- package/lib/types.d.ts +67 -0
- package/lib/utils.cjs +32 -0
- package/lib/utils.d.ts +16 -0
- package/package.json +128 -0
|
@@ -0,0 +1,2553 @@
|
|
|
1
|
+
(function (global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('tslib'), require('@decaf-ts/core'), require('@decaf-ts/db-decorators'), require('reflect-metadata'), require('@decaf-ts/decorator-validation'), require('@decaf-ts/reflection'), require('@decaf-ts/logging'), require('typeorm'), require('typeorm/util/ObjectUtils')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'tslib', '@decaf-ts/core', '@decaf-ts/db-decorators', 'reflect-metadata', '@decaf-ts/decorator-validation', '@decaf-ts/reflection', '@decaf-ts/logging', 'typeorm', 'typeorm/util/ObjectUtils'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["for-typeorm"] = {}, global.tslib, global.core, global.dbDecorators, null, global.decoratorValidation, global.reflection, global.logging, global.typeorm, global.ObjectUtils));
|
|
5
|
+
})(this, (function (exports, tslib, core, dbDecorators, reflectMetadata, decoratorValidation, reflection, logging, typeorm, ObjectUtils) { 'use strict';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @description Regular expression to identify reserved attributes for SQL contexts.
|
|
9
|
+
* @summary Matches attribute names that conflict with SQL reserved keywords to prevent invalid schema or query generation.
|
|
10
|
+
* @const reservedAttributes
|
|
11
|
+
* @memberOf module:for-typeorm
|
|
12
|
+
*/
|
|
13
|
+
const reservedAttributes = /^(select|from|where|and|or|insert|update|delete|drop|create|table|index|primary|key|foreign|references|constraint|unique|check|default|null|not|as|order|by|group|having|limit|offset|join|inner|outer|left|right|full|on|using|values|returning|set|into|case|when|then|else|end|cast|coalesce|exists|any|all|some|in|between|like|ilike|similar|to|is|true|false|asc|desc|distinct|union|intersect|except|natural|lateral|window|over|partition|range|rows|unbounded|preceding|following|current|row|with|recursive|materialized|view|function|trigger|procedure|language|returns|return|declare|begin|commit|rollback|savepoint|transaction|temporary|temp|if|loop|while|for|continue|exit|raise|exception|notice|info|log|debug|assert|execute|perform|get|diagnostics|call|do|alias|comment|vacuum|analyze|explain|copy|grant|revoke|privileges|public|usage|schema|sequence|owned|owner|tablespace|storage|inherits|type|operator|collate|collation|cascade|restrict|add|alter|column|rename|to|enable|disable|force|no|instead|of|before|after|each|statement|row|execute|also|only|exclude|nulls|others|ordinality|ties|nothing|cache|cycle|increment|minvalue|maxvalue|start|restart|by|called|returns|language|immutable|stable|volatile|strict|security|definer|invoker|cost|rows|support|handler|inline|validator|options|storage|inheritance|oids|without|data|dictionary|encoding|lc_collate|lc_ctype|connection|limit|password|valid|until|superuser|nosuperuser|createdb|nocreatedb|createrole|nocreaterole|inherit|noinherit|login|nologin|replication|noreplication|bypassrls|nobypassrls|encrypted|unencrypted|new|old|session_user|current_user|current_role|current_schema|current_catalog|current_date|current_time|current_timestamp|localtime|localtimestamp|current_database|inet|cidr|macaddr|macaddr8|bit|varbit|tsvector|tsquery|uuid|xml|json|jsonb|int|integer|smallint|bigint|decimal|numeric|real|double|precision|float|boolean|bool|char|character|varchar|text|bytea|date|time|timestamp|interval|point|line|lseg|box|path|polygon|circle|money|void)$/i;
|
|
14
|
+
const TypeORMFlavour = "type-orm";
|
|
15
|
+
/**
|
|
16
|
+
* @description Shape of the TypeORMKeys constant.
|
|
17
|
+
* @summary Describes the keys and their meanings used by the TypeORM adapter.
|
|
18
|
+
* @typedef TypeORMKeysDef
|
|
19
|
+
* @property {string} SEPARATOR Separator used to join table and column identifiers.
|
|
20
|
+
* @property {string} ID Default primary key field name.
|
|
21
|
+
* @property {string} VERSION Version field used for optimistic locking.
|
|
22
|
+
* @property {string} DELETED Soft-delete timestamp field.
|
|
23
|
+
* @property {string} TABLE Database table identifier key.
|
|
24
|
+
* @property {string} SCHEMA Database schema identifier key.
|
|
25
|
+
* @property {string} SEQUENCE Database sequence name key.
|
|
26
|
+
* @property {string} INDEX Index identifier key.
|
|
27
|
+
* @memberOf module:for-typeorm
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* @description Key constants used by the TypeORM adapter.
|
|
31
|
+
* @summary Collection of string constants that identify common database properties and adapter-specific keys.
|
|
32
|
+
* @const TypeORMKeys
|
|
33
|
+
* @type {TypeORMKeysDef}
|
|
34
|
+
* @memberOf module:for-typeorm
|
|
35
|
+
*/
|
|
36
|
+
const TypeORMKeys = {
|
|
37
|
+
SEPARATOR: ".",
|
|
38
|
+
ID: "id",
|
|
39
|
+
VERSION: "version",
|
|
40
|
+
DELETED: "deleted_at",
|
|
41
|
+
TABLE: "table_name",
|
|
42
|
+
SCHEMA: "schema_name",
|
|
43
|
+
SEQUENCE: "sequence_name",
|
|
44
|
+
INDEX: "index",
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @description Error thrown when there is an issue with TypeORM indexes.
|
|
49
|
+
* @summary Represents an error related to index generation or handling within the TypeORM adapter.
|
|
50
|
+
* @param {string|Error} msg The error message or Error object.
|
|
51
|
+
* @class
|
|
52
|
+
* @category Errors
|
|
53
|
+
* @example
|
|
54
|
+
* // Example of using IndexError
|
|
55
|
+
* try {
|
|
56
|
+
* // Some code that might throw an index error
|
|
57
|
+
* throw new IndexError("Index not found");
|
|
58
|
+
* } catch (error) {
|
|
59
|
+
* if (error instanceof IndexError) {
|
|
60
|
+
* console.error("Index error occurred:", error.message);
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
*/
|
|
64
|
+
class IndexError extends dbDecorators.BaseError {
|
|
65
|
+
constructor(msg) {
|
|
66
|
+
super(IndexError.name, msg, 404);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @description SQL operators available for building TypeORM queries.
|
|
72
|
+
* @summary Enumeration of common SQL operators intended for use within TypeORM query construction and translation layers.
|
|
73
|
+
* @enum {string}
|
|
74
|
+
* @memberOf module:for-typeorm
|
|
75
|
+
*/
|
|
76
|
+
exports.SQLOperator = void 0;
|
|
77
|
+
(function (SQLOperator) {
|
|
78
|
+
SQLOperator["EQUAL"] = "=";
|
|
79
|
+
SQLOperator["NOT_EQUAL"] = "<>";
|
|
80
|
+
SQLOperator["LESS_THAN"] = "<";
|
|
81
|
+
SQLOperator["LESS_THAN_OR_EQUAL"] = "<=";
|
|
82
|
+
SQLOperator["GREATER_THAN"] = ">";
|
|
83
|
+
SQLOperator["GREATER_THAN_OR_EQUAL"] = ">=";
|
|
84
|
+
SQLOperator["IN"] = "IN";
|
|
85
|
+
SQLOperator["NOT_IN"] = "NOT IN";
|
|
86
|
+
SQLOperator["LIKE"] = "LIKE";
|
|
87
|
+
SQLOperator["ILIKE"] = "ILIKE";
|
|
88
|
+
SQLOperator["BETWEEN"] = "BETWEEN";
|
|
89
|
+
SQLOperator["IS_NULL"] = "IS NULL";
|
|
90
|
+
SQLOperator["IS_NOT_NULL"] = "IS NOT NULL";
|
|
91
|
+
SQLOperator["EXISTS"] = "EXISTS";
|
|
92
|
+
SQLOperator["NOT_EXISTS"] = "NOT EXISTS";
|
|
93
|
+
SQLOperator["ANY"] = "ANY";
|
|
94
|
+
SQLOperator["ALL"] = "ALL";
|
|
95
|
+
SQLOperator["SOME"] = "SOME";
|
|
96
|
+
})(exports.SQLOperator || (exports.SQLOperator = {}));
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @description Default query limit for TypeORM-backed queries.
|
|
100
|
+
* @summary Maximum number of records to return in a single page when paginating results.
|
|
101
|
+
* @const TypeORMQueryLimit
|
|
102
|
+
* @memberOf module:for-typeorm
|
|
103
|
+
*/
|
|
104
|
+
const TypeORMQueryLimit = 250;
|
|
105
|
+
/**
|
|
106
|
+
* @description Mapping of operator names to SQL operators.
|
|
107
|
+
* @summary Constants for comparison operators used when translating high-level filters into SQL via TypeORM.
|
|
108
|
+
* @typedef {Object} PostgreSQLOperatorType
|
|
109
|
+
* @property {string} EQUAL Equality operator (=)
|
|
110
|
+
* @property {string} DIFFERENT Inequality operator (<>)
|
|
111
|
+
* @property {string} BIGGER Greater than operator (>)
|
|
112
|
+
* @property {string} BIGGER_EQ Greater than or equal operator (>=)
|
|
113
|
+
* @property {string} SMALLER Less than operator (<)
|
|
114
|
+
* @property {string} SMALLER_EQ Less than or equal operator (<=)
|
|
115
|
+
* @property {string} NOT Negation operator (NOT)
|
|
116
|
+
* @property {string} IN In array operator (IN)
|
|
117
|
+
* @property {string} REGEXP Regular expression operator (~)
|
|
118
|
+
* @property {string} IREGEXP Case-insensitive regular expression operator (~*)
|
|
119
|
+
* @property {string} LIKE Pattern matching operator (LIKE)
|
|
120
|
+
* @property {string} ILIKE Case-insensitive pattern matching operator (ILIKE)
|
|
121
|
+
* @property {string} BETWEEN Range operator (BETWEEN)
|
|
122
|
+
* @property {string} IS_NULL NULL check operator (IS NULL)
|
|
123
|
+
* @property {string} IS_NOT_NULL NOT NULL check operator (IS NOT NULL)
|
|
124
|
+
* @const TypeORMOperator
|
|
125
|
+
* @type {PostgreSQLOperatorType}
|
|
126
|
+
* @memberOf module:for-typeorm
|
|
127
|
+
*/
|
|
128
|
+
const TypeORMOperator = {
|
|
129
|
+
EQUAL: exports.SQLOperator.EQUAL,
|
|
130
|
+
DIFFERENT: exports.SQLOperator.NOT_EQUAL,
|
|
131
|
+
BIGGER: exports.SQLOperator.GREATER_THAN,
|
|
132
|
+
BIGGER_EQ: exports.SQLOperator.GREATER_THAN_OR_EQUAL,
|
|
133
|
+
SMALLER: exports.SQLOperator.LESS_THAN,
|
|
134
|
+
SMALLER_EQ: exports.SQLOperator.LESS_THAN_OR_EQUAL,
|
|
135
|
+
BETWEEN: exports.SQLOperator.BETWEEN,
|
|
136
|
+
NOT: "NOT",
|
|
137
|
+
IN: exports.SQLOperator.IN,
|
|
138
|
+
IS_NULL: exports.SQLOperator.IS_NULL,
|
|
139
|
+
IS_NOT_NULL: exports.SQLOperator.IS_NOT_NULL,
|
|
140
|
+
REGEXP: "~",
|
|
141
|
+
IREGEXP: "~*",
|
|
142
|
+
LIKE: exports.SQLOperator.LIKE,
|
|
143
|
+
ILIKE: exports.SQLOperator.ILIKE,
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* @description Mapping of logical operator names to SQL operators.
|
|
147
|
+
* @summary Constants for logical operators used when building WHERE clause groups in TypeORM queries.
|
|
148
|
+
* @typedef {Object} PostgreSQLGroupOperatorType
|
|
149
|
+
* @property {string} AND Logical AND operator (AND)
|
|
150
|
+
* @property {string} OR Logical OR operator (OR)
|
|
151
|
+
* @const TypeORMGroupOperator
|
|
152
|
+
* @type {PostgreSQLGroupOperatorType}
|
|
153
|
+
* @memberOf module:for-typeorm
|
|
154
|
+
*/
|
|
155
|
+
const TypeORMGroupOperator = {
|
|
156
|
+
AND: "AND",
|
|
157
|
+
OR: "OR",
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* @description Special constant values used in queries.
|
|
161
|
+
* @summary String constants representing special values used while composing SQL with TypeORM.
|
|
162
|
+
* @typedef {Object} PostgreSQLConstType
|
|
163
|
+
* @property {string} NULL String representation of null value.
|
|
164
|
+
* @const TypeORMConst
|
|
165
|
+
* @memberOf module:for-typeorm
|
|
166
|
+
*/
|
|
167
|
+
const TypeORMConst = {
|
|
168
|
+
NULL: "NULL",
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* @description Paginator for TypeORM query results.
|
|
173
|
+
* @summary Implements pagination for TypeORM-built queries using take/skip for efficient navigation through result sets.
|
|
174
|
+
* @template M The model type that extends Model.
|
|
175
|
+
* @template R The result type.
|
|
176
|
+
* @param {TypeORMAdapter} adapter The TypeORM adapter.
|
|
177
|
+
* @param {TypeORMQuery} query The query container to paginate.
|
|
178
|
+
* @param {number} size The page size.
|
|
179
|
+
* @param {Constructor<M>} clazz The model constructor.
|
|
180
|
+
* @class TypeORMPaginator
|
|
181
|
+
* @example
|
|
182
|
+
* // Example of using TypeORMPaginator
|
|
183
|
+
* const paginator = new TypeORMPaginator(adapter, { query: qb }, 10, User);
|
|
184
|
+
* const page1 = await paginator.page(1);
|
|
185
|
+
* const page2 = await paginator.page(2);
|
|
186
|
+
*/
|
|
187
|
+
class TypeORMPaginator extends core.Paginator {
|
|
188
|
+
/**
|
|
189
|
+
* @description Gets the total number of pages
|
|
190
|
+
* @summary Returns the total number of pages based on the record count and page size
|
|
191
|
+
* @return {number} The total number of pages
|
|
192
|
+
*/
|
|
193
|
+
get total() {
|
|
194
|
+
return this._totalPages;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* @description Gets the total record count
|
|
198
|
+
* @summary Returns the total number of records matching the query
|
|
199
|
+
* @return {number} The total record count
|
|
200
|
+
*/
|
|
201
|
+
get count() {
|
|
202
|
+
return this._recordCount;
|
|
203
|
+
}
|
|
204
|
+
get repo() {
|
|
205
|
+
if (!this.__repo) {
|
|
206
|
+
this.__repo = this.adapter.dataSource.getRepository(this.clazz[decoratorValidation.ModelKeys.ANCHOR]);
|
|
207
|
+
}
|
|
208
|
+
return this.__repo;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* @description Creates a new TypeORMPaginator instance.
|
|
212
|
+
* @summary Initializes a paginator for TypeORM query results.
|
|
213
|
+
* @param {TypeORMAdapter} adapter The TypeORM adapter.
|
|
214
|
+
* @param {TypeORMQuery} query The TypeORM query container to paginate.
|
|
215
|
+
* @param {number} size The page size.
|
|
216
|
+
* @param {Constructor<M>} clazz The model constructor.
|
|
217
|
+
*/
|
|
218
|
+
constructor(adapter, query, size, clazz) {
|
|
219
|
+
super(adapter, query, size, clazz);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* @description Prepares a query for pagination
|
|
223
|
+
* @summary Modifies the raw query to include pagination parameters
|
|
224
|
+
* @param {TypeORMQuery} rawStatement - The original PostgreSQL query
|
|
225
|
+
* @return {TypeORMQuery} The prepared query with pagination parameters
|
|
226
|
+
*/
|
|
227
|
+
prepare(rawStatement) {
|
|
228
|
+
const query = { ...rawStatement };
|
|
229
|
+
return query;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* @description Retrieves a specific page of results.
|
|
233
|
+
* @summary Executes the query with pagination and processes the results.
|
|
234
|
+
* @param {number} [page=1] The page number to retrieve.
|
|
235
|
+
* @return {Promise<R[]>} A promise that resolves to an array of results.
|
|
236
|
+
* @throws {PagingError} If trying to access an invalid page or if no class is defined.
|
|
237
|
+
* @mermaid
|
|
238
|
+
* sequenceDiagram
|
|
239
|
+
* participant Client
|
|
240
|
+
* participant Paginator as TypeORMPaginator
|
|
241
|
+
* participant Adapter
|
|
242
|
+
* participant DB as Database
|
|
243
|
+
*
|
|
244
|
+
* Client->>Paginator: page(pageNumber)
|
|
245
|
+
* Note over Paginator: Prepare options (skip/take)
|
|
246
|
+
*
|
|
247
|
+
* alt First time or need count
|
|
248
|
+
* Paginator->>Adapter: Get count
|
|
249
|
+
* Adapter->>DB: Execute COUNT
|
|
250
|
+
* DB-->>Adapter: count
|
|
251
|
+
* Adapter-->>Paginator: count
|
|
252
|
+
* Paginator->>Paginator: Calculate total pages
|
|
253
|
+
* end
|
|
254
|
+
*
|
|
255
|
+
* Paginator->>Adapter: Execute query
|
|
256
|
+
* Adapter->>DB: findAndCount(options)
|
|
257
|
+
* DB-->>Adapter: rows, count
|
|
258
|
+
* Adapter-->>Paginator: rows, count
|
|
259
|
+
*
|
|
260
|
+
* Paginator->>Paginator: Map rows to models
|
|
261
|
+
* Paginator-->>Client: results
|
|
262
|
+
*/
|
|
263
|
+
async page(page = 1) {
|
|
264
|
+
const statement = { ...this.statement };
|
|
265
|
+
// Get total count if not already calculated
|
|
266
|
+
if (!this._recordCount || !this._totalPages) {
|
|
267
|
+
this._totalPages = this._recordCount = 0;
|
|
268
|
+
}
|
|
269
|
+
const opts = Object.assign(statement, {
|
|
270
|
+
skip: (this.current || 0) * this.size,
|
|
271
|
+
take: this.size,
|
|
272
|
+
});
|
|
273
|
+
// this.validatePage(page);
|
|
274
|
+
const result = await this.repo.findAndCount(opts);
|
|
275
|
+
this._recordCount = result[1];
|
|
276
|
+
this._totalPages = Math.ceil(this._recordCount / this.size);
|
|
277
|
+
if (!this.clazz)
|
|
278
|
+
throw new core.PagingError("No statement target defined");
|
|
279
|
+
const pkDef = dbDecorators.findPrimaryKey(new this.clazz());
|
|
280
|
+
const rows = result[0] || [];
|
|
281
|
+
const results =
|
|
282
|
+
// statement.columns && statement.columns.length
|
|
283
|
+
// ? rows // has columns means it's not full model
|
|
284
|
+
rows.map((row) => {
|
|
285
|
+
return this.adapter.revert(row, this.clazz, pkDef.id, row[pkDef.id]);
|
|
286
|
+
});
|
|
287
|
+
this._currentPage = page;
|
|
288
|
+
return results;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @description Translates core operators to TypeORM SQL operators.
|
|
294
|
+
* @summary Converts Decaf.ts core operators to their equivalent SQL operators used by the TypeORM adapter.
|
|
295
|
+
* @param {GroupOperator | Operator} operator The core operator to translate.
|
|
296
|
+
* @return {SQLOperator | string} The equivalent SQL operator.
|
|
297
|
+
* @throws {QueryError} If no translation exists for the given operator.
|
|
298
|
+
* @function translateOperators
|
|
299
|
+
* @memberOf module:for-typeorm
|
|
300
|
+
* @mermaid
|
|
301
|
+
* sequenceDiagram
|
|
302
|
+
* participant Caller
|
|
303
|
+
* participant translateOperators
|
|
304
|
+
* participant PostgreSQLOperator
|
|
305
|
+
* participant PostgreSQLGroupOperator
|
|
306
|
+
*
|
|
307
|
+
* Caller->>translateOperators: operator
|
|
308
|
+
*
|
|
309
|
+
* translateOperators->>PostgreSQLOperator: Check for match
|
|
310
|
+
* alt Found in PostgreSQLOperator
|
|
311
|
+
* PostgreSQLOperator-->>translateOperators: Return matching operator
|
|
312
|
+
* translateOperators-->>Caller: Return SQLOperator
|
|
313
|
+
* else Not found
|
|
314
|
+
* translateOperators->>PostgreSQLGroupOperator: Check for match
|
|
315
|
+
* alt Found in PostgreSQLGroupOperator
|
|
316
|
+
* PostgreSQLGroupOperator-->>translateOperators: Return matching operator
|
|
317
|
+
* translateOperators-->>Caller: Return string
|
|
318
|
+
* else Not found
|
|
319
|
+
* translateOperators-->>Caller: Throw QueryError
|
|
320
|
+
* end
|
|
321
|
+
* end
|
|
322
|
+
*/
|
|
323
|
+
function translateOperators(operator) {
|
|
324
|
+
for (const operators of [TypeORMOperator, TypeORMGroupOperator]) {
|
|
325
|
+
const el = Object.keys(operators).find((k) => k === operator);
|
|
326
|
+
if (el)
|
|
327
|
+
return operators[el];
|
|
328
|
+
}
|
|
329
|
+
throw new core.QueryError(`Could not find adapter translation for operator ${operator}`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* @description Statement builder for TypeORM-backed queries.
|
|
334
|
+
* @summary Provides a fluent interface for building SQL queries via TypeORM's SelectQueryBuilder with type safety and Decaf.ts abstractions.
|
|
335
|
+
* @template M The model type that extends Model.
|
|
336
|
+
* @template R The result type returned from execution.
|
|
337
|
+
* @param {TypeORMAdapter} adapter The TypeORM adapter.
|
|
338
|
+
* @class TypeORMStatement
|
|
339
|
+
* @example
|
|
340
|
+
* // Example using TypeORMStatement
|
|
341
|
+
* const statement = new TypeORMStatement<User, User[]>(adapter);
|
|
342
|
+
* const users = await statement
|
|
343
|
+
* .from(User)
|
|
344
|
+
* .where(Condition.attribute<User>('age').gt(18))
|
|
345
|
+
* .orderBy('lastName', 'asc')
|
|
346
|
+
* .limit(10)
|
|
347
|
+
* .execute();
|
|
348
|
+
*/
|
|
349
|
+
class TypeORMStatement extends core.Statement {
|
|
350
|
+
constructor(adapter) {
|
|
351
|
+
super(adapter);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* @description Builds a TypeORM SelectQueryBuilder from the statement.
|
|
355
|
+
* @summary Converts the statement's conditions, selectors, and options into a TypeORM-backed query object.
|
|
356
|
+
* @return {TypeORMQuery} The built TypeORM query container.
|
|
357
|
+
* @throws {Error} If there are invalid query conditions.
|
|
358
|
+
* @mermaid
|
|
359
|
+
* sequenceDiagram
|
|
360
|
+
* participant Statement
|
|
361
|
+
* participant Repository
|
|
362
|
+
* participant parseCondition
|
|
363
|
+
*
|
|
364
|
+
* Statement->>Statement: build()
|
|
365
|
+
* Note over Statement: Initialize query
|
|
366
|
+
* Statement->>Repository: Get table name
|
|
367
|
+
* Repository-->>Statement: Return table name
|
|
368
|
+
* Statement->>Statement: Create base query
|
|
369
|
+
*
|
|
370
|
+
* alt Has selectSelector
|
|
371
|
+
* Statement->>Statement: Add columns to query
|
|
372
|
+
* end
|
|
373
|
+
*
|
|
374
|
+
* alt Has whereCondition
|
|
375
|
+
* Statement->>Statement: Create combined condition with table
|
|
376
|
+
* Statement->>parseCondition: Parse condition
|
|
377
|
+
* parseCondition-->>Statement: Return parsed conditions
|
|
378
|
+
* Statement->>Statement: Add conditions to query
|
|
379
|
+
* end
|
|
380
|
+
*
|
|
381
|
+
* alt Has orderBySelector
|
|
382
|
+
* Statement->>Statement: Add orderBy to query
|
|
383
|
+
* end
|
|
384
|
+
*
|
|
385
|
+
* alt Has limitSelector
|
|
386
|
+
* Statement->>Statement: Set limit
|
|
387
|
+
* else
|
|
388
|
+
* Statement->>Statement: Use default limit
|
|
389
|
+
* end
|
|
390
|
+
*
|
|
391
|
+
* alt Has offsetSelector
|
|
392
|
+
* Statement->>Statement: Set offset
|
|
393
|
+
* end
|
|
394
|
+
*
|
|
395
|
+
* Statement-->>Statement: Return query
|
|
396
|
+
*/
|
|
397
|
+
build() {
|
|
398
|
+
const log = this.log.for(this.build);
|
|
399
|
+
const tableName = core.Repository.table(this.fromSelector);
|
|
400
|
+
const m = new this.fromSelector();
|
|
401
|
+
const q = {
|
|
402
|
+
query: this.adapter.dataSource
|
|
403
|
+
.getRepository(this.fromSelector[decoratorValidation.ModelKeys.ANCHOR])
|
|
404
|
+
.createQueryBuilder(tableName),
|
|
405
|
+
};
|
|
406
|
+
if (this.selectSelector)
|
|
407
|
+
q.query = q.query.select(this.selectSelector.map((s) => `${tableName}.${s}`));
|
|
408
|
+
else
|
|
409
|
+
q.query = q.query.select();
|
|
410
|
+
//
|
|
411
|
+
// q.query = (q.query as SelectQueryBuilder<any>).from(
|
|
412
|
+
// this.fromSelector[ModelKeys.ANCHOR as keyof typeof this.fromSelector],
|
|
413
|
+
// tableName
|
|
414
|
+
// );
|
|
415
|
+
if (this.whereCondition)
|
|
416
|
+
q.query = this.parseCondition(this.whereCondition, tableName, q.query).query;
|
|
417
|
+
let orderByArgs;
|
|
418
|
+
if (!this.orderBySelector)
|
|
419
|
+
orderByArgs = [
|
|
420
|
+
`${tableName}.${dbDecorators.findPrimaryKey(m).id}`,
|
|
421
|
+
core.OrderDirection.ASC.toUpperCase(),
|
|
422
|
+
];
|
|
423
|
+
else
|
|
424
|
+
orderByArgs = [
|
|
425
|
+
`${tableName}.${this.orderBySelector[0]}`,
|
|
426
|
+
this.orderBySelector[1].toUpperCase(),
|
|
427
|
+
];
|
|
428
|
+
q.query = q.query.orderBy(...orderByArgs);
|
|
429
|
+
if (this.limitSelector) {
|
|
430
|
+
q.query = q.query.limit(this.limitSelector);
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
log.debug(`No limit selector defined. Using default limit of ${TypeORMQueryLimit}`);
|
|
434
|
+
q.query = q.query.limit(TypeORMQueryLimit);
|
|
435
|
+
}
|
|
436
|
+
// Add offset
|
|
437
|
+
if (this.offsetSelector)
|
|
438
|
+
q.query = q.query.skip(this.offsetSelector);
|
|
439
|
+
return q;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* @description Creates a paginator for the statement.
|
|
443
|
+
* @summary Builds the query and returns a TypeORMPaginator for paginated results.
|
|
444
|
+
* @template R The result type.
|
|
445
|
+
* @param {number} size The page size.
|
|
446
|
+
* @return {Promise<Paginator<M, R, TypeORMQuery>>} A promise that resolves to a paginator.
|
|
447
|
+
* @throws {InternalError} If there's an error building the query.
|
|
448
|
+
*/
|
|
449
|
+
async paginate(size) {
|
|
450
|
+
try {
|
|
451
|
+
const query = this.build();
|
|
452
|
+
const transformedQuery = {};
|
|
453
|
+
const a = query.query;
|
|
454
|
+
if (this.whereCondition)
|
|
455
|
+
transformedQuery.where = this.parseConditionForPagination(this.whereCondition, core.Repository.table(this.fromSelector));
|
|
456
|
+
if (this.orderBySelector)
|
|
457
|
+
transformedQuery.order = {
|
|
458
|
+
[this.orderBySelector[0]]: this.orderBySelector[1].toString(),
|
|
459
|
+
};
|
|
460
|
+
return new TypeORMPaginator(this.adapter, transformedQuery, size, this.fromSelector);
|
|
461
|
+
}
|
|
462
|
+
catch (e) {
|
|
463
|
+
throw new dbDecorators.InternalError(e);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* @description Processes a record.
|
|
468
|
+
* @summary Converts a raw result row to a model instance using the adapter.
|
|
469
|
+
* @param {any} r The raw record.
|
|
470
|
+
* @param {keyof M} pkAttr The primary key attribute of the model.
|
|
471
|
+
* @param {"Number" | "BigInt" | undefined} sequenceType The type of the sequence.
|
|
472
|
+
* @return {any} The processed record.
|
|
473
|
+
*/
|
|
474
|
+
processRecord(r, pkAttr) {
|
|
475
|
+
if (typeof r[pkAttr] !== "undefined") {
|
|
476
|
+
return this.adapter.revert(r, this.fromSelector, pkAttr, r[pkAttr]);
|
|
477
|
+
}
|
|
478
|
+
return r;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* @description Executes a raw TypeORM query builder.
|
|
482
|
+
* @summary Sends the built SelectQueryBuilder to the database via TypeORM and returns the results.
|
|
483
|
+
* @template R The result type.
|
|
484
|
+
* @param {TypeORMQuery} rawInput The query container to execute.
|
|
485
|
+
* @return {Promise<R>} A promise that resolves to the query results.
|
|
486
|
+
*/
|
|
487
|
+
async raw(rawInput) {
|
|
488
|
+
const log = this.log.for(this.raw);
|
|
489
|
+
log.debug(`Executing raw query: ${rawInput.query.getSql()}`);
|
|
490
|
+
return (await rawInput.query.getMany());
|
|
491
|
+
}
|
|
492
|
+
parseConditionForPagination(condition, tableName, counter = 0, conditionalOp) {
|
|
493
|
+
throw new dbDecorators.InternalError("Not implemented");
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* @description Parses a condition into PostgreSQL conditions
|
|
497
|
+
* @summary Converts a Condition object into PostgreSQL condition structures
|
|
498
|
+
* @param {Condition<M>} condition - The condition to parse
|
|
499
|
+
* @param {string} [tableName] - the positional index of the arguments
|
|
500
|
+
* @return {TypeORMQuery} The PostgresSQL condition
|
|
501
|
+
* @mermaid
|
|
502
|
+
* sequenceDiagram
|
|
503
|
+
* participant Statement
|
|
504
|
+
* participant translateOperators
|
|
505
|
+
* participant parseCondition
|
|
506
|
+
*
|
|
507
|
+
* Statement->>Statement: parseCondition(condition)
|
|
508
|
+
*
|
|
509
|
+
* Note over Statement: Extract condition parts
|
|
510
|
+
*
|
|
511
|
+
* alt Simple comparison operator
|
|
512
|
+
* Statement->>translateOperators: translateOperators(operator)
|
|
513
|
+
* translateOperators-->>Statement: Return PostgreSQL operator
|
|
514
|
+
* Statement->>Statement: Create condition with column, operator, and value
|
|
515
|
+
* else NOT operator
|
|
516
|
+
* Statement->>Statement: parseCondition(attr1)
|
|
517
|
+
* Statement->>Statement: Add NOT to conditions
|
|
518
|
+
* else AND/OR operator
|
|
519
|
+
* Statement->>Statement: parseCondition(attr1)
|
|
520
|
+
* Statement->>Statement: parseCondition(comparison)
|
|
521
|
+
* Statement->>Statement: Combine conditions with AND/OR
|
|
522
|
+
* end
|
|
523
|
+
*
|
|
524
|
+
* Statement-->>Statement: Return conditions array
|
|
525
|
+
*/
|
|
526
|
+
parseCondition(condition, tableName, qb, counter = 0, conditionalOp) {
|
|
527
|
+
const { attr1, operator, comparison } = condition;
|
|
528
|
+
function parse() {
|
|
529
|
+
const sqlOperator = translateOperators(operator);
|
|
530
|
+
const attrRef = `${attr1}${counter}`;
|
|
531
|
+
const queryStr = `${tableName}.${attr1} ${sqlOperator} :${attrRef}`;
|
|
532
|
+
const values = {
|
|
533
|
+
[attrRef]: comparison,
|
|
534
|
+
};
|
|
535
|
+
switch (conditionalOp) {
|
|
536
|
+
case core.GroupOperator.AND:
|
|
537
|
+
return {
|
|
538
|
+
query: qb.andWhere(queryStr, values),
|
|
539
|
+
};
|
|
540
|
+
case core.GroupOperator.OR:
|
|
541
|
+
return {
|
|
542
|
+
query: qb.orWhere(queryStr, values),
|
|
543
|
+
};
|
|
544
|
+
case core.Operator.NOT:
|
|
545
|
+
throw new Error("NOT operator not implemented");
|
|
546
|
+
default:
|
|
547
|
+
return {
|
|
548
|
+
query: qb.where(queryStr, values),
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
if ([core.GroupOperator.AND, core.GroupOperator.OR, core.Operator.NOT].indexOf(operator) === -1) {
|
|
553
|
+
return parse();
|
|
554
|
+
}
|
|
555
|
+
// For NOT operator
|
|
556
|
+
else if (operator === core.Operator.NOT) {
|
|
557
|
+
throw new Error("NOT operator not implemented");
|
|
558
|
+
}
|
|
559
|
+
// For AND/OR operators
|
|
560
|
+
else {
|
|
561
|
+
qb = this.parseCondition(attr1, tableName, qb, ++counter)
|
|
562
|
+
.query;
|
|
563
|
+
return this.parseCondition(comparison, tableName, qb, ++counter, operator);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* @description Abstract implementation of a database sequence for TypeORM.
|
|
570
|
+
* @summary Provides the basic functionality for {@link Sequence}s, delegating to the {@link TypeORMAdapter} to fetch and increment values while handling type parsing and error translation.
|
|
571
|
+
* @param {SequenceOptions} options The sequence configuration options (name, type, startWith, incrementBy, etc.).
|
|
572
|
+
* @param {TypeORMAdapter} adapter The TypeORM adapter used to execute sequence operations.
|
|
573
|
+
* @class TypeORMSequence
|
|
574
|
+
* @implements Sequence
|
|
575
|
+
* @example
|
|
576
|
+
* // Create and use a TypeORM-backed sequence
|
|
577
|
+
* const seq = new TypeORMSequence({ name: "user_id_seq", type: "Number", startWith: 1, incrementBy: 1 }, adapter);
|
|
578
|
+
* const nextId = await seq.next();
|
|
579
|
+
*
|
|
580
|
+
* @mermaid
|
|
581
|
+
* sequenceDiagram
|
|
582
|
+
* participant App
|
|
583
|
+
* participant Seq as TypeORMSequence
|
|
584
|
+
* participant Adapter as TypeORMAdapter
|
|
585
|
+
* participant DB as Database
|
|
586
|
+
* App->>Seq: next()
|
|
587
|
+
* Seq->>Seq: current()
|
|
588
|
+
* Seq->>Adapter: raw(SELECT current_value ...)
|
|
589
|
+
* Adapter->>DB: Query current value
|
|
590
|
+
* DB-->>Adapter: current_value
|
|
591
|
+
* Adapter-->>Seq: value
|
|
592
|
+
* Seq->>Seq: increment(current)
|
|
593
|
+
* Seq->>Adapter: raw(nextval(name))
|
|
594
|
+
* Adapter->>DB: nextval()
|
|
595
|
+
* DB-->>Adapter: next value
|
|
596
|
+
* Adapter-->>Seq: value
|
|
597
|
+
* Seq-->>App: parsed next value
|
|
598
|
+
*/
|
|
599
|
+
class TypeORMSequence extends core.Sequence {
|
|
600
|
+
constructor(options, adapter) {
|
|
601
|
+
super(options);
|
|
602
|
+
this.adapter = adapter;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* @summary Retrieves the current value for the sequence
|
|
606
|
+
* @protected
|
|
607
|
+
*/
|
|
608
|
+
async current() {
|
|
609
|
+
const { name } = this.options;
|
|
610
|
+
try {
|
|
611
|
+
const seq = await this.adapter.raw({
|
|
612
|
+
query: `SELECT current_value FROM information_schema.sequences WHERE sequence_name = $1`,
|
|
613
|
+
values: [name],
|
|
614
|
+
});
|
|
615
|
+
return this.parse(seq.current_value);
|
|
616
|
+
}
|
|
617
|
+
catch (e) {
|
|
618
|
+
throw this.adapter.parseError(e);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* @summary Parses the {@link Sequence} value
|
|
623
|
+
*
|
|
624
|
+
* @protected
|
|
625
|
+
* @param value
|
|
626
|
+
*/
|
|
627
|
+
parse(value) {
|
|
628
|
+
return core.Sequence.parseValue(this.options.type, value);
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* @summary increments the sequence
|
|
632
|
+
* @description Sequence specific implementation
|
|
633
|
+
*
|
|
634
|
+
* @param {string | number | bigint} current
|
|
635
|
+
* @param count
|
|
636
|
+
* @protected
|
|
637
|
+
*/
|
|
638
|
+
async increment(current, count) {
|
|
639
|
+
const { type, incrementBy, name, startWith } = this.options;
|
|
640
|
+
if (type !== "Number" && type !== "BigInt")
|
|
641
|
+
throw new dbDecorators.InternalError(`Cannot increment sequence of type ${type} with ${count}`);
|
|
642
|
+
let next;
|
|
643
|
+
try {
|
|
644
|
+
next = await this.adapter.raw({
|
|
645
|
+
query: `SELECT nextval($1);`,
|
|
646
|
+
values: [name],
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
catch (e) {
|
|
650
|
+
if (!(e instanceof dbDecorators.NotFoundError))
|
|
651
|
+
throw e;
|
|
652
|
+
next = await this.adapter.raw({
|
|
653
|
+
query: `CREATE SEQUENCE IF NOT EXISTS $1 START WITH $2 INCREMENT BY $3 NO CYCLE;`,
|
|
654
|
+
values: [name, startWith, incrementBy],
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
return next;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* @summary Generates the next value in th sequence
|
|
661
|
+
* @description calls {@link Sequence#parse} on the current value
|
|
662
|
+
* followed by {@link Sequence#increment}
|
|
663
|
+
*
|
|
664
|
+
*/
|
|
665
|
+
async next() {
|
|
666
|
+
const current = await this.current();
|
|
667
|
+
return this.increment(current);
|
|
668
|
+
}
|
|
669
|
+
async range(count) {
|
|
670
|
+
const current = (await this.current());
|
|
671
|
+
const incrementBy = this.parse(this.options.incrementBy);
|
|
672
|
+
const next = await this.increment(current, this.parse(count) * incrementBy);
|
|
673
|
+
const range = [];
|
|
674
|
+
for (let i = 1; i <= count; i++) {
|
|
675
|
+
range.push(current + incrementBy * this.parse(i));
|
|
676
|
+
}
|
|
677
|
+
if (range[range.length - 1] !== next)
|
|
678
|
+
throw new dbDecorators.InternalError("Miscalculation of range");
|
|
679
|
+
return range;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* @description Generates a name for a CouchDB index
|
|
685
|
+
* @summary Creates a standardized name for a CouchDB index by combining name parts, compositions, and direction
|
|
686
|
+
* @param {string[]} name - Array of name parts for the index
|
|
687
|
+
* @param {OrderDirection} [direction] - Optional sort direction for the index
|
|
688
|
+
* @param {string[]} [compositions] - Optional additional attributes to include in the index name
|
|
689
|
+
* @param {string} [separator=DefaultSeparator] - The separator to use between parts of the index name
|
|
690
|
+
* @return {string} The generated index name
|
|
691
|
+
* @memberOf module:for-couchdb
|
|
692
|
+
*/
|
|
693
|
+
function generateIndexName(name, direction, compositions, separator = dbDecorators.DefaultSeparator) {
|
|
694
|
+
return [
|
|
695
|
+
...name.map((n) => (n === TypeORMKeys.TABLE ? "table" : n)),
|
|
696
|
+
...([]),
|
|
697
|
+
...([]),
|
|
698
|
+
TypeORMKeys.INDEX,
|
|
699
|
+
].join(separator);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* @description Generates CouchDB index configurations for models
|
|
703
|
+
* @summary Creates a set of CouchDB index configurations based on the metadata of the provided models
|
|
704
|
+
* @template M - The model type that extends Model
|
|
705
|
+
* @param models - Array of model constructors to generate indexes for
|
|
706
|
+
* @return {TypeORMQuery} Array of CouchDB index configurations
|
|
707
|
+
* @function generateIndexes
|
|
708
|
+
* @memberOf module:for-couchdb
|
|
709
|
+
* @mermaid
|
|
710
|
+
* sequenceDiagram
|
|
711
|
+
* participant Caller
|
|
712
|
+
* participant generateIndexes
|
|
713
|
+
* participant generateIndexName
|
|
714
|
+
* participant Repository
|
|
715
|
+
*
|
|
716
|
+
* Caller->>generateIndexes: models
|
|
717
|
+
*
|
|
718
|
+
* Note over generateIndexes: Create base table index
|
|
719
|
+
* generateIndexes->>generateIndexName: [CouchDBKeys.TABLE]
|
|
720
|
+
* generateIndexName-->>generateIndexes: tableName
|
|
721
|
+
* generateIndexes->>generateIndexes: Create table index config
|
|
722
|
+
*
|
|
723
|
+
* loop For each model
|
|
724
|
+
* generateIndexes->>Repository: Get indexes metadata
|
|
725
|
+
* Repository-->>generateIndexes: index metadata
|
|
726
|
+
*
|
|
727
|
+
* loop For each index in metadata
|
|
728
|
+
* Note over generateIndexes: Extract index properties
|
|
729
|
+
* generateIndexes->>Repository: Get table name
|
|
730
|
+
* Repository-->>generateIndexes: tableName
|
|
731
|
+
*
|
|
732
|
+
* Note over generateIndexes: Define nested generate function
|
|
733
|
+
*
|
|
734
|
+
* generateIndexes->>generateIndexes: Call generate() for default order
|
|
735
|
+
* Note over generateIndexes: Create index name and config
|
|
736
|
+
*
|
|
737
|
+
* alt Has directions
|
|
738
|
+
* loop For each direction
|
|
739
|
+
* generateIndexes->>generateIndexes: Call generate(direction)
|
|
740
|
+
* Note over generateIndexes: Create ordered index config
|
|
741
|
+
* end
|
|
742
|
+
* end
|
|
743
|
+
* end
|
|
744
|
+
* end
|
|
745
|
+
*
|
|
746
|
+
* generateIndexes-->>Caller: Array of index configurations
|
|
747
|
+
*/
|
|
748
|
+
function generateIndexes(models) {
|
|
749
|
+
const tableName = generateIndexName([TypeORMKeys.TABLE]);
|
|
750
|
+
const indexes = {};
|
|
751
|
+
indexes[tableName] = {
|
|
752
|
+
query: ``,
|
|
753
|
+
values: [],
|
|
754
|
+
};
|
|
755
|
+
models.forEach((m) => {
|
|
756
|
+
const ind = core.Repository.indexes(m);
|
|
757
|
+
Object.entries(ind).forEach(([key, value]) => {
|
|
758
|
+
const k = Object.keys(value)[0];
|
|
759
|
+
let { compositions } = value[k];
|
|
760
|
+
const tableName = core.Repository.table(m);
|
|
761
|
+
compositions = compositions || [];
|
|
762
|
+
function generate() {
|
|
763
|
+
const name = [key, ...compositions, core.PersistenceKeys.INDEX].join(dbDecorators.DefaultSeparator);
|
|
764
|
+
indexes[name] = {
|
|
765
|
+
query: `CREATE INDEX $1 ON $2 ($3);`,
|
|
766
|
+
values: [name, tableName, key],
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
generate();
|
|
770
|
+
});
|
|
771
|
+
});
|
|
772
|
+
return Object.values(indexes);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* @description Repository implementation backed by TypeORM.
|
|
777
|
+
* @summary Provides CRUD operations for a given Model using the {@link TypeORMAdapter}, including bulk operations and query builder access while preserving Decaf.ts repository semantics.
|
|
778
|
+
* @template M Type extending Model that this repository will manage.
|
|
779
|
+
* @param {TypeORMAdapter} adapter The adapter used to execute persistence operations.
|
|
780
|
+
* @param {Constructor<M>} model The Model constructor associated with this repository.
|
|
781
|
+
* @param {...any[]} args Optional arguments forwarded to the base Repository.
|
|
782
|
+
* @class TypeORMRepository
|
|
783
|
+
* @example
|
|
784
|
+
* // Creating a repository
|
|
785
|
+
* const repo = new TypeORMRepository<User>(adapter, User);
|
|
786
|
+
* const created = await repo.create(new User({ name: "Alice" }));
|
|
787
|
+
* const read = await repo.read(created.id);
|
|
788
|
+
*
|
|
789
|
+
* // Bulk create
|
|
790
|
+
* await repo.createAll([new User({ name: "A" }), new User({ name: "B" })]);
|
|
791
|
+
*
|
|
792
|
+
* // Using the query builder
|
|
793
|
+
* const qb = repo.queryBuilder();
|
|
794
|
+
* const rows = await qb.where("name = :name", { name: "Alice" }).getMany();
|
|
795
|
+
*
|
|
796
|
+
* @mermaid
|
|
797
|
+
* sequenceDiagram
|
|
798
|
+
* participant App
|
|
799
|
+
* participant Repo as TypeORMRepository
|
|
800
|
+
* participant Adapter as TypeORMAdapter
|
|
801
|
+
* participant DB as TypeORM/DataSource
|
|
802
|
+
*
|
|
803
|
+
* App->>Repo: create(model)
|
|
804
|
+
* Repo->>Adapter: prepare(model, pk)
|
|
805
|
+
* Adapter-->>Repo: { record, id, transient }
|
|
806
|
+
* Repo->>Adapter: create(table, id, model, ...args)
|
|
807
|
+
* Adapter->>DB: INSERT ...
|
|
808
|
+
* DB-->>Adapter: row
|
|
809
|
+
* Adapter-->>Repo: row
|
|
810
|
+
* Repo->>Adapter: revert(row, clazz, pk, id)
|
|
811
|
+
* Adapter-->>Repo: model
|
|
812
|
+
* Repo-->>App: model
|
|
813
|
+
*/
|
|
814
|
+
exports.TypeORMRepository = class TypeORMRepository extends core.Repository {
|
|
815
|
+
constructor(adapter, model, ...args) {
|
|
816
|
+
super(adapter, model, ...args);
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* @description Creates a TypeORM query builder for the repository entity.
|
|
820
|
+
* @summary Returns a SelectQueryBuilder bound to this repository's entity for advanced querying.
|
|
821
|
+
* @return {import("typeorm").SelectQueryBuilder<any>} A TypeORM SelectQueryBuilder instance.
|
|
822
|
+
*/
|
|
823
|
+
queryBuilder() {
|
|
824
|
+
const repo = this.adapter.dataSource.getRepository(this.class[decoratorValidation.ModelKeys.ANCHOR]);
|
|
825
|
+
return repo.createQueryBuilder();
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* @description Creates and persists a model instance.
|
|
829
|
+
* @summary Prepares the model, delegates insertion to the adapter, and rehydrates the persisted state back into a Model instance.
|
|
830
|
+
* @param {M} model The model to create.
|
|
831
|
+
* @param {...any[]} args Optional arguments/context.
|
|
832
|
+
* @return {Promise<M>} The created model instance.
|
|
833
|
+
*/
|
|
834
|
+
async create(model, ...args) {
|
|
835
|
+
// eslint-disable-next-line prefer-const
|
|
836
|
+
let { record, id, transient } = this.adapter.prepare(model, this.pk);
|
|
837
|
+
record = await this.adapter.create(this.class[decoratorValidation.ModelKeys.ANCHOR], id, model, ...args);
|
|
838
|
+
let c = undefined;
|
|
839
|
+
if (args.length)
|
|
840
|
+
c = args[args.length - 1];
|
|
841
|
+
return this.adapter.revert(record, this.class, this.pk, id, c && c.get("rebuildWithTransient") ? transient : undefined);
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* @description Reads a model from the database by ID.
|
|
845
|
+
* @summary Retrieves a model instance from the database using its primary key.
|
|
846
|
+
* @param {string|number|bigint} id - The primary key of the model to read.
|
|
847
|
+
* @param {...any[]} args - Additional arguments.
|
|
848
|
+
* @return {Promise<M>} The retrieved model instance.
|
|
849
|
+
*/
|
|
850
|
+
async read(id,
|
|
851
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
852
|
+
...args) {
|
|
853
|
+
const m = await this.adapter.read(this.class[decoratorValidation.ModelKeys.ANCHOR], id, this.pk);
|
|
854
|
+
return this.adapter.revert(m, this.class, this.pk, id);
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* @description Updates and persists a model instance.
|
|
858
|
+
* @summary Prepares the model, delegates update to the adapter, and rehydrates the persisted state back into a Model instance.
|
|
859
|
+
* @param {M} model The model to update.
|
|
860
|
+
* @param {...any[]} args Optional arguments/context.
|
|
861
|
+
* @return {Promise<M>} The updated model instance.
|
|
862
|
+
*/
|
|
863
|
+
async update(model, ...args) {
|
|
864
|
+
// eslint-disable-next-line prefer-const
|
|
865
|
+
let { record, id, transient } = this.adapter.prepare(model, this.pk);
|
|
866
|
+
record = await this.adapter.update(this.class[decoratorValidation.ModelKeys.ANCHOR], id, model, ...args);
|
|
867
|
+
return this.adapter.revert(record, this.class, this.pk, id, transient);
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* @description Deletes a model from the database by ID.
|
|
871
|
+
* @summary Removes a model instance from the database using its primary key.
|
|
872
|
+
* @param {string|number|bigint} id - The primary key of the model to delete.
|
|
873
|
+
* @param {...any[]} args - Additional arguments.
|
|
874
|
+
* @return {Promise<M>} The deleted model instance.
|
|
875
|
+
*/
|
|
876
|
+
async delete(id, ...args) {
|
|
877
|
+
const m = await this.adapter.delete(this.class[decoratorValidation.ModelKeys.ANCHOR], id, this.pk, ...args);
|
|
878
|
+
return this.adapter.revert(m, this.class, this.pk, id);
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* @description Validates and prepares models for bulk creation.
|
|
882
|
+
* @summary Applies decorator-based validations and returns transformed models with context args for createAll.
|
|
883
|
+
* @param {M[]} models The models to be created.
|
|
884
|
+
* @param {...any[]} args Optional arguments/context.
|
|
885
|
+
* @return {Promise<[M[], ...any[]]>} The prepared models and forwarded args tuple.
|
|
886
|
+
*/
|
|
887
|
+
async createAllPrefix(models, ...args) {
|
|
888
|
+
const contextArgs = await dbDecorators.Context.args(dbDecorators.OperationKeys.CREATE, this.class, args, this.adapter, this._overrides || {});
|
|
889
|
+
if (!models.length)
|
|
890
|
+
return [models, ...contextArgs.args];
|
|
891
|
+
models = await Promise.all(models.map(async (m) => {
|
|
892
|
+
m = new this.class(m);
|
|
893
|
+
await dbDecorators.enforceDBDecorators(this, contextArgs.context, m, dbDecorators.OperationKeys.CREATE, dbDecorators.OperationKeys.ON);
|
|
894
|
+
return m;
|
|
895
|
+
}));
|
|
896
|
+
const errors = models
|
|
897
|
+
.map((m) => m.hasErrors(...(contextArgs.context.get("ignoredValidationProperties") || [])))
|
|
898
|
+
.reduce((accum, e, i) => {
|
|
899
|
+
if (e)
|
|
900
|
+
accum =
|
|
901
|
+
typeof accum === "string"
|
|
902
|
+
? accum + `\n - ${i}: ${e.toString()}`
|
|
903
|
+
: ` - ${i}: ${e.toString()}`;
|
|
904
|
+
return accum;
|
|
905
|
+
}, undefined);
|
|
906
|
+
if (errors)
|
|
907
|
+
throw new dbDecorators.ValidationError(errors);
|
|
908
|
+
return [models, ...contextArgs.args];
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* @description Creates multiple models at once.
|
|
912
|
+
* @summary Prepares, persists, and rehydrates a batch of models.
|
|
913
|
+
* @param {M[]} models The models to create.
|
|
914
|
+
* @param {...any[]} args Optional arguments/context.
|
|
915
|
+
* @return {Promise<M[]>} The created models.
|
|
916
|
+
*/
|
|
917
|
+
async createAll(models, ...args) {
|
|
918
|
+
if (!models.length)
|
|
919
|
+
return models;
|
|
920
|
+
const prepared = models.map((m) => this.adapter.prepare(m, this.pk));
|
|
921
|
+
const ids = prepared.map((p) => p.id);
|
|
922
|
+
let records = prepared.map((p) => p.record);
|
|
923
|
+
records = await this.adapter.createAll(this.class[decoratorValidation.ModelKeys.ANCHOR], ids, models, ...args);
|
|
924
|
+
return records.map((r, i) => this.adapter.revert(r, this.class, this.pk, ids[i]));
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* @description Reads multiple models by their primary keys.
|
|
928
|
+
* @summary Retrieves a list of models corresponding to the provided keys.
|
|
929
|
+
* @param {(string[]|number[])} keys The primary keys to read.
|
|
930
|
+
* @param {...any[]} args Optional arguments/context.
|
|
931
|
+
* @return {Promise<M[]>} The retrieved models.
|
|
932
|
+
*/
|
|
933
|
+
async readAll(keys, ...args) {
|
|
934
|
+
const records = await this.adapter.readAll(this.class[decoratorValidation.ModelKeys.ANCHOR], keys, this.pk, ...args);
|
|
935
|
+
return records.map((r, i) => this.adapter.revert(r, this.class, this.pk, keys[i]));
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* @description Updates multiple models at once.
|
|
939
|
+
* @summary Persists a batch of model updates and returns their rehydrated instances.
|
|
940
|
+
* @param {M[]} models The models to update.
|
|
941
|
+
* @param {...any[]} args Optional arguments/context.
|
|
942
|
+
* @return {Promise<M[]>} The updated models.
|
|
943
|
+
*/
|
|
944
|
+
async updateAll(models, ...args) {
|
|
945
|
+
const records = models.map((m) => this.adapter.prepare(m, this.pk));
|
|
946
|
+
const updated = await this.adapter.updateAll(this.class[decoratorValidation.ModelKeys.ANCHOR], records.map((r) => r.id), models, this.pk, ...args);
|
|
947
|
+
return updated.map((u, i) => this.adapter.revert(u, this.class, this.pk, records[i].id));
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* @description Deletes multiple models at once.
|
|
951
|
+
* @summary Removes a list of models by their primary keys and returns their last persisted states.
|
|
952
|
+
* @param {(string[]|number[])} keys The primary keys to delete.
|
|
953
|
+
* @param {...any[]} args Optional arguments/context.
|
|
954
|
+
* @return {Promise<M[]>} The deleted models.
|
|
955
|
+
*/
|
|
956
|
+
async deleteAll(keys, ...args) {
|
|
957
|
+
const results = await this.adapter.deleteAll(this.class[decoratorValidation.ModelKeys.ANCHOR], keys, this.pk, ...args);
|
|
958
|
+
return results.map((r, i) => this.adapter.revert(r, this.class, this.pk, keys[i]));
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
exports.TypeORMRepository = tslib.__decorate([
|
|
962
|
+
core.uses(TypeORMFlavour),
|
|
963
|
+
tslib.__metadata("design:paramtypes", [TypeORMAdapter, Object, Object])
|
|
964
|
+
], exports.TypeORMRepository);
|
|
965
|
+
|
|
966
|
+
/**
|
|
967
|
+
* @description TypeORM event subscriber that forwards entity lifecycle events to the adapter.
|
|
968
|
+
* @summary Listens for insert, update, and remove events emitted by TypeORM and notifies the Decaf.ts adapter so that observers can be updated accordingly.
|
|
969
|
+
* @param {TypeORMAdapter} adapter The TypeORM adapter used to propagate events and look up metadata.
|
|
970
|
+
* @class
|
|
971
|
+
* @example
|
|
972
|
+
* // Registering the subscriber when creating a DataSource
|
|
973
|
+
* // dataSourceOptions.subscribers = [new TypeORMEventSubscriber(adapter)];
|
|
974
|
+
*
|
|
975
|
+
* @mermaid
|
|
976
|
+
* sequenceDiagram
|
|
977
|
+
* participant TypeORM
|
|
978
|
+
* participant Subscriber as TypeORMEventSubscriber
|
|
979
|
+
* participant Adapter as TypeORMAdapter
|
|
980
|
+
* participant Observers
|
|
981
|
+
*
|
|
982
|
+
* TypeORM->>Subscriber: afterInsert(entity)
|
|
983
|
+
* Subscriber->>Adapter: updateObservers(table, CREATE, [id])
|
|
984
|
+
* Adapter->>Observers: notify(table, CREATE, [id])
|
|
985
|
+
*
|
|
986
|
+
* TypeORM->>Subscriber: afterUpdate(event)
|
|
987
|
+
* Subscriber->>Adapter: updateObservers(table, UPDATE, [id])
|
|
988
|
+
* Adapter->>Observers: notify(table, UPDATE, [id])
|
|
989
|
+
*
|
|
990
|
+
* TypeORM->>Subscriber: afterRemove(event)
|
|
991
|
+
* Subscriber->>Adapter: updateObservers(table, DELETE, [id])
|
|
992
|
+
* Adapter->>Observers: notify(table, DELETE, [id])
|
|
993
|
+
*/
|
|
994
|
+
let TypeORMEventSubscriber = class TypeORMEventSubscriber {
|
|
995
|
+
constructor(handler) {
|
|
996
|
+
this.handler = handler;
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* @description Handles post-insert events.
|
|
1000
|
+
* @summary Notifies observers about a create operation for the inserted entity.
|
|
1001
|
+
* @param {InsertEvent<any>} event The TypeORM insert event.
|
|
1002
|
+
* @return {Promise<any>|void} A promise when async or void otherwise.
|
|
1003
|
+
*/
|
|
1004
|
+
afterInsert(event) {
|
|
1005
|
+
const constructor = decoratorValidation.Model.get(event.entity.constructor.name);
|
|
1006
|
+
if (!constructor)
|
|
1007
|
+
throw new dbDecorators.InternalError(`No registered model found for ${event.entity.constructor.name}`);
|
|
1008
|
+
const tableName = core.Repository.table(constructor);
|
|
1009
|
+
this.handler(tableName, dbDecorators.OperationKeys.CREATE, [event.entityId]);
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* @description Handles post-remove events.
|
|
1013
|
+
* @summary Notifies observers about a delete operation for the removed entity.
|
|
1014
|
+
* @param {RemoveEvent<any>} event The TypeORM remove event.
|
|
1015
|
+
* @return {Promise<any>|void} A promise when async or void otherwise.
|
|
1016
|
+
*/
|
|
1017
|
+
afterRemove(event) {
|
|
1018
|
+
const constructor = decoratorValidation.Model.get(event.entity.constructor.name);
|
|
1019
|
+
if (!constructor)
|
|
1020
|
+
throw new dbDecorators.InternalError(`No registered model found for ${event.entity.constructor.name}`);
|
|
1021
|
+
const tableName = core.Repository.table(constructor);
|
|
1022
|
+
this.handler(tableName, dbDecorators.OperationKeys.DELETE, [event.entityId]);
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* @description Handles post-update events.
|
|
1026
|
+
* @summary Notifies observers about an update operation for the modified entity.
|
|
1027
|
+
* @param {UpdateEvent<any>} event The TypeORM update event.
|
|
1028
|
+
* @return {Promise<any>|void} A promise when async or void otherwise.
|
|
1029
|
+
*/
|
|
1030
|
+
afterUpdate(event) {
|
|
1031
|
+
const constructor = decoratorValidation.Model.get(event.databaseEntity.constructor.name);
|
|
1032
|
+
if (!constructor)
|
|
1033
|
+
throw new dbDecorators.InternalError(`No registered model found for ${event.databaseEntity.constructor.name}`);
|
|
1034
|
+
const tableName = core.Repository.table(constructor);
|
|
1035
|
+
return this.handler(tableName, dbDecorators.OperationKeys.UPDATE, [
|
|
1036
|
+
event.entity["id"],
|
|
1037
|
+
]);
|
|
1038
|
+
}
|
|
1039
|
+
};
|
|
1040
|
+
TypeORMEventSubscriber = tslib.__decorate([
|
|
1041
|
+
typeorm.EventSubscriber(),
|
|
1042
|
+
tslib.__metadata("design:paramtypes", [Function])
|
|
1043
|
+
], TypeORMEventSubscriber);
|
|
1044
|
+
|
|
1045
|
+
/**
|
|
1046
|
+
* @description Dispatcher for TypeORM-driven change events.
|
|
1047
|
+
* @summary Subscribes a TypeORM DataSource with a custom EntitySubscriber to notify observers when records are created, updated, or deleted.
|
|
1048
|
+
* @param {number} [timeout=5000] Timeout in milliseconds for initialization retries.
|
|
1049
|
+
* @class TypeORMDispatch
|
|
1050
|
+
* @example
|
|
1051
|
+
* // Create a dispatcher for a TypeORM DataSource
|
|
1052
|
+
* const dispatch = new TypeORMDispatch();
|
|
1053
|
+
* await dispatch.observe(adapter, adapter.dataSource.options);
|
|
1054
|
+
*
|
|
1055
|
+
* // The dispatcher registers a TypeORMEventSubscriber and notifies observers when entities change.
|
|
1056
|
+
* @mermaid
|
|
1057
|
+
* classDiagram
|
|
1058
|
+
* class Dispatch {
|
|
1059
|
+
* +initialize()
|
|
1060
|
+
* +updateObservers()
|
|
1061
|
+
* }
|
|
1062
|
+
* class TypeORMDispatch {
|
|
1063
|
+
* -observerLastUpdate?: string
|
|
1064
|
+
* -attemptCounter: number
|
|
1065
|
+
* -timeout: number
|
|
1066
|
+
* +constructor(timeout)
|
|
1067
|
+
* #notificationHandler()
|
|
1068
|
+
* #initialize()
|
|
1069
|
+
* }
|
|
1070
|
+
* Dispatch <|-- TypeORMDispatch
|
|
1071
|
+
*/
|
|
1072
|
+
class TypeORMDispatch extends core.Dispatch {
|
|
1073
|
+
constructor(timeout = 5000) {
|
|
1074
|
+
super();
|
|
1075
|
+
this.timeout = timeout;
|
|
1076
|
+
this.attemptCounter = 0;
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* @description Processes TypeORM notification events.
|
|
1080
|
+
* @summary Handles change notifications (translated from TypeORM events) and notifies observers about record changes.
|
|
1081
|
+
* @param {string} table The notification payload.
|
|
1082
|
+
* @param {OperationKeys} operation The notification payload.
|
|
1083
|
+
* @param {EventIds} ids The notification payload.
|
|
1084
|
+
* @return {Promise<void>} A promise that resolves when all notifications have been processed.
|
|
1085
|
+
* @mermaid
|
|
1086
|
+
* sequenceDiagram
|
|
1087
|
+
* participant D as PostgreSQLDispatch
|
|
1088
|
+
* participant L as Logger
|
|
1089
|
+
* participant O as Observers
|
|
1090
|
+
* Note over D: Receive notification from PostgreSQL
|
|
1091
|
+
* D->>D: Parse notification payload
|
|
1092
|
+
* D->>D: Extract table, operation, and ids
|
|
1093
|
+
* D->>O: updateObservers(table, operation, ids)
|
|
1094
|
+
* D->>D: Update observerLastUpdate
|
|
1095
|
+
* D->>L: Log successful dispatch
|
|
1096
|
+
*/
|
|
1097
|
+
async notificationHandler(table, operation, ids) {
|
|
1098
|
+
const log = this.log.for(this.notificationHandler);
|
|
1099
|
+
try {
|
|
1100
|
+
// Notify observers
|
|
1101
|
+
await this.updateObservers(table, operation, ids);
|
|
1102
|
+
this.observerLastUpdate = new Date().toISOString();
|
|
1103
|
+
log.verbose(`Observer refresh dispatched by ${operation} for ${table}`);
|
|
1104
|
+
log.debug(`pks: ${ids}`);
|
|
1105
|
+
}
|
|
1106
|
+
catch (e) {
|
|
1107
|
+
log.error(`Failed to process notification: ${e}`);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* @description Initializes the dispatcher and subscribes to TypeORM notifications.
|
|
1112
|
+
* @summary Registers the TypeORMEventSubscriber on the DataSource and logs the subscription lifecycle.
|
|
1113
|
+
* @return {Promise<void>} A promise that resolves when the subscription is established.
|
|
1114
|
+
* @mermaid
|
|
1115
|
+
* sequenceDiagram
|
|
1116
|
+
* participant D as TypeORMDispatch
|
|
1117
|
+
* participant S as subscribeToTypeORM
|
|
1118
|
+
* participant DS as TypeORM DataSource
|
|
1119
|
+
* participant L as Logger
|
|
1120
|
+
* D->>S: Call subscribeToTypeORM
|
|
1121
|
+
* S->>S: Check adapter and native
|
|
1122
|
+
* alt No adapter or native
|
|
1123
|
+
* S-->>S: throw InternalError
|
|
1124
|
+
* end
|
|
1125
|
+
* S->>DS: initialize()
|
|
1126
|
+
* S->>DS: subscribers.push(TypeORMEventSubscriber)
|
|
1127
|
+
* alt Success
|
|
1128
|
+
* DS-->>S: Subscription established
|
|
1129
|
+
* S-->>D: Promise resolves
|
|
1130
|
+
* D->>L: Log successful subscription
|
|
1131
|
+
* else Error
|
|
1132
|
+
* DS-->>S: Error
|
|
1133
|
+
* S-->>D: Promise rejects
|
|
1134
|
+
* end
|
|
1135
|
+
*/
|
|
1136
|
+
async initialize() {
|
|
1137
|
+
async function subscribeToTypeORM() {
|
|
1138
|
+
if (!this.adapter || !this.native) {
|
|
1139
|
+
throw new dbDecorators.InternalError(`No adapter/native observed for dispatch`);
|
|
1140
|
+
}
|
|
1141
|
+
const adapter = this.adapter;
|
|
1142
|
+
try {
|
|
1143
|
+
if (!adapter.dataSource.isInitialized)
|
|
1144
|
+
await adapter.dataSource.initialize();
|
|
1145
|
+
adapter.dataSource.subscribers.push(new TypeORMEventSubscriber(this.notificationHandler.bind(this)));
|
|
1146
|
+
}
|
|
1147
|
+
catch (e) {
|
|
1148
|
+
throw new dbDecorators.InternalError(e);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
subscribeToTypeORM
|
|
1152
|
+
.call(this)
|
|
1153
|
+
.then(() => {
|
|
1154
|
+
this.log.info(`Subscribed to TypeORM notifications`);
|
|
1155
|
+
})
|
|
1156
|
+
.catch((e) => {
|
|
1157
|
+
throw new dbDecorators.InternalError(`Failed to subscribe to TypeORM notifications: ${e}`);
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* Cleanup method to release resources when the dispatcher is no longer needed
|
|
1162
|
+
*/
|
|
1163
|
+
cleanup() {
|
|
1164
|
+
// if (this.adapter) {
|
|
1165
|
+
//
|
|
1166
|
+
// const adapter = this.adapter as TypeORMAdapter;
|
|
1167
|
+
// await adapter.dataSource.destroy();
|
|
1168
|
+
// }
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* @description Converts a JavaScript RegExp pattern to a PostgreSQL POSIX pattern string.
|
|
1174
|
+
* @summary Accepts either a RegExp object or a string representation (/pattern/flags) and returns the raw pattern compatible with PostgreSQL's ~ and ~* operators.
|
|
1175
|
+
* @param {RegExp|string} jsRegex JavaScript RegExp object or pattern string.
|
|
1176
|
+
* @return {string} PostgreSQL-compatible regex pattern string.
|
|
1177
|
+
* @function convertJsRegexToPostgres
|
|
1178
|
+
* @mermaid
|
|
1179
|
+
* sequenceDiagram
|
|
1180
|
+
* participant App
|
|
1181
|
+
* participant Utils as convertJsRegexToPostgres
|
|
1182
|
+
* App->>Utils: convertJsRegexToPostgres(RegExp("foo.*","i"))
|
|
1183
|
+
* Utils->>Utils: Parse string or use RegExp.source
|
|
1184
|
+
* Utils-->>App: "foo.*"
|
|
1185
|
+
* @memberOf module:for-typeorm
|
|
1186
|
+
*/
|
|
1187
|
+
function convertJsRegexToPostgres(jsRegex) {
|
|
1188
|
+
const rxp = new RegExp(/^\/(.+)\/(\w+)$/g);
|
|
1189
|
+
if (typeof jsRegex === "string") {
|
|
1190
|
+
const match = rxp.exec(jsRegex);
|
|
1191
|
+
if (match) {
|
|
1192
|
+
const [, p] = match;
|
|
1193
|
+
jsRegex = p;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
const regex = typeof jsRegex === "string" ? new RegExp(jsRegex) : jsRegex;
|
|
1197
|
+
const pattern = regex.source;
|
|
1198
|
+
return pattern;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
function aggregateOrNewColumn(target, property, columns, options = {}, mode = "regular") {
|
|
1202
|
+
const cols = columns.filter((c) => c.target === target && c.propertyName === property);
|
|
1203
|
+
if (cols.length > 1)
|
|
1204
|
+
throw new Error(`Multiple columns for ${property} found for given target: ${columns.map((c) => c.propertyName).join(", ")}`);
|
|
1205
|
+
if (cols.length === 0) {
|
|
1206
|
+
columns.push({
|
|
1207
|
+
target: target,
|
|
1208
|
+
propertyName: property,
|
|
1209
|
+
mode: mode,
|
|
1210
|
+
options: options,
|
|
1211
|
+
});
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
const column = cols[0];
|
|
1215
|
+
Object.defineProperty(column, "options", {
|
|
1216
|
+
value: { ...column.options, ...options },
|
|
1217
|
+
writable: true,
|
|
1218
|
+
enumerable: true,
|
|
1219
|
+
configurable: true,
|
|
1220
|
+
});
|
|
1221
|
+
if (mode !== "regular")
|
|
1222
|
+
Object.defineProperty(column, "mode", {
|
|
1223
|
+
value: mode,
|
|
1224
|
+
writable: true,
|
|
1225
|
+
enumerable: true,
|
|
1226
|
+
configurable: true,
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* Column decorator is used to mark a specific class property as a table column.
|
|
1232
|
+
* Only properties decorated with this decorator will be persisted to the database when entity be saved.
|
|
1233
|
+
*/
|
|
1234
|
+
function Column(typeOrOptions, options) {
|
|
1235
|
+
return function (object, propertyName) {
|
|
1236
|
+
// normalize parameters
|
|
1237
|
+
let type;
|
|
1238
|
+
if (typeof typeOrOptions === "string" ||
|
|
1239
|
+
typeof typeOrOptions === "function") {
|
|
1240
|
+
type = typeOrOptions;
|
|
1241
|
+
}
|
|
1242
|
+
else if (typeOrOptions) {
|
|
1243
|
+
options = typeOrOptions;
|
|
1244
|
+
type = typeOrOptions.type;
|
|
1245
|
+
}
|
|
1246
|
+
if (!options)
|
|
1247
|
+
options = {};
|
|
1248
|
+
// if type is not given explicitly then try to guess it
|
|
1249
|
+
const reflectMetadataType = Reflect && Reflect.getMetadata
|
|
1250
|
+
? Reflect.getMetadata("design:type", object, propertyName)
|
|
1251
|
+
: undefined;
|
|
1252
|
+
if (!type && reflectMetadataType)
|
|
1253
|
+
// if type is not given explicitly then try to guess it
|
|
1254
|
+
type = reflectMetadataType;
|
|
1255
|
+
// check if there is no type in column options then set type from first function argument, or guessed one
|
|
1256
|
+
if (!options.type && type)
|
|
1257
|
+
options.type = type;
|
|
1258
|
+
// specify HSTORE type if column is HSTORE
|
|
1259
|
+
if (options.type === "hstore" && !options.hstoreType)
|
|
1260
|
+
options.hstoreType = reflectMetadataType === Object ? "object" : "string";
|
|
1261
|
+
if (typeof typeOrOptions === "function") {
|
|
1262
|
+
// register an embedded
|
|
1263
|
+
typeorm.getMetadataArgsStorage().embeddeds.push({
|
|
1264
|
+
target: object.constructor,
|
|
1265
|
+
propertyName: propertyName,
|
|
1266
|
+
isArray: reflectMetadataType === Array || options.array === true,
|
|
1267
|
+
prefix: options.prefix !== undefined ? options.prefix : undefined,
|
|
1268
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
1269
|
+
type: typeOrOptions,
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
else {
|
|
1273
|
+
// register a regular column
|
|
1274
|
+
// if we still don't have a type then we need to give error to user that type is required
|
|
1275
|
+
if (!options.type)
|
|
1276
|
+
throw new typeorm.ColumnTypeUndefinedError(object, propertyName);
|
|
1277
|
+
// create unique
|
|
1278
|
+
if (options.unique === true)
|
|
1279
|
+
typeorm.getMetadataArgsStorage().uniques.push({
|
|
1280
|
+
target: object.constructor,
|
|
1281
|
+
columns: [propertyName],
|
|
1282
|
+
});
|
|
1283
|
+
const columns = typeorm.getMetadataArgsStorage().columns;
|
|
1284
|
+
aggregateOrNewColumn(object.constructor, propertyName, columns, options);
|
|
1285
|
+
if (options.generated) {
|
|
1286
|
+
typeorm.getMetadataArgsStorage().generations.push({
|
|
1287
|
+
target: object.constructor,
|
|
1288
|
+
propertyName: propertyName,
|
|
1289
|
+
strategy: typeof options.generated === "string"
|
|
1290
|
+
? options.generated
|
|
1291
|
+
: "increment",
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
};
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
function UpdateDateColumn(options) {
|
|
1299
|
+
return function (object, propertyName) {
|
|
1300
|
+
const columns = typeorm.getMetadataArgsStorage().columns;
|
|
1301
|
+
aggregateOrNewColumn(object.constructor, propertyName, columns, {}, "updateDate");
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
function CreateDateColumn(options) {
|
|
1306
|
+
return function (object, propertyName) {
|
|
1307
|
+
const columns = typeorm.getMetadataArgsStorage().columns;
|
|
1308
|
+
aggregateOrNewColumn(object.constructor, propertyName, columns, {}, "createDate");
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
/**
|
|
1313
|
+
* Column decorator is used to mark a specific class property as a table column.
|
|
1314
|
+
* Only properties decorated with this decorator will be persisted to the database when entity be saved.
|
|
1315
|
+
* This column creates an integer PRIMARY COLUMN with generated set to true.
|
|
1316
|
+
*/
|
|
1317
|
+
function PrimaryGeneratedColumn(strategyOrOptions, maybeOptions) {
|
|
1318
|
+
// normalize parameters
|
|
1319
|
+
const options = {};
|
|
1320
|
+
let strategy;
|
|
1321
|
+
{
|
|
1322
|
+
strategy = "increment";
|
|
1323
|
+
}
|
|
1324
|
+
if (ObjectUtils.ObjectUtils.isObject(maybeOptions))
|
|
1325
|
+
Object.assign(options, maybeOptions);
|
|
1326
|
+
return function (object, propertyName) {
|
|
1327
|
+
// if column type is not explicitly set then determine it based on generation strategy
|
|
1328
|
+
if (!options.type) {
|
|
1329
|
+
if (strategy === "increment" || strategy === "identity") {
|
|
1330
|
+
options.type = Number;
|
|
1331
|
+
}
|
|
1332
|
+
else if (strategy === "uuid") {
|
|
1333
|
+
options.type = "uuid";
|
|
1334
|
+
}
|
|
1335
|
+
else if (strategy === "rowid") {
|
|
1336
|
+
options.type = "int";
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
// explicitly set a primary and generated to column options
|
|
1340
|
+
options.primary = true;
|
|
1341
|
+
const columns = typeorm.getMetadataArgsStorage().columns;
|
|
1342
|
+
aggregateOrNewColumn(object.constructor, propertyName, columns, options);
|
|
1343
|
+
// register generated metadata args
|
|
1344
|
+
typeorm.getMetadataArgsStorage().generations.push({
|
|
1345
|
+
target: object.constructor,
|
|
1346
|
+
propertyName: propertyName,
|
|
1347
|
+
strategy: strategy,
|
|
1348
|
+
});
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
/**
|
|
1353
|
+
* Column decorator is used to mark a specific class property as a table column.
|
|
1354
|
+
* Only properties decorated with this decorator will be persisted to the database when entity be saved.
|
|
1355
|
+
* Primary columns also creates a PRIMARY KEY for this column in a db.
|
|
1356
|
+
*/
|
|
1357
|
+
function PrimaryColumn(typeOrOptions, options) {
|
|
1358
|
+
return function (object, propertyName) {
|
|
1359
|
+
// normalize parameters
|
|
1360
|
+
let type;
|
|
1361
|
+
if (typeof typeOrOptions === "string" ||
|
|
1362
|
+
typeOrOptions === String ||
|
|
1363
|
+
typeOrOptions === Boolean ||
|
|
1364
|
+
typeOrOptions === Number) {
|
|
1365
|
+
type = typeOrOptions;
|
|
1366
|
+
}
|
|
1367
|
+
else {
|
|
1368
|
+
options = Object.assign({}, typeOrOptions);
|
|
1369
|
+
}
|
|
1370
|
+
if (!options)
|
|
1371
|
+
options = {};
|
|
1372
|
+
// if type is not given explicitly then try to guess it
|
|
1373
|
+
const reflectMetadataType = Reflect && Reflect.getMetadata
|
|
1374
|
+
? Reflect.getMetadata("design:type", object, propertyName)
|
|
1375
|
+
: undefined;
|
|
1376
|
+
if (!type && reflectMetadataType)
|
|
1377
|
+
type = reflectMetadataType;
|
|
1378
|
+
// check if there is no type in column options then set type from first function argument, or guessed one
|
|
1379
|
+
if (!options.type && type)
|
|
1380
|
+
options.type = type;
|
|
1381
|
+
// if we still don't have a type then we need to give error to user that type is required
|
|
1382
|
+
if (!options.type)
|
|
1383
|
+
throw new typeorm.ColumnTypeUndefinedError(object, propertyName);
|
|
1384
|
+
// check if column is not nullable, because we cannot allow a primary key to be nullable
|
|
1385
|
+
if (options.nullable)
|
|
1386
|
+
throw new typeorm.PrimaryColumnCannotBeNullableError(object, propertyName);
|
|
1387
|
+
// explicitly set a primary to column options
|
|
1388
|
+
options.primary = true;
|
|
1389
|
+
const columns = typeorm.getMetadataArgsStorage().columns;
|
|
1390
|
+
aggregateOrNewColumn(object.constructor, propertyName, columns, options);
|
|
1391
|
+
if (options.generated) {
|
|
1392
|
+
typeorm.getMetadataArgsStorage().generations.push({
|
|
1393
|
+
target: object.constructor,
|
|
1394
|
+
propertyName: propertyName,
|
|
1395
|
+
strategy: typeof options.generated === "string"
|
|
1396
|
+
? options.generated
|
|
1397
|
+
: "increment",
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
/**
|
|
1404
|
+
* This decorator is used to mark classes that will be an entity (table or document depend on database type).
|
|
1405
|
+
* Database schema will be created for all classes decorated with it, and Repository can be retrieved and used for it.
|
|
1406
|
+
*/
|
|
1407
|
+
function Entity(nameOrOptions, maybeOptions) {
|
|
1408
|
+
const options = (ObjectUtils.ObjectUtils.isObject(nameOrOptions)
|
|
1409
|
+
? nameOrOptions
|
|
1410
|
+
: maybeOptions) || {};
|
|
1411
|
+
const name = options.name;
|
|
1412
|
+
return function (target) {
|
|
1413
|
+
const tables = typeorm.getMetadataArgsStorage().tables;
|
|
1414
|
+
tables.push({
|
|
1415
|
+
target: target,
|
|
1416
|
+
name: name,
|
|
1417
|
+
type: "regular",
|
|
1418
|
+
orderBy: options.orderBy ? options.orderBy : undefined,
|
|
1419
|
+
engine: options.engine ? options.engine : undefined,
|
|
1420
|
+
database: options.database ? options.database : undefined,
|
|
1421
|
+
schema: options.schema ? options.schema : undefined,
|
|
1422
|
+
synchronize: options.synchronize,
|
|
1423
|
+
withoutRowid: options.withoutRowid,
|
|
1424
|
+
comment: options.comment ? options.comment : undefined,
|
|
1425
|
+
});
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
async function createdByOnPostgresCreateUpdate(context, data, key, model) {
|
|
1430
|
+
try {
|
|
1431
|
+
const user = context.get("user");
|
|
1432
|
+
model[key] = user;
|
|
1433
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1434
|
+
}
|
|
1435
|
+
catch (e) {
|
|
1436
|
+
throw new dbDecorators.InternalError("No User found in context. Please provide a user in the context");
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* @description Adapter for TypeORM-backed persistence operations.
|
|
1441
|
+
* @summary Implements the Decaf.ts Adapter over a TypeORM DataSource, providing CRUD operations, query/statement factories, sequence management, error parsing, and decoration helpers.
|
|
1442
|
+
* @template Y The native configuration type (TypeORM DataSourceOptions).
|
|
1443
|
+
* @template F The repository flags type.
|
|
1444
|
+
* @template C The context type.
|
|
1445
|
+
* @param {DataSourceOptions} scope The DataSource options for the adapter.
|
|
1446
|
+
* @param {string} flavour The flavour of the adapter.
|
|
1447
|
+
* @param {string} [alias] Optional alias for the adapter.
|
|
1448
|
+
* @class TypeORMAdapter
|
|
1449
|
+
* @example
|
|
1450
|
+
* const adapter = new TypeORMAdapter({ type: 'postgres', /* ... *\/ });
|
|
1451
|
+
* await adapter.initialize();
|
|
1452
|
+
* const repo = new (adapter.repository<User>())(adapter, User);
|
|
1453
|
+
* const created = await repo.create(new User({ name: 'Alice' }));
|
|
1454
|
+
*
|
|
1455
|
+
* @mermaid
|
|
1456
|
+
* sequenceDiagram
|
|
1457
|
+
* participant App
|
|
1458
|
+
* participant Adapter as TypeORMAdapter
|
|
1459
|
+
* participant Repo as TypeORMRepository
|
|
1460
|
+
* participant DS as TypeORM DataSource
|
|
1461
|
+
*
|
|
1462
|
+
* App->>Adapter: new TypeORMAdapter(opts)
|
|
1463
|
+
* Adapter->>DS: initialize()
|
|
1464
|
+
* App->>Adapter: repository()
|
|
1465
|
+
* Adapter-->>App: TypeORMRepository
|
|
1466
|
+
* App->>Repo: create(model)
|
|
1467
|
+
* Repo->>Adapter: prepare/create/revert
|
|
1468
|
+
* Adapter-->>Repo: Model
|
|
1469
|
+
* Repo-->>App: Model
|
|
1470
|
+
*/
|
|
1471
|
+
class TypeORMAdapter extends core.Adapter {
|
|
1472
|
+
get dataSource() {
|
|
1473
|
+
if (!this._dataSource) {
|
|
1474
|
+
const models = core.Adapter.models(this.flavour);
|
|
1475
|
+
this._dataSource = new typeorm.DataSource(Object.assign(this.native, {
|
|
1476
|
+
entities: models.map((c) => c[decoratorValidation.ModelKeys.ANCHOR]),
|
|
1477
|
+
}));
|
|
1478
|
+
}
|
|
1479
|
+
return this._dataSource;
|
|
1480
|
+
}
|
|
1481
|
+
// protected dataSou
|
|
1482
|
+
constructor(options, alias) {
|
|
1483
|
+
super(options, TypeORMFlavour, alias);
|
|
1484
|
+
}
|
|
1485
|
+
async flags(operation, model, flags) {
|
|
1486
|
+
const f = await super.flags(operation, model, flags);
|
|
1487
|
+
const newObj = {
|
|
1488
|
+
user: (await TypeORMAdapter.getCurrentUser(this.dataSource)),
|
|
1489
|
+
};
|
|
1490
|
+
const m = new model();
|
|
1491
|
+
const exceptions = [];
|
|
1492
|
+
if (operation === dbDecorators.OperationKeys.CREATE) {
|
|
1493
|
+
const pk = dbDecorators.findPrimaryKey(m).id;
|
|
1494
|
+
exceptions.push(pk);
|
|
1495
|
+
}
|
|
1496
|
+
if (operation === dbDecorators.OperationKeys.CREATE ||
|
|
1497
|
+
operation === dbDecorators.OperationKeys.UPDATE) {
|
|
1498
|
+
const decs = Object.keys(m).reduce((accum, key) => {
|
|
1499
|
+
const decs = reflection.Reflection.getPropertyDecorators(decoratorValidation.ValidationKeys.REFLECT, m, key, true);
|
|
1500
|
+
const dec = decs.decorators.find((dec) => dec.key === dbDecorators.DBKeys.TIMESTAMP &&
|
|
1501
|
+
dec.props.operation.indexOf(operation) !== -1);
|
|
1502
|
+
if (dec) {
|
|
1503
|
+
accum[key] = dec.props;
|
|
1504
|
+
}
|
|
1505
|
+
return accum;
|
|
1506
|
+
}, {});
|
|
1507
|
+
exceptions.push(...Object.keys(decs));
|
|
1508
|
+
}
|
|
1509
|
+
newObj.ignoredValidationProperties = (f.ignoredValidationProperties ? f.ignoredValidationProperties : []).concat(...exceptions);
|
|
1510
|
+
return Object.assign(f, newObj);
|
|
1511
|
+
}
|
|
1512
|
+
Dispatch() {
|
|
1513
|
+
return new TypeORMDispatch();
|
|
1514
|
+
}
|
|
1515
|
+
repository() {
|
|
1516
|
+
return exports.TypeORMRepository;
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* @description Creates a new Postgres statement for querying
|
|
1520
|
+
* @summary Factory method that creates a new PostgresStatement instance for building queries
|
|
1521
|
+
* @template M - The model type
|
|
1522
|
+
* @return {TypeORMStatement<M, any>} A new PostgresStatement instance
|
|
1523
|
+
*/
|
|
1524
|
+
Statement() {
|
|
1525
|
+
return new TypeORMStatement(this);
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* @description Creates a new PostgreSQL sequence
|
|
1529
|
+
* @summary Factory method that creates a new PostgreSQLSequence instance for managing sequences
|
|
1530
|
+
* @param {SequenceOptions} options - The options for the sequence
|
|
1531
|
+
* @return {Promise<Sequence>} A promise that resolves to a new Sequence instance
|
|
1532
|
+
*/
|
|
1533
|
+
async Sequence(options) {
|
|
1534
|
+
return new TypeORMSequence(options, this);
|
|
1535
|
+
}
|
|
1536
|
+
/**
|
|
1537
|
+
* @description Initializes the adapter by creating indexes for all managed models
|
|
1538
|
+
* @summary Sets up the necessary database indexes for all models managed by this adapter
|
|
1539
|
+
* @return {Promise<void>} A promise that resolves when initialization is complete
|
|
1540
|
+
*/
|
|
1541
|
+
async initialize() {
|
|
1542
|
+
const ds = this.dataSource;
|
|
1543
|
+
try {
|
|
1544
|
+
await ds.initialize();
|
|
1545
|
+
}
|
|
1546
|
+
catch (e) {
|
|
1547
|
+
throw this.parseError(e);
|
|
1548
|
+
}
|
|
1549
|
+
const log = this.log.for(this.initialize);
|
|
1550
|
+
log.verbose(`${this.flavour} adapter initialized`);
|
|
1551
|
+
}
|
|
1552
|
+
/**
|
|
1553
|
+
* @description Creates indexes for the given models
|
|
1554
|
+
* @summary Abstract method that must be implemented to create database indexes for the specified models
|
|
1555
|
+
* @template M - The model type
|
|
1556
|
+
* @param {...Constructor<M>} models - The model constructors to create indexes for
|
|
1557
|
+
* @return {Promise<void>} A promise that resolves when all indexes are created
|
|
1558
|
+
*/
|
|
1559
|
+
async index(...models) {
|
|
1560
|
+
const indexes = generateIndexes(models);
|
|
1561
|
+
try {
|
|
1562
|
+
await this.dataSource.query("BEGIN");
|
|
1563
|
+
for (const index of indexes) {
|
|
1564
|
+
await this.dataSource.query(index.query, index.values);
|
|
1565
|
+
}
|
|
1566
|
+
await this.dataSource.query("COMMIT");
|
|
1567
|
+
}
|
|
1568
|
+
catch (e) {
|
|
1569
|
+
await this.dataSource.query("ROLLBACK");
|
|
1570
|
+
throw this.parseError(e);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* @description Executes a raw SQL query against the database
|
|
1575
|
+
* @summary Abstract method that must be implemented to execute raw SQL queries
|
|
1576
|
+
* @template R - The result type
|
|
1577
|
+
* @param {TypeORMQuery} q - The query to execute
|
|
1578
|
+
* @return {Promise<R>} A promise that resolves to the query result
|
|
1579
|
+
*/
|
|
1580
|
+
async raw(q) {
|
|
1581
|
+
const log = this.log.for(this.raw);
|
|
1582
|
+
try {
|
|
1583
|
+
if (!this.dataSource.isInitialized)
|
|
1584
|
+
await this.dataSource.initialize();
|
|
1585
|
+
}
|
|
1586
|
+
catch (e) {
|
|
1587
|
+
throw this.parseError(e);
|
|
1588
|
+
}
|
|
1589
|
+
try {
|
|
1590
|
+
const { query, values } = q;
|
|
1591
|
+
log.debug(`executing query: ${query.getSql()}`);
|
|
1592
|
+
const response = await this.dataSource.query(query, values);
|
|
1593
|
+
return response;
|
|
1594
|
+
}
|
|
1595
|
+
catch (e) {
|
|
1596
|
+
throw this.parseError(e);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
prepare(model, pk, child = false) {
|
|
1600
|
+
const prepared = super.prepare(model, pk);
|
|
1601
|
+
prepared.record = Object.entries(prepared.record).reduce((accum, [key, value]) => {
|
|
1602
|
+
if (key === core.PersistenceKeys.METADATA || this.isReserved(key))
|
|
1603
|
+
return accum;
|
|
1604
|
+
if (value === undefined) {
|
|
1605
|
+
return accum;
|
|
1606
|
+
}
|
|
1607
|
+
if (value instanceof Date) {
|
|
1608
|
+
value = new Date(value.getTime());
|
|
1609
|
+
}
|
|
1610
|
+
else if (decoratorValidation.Model.isModel(value)) {
|
|
1611
|
+
value = this.prepare(value, dbDecorators.findPrimaryKey(value).id, true).record;
|
|
1612
|
+
}
|
|
1613
|
+
else {
|
|
1614
|
+
switch (typeof value) {
|
|
1615
|
+
case "string":
|
|
1616
|
+
value = `${value}`;
|
|
1617
|
+
break;
|
|
1618
|
+
//do nothing;
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
accum[key] = value;
|
|
1622
|
+
return accum;
|
|
1623
|
+
}, {});
|
|
1624
|
+
const constr = decoratorValidation.Model.get(model.constructor.name);
|
|
1625
|
+
if (!constr)
|
|
1626
|
+
throw new dbDecorators.InternalError(`Model ${model.constructor.name} not found in registry`);
|
|
1627
|
+
const result = child
|
|
1628
|
+
? new constr[decoratorValidation.ModelKeys.ANCHOR]()
|
|
1629
|
+
: new constr();
|
|
1630
|
+
if (child)
|
|
1631
|
+
Object.defineProperty(result, "constructor", {
|
|
1632
|
+
configurable: false,
|
|
1633
|
+
enumerable: false,
|
|
1634
|
+
value: constr[decoratorValidation.ModelKeys.ANCHOR],
|
|
1635
|
+
writable: false,
|
|
1636
|
+
});
|
|
1637
|
+
Object.entries(prepared.record).forEach(([key, val]) => (result[key] = val));
|
|
1638
|
+
prepared.record = result;
|
|
1639
|
+
return prepared;
|
|
1640
|
+
}
|
|
1641
|
+
revert(obj, clazz, pk, id, transient) {
|
|
1642
|
+
const log = this.log.for(this.revert);
|
|
1643
|
+
if (transient) {
|
|
1644
|
+
log.verbose(`re-adding transient properties: ${Object.keys(transient).join(", ")}`);
|
|
1645
|
+
Object.entries(transient).forEach(([key, val]) => {
|
|
1646
|
+
if (key in obj)
|
|
1647
|
+
throw new dbDecorators.InternalError(`Transient property ${key} already exists on model ${typeof clazz === "string" ? clazz : clazz.name}. should be impossible`);
|
|
1648
|
+
obj[key] = val;
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
return new clazz(obj);
|
|
1652
|
+
}
|
|
1653
|
+
/**
|
|
1654
|
+
* @description Creates a new record in the database
|
|
1655
|
+
* @summary Abstract method that must be implemented to create a new record
|
|
1656
|
+
* @param {string} tableName - The name of the table
|
|
1657
|
+
* @param {string|number} id - The ID of the record
|
|
1658
|
+
* @param {Record<string, any>} model - The model to create
|
|
1659
|
+
* @param {...any[]} args - Additional arguments
|
|
1660
|
+
* @return {Promise<Record<string, any>>} A promise that resolves to the created record
|
|
1661
|
+
*/
|
|
1662
|
+
async create(tableName, id, model,
|
|
1663
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1664
|
+
...args) {
|
|
1665
|
+
const m = tableName;
|
|
1666
|
+
try {
|
|
1667
|
+
const repo = this.dataSource.getRepository(m);
|
|
1668
|
+
return await repo.save(model);
|
|
1669
|
+
}
|
|
1670
|
+
catch (e) {
|
|
1671
|
+
throw this.parseError(e);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* @description Reads a record from the database
|
|
1676
|
+
* @summary Abstract method that must be implemented to read a record
|
|
1677
|
+
* @param {string} tableName - The name of the table
|
|
1678
|
+
* @param {string|number} id - The ID of the record
|
|
1679
|
+
* @param {string} pk - primary key colum
|
|
1680
|
+
* @return {Promise<Record<string, any>>} A promise that resolves to the read record
|
|
1681
|
+
*/
|
|
1682
|
+
async read(tableName, id, pk) {
|
|
1683
|
+
const m = tableName;
|
|
1684
|
+
let result;
|
|
1685
|
+
try {
|
|
1686
|
+
const repo = this.dataSource.getRepository(m);
|
|
1687
|
+
const q = {
|
|
1688
|
+
where: {
|
|
1689
|
+
[pk]: id,
|
|
1690
|
+
},
|
|
1691
|
+
};
|
|
1692
|
+
result = (await repo.findOne(q));
|
|
1693
|
+
}
|
|
1694
|
+
catch (e) {
|
|
1695
|
+
throw this.parseError(e);
|
|
1696
|
+
}
|
|
1697
|
+
if (!result)
|
|
1698
|
+
throw new dbDecorators.NotFoundError(`Record with id: ${id} not found in table ${typeof tableName === "string" ? tableName : core.Repository.table(tableName)}`);
|
|
1699
|
+
return result;
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* @description Updates a record in the database
|
|
1703
|
+
* @summary Abstract method that must be implemented to update a record
|
|
1704
|
+
* @param {string} tableName - The name of the table
|
|
1705
|
+
* @param {string|number} id - The ID of the record
|
|
1706
|
+
* @param {Record<string, any>} model - The model to update
|
|
1707
|
+
* @param {string} pk - Additional arguments
|
|
1708
|
+
* @return A promise that resolves to the updated record
|
|
1709
|
+
*/
|
|
1710
|
+
async update(tableName, id, model,
|
|
1711
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1712
|
+
...args) {
|
|
1713
|
+
const m = tableName;
|
|
1714
|
+
try {
|
|
1715
|
+
const repo = this.dataSource.getRepository(m);
|
|
1716
|
+
return repo.save(model);
|
|
1717
|
+
}
|
|
1718
|
+
catch (e) {
|
|
1719
|
+
throw this.parseError(e);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
/**
|
|
1723
|
+
* @description Deletes a record from the database
|
|
1724
|
+
* @summary Abstract method that must be implemented to delete a record
|
|
1725
|
+
* @param {string} tableName - The name of the table
|
|
1726
|
+
* @param {string|number} id - The ID of the record
|
|
1727
|
+
* @param {string} pk - Additional arguments
|
|
1728
|
+
* @return A promise that resolves to the deleted record
|
|
1729
|
+
*/
|
|
1730
|
+
async delete(tableName, id, pk,
|
|
1731
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1732
|
+
...args) {
|
|
1733
|
+
const m = tableName;
|
|
1734
|
+
try {
|
|
1735
|
+
const repo = this.dataSource.getRepository(m);
|
|
1736
|
+
const model = await this.read(tableName, id, pk);
|
|
1737
|
+
const res = await repo.delete(id);
|
|
1738
|
+
return model;
|
|
1739
|
+
}
|
|
1740
|
+
catch (e) {
|
|
1741
|
+
throw this.parseError(e);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
async createAll(tableName, id, model,
|
|
1745
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1746
|
+
...args) {
|
|
1747
|
+
const m = tableName;
|
|
1748
|
+
try {
|
|
1749
|
+
const repo = this.dataSource.getRepository(m);
|
|
1750
|
+
const result = await repo.insert(model);
|
|
1751
|
+
return this.readAll(tableName, result.identifiers.map((id) => id.id), "id");
|
|
1752
|
+
}
|
|
1753
|
+
catch (e) {
|
|
1754
|
+
throw this.parseError(e);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
async readAll(tableName, id, pk,
|
|
1758
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1759
|
+
...args) {
|
|
1760
|
+
if (!id.length)
|
|
1761
|
+
return [];
|
|
1762
|
+
const m = tableName;
|
|
1763
|
+
try {
|
|
1764
|
+
const repo = this.dataSource.getRepository(m);
|
|
1765
|
+
return repo.findBy({ [pk]: typeorm.In(id) });
|
|
1766
|
+
}
|
|
1767
|
+
catch (e) {
|
|
1768
|
+
throw this.parseError(e);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
async updateAll(tableName, ids, model, pk, ...args) {
|
|
1772
|
+
const result = [];
|
|
1773
|
+
for (const m of model) {
|
|
1774
|
+
result.push(await this.update(tableName, m[pk], m, ...args));
|
|
1775
|
+
}
|
|
1776
|
+
return result;
|
|
1777
|
+
}
|
|
1778
|
+
async deleteAll(tableName, ids, pk,
|
|
1779
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1780
|
+
...args) {
|
|
1781
|
+
if (!ids.length)
|
|
1782
|
+
return [];
|
|
1783
|
+
const m = tableName;
|
|
1784
|
+
try {
|
|
1785
|
+
const repo = this.dataSource.getRepository(m);
|
|
1786
|
+
const models = await this.readAll(tableName, ids, pk);
|
|
1787
|
+
await repo.delete(ids);
|
|
1788
|
+
return models;
|
|
1789
|
+
}
|
|
1790
|
+
catch (e) {
|
|
1791
|
+
throw this.parseError(e);
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* @description Parses an error and converts it to a BaseError
|
|
1796
|
+
* @summary Converts various error types to appropriate BaseError subtypes
|
|
1797
|
+
* @param {Error|string} err - The error to parse
|
|
1798
|
+
* @param {string} [reason] - Optional reason for the error
|
|
1799
|
+
* @return {BaseError} The parsed error as a BaseError
|
|
1800
|
+
*/
|
|
1801
|
+
parseError(err, reason) {
|
|
1802
|
+
return TypeORMAdapter.parseError(err, reason);
|
|
1803
|
+
}
|
|
1804
|
+
/**
|
|
1805
|
+
* @description Checks if an attribute is reserved
|
|
1806
|
+
* @summary Determines if an attribute name is reserved in PostgreSQL
|
|
1807
|
+
* @param {string} attr - The attribute name to check
|
|
1808
|
+
* @return {boolean} True if the attribute is reserved, false otherwise
|
|
1809
|
+
*/
|
|
1810
|
+
isReserved(attr) {
|
|
1811
|
+
return !!attr.match(reservedAttributes);
|
|
1812
|
+
}
|
|
1813
|
+
/**
|
|
1814
|
+
* @description Static method to parse an error and convert it to a BaseError
|
|
1815
|
+
* @summary Converts various error types to appropriate BaseError subtypes based on PostgreSQL error codes and messages
|
|
1816
|
+
* @param {Error|string} err - The error to parse
|
|
1817
|
+
* @param {string} [reason] - Optional reason for the error
|
|
1818
|
+
* @return {BaseError} The parsed error as a BaseError
|
|
1819
|
+
* @mermaid
|
|
1820
|
+
* sequenceDiagram
|
|
1821
|
+
* participant Caller
|
|
1822
|
+
* participant parseError
|
|
1823
|
+
* participant ErrorTypes
|
|
1824
|
+
*
|
|
1825
|
+
* Caller->>parseError: err, reason
|
|
1826
|
+
* Note over parseError: Check if err is already a BaseError
|
|
1827
|
+
* alt err is BaseError
|
|
1828
|
+
* parseError-->>Caller: return err
|
|
1829
|
+
* else err is string
|
|
1830
|
+
* Note over parseError: Extract code from string
|
|
1831
|
+
* alt code matches "duplicate key|already exists"
|
|
1832
|
+
* parseError->>ErrorTypes: new ConflictError(code)
|
|
1833
|
+
* ErrorTypes-->>Caller: ConflictError
|
|
1834
|
+
* else code matches "does not exist|not found"
|
|
1835
|
+
* parseError->>ErrorTypes: new NotFoundError(code)
|
|
1836
|
+
* ErrorTypes-->>Caller: NotFoundError
|
|
1837
|
+
* end
|
|
1838
|
+
* else err has code property
|
|
1839
|
+
* Note over parseError: Extract code and reason
|
|
1840
|
+
* else
|
|
1841
|
+
* Note over parseError: Use err.message as code
|
|
1842
|
+
* end
|
|
1843
|
+
*
|
|
1844
|
+
* Note over parseError: Switch on PostgreSQL error code
|
|
1845
|
+
* alt code is 23505 (unique_violation)
|
|
1846
|
+
* parseError->>ErrorTypes: new ConflictError(reason)
|
|
1847
|
+
* ErrorTypes-->>Caller: ConflictError
|
|
1848
|
+
* else code is 23503 (foreign_key_violation)
|
|
1849
|
+
* parseError->>ErrorTypes: new ConflictError(reason)
|
|
1850
|
+
* ErrorTypes-->>Caller: ConflictError
|
|
1851
|
+
* else code is 42P01 (undefined_table)
|
|
1852
|
+
* parseError->>ErrorTypes: new NotFoundError(reason)
|
|
1853
|
+
* ErrorTypes-->>Caller: NotFoundError
|
|
1854
|
+
* else code is 42703 (undefined_column)
|
|
1855
|
+
* parseError->>ErrorTypes: new NotFoundError(reason)
|
|
1856
|
+
* ErrorTypes-->>Caller: NotFoundError
|
|
1857
|
+
* else code is 42P07 (duplicate_table)
|
|
1858
|
+
* parseError->>ErrorTypes: new ConflictError(reason)
|
|
1859
|
+
* ErrorTypes-->>Caller: ConflictError
|
|
1860
|
+
* else code is 42P16 (invalid_table_definition)
|
|
1861
|
+
* parseError->>ErrorTypes: new IndexError(err)
|
|
1862
|
+
* ErrorTypes-->>Caller: IndexError
|
|
1863
|
+
* else code matches "ECONNREFUSED"
|
|
1864
|
+
* parseError->>ErrorTypes: new ConnectionError(err)
|
|
1865
|
+
* ErrorTypes-->>Caller: ConnectionError
|
|
1866
|
+
* else
|
|
1867
|
+
* parseError->>ErrorTypes: new InternalError(err)
|
|
1868
|
+
* ErrorTypes-->>Caller: InternalError
|
|
1869
|
+
* end
|
|
1870
|
+
*/
|
|
1871
|
+
static parseError(err, reason) {
|
|
1872
|
+
if (err instanceof dbDecorators.BaseError)
|
|
1873
|
+
return err;
|
|
1874
|
+
const code = typeof err === "string" ? err : err.message;
|
|
1875
|
+
if (code.match(/duplicate key|already exists/g))
|
|
1876
|
+
return new dbDecorators.ConflictError(code);
|
|
1877
|
+
if (code.match(/does not exist|not found/g))
|
|
1878
|
+
return new dbDecorators.NotFoundError(code);
|
|
1879
|
+
// PostgreSQL error codes: https://www.postgresql.org/docs/current/errcodes-appendix.html
|
|
1880
|
+
switch (code.toString()) {
|
|
1881
|
+
// Integrity constraint violations
|
|
1882
|
+
case "23505": // unique_violation
|
|
1883
|
+
case "23503": // foreign_key_violation
|
|
1884
|
+
case "42P07": // duplicate_table
|
|
1885
|
+
return new dbDecorators.ConflictError(reason);
|
|
1886
|
+
// Object not found errors
|
|
1887
|
+
case "42P01": // undefined_table
|
|
1888
|
+
case "42703": // undefined_column
|
|
1889
|
+
return new dbDecorators.NotFoundError(reason);
|
|
1890
|
+
// Invalid object definition
|
|
1891
|
+
case "42P16": // invalid_table_definition
|
|
1892
|
+
return new IndexError(err);
|
|
1893
|
+
// Connection errors
|
|
1894
|
+
default:
|
|
1895
|
+
if (code.toString().match(/ECONNREFUSED/g))
|
|
1896
|
+
return new core.ConnectionError(err);
|
|
1897
|
+
return new dbDecorators.InternalError(err);
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
static async connect(config) {
|
|
1901
|
+
const con = new typeorm.DataSource(config);
|
|
1902
|
+
if (!con.isInitialized)
|
|
1903
|
+
await con.initialize();
|
|
1904
|
+
return con;
|
|
1905
|
+
}
|
|
1906
|
+
static async createDatabase(dataSource, dbName) {
|
|
1907
|
+
const log = logging.Logging.for(this.createDatabase);
|
|
1908
|
+
log.verbose(`Creating database ${dbName}`);
|
|
1909
|
+
try {
|
|
1910
|
+
await dataSource.query(`CREATE DATABASE ${dbName}`);
|
|
1911
|
+
log.info(`Created database ${dbName}`);
|
|
1912
|
+
}
|
|
1913
|
+
catch (e) {
|
|
1914
|
+
throw this.parseError(e);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
static async createNotifyFunction(dataSource, user) {
|
|
1918
|
+
const log = logging.Logging.for(this.createNotifyFunction);
|
|
1919
|
+
log.verbose(`Creating notify function`);
|
|
1920
|
+
try {
|
|
1921
|
+
await dataSource.query(`CREATE OR REPLACE FUNCTION notify_table_changes()
|
|
1922
|
+
RETURNS trigger AS $$
|
|
1923
|
+
BEGIN
|
|
1924
|
+
PERFORM pg_notify(
|
|
1925
|
+
'table_changes',
|
|
1926
|
+
json_build_object(
|
|
1927
|
+
'table', TG_TABLE_NAME,
|
|
1928
|
+
'action', TG_OP,
|
|
1929
|
+
'data', row_to_json(NEW),
|
|
1930
|
+
'old_data', row_to_json(OLD)
|
|
1931
|
+
)::text
|
|
1932
|
+
);
|
|
1933
|
+
RETURN NEW;
|
|
1934
|
+
END;
|
|
1935
|
+
$$ LANGUAGE plpgsql SECURITY DEFINER
|
|
1936
|
+
;`);
|
|
1937
|
+
await dataSource.query(`ALTER FUNCTION notify_table_changes() OWNER TO ${user};`);
|
|
1938
|
+
await dataSource.query(`
|
|
1939
|
+
GRANT EXECUTE ON FUNCTION notify_table_changes() TO public;
|
|
1940
|
+
`);
|
|
1941
|
+
log.info(`Created notify function`);
|
|
1942
|
+
}
|
|
1943
|
+
catch (e) {
|
|
1944
|
+
throw this.parseError(e);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
static async deleteDatabase(dataSource, dbName, user) {
|
|
1948
|
+
try {
|
|
1949
|
+
if (user)
|
|
1950
|
+
await dataSource.query(`DROP OWNED BY ${user} CASCADE;`);
|
|
1951
|
+
await dataSource.query(`DROP DATABASE ${dbName}`);
|
|
1952
|
+
}
|
|
1953
|
+
catch (e) {
|
|
1954
|
+
throw this.parseError(e);
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
static async createUser(dataSource, dbName, user, password) {
|
|
1958
|
+
try {
|
|
1959
|
+
await dataSource.query(`CREATE USER ${user} WITH PASSWORD '${password}'`);
|
|
1960
|
+
await dataSource.query(`GRANT CONNECT ON DATABASE ${dbName} TO ${user}`);
|
|
1961
|
+
await dataSource.query(`GRANT USAGE ON SCHEMA public TO ${user}`);
|
|
1962
|
+
await dataSource.query(`GRANT CREATE ON SCHEMA public TO ${user}`);
|
|
1963
|
+
await dataSource.query(`GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ${user}`);
|
|
1964
|
+
await dataSource.query(`GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ${user}`);
|
|
1965
|
+
await dataSource.query(`GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO ${user}`);
|
|
1966
|
+
await dataSource.query(`ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO ${user}`);
|
|
1967
|
+
await dataSource.query(`ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO ${user}`);
|
|
1968
|
+
}
|
|
1969
|
+
catch (e) {
|
|
1970
|
+
throw this.parseError(e);
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
static async deleteUser(client, user, admin) {
|
|
1974
|
+
try {
|
|
1975
|
+
await client.query(`REASSIGN OWNED BY ${user} TO ${admin}`);
|
|
1976
|
+
await client.query(`REVOKE ALL ON ALL TABLES IN SCHEMA public FROM ${user}`);
|
|
1977
|
+
await client.query(`REVOKE ALL ON SCHEMA public FROM ${user}`);
|
|
1978
|
+
await client.query(`REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM ${user}`);
|
|
1979
|
+
await client.query(`REVOKE ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public FROM ${user}`);
|
|
1980
|
+
await client.query(`ALTER DEFAULT PRIVILEGES FOR ROLE ${admin} IN SCHEMA public REVOKE ALL ON TABLES FROM ${user}`);
|
|
1981
|
+
await client.query(`ALTER DEFAULT PRIVILEGES FOR ROLE ${admin} IN SCHEMA public REVOKE ALL ON SEQUENCES FROM ${user};`);
|
|
1982
|
+
await client.query(`ALTER DEFAULT PRIVILEGES FOR ROLE ${admin} IN SCHEMA public REVOKE ALL ON FUNCTIONS FROM ${user}`);
|
|
1983
|
+
await client.query(`DROP OWNED BY ${user} CASCADE`);
|
|
1984
|
+
await client.query(`DROP USER IF EXISTS "${user}"`);
|
|
1985
|
+
}
|
|
1986
|
+
catch (e) {
|
|
1987
|
+
throw this.parseError(e);
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
static parseTypeToPostgres(type, isPk, isFk = false) {
|
|
1991
|
+
switch (type.toLowerCase()) {
|
|
1992
|
+
case "string":
|
|
1993
|
+
return isPk ? "TEXT PRIMARY KEY" : isFk ? "TEXT" : "VARCHAR";
|
|
1994
|
+
case "number":
|
|
1995
|
+
return isPk ? "SERIAL PRIMARY KEY" : "INTEGER";
|
|
1996
|
+
case "boolean":
|
|
1997
|
+
return "BOOLEAN";
|
|
1998
|
+
case "date":
|
|
1999
|
+
return "TIMESTAMP";
|
|
2000
|
+
case "bigint":
|
|
2001
|
+
return isPk ? "BIGINT PRIMARY KEY" : "BIGINT";
|
|
2002
|
+
default: {
|
|
2003
|
+
const m = decoratorValidation.Model.get(type);
|
|
2004
|
+
if (m) {
|
|
2005
|
+
const mm = new m();
|
|
2006
|
+
const type = reflection.Reflection.getTypeFromDecorator(mm, dbDecorators.findPrimaryKey(mm).id);
|
|
2007
|
+
return {
|
|
2008
|
+
model: m,
|
|
2009
|
+
pkType: type,
|
|
2010
|
+
};
|
|
2011
|
+
}
|
|
2012
|
+
throw new dbDecorators.InternalError(`Unsupported type: ${type}`);
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
static parseValidationToPostgres(prop, type, isPk, key, options) {
|
|
2017
|
+
switch (key) {
|
|
2018
|
+
case decoratorValidation.ValidationKeys.REQUIRED:
|
|
2019
|
+
return "NOT NULL";
|
|
2020
|
+
case decoratorValidation.ValidationKeys.MAX_LENGTH:
|
|
2021
|
+
if (isPk || !options || type.toLowerCase() !== "string") {
|
|
2022
|
+
return "";
|
|
2023
|
+
}
|
|
2024
|
+
return `(${options[decoratorValidation.ValidationKeys.MAX_LENGTH]})`;
|
|
2025
|
+
case decoratorValidation.ValidationKeys.MIN_LENGTH:
|
|
2026
|
+
return `CONSTRAINT ${prop}_min_length_check CHECK (LENGTH(${prop}) >= ${options[decoratorValidation.ValidationKeys.MIN_LENGTH]})`;
|
|
2027
|
+
case decoratorValidation.ValidationKeys.PATTERN:
|
|
2028
|
+
case decoratorValidation.ValidationKeys.URL:
|
|
2029
|
+
case decoratorValidation.ValidationKeys.EMAIL:
|
|
2030
|
+
return `CONSTRAINT ${prop}_pattern_check CHECK (${prop} ~ '${convertJsRegexToPostgres(options[decoratorValidation.ValidationKeys.PATTERN])}')`;
|
|
2031
|
+
case decoratorValidation.ValidationKeys.TYPE:
|
|
2032
|
+
case decoratorValidation.ValidationKeys.DATE:
|
|
2033
|
+
return "";
|
|
2034
|
+
case decoratorValidation.ValidationKeys.MIN:
|
|
2035
|
+
return `CONSTRAINT ${prop}_${key}_check CHECK (${prop} >= ${options[decoratorValidation.ValidationKeys.MIN]})`;
|
|
2036
|
+
case decoratorValidation.ValidationKeys.MAX:
|
|
2037
|
+
return `CONSTRAINT ${prop}_${key}_check CHECK (${prop} <= ${options[decoratorValidation.ValidationKeys.MAX]})`;
|
|
2038
|
+
case decoratorValidation.ValidationKeys.PASSWORD:
|
|
2039
|
+
default:
|
|
2040
|
+
throw new dbDecorators.InternalError(`Unsupported type: ${key}`);
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
static parseRelationsToPostgres(prop, clazz, pk, key, options) {
|
|
2044
|
+
const tableName = core.Repository.table(clazz);
|
|
2045
|
+
const { cascade } = options;
|
|
2046
|
+
const cascadeStr = `${cascade.update ? " ON UPDATE CASCADE" : ""}${cascade.delete ? " ON DELETE CASCADE" : ""}`;
|
|
2047
|
+
switch (`relations${key}`) {
|
|
2048
|
+
case core.PersistenceKeys.ONE_TO_ONE:
|
|
2049
|
+
return `FOREIGN KEY (${prop}) REFERENCES ${tableName}(${pk})${cascadeStr}`;
|
|
2050
|
+
default:
|
|
2051
|
+
throw new dbDecorators.InternalError(`Unsupported operation: ${key}`);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
static async createTable(client, model) {
|
|
2055
|
+
const result = {};
|
|
2056
|
+
const m = new model({});
|
|
2057
|
+
const tableName = core.Repository.table(model);
|
|
2058
|
+
const { id } = dbDecorators.findPrimaryKey(m);
|
|
2059
|
+
let isPk, column;
|
|
2060
|
+
const properties = Object.getOwnPropertyNames(m);
|
|
2061
|
+
for (const prop of properties) {
|
|
2062
|
+
if (typeof this[prop] === "function" ||
|
|
2063
|
+
prop.toString().startsWith("_") ||
|
|
2064
|
+
prop === "constructor") {
|
|
2065
|
+
continue;
|
|
2066
|
+
}
|
|
2067
|
+
isPk = prop === id;
|
|
2068
|
+
column = core.Repository.column(m, prop.toString());
|
|
2069
|
+
const allDecs = reflection.Reflection.getPropertyDecorators(decoratorValidation.ValidationKeys.REFLECT, m, prop.toString(), false, true);
|
|
2070
|
+
const decoratorData = allDecs.decorators.reduce((accum, el) => {
|
|
2071
|
+
const { key, props } = el;
|
|
2072
|
+
if (key === decoratorValidation.ModelKeys.TYPE && !accum[decoratorValidation.ValidationKeys.TYPE]) {
|
|
2073
|
+
accum[decoratorValidation.ValidationKeys.TYPE] = {
|
|
2074
|
+
customTypes: [props.name],
|
|
2075
|
+
message: decoratorValidation.DEFAULT_ERROR_MESSAGES.TYPE,
|
|
2076
|
+
description: "defines the accepted types for the attribute",
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
2079
|
+
else if (key !== decoratorValidation.ValidationKeys.TYPE) {
|
|
2080
|
+
// do nothing. we can only support basis ctypes at this time
|
|
2081
|
+
accum[key] = props;
|
|
2082
|
+
}
|
|
2083
|
+
return accum;
|
|
2084
|
+
}, {});
|
|
2085
|
+
const dbDecs = reflection.Reflection.getPropertyDecorators(core.Repository.key("relations"), m, prop.toString(), true, true);
|
|
2086
|
+
const query = [];
|
|
2087
|
+
const constraints = [];
|
|
2088
|
+
const foreignKeys = [];
|
|
2089
|
+
let typeData = undefined;
|
|
2090
|
+
let childClass = undefined;
|
|
2091
|
+
let childPk;
|
|
2092
|
+
if (Object.keys(decoratorData).length) {
|
|
2093
|
+
typeData = decoratorData[decoratorValidation.ValidationKeys.TYPE];
|
|
2094
|
+
if (!typeData) {
|
|
2095
|
+
throw new Error(`Missing type information`);
|
|
2096
|
+
}
|
|
2097
|
+
let parsedType = this.parseTypeToPostgres(typeof typeData.customTypes[0] === "function"
|
|
2098
|
+
? typeData.customTypes[0]()
|
|
2099
|
+
: typeData.customTypes[0], isPk);
|
|
2100
|
+
if (typeof parsedType === "string") {
|
|
2101
|
+
parsedType = { model: parsedType };
|
|
2102
|
+
}
|
|
2103
|
+
let typeStr = parsedType.model;
|
|
2104
|
+
if (typeof typeStr !== "string") {
|
|
2105
|
+
if (Array.isArray(typeStr)) {
|
|
2106
|
+
console.log(typeStr);
|
|
2107
|
+
}
|
|
2108
|
+
// continue;
|
|
2109
|
+
// const res: Record<string, PostgresTableSpec> = await this.createTable(pool, typeStr);
|
|
2110
|
+
try {
|
|
2111
|
+
childClass = parsedType.model;
|
|
2112
|
+
const m = new childClass();
|
|
2113
|
+
childPk = dbDecorators.findPrimaryKey(m);
|
|
2114
|
+
typeStr = this.parseTypeToPostgres(parsedType.pkType, false, true);
|
|
2115
|
+
await this.createTable(client, childClass);
|
|
2116
|
+
}
|
|
2117
|
+
catch (e) {
|
|
2118
|
+
if (!(e instanceof dbDecorators.ConflictError))
|
|
2119
|
+
throw e;
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
let tp = Array.isArray(typeData.customTypes)
|
|
2123
|
+
? typeData.customTypes[0]
|
|
2124
|
+
: typeData.customTypes;
|
|
2125
|
+
tp = typeof tp === "function" && !tp.name ? tp() : tp;
|
|
2126
|
+
const validationStr = this.parseValidationToPostgres(column, tp, isPk, decoratorValidation.ValidationKeys.MAX_LENGTH, decoratorData[decoratorValidation.ValidationKeys.MAX_LENGTH] || {
|
|
2127
|
+
[decoratorValidation.ValidationKeys.MAX_LENGTH]: 255,
|
|
2128
|
+
});
|
|
2129
|
+
const q = `${column} ${typeStr}${validationStr}`;
|
|
2130
|
+
if (isPk) {
|
|
2131
|
+
query.unshift(q);
|
|
2132
|
+
}
|
|
2133
|
+
else {
|
|
2134
|
+
query.push(q);
|
|
2135
|
+
}
|
|
2136
|
+
for (const [key, props] of Object.entries(decoratorData).filter(([k]) => ![decoratorValidation.ValidationKeys.TYPE, decoratorValidation.ValidationKeys.MAX_LENGTH].includes(k))) {
|
|
2137
|
+
const validation = this.parseValidationToPostgres(column, tp, isPk, key, props);
|
|
2138
|
+
if (validation.startsWith("CONSTRAINT")) {
|
|
2139
|
+
constraints.push(validation);
|
|
2140
|
+
}
|
|
2141
|
+
else {
|
|
2142
|
+
if (validation) {
|
|
2143
|
+
query.push(validation);
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
// TODO ignore for now. this leaves foreign keys out
|
|
2149
|
+
// eslint-disable-next-line no-constant-binary-expression
|
|
2150
|
+
if ((dbDecs && dbDecs.decorators.length)) {
|
|
2151
|
+
if (!typeData)
|
|
2152
|
+
throw new Error(`Missing type information`);
|
|
2153
|
+
for (const decorator of dbDecs.decorators) {
|
|
2154
|
+
const { key, props } = decorator;
|
|
2155
|
+
const validation = this.parseRelationsToPostgres(column, childClass, childPk.id, key, props);
|
|
2156
|
+
if (validation.startsWith("FOREIGN")) {
|
|
2157
|
+
foreignKeys.push(validation);
|
|
2158
|
+
}
|
|
2159
|
+
else {
|
|
2160
|
+
throw new dbDecorators.InternalError(`Unsupported relation: ${key}`);
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
result[prop.toString()] = {
|
|
2165
|
+
query: query.join(" "),
|
|
2166
|
+
values: [],
|
|
2167
|
+
primaryKey: isPk,
|
|
2168
|
+
constraints: constraints,
|
|
2169
|
+
foreignKeys: foreignKeys,
|
|
2170
|
+
};
|
|
2171
|
+
}
|
|
2172
|
+
const values = Object.values(result);
|
|
2173
|
+
const query = values.map((r) => r.query).join(",\n");
|
|
2174
|
+
const constraints = values
|
|
2175
|
+
.filter((c) => !!c.constraints.length)
|
|
2176
|
+
.map((r) => r.constraints)
|
|
2177
|
+
.join(",\n");
|
|
2178
|
+
const foreignKeys = values
|
|
2179
|
+
.filter((c) => !!c.foreignKeys.length)
|
|
2180
|
+
.map((r) => r.foreignKeys)
|
|
2181
|
+
.join(",\n");
|
|
2182
|
+
const vals = [query, constraints];
|
|
2183
|
+
if (foreignKeys) {
|
|
2184
|
+
vals.push(foreignKeys);
|
|
2185
|
+
}
|
|
2186
|
+
const queryString = `CREATE TABLE ${tableName} (${vals.filter((v) => !!v).join(",\n")})`;
|
|
2187
|
+
try {
|
|
2188
|
+
await client.query(queryString);
|
|
2189
|
+
await client.query(`CREATE TRIGGER notify_changes_${tableName}
|
|
2190
|
+
AFTER INSERT OR UPDATE OR DELETE ON ${tableName}
|
|
2191
|
+
FOR EACH ROW
|
|
2192
|
+
EXECUTE FUNCTION notify_table_changes();`);
|
|
2193
|
+
}
|
|
2194
|
+
catch (e) {
|
|
2195
|
+
throw this.parseError(e);
|
|
2196
|
+
}
|
|
2197
|
+
return result;
|
|
2198
|
+
}
|
|
2199
|
+
static async getCurrentUser(client) {
|
|
2200
|
+
const queryString = `SELECT CURRENT_USER;`;
|
|
2201
|
+
try {
|
|
2202
|
+
const result = await client.query(queryString);
|
|
2203
|
+
return result[0].current_user;
|
|
2204
|
+
}
|
|
2205
|
+
catch (e) {
|
|
2206
|
+
throw this.parseError(e);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
static decoration() {
|
|
2210
|
+
// @table() => @Entity()
|
|
2211
|
+
const tableKey = core.Adapter.key(core.PersistenceKeys.TABLE);
|
|
2212
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2213
|
+
.for(tableKey)
|
|
2214
|
+
.extend((original) => Entity()(original[decoratorValidation.ModelKeys.ANCHOR] || original))
|
|
2215
|
+
.apply();
|
|
2216
|
+
// @pk() => @PrimaryGeneratedColumn() | @PrimaryColumn()
|
|
2217
|
+
const pkKey = core.Repository.key(dbDecorators.DBKeys.ID);
|
|
2218
|
+
function pkDec(options) {
|
|
2219
|
+
const decorators = [
|
|
2220
|
+
decoratorValidation.required(),
|
|
2221
|
+
dbDecorators.readonly(),
|
|
2222
|
+
decoratorValidation.propMetadata(pkKey, options),
|
|
2223
|
+
];
|
|
2224
|
+
if (options.type)
|
|
2225
|
+
decorators.push(PrimaryGeneratedColumn());
|
|
2226
|
+
else
|
|
2227
|
+
decorators.push(PrimaryColumn({ unique: true }));
|
|
2228
|
+
return reflection.apply(...decorators);
|
|
2229
|
+
}
|
|
2230
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2231
|
+
.for(pkKey)
|
|
2232
|
+
.define({
|
|
2233
|
+
decorator: pkDec,
|
|
2234
|
+
})
|
|
2235
|
+
.apply();
|
|
2236
|
+
// @column("columnName") => @Column({name: "columnName"})
|
|
2237
|
+
const columnKey = core.Adapter.key(core.PersistenceKeys.COLUMN);
|
|
2238
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2239
|
+
.for(columnKey)
|
|
2240
|
+
.extend({
|
|
2241
|
+
decorator: function columm(name) {
|
|
2242
|
+
return function column(obj, prop) {
|
|
2243
|
+
return Column({
|
|
2244
|
+
name: name || prop,
|
|
2245
|
+
nullable: true,
|
|
2246
|
+
})(obj, prop);
|
|
2247
|
+
};
|
|
2248
|
+
},
|
|
2249
|
+
transform: (args) => {
|
|
2250
|
+
const columnName = args[1];
|
|
2251
|
+
return [columnName];
|
|
2252
|
+
},
|
|
2253
|
+
})
|
|
2254
|
+
.apply();
|
|
2255
|
+
// @unique => @Column({unique: true})
|
|
2256
|
+
const uniqueKey = core.Adapter.key(core.PersistenceKeys.UNIQUE);
|
|
2257
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2258
|
+
.for(uniqueKey)
|
|
2259
|
+
.define(decoratorValidation.propMetadata(uniqueKey, {}))
|
|
2260
|
+
.extend(Column({ unique: true }))
|
|
2261
|
+
.apply();
|
|
2262
|
+
// @required => @Column({ nullable: false })
|
|
2263
|
+
const requiredKey = decoratorValidation.Validation.key(decoratorValidation.ValidationKeys.REQUIRED);
|
|
2264
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2265
|
+
.for(requiredKey)
|
|
2266
|
+
.extend(Column({ nullable: false }))
|
|
2267
|
+
.apply();
|
|
2268
|
+
// @version => @VersionColumn()
|
|
2269
|
+
const versionKey = core.Repository.key(dbDecorators.DBKeys.VERSION);
|
|
2270
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2271
|
+
.for(versionKey)
|
|
2272
|
+
.define(decoratorValidation.type(Number.name), typeorm.VersionColumn())
|
|
2273
|
+
.apply();
|
|
2274
|
+
function ValidationUpdateKey(key) {
|
|
2275
|
+
return dbDecorators.UpdateValidationKeys.REFLECT + key;
|
|
2276
|
+
}
|
|
2277
|
+
// @timestamp(op) => @CreateDateColumn() || @UpdateDateColumn()
|
|
2278
|
+
const timestampKey = ValidationUpdateKey(dbDecorators.DBKeys.TIMESTAMP);
|
|
2279
|
+
function ts(operation, format) {
|
|
2280
|
+
const decorators = [
|
|
2281
|
+
decoratorValidation.date(format, dbDecorators.DEFAULT_ERROR_MESSAGES.TIMESTAMP.DATE),
|
|
2282
|
+
decoratorValidation.required(dbDecorators.DEFAULT_ERROR_MESSAGES.TIMESTAMP.REQUIRED),
|
|
2283
|
+
decoratorValidation.propMetadata(decoratorValidation.Validation.key(dbDecorators.DBKeys.TIMESTAMP), {
|
|
2284
|
+
operation: operation,
|
|
2285
|
+
format: format,
|
|
2286
|
+
}),
|
|
2287
|
+
];
|
|
2288
|
+
if (operation.indexOf(dbDecorators.OperationKeys.UPDATE) !== -1)
|
|
2289
|
+
decorators.push(decoratorValidation.propMetadata(timestampKey, {
|
|
2290
|
+
message: dbDecorators.DEFAULT_ERROR_MESSAGES.TIMESTAMP.INVALID,
|
|
2291
|
+
}));
|
|
2292
|
+
else
|
|
2293
|
+
decorators.push(dbDecorators.readonly());
|
|
2294
|
+
return reflection.apply(...decorators);
|
|
2295
|
+
}
|
|
2296
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2297
|
+
.for(timestampKey)
|
|
2298
|
+
.define({
|
|
2299
|
+
decorator: ts,
|
|
2300
|
+
})
|
|
2301
|
+
.extend({
|
|
2302
|
+
decorator: function timestamp(...ops) {
|
|
2303
|
+
return function timestamp(obj, prop) {
|
|
2304
|
+
if (ops.indexOf(dbDecorators.OperationKeys.UPDATE) !== -1)
|
|
2305
|
+
return UpdateDateColumn()(obj, prop);
|
|
2306
|
+
return CreateDateColumn()(obj, prop);
|
|
2307
|
+
};
|
|
2308
|
+
},
|
|
2309
|
+
transform: (args) => {
|
|
2310
|
+
return args[0];
|
|
2311
|
+
},
|
|
2312
|
+
})
|
|
2313
|
+
.apply();
|
|
2314
|
+
// @oneToOne(clazz) => @OneToOne(() => clazz)
|
|
2315
|
+
const oneToOneKey = core.Repository.key(core.PersistenceKeys.ONE_TO_ONE);
|
|
2316
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2317
|
+
.for(oneToOneKey)
|
|
2318
|
+
.define({
|
|
2319
|
+
decorator: function oneToOne(clazz, cascade, populate) {
|
|
2320
|
+
const metadata = {
|
|
2321
|
+
class: (clazz.name ? clazz.name : clazz),
|
|
2322
|
+
cascade: cascade,
|
|
2323
|
+
populate: populate,
|
|
2324
|
+
};
|
|
2325
|
+
const ormMeta = {
|
|
2326
|
+
cascade: cascade.update === core.Cascade.CASCADE ||
|
|
2327
|
+
cascade.delete === core.Cascade.CASCADE,
|
|
2328
|
+
onDelete: cascade.delete ? "CASCADE" : "DEFAULT",
|
|
2329
|
+
onUpdate: cascade.update ? "CASCADE" : "DEFAULT",
|
|
2330
|
+
nullable: true,
|
|
2331
|
+
eager: populate,
|
|
2332
|
+
};
|
|
2333
|
+
return reflection.apply(decoratorValidation.prop(core.PersistenceKeys.RELATIONS), decoratorValidation.type([
|
|
2334
|
+
(typeof clazz === "function" && !clazz.name
|
|
2335
|
+
? clazz
|
|
2336
|
+
: clazz.name),
|
|
2337
|
+
String.name,
|
|
2338
|
+
Number.name,
|
|
2339
|
+
BigInt.name,
|
|
2340
|
+
]), decoratorValidation.propMetadata(oneToOneKey, metadata), typeorm.OneToOne(() => {
|
|
2341
|
+
if (!clazz.name)
|
|
2342
|
+
clazz = clazz();
|
|
2343
|
+
if (!clazz[decoratorValidation.ModelKeys.ANCHOR])
|
|
2344
|
+
throw new dbDecorators.InternalError("Original Model not found in constructor");
|
|
2345
|
+
return clazz[decoratorValidation.ModelKeys.ANCHOR];
|
|
2346
|
+
}, (model) => {
|
|
2347
|
+
const pk = dbDecorators.findPrimaryKey(new clazz()).id;
|
|
2348
|
+
return model[pk];
|
|
2349
|
+
}, ormMeta), typeorm.JoinColumn());
|
|
2350
|
+
},
|
|
2351
|
+
})
|
|
2352
|
+
.apply();
|
|
2353
|
+
// @oneToMany(clazz) => @OneToMany(() => clazz)
|
|
2354
|
+
const oneToManyKey = core.Repository.key(core.PersistenceKeys.ONE_TO_MANY);
|
|
2355
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2356
|
+
.for(oneToManyKey)
|
|
2357
|
+
.define({
|
|
2358
|
+
decorator: function oneToMany(clazz, cascade, populate) {
|
|
2359
|
+
const metadata = {
|
|
2360
|
+
class: (clazz.name ? clazz.name : clazz),
|
|
2361
|
+
cascade: cascade,
|
|
2362
|
+
populate: populate,
|
|
2363
|
+
};
|
|
2364
|
+
return reflection.apply(decoratorValidation.prop(core.PersistenceKeys.RELATIONS), decoratorValidation.list(clazz), decoratorValidation.propMetadata(oneToManyKey, metadata), function OneToManyWrapper(obj, prop) {
|
|
2365
|
+
const ormMeta = {
|
|
2366
|
+
cascade: cascade.update === core.Cascade.CASCADE ||
|
|
2367
|
+
cascade.delete === core.Cascade.CASCADE,
|
|
2368
|
+
onDelete: cascade.delete ? "CASCADE" : "DEFAULT",
|
|
2369
|
+
onUpdate: cascade.update ? "CASCADE" : "DEFAULT",
|
|
2370
|
+
nullable: true,
|
|
2371
|
+
eager: populate,
|
|
2372
|
+
};
|
|
2373
|
+
return typeorm.OneToMany(() => {
|
|
2374
|
+
if (!clazz.name)
|
|
2375
|
+
clazz = clazz();
|
|
2376
|
+
if (!clazz[decoratorValidation.ModelKeys.ANCHOR])
|
|
2377
|
+
throw new dbDecorators.InternalError("Original Model not found in constructor");
|
|
2378
|
+
return clazz[decoratorValidation.ModelKeys.ANCHOR];
|
|
2379
|
+
}, (model) => {
|
|
2380
|
+
if (!clazz.name)
|
|
2381
|
+
clazz = clazz();
|
|
2382
|
+
const m = new clazz();
|
|
2383
|
+
const crossRelationKey = Object.keys(m).find((k) => {
|
|
2384
|
+
const decs = reflection.Reflection.getPropertyDecorators(core.Repository.key(core.PersistenceKeys.MANY_TO_ONE), m, k, true);
|
|
2385
|
+
if (!decs || !decs.decorators || !decs.decorators.length)
|
|
2386
|
+
return false;
|
|
2387
|
+
const designType = Reflect.getMetadata(decoratorValidation.ModelKeys.TYPE, m, k);
|
|
2388
|
+
if (!designType)
|
|
2389
|
+
throw new dbDecorators.InternalError(`No Type Definition found for ${k} in ${m.constructor.name}`);
|
|
2390
|
+
return designType.name === obj.constructor.name;
|
|
2391
|
+
});
|
|
2392
|
+
if (!crossRelationKey)
|
|
2393
|
+
throw new dbDecorators.InternalError(`Cross relation not found. Did you use @manyToOne on the ${clazz.name}?`);
|
|
2394
|
+
return model[crossRelationKey];
|
|
2395
|
+
}, ormMeta)(obj, prop);
|
|
2396
|
+
});
|
|
2397
|
+
},
|
|
2398
|
+
})
|
|
2399
|
+
.apply();
|
|
2400
|
+
// @manyToOne(clazz) => @ManyToOne(() => clazz)
|
|
2401
|
+
const manyToOneKey = core.Repository.key(core.PersistenceKeys.MANY_TO_ONE);
|
|
2402
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2403
|
+
.for(manyToOneKey)
|
|
2404
|
+
.define({
|
|
2405
|
+
decorator: function manyToOne(clazz, cascade, populate) {
|
|
2406
|
+
const metadata = {
|
|
2407
|
+
class: (clazz.name ? clazz.name : clazz),
|
|
2408
|
+
cascade: cascade,
|
|
2409
|
+
populate: populate,
|
|
2410
|
+
};
|
|
2411
|
+
({
|
|
2412
|
+
cascade: cascade.update === core.Cascade.CASCADE ||
|
|
2413
|
+
cascade.delete === core.Cascade.CASCADE,
|
|
2414
|
+
onDelete: cascade.delete ? "CASCADE" : "DEFAULT",
|
|
2415
|
+
onUpdate: cascade.update ? "CASCADE" : "DEFAULT"});
|
|
2416
|
+
return reflection.apply(decoratorValidation.prop(core.PersistenceKeys.RELATIONS), decoratorValidation.type([
|
|
2417
|
+
(typeof clazz === "function" && !clazz.name
|
|
2418
|
+
? clazz
|
|
2419
|
+
: clazz.name),
|
|
2420
|
+
String.name,
|
|
2421
|
+
Number.name,
|
|
2422
|
+
BigInt.name,
|
|
2423
|
+
]), decoratorValidation.propMetadata(manyToOneKey, metadata), function ManyToOneWrapper(obj, prop) {
|
|
2424
|
+
return typeorm.ManyToOne(() => {
|
|
2425
|
+
if (!clazz.name)
|
|
2426
|
+
clazz = clazz();
|
|
2427
|
+
if (!clazz[decoratorValidation.ModelKeys.ANCHOR])
|
|
2428
|
+
throw new dbDecorators.InternalError("Original Model not found in constructor");
|
|
2429
|
+
return clazz[decoratorValidation.ModelKeys.ANCHOR];
|
|
2430
|
+
}, (model) => {
|
|
2431
|
+
if (!clazz.name)
|
|
2432
|
+
clazz = clazz();
|
|
2433
|
+
const m = new clazz();
|
|
2434
|
+
const crossRelationKey = Object.keys(m).find((k) => {
|
|
2435
|
+
const decs = reflection.Reflection.getPropertyDecorators(core.Repository.key(core.PersistenceKeys.ONE_TO_MANY), m, k, true);
|
|
2436
|
+
if (!decs || !decs.decorators || !decs.decorators.length)
|
|
2437
|
+
return false;
|
|
2438
|
+
const listDec = Reflect.getMetadata(decoratorValidation.Validation.key(decoratorValidation.ValidationKeys.LIST), m, k);
|
|
2439
|
+
if (!listDec)
|
|
2440
|
+
throw new dbDecorators.InternalError(`No Type Definition found for ${k} in ${m.constructor.name}`);
|
|
2441
|
+
const name = listDec.clazz[0]().name;
|
|
2442
|
+
return name === obj.constructor.name;
|
|
2443
|
+
});
|
|
2444
|
+
if (!crossRelationKey)
|
|
2445
|
+
throw new dbDecorators.InternalError(`Cross relation not found. Did you use @manyToOne on the ${clazz.name}?`);
|
|
2446
|
+
return model[crossRelationKey];
|
|
2447
|
+
})(obj, prop);
|
|
2448
|
+
});
|
|
2449
|
+
},
|
|
2450
|
+
})
|
|
2451
|
+
.apply();
|
|
2452
|
+
// @manyToMany(clazz) => @ManyToMany(() => clazz)
|
|
2453
|
+
const manyToManyKey = core.Repository.key(core.PersistenceKeys.MANY_TO_MANY);
|
|
2454
|
+
decoratorValidation.Decoration.flavouredAs(TypeORMFlavour)
|
|
2455
|
+
.for(manyToManyKey)
|
|
2456
|
+
.define({
|
|
2457
|
+
decorator: function manyToMany(clazz, cascade, populate) {
|
|
2458
|
+
const metadata = {
|
|
2459
|
+
class: clazz.name,
|
|
2460
|
+
cascade: cascade,
|
|
2461
|
+
populate: populate,
|
|
2462
|
+
};
|
|
2463
|
+
const ormMeta = {
|
|
2464
|
+
cascade: cascade.update === core.Cascade.CASCADE ||
|
|
2465
|
+
cascade.delete === core.Cascade.CASCADE,
|
|
2466
|
+
onDelete: cascade.delete ? "CASCADE" : "DEFAULT",
|
|
2467
|
+
onUpdate: cascade.update ? "CASCADE" : "DEFAULT",
|
|
2468
|
+
nullable: true,
|
|
2469
|
+
eager: populate,
|
|
2470
|
+
};
|
|
2471
|
+
return reflection.apply(decoratorValidation.prop(core.PersistenceKeys.RELATIONS), decoratorValidation.list(clazz), decoratorValidation.propMetadata(manyToManyKey, metadata), typeorm.ManyToMany(() => {
|
|
2472
|
+
if (!clazz.name)
|
|
2473
|
+
clazz = clazz();
|
|
2474
|
+
if (!clazz[decoratorValidation.ModelKeys.ANCHOR])
|
|
2475
|
+
throw new dbDecorators.InternalError("Original Model not found in constructor");
|
|
2476
|
+
return clazz[decoratorValidation.ModelKeys.ANCHOR];
|
|
2477
|
+
}, (model) => {
|
|
2478
|
+
if (!clazz.name)
|
|
2479
|
+
clazz = clazz();
|
|
2480
|
+
const pk = dbDecorators.findPrimaryKey(new clazz()).id;
|
|
2481
|
+
return model[pk];
|
|
2482
|
+
}, ormMeta), typeorm.JoinTable());
|
|
2483
|
+
},
|
|
2484
|
+
})
|
|
2485
|
+
.apply();
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
tslib.__decorate([
|
|
2489
|
+
core.final(),
|
|
2490
|
+
tslib.__metadata("design:type", Function),
|
|
2491
|
+
tslib.__metadata("design:paramtypes", []),
|
|
2492
|
+
tslib.__metadata("design:returntype", TypeORMDispatch)
|
|
2493
|
+
], TypeORMAdapter.prototype, "Dispatch", null);
|
|
2494
|
+
tslib.__decorate([
|
|
2495
|
+
core.final(),
|
|
2496
|
+
tslib.__metadata("design:type", Function),
|
|
2497
|
+
tslib.__metadata("design:paramtypes", []),
|
|
2498
|
+
tslib.__metadata("design:returntype", Object)
|
|
2499
|
+
], TypeORMAdapter.prototype, "repository", null);
|
|
2500
|
+
tslib.__decorate([
|
|
2501
|
+
core.final(),
|
|
2502
|
+
tslib.__metadata("design:type", Function),
|
|
2503
|
+
tslib.__metadata("design:paramtypes", []),
|
|
2504
|
+
tslib.__metadata("design:returntype", TypeORMStatement)
|
|
2505
|
+
], TypeORMAdapter.prototype, "Statement", null);
|
|
2506
|
+
tslib.__decorate([
|
|
2507
|
+
core.final(),
|
|
2508
|
+
tslib.__metadata("design:type", Function),
|
|
2509
|
+
tslib.__metadata("design:paramtypes", [Object]),
|
|
2510
|
+
tslib.__metadata("design:returntype", Promise)
|
|
2511
|
+
], TypeORMAdapter.prototype, "Sequence", null);
|
|
2512
|
+
tslib.__decorate([
|
|
2513
|
+
core.final(),
|
|
2514
|
+
tslib.__metadata("design:type", Function),
|
|
2515
|
+
tslib.__metadata("design:paramtypes", [Object]),
|
|
2516
|
+
tslib.__metadata("design:returntype", Promise)
|
|
2517
|
+
], TypeORMAdapter.prototype, "index", null);
|
|
2518
|
+
|
|
2519
|
+
TypeORMAdapter.decoration();
|
|
2520
|
+
/**
|
|
2521
|
+
* @description TypeORM integration for Decaf.ts.
|
|
2522
|
+
* @summary Provides the TypeORM-backed implementation of the Decaf.ts data access abstractions, including the adapter, repository, statement builder, pagination utilities, index helpers, and type definitions. Key exports include {@link TypeORMAdapter}, {@link TypeORMRepository}, {@link TypeORMStatement}, {@link TypeORMPaginator}, and index generation utilities.
|
|
2523
|
+
* @module for-typeorm
|
|
2524
|
+
*/
|
|
2525
|
+
/**
|
|
2526
|
+
* @description Stores the current package version.
|
|
2527
|
+
* @summary The version string of the for-typeorm package.
|
|
2528
|
+
* @const VERSION
|
|
2529
|
+
* @memberOf module:for-typeorm
|
|
2530
|
+
*/
|
|
2531
|
+
const VERSION = "0.0.6";
|
|
2532
|
+
|
|
2533
|
+
exports.IndexError = IndexError;
|
|
2534
|
+
exports.TypeORMAdapter = TypeORMAdapter;
|
|
2535
|
+
exports.TypeORMConst = TypeORMConst;
|
|
2536
|
+
exports.TypeORMDispatch = TypeORMDispatch;
|
|
2537
|
+
exports.TypeORMFlavour = TypeORMFlavour;
|
|
2538
|
+
exports.TypeORMGroupOperator = TypeORMGroupOperator;
|
|
2539
|
+
exports.TypeORMKeys = TypeORMKeys;
|
|
2540
|
+
exports.TypeORMOperator = TypeORMOperator;
|
|
2541
|
+
exports.TypeORMPaginator = TypeORMPaginator;
|
|
2542
|
+
exports.TypeORMQueryLimit = TypeORMQueryLimit;
|
|
2543
|
+
exports.TypeORMSequence = TypeORMSequence;
|
|
2544
|
+
exports.TypeORMStatement = TypeORMStatement;
|
|
2545
|
+
exports.VERSION = VERSION;
|
|
2546
|
+
exports.convertJsRegexToPostgres = convertJsRegexToPostgres;
|
|
2547
|
+
exports.createdByOnPostgresCreateUpdate = createdByOnPostgresCreateUpdate;
|
|
2548
|
+
exports.generateIndexes = generateIndexes;
|
|
2549
|
+
exports.reservedAttributes = reservedAttributes;
|
|
2550
|
+
exports.translateOperators = translateOperators;
|
|
2551
|
+
|
|
2552
|
+
}));
|
|
2553
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yLXR5cGVvcm0uY2pzIiwic291cmNlcyI6WyIuLi9zcmMvY29uc3RhbnRzLnRzIiwiLi4vc3JjL2Vycm9ycy50cyIsIi4uL3NyYy90eXBlcy50cyIsIi4uL3NyYy9xdWVyeS9jb25zdGFudHMudHMiLCIuLi9zcmMvcXVlcnkvUGFnaW5hdG9yLnRzIiwiLi4vc3JjL3F1ZXJ5L3RyYW5zbGF0ZS50cyIsIi4uL3NyYy9xdWVyeS9TdGF0ZW1lbnQudHMiLCIuLi9zcmMvc2VxdWVuY2VzL1NlcXVlbmNlLnRzIiwiLi4vc3JjL2luZGV4ZXMvZ2VuZXJhdG9yLnRzIiwiLi4vc3JjL1R5cGVPUk1SZXBvc2l0b3J5LnRzIiwiLi4vc3JjL1R5cGVPUk1FdmVudFN1YnNjcmliZXIudHMiLCIuLi9zcmMvVHlwZU9STURpc3BhdGNoLnRzIiwiLi4vc3JjL3V0aWxzLnRzIiwiLi4vc3JjL292ZXJyaWRlcy91dGlscy50cyIsIi4uL3NyYy9vdmVycmlkZXMvQ29sdW1uLnRzIiwiLi4vc3JjL292ZXJyaWRlcy9VcGRhdGVEYXRlQ29sdW1uLnRzIiwiLi4vc3JjL292ZXJyaWRlcy9DcmVhdGVEYXRlQ29sdW1uLnRzIiwiLi4vc3JjL292ZXJyaWRlcy9QcmltYXJ5R2VuZXJhdGVkQ29sdW1uLnRzIiwiLi4vc3JjL292ZXJyaWRlcy9QcmltYXJ5Q29sdW1uLnRzIiwiLi4vc3JjL292ZXJyaWRlcy9FbnRpdHkudHMiLCIuLi9zcmMvVHlwZU9STUFkYXB0ZXIudHMiLCIuLi9zcmMvaW5kZXgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAZGVzY3JpcHRpb24gUmVndWxhciBleHByZXNzaW9uIHRvIGlkZW50aWZ5IHJlc2VydmVkIGF0dHJpYnV0ZXMgZm9yIFNRTCBjb250ZXh0cy5cbiAqIEBzdW1tYXJ5IE1hdGNoZXMgYXR0cmlidXRlIG5hbWVzIHRoYXQgY29uZmxpY3Qgd2l0aCBTUUwgcmVzZXJ2ZWQga2V5d29yZHMgdG8gcHJldmVudCBpbnZhbGlkIHNjaGVtYSBvciBxdWVyeSBnZW5lcmF0aW9uLlxuICogQGNvbnN0IHJlc2VydmVkQXR0cmlidXRlc1xuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItdHlwZW9ybVxuICovXG5leHBvcnQgY29uc3QgcmVzZXJ2ZWRBdHRyaWJ1dGVzID1cbiAgL14oc2VsZWN0fGZyb218d2hlcmV8YW5kfG9yfGluc2VydHx1cGRhdGV8ZGVsZXRlfGRyb3B8Y3JlYXRlfHRhYmxlfGluZGV4fHByaW1hcnl8a2V5fGZvcmVpZ258cmVmZXJlbmNlc3xjb25zdHJhaW50fHVuaXF1ZXxjaGVja3xkZWZhdWx0fG51bGx8bm90fGFzfG9yZGVyfGJ5fGdyb3VwfGhhdmluZ3xsaW1pdHxvZmZzZXR8am9pbnxpbm5lcnxvdXRlcnxsZWZ0fHJpZ2h0fGZ1bGx8b258dXNpbmd8dmFsdWVzfHJldHVybmluZ3xzZXR8aW50b3xjYXNlfHdoZW58dGhlbnxlbHNlfGVuZHxjYXN0fGNvYWxlc2NlfGV4aXN0c3xhbnl8YWxsfHNvbWV8aW58YmV0d2VlbnxsaWtlfGlsaWtlfHNpbWlsYXJ8dG98aXN8dHJ1ZXxmYWxzZXxhc2N8ZGVzY3xkaXN0aW5jdHx1bmlvbnxpbnRlcnNlY3R8ZXhjZXB0fG5hdHVyYWx8bGF0ZXJhbHx3aW5kb3d8b3ZlcnxwYXJ0aXRpb258cmFuZ2V8cm93c3x1bmJvdW5kZWR8cHJlY2VkaW5nfGZvbGxvd2luZ3xjdXJyZW50fHJvd3x3aXRofHJlY3Vyc2l2ZXxtYXRlcmlhbGl6ZWR8dmlld3xmdW5jdGlvbnx0cmlnZ2VyfHByb2NlZHVyZXxsYW5ndWFnZXxyZXR1cm5zfHJldHVybnxkZWNsYXJlfGJlZ2lufGNvbW1pdHxyb2xsYmFja3xzYXZlcG9pbnR8dHJhbnNhY3Rpb258dGVtcG9yYXJ5fHRlbXB8aWZ8bG9vcHx3aGlsZXxmb3J8Y29udGludWV8ZXhpdHxyYWlzZXxleGNlcHRpb258bm90aWNlfGluZm98bG9nfGRlYnVnfGFzc2VydHxleGVjdXRlfHBlcmZvcm18Z2V0fGRpYWdub3N0aWNzfGNhbGx8ZG98YWxpYXN8Y29tbWVudHx2YWN1dW18YW5hbHl6ZXxleHBsYWlufGNvcHl8Z3JhbnR8cmV2b2tlfHByaXZpbGVnZXN8cHVibGljfHVzYWdlfHNjaGVtYXxzZXF1ZW5jZXxvd25lZHxvd25lcnx0YWJsZXNwYWNlfHN0b3JhZ2V8aW5oZXJpdHN8dHlwZXxvcGVyYXRvcnxjb2xsYXRlfGNvbGxhdGlvbnxjYXNjYWRlfHJlc3RyaWN0fGFkZHxhbHRlcnxjb2x1bW58cmVuYW1lfHRvfGVuYWJsZXxkaXNhYmxlfGZvcmNlfG5vfGluc3RlYWR8b2Z8YmVmb3JlfGFmdGVyfGVhY2h8c3RhdGVtZW50fHJvd3xleGVjdXRlfGFsc298b25seXxleGNsdWRlfG51bGxzfG90aGVyc3xvcmRpbmFsaXR5fHRpZXN8bm90aGluZ3xjYWNoZXxjeWNsZXxpbmNyZW1lbnR8bWludmFsdWV8bWF4dmFsdWV8c3RhcnR8cmVzdGFydHxieXxjYWxsZWR8cmV0dXJuc3xsYW5ndWFnZXxpbW11dGFibGV8c3RhYmxlfHZvbGF0aWxlfHN0cmljdHxzZWN1cml0eXxkZWZpbmVyfGludm9rZXJ8Y29zdHxyb3dzfHN1cHBvcnR8aGFuZGxlcnxpbmxpbmV8dmFsaWRhdG9yfG9wdGlvbnN8c3RvcmFnZXxpbmhlcml0YW5jZXxvaWRzfHdpdGhvdXR8ZGF0YXxkaWN0aW9uYXJ5fGVuY29kaW5nfGxjX2NvbGxhdGV8bGNfY3R5cGV8Y29ubmVjdGlvbnxsaW1pdHxwYXNzd29yZHx2YWxpZHx1bnRpbHxzdXBlcnVzZXJ8bm9zdXBlcnVzZXJ8Y3JlYXRlZGJ8bm9jcmVhdGVkYnxjcmVhdGVyb2xlfG5vY3JlYXRlcm9sZXxpbmhlcml0fG5vaW5oZXJpdHxsb2dpbnxub2xvZ2lufHJlcGxpY2F0aW9ufG5vcmVwbGljYXRpb258YnlwYXNzcmxzfG5vYnlwYXNzcmxzfGVuY3J5cHRlZHx1bmVuY3J5cHRlZHxuZXd8b2xkfHNlc3Npb25fdXNlcnxjdXJyZW50X3VzZXJ8Y3VycmVudF9yb2xlfGN1cnJlbnRfc2NoZW1hfGN1cnJlbnRfY2F0YWxvZ3xjdXJyZW50X2RhdGV8Y3VycmVudF90aW1lfGN1cnJlbnRfdGltZXN0YW1wfGxvY2FsdGltZXxsb2NhbHRpbWVzdGFtcHxjdXJyZW50X2RhdGFiYXNlfGluZXR8Y2lkcnxtYWNhZGRyfG1hY2FkZHI4fGJpdHx2YXJiaXR8dHN2ZWN0b3J8dHNxdWVyeXx1dWlkfHhtbHxqc29ufGpzb25ifGludHxpbnRlZ2VyfHNtYWxsaW50fGJpZ2ludHxkZWNpbWFsfG51bWVyaWN8cmVhbHxkb3VibGV8cHJlY2lzaW9ufGZsb2F0fGJvb2xlYW58Ym9vbHxjaGFyfGNoYXJhY3Rlcnx2YXJjaGFyfHRleHR8Ynl0ZWF8ZGF0ZXx0aW1lfHRpbWVzdGFtcHxpbnRlcnZhbHxwb2ludHxsaW5lfGxzZWd8Ym94fHBhdGh8cG9seWdvbnxjaXJjbGV8bW9uZXl8dm9pZCkkL2k7XG5cbmV4cG9ydCBjb25zdCBUeXBlT1JNRmxhdm91ciA9IFwidHlwZS1vcm1cIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU2hhcGUgb2YgdGhlIFR5cGVPUk1LZXlzIGNvbnN0YW50LlxuICogQHN1bW1hcnkgRGVzY3JpYmVzIHRoZSBrZXlzIGFuZCB0aGVpciBtZWFuaW5ncyB1c2VkIGJ5IHRoZSBUeXBlT1JNIGFkYXB0ZXIuXG4gKiBAdHlwZWRlZiBUeXBlT1JNS2V5c0RlZlxuICogQHByb3BlcnR5IHtzdHJpbmd9IFNFUEFSQVRPUiBTZXBhcmF0b3IgdXNlZCB0byBqb2luIHRhYmxlIGFuZCBjb2x1bW4gaWRlbnRpZmllcnMuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gSUQgRGVmYXVsdCBwcmltYXJ5IGtleSBmaWVsZCBuYW1lLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IFZFUlNJT04gVmVyc2lvbiBmaWVsZCB1c2VkIGZvciBvcHRpbWlzdGljIGxvY2tpbmcuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gREVMRVRFRCBTb2Z0LWRlbGV0ZSB0aW1lc3RhbXAgZmllbGQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gVEFCTEUgRGF0YWJhc2UgdGFibGUgaWRlbnRpZmllciBrZXkuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gU0NIRU1BIERhdGFiYXNlIHNjaGVtYSBpZGVudGlmaWVyIGtleS5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBTRVFVRU5DRSBEYXRhYmFzZSBzZXF1ZW5jZSBuYW1lIGtleS5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBJTkRFWCBJbmRleCBpZGVudGlmaWVyIGtleS5cbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLXR5cGVvcm1cbiAqL1xuLyoqXG4gKiBAZGVzY3JpcHRpb24gS2V5IGNvbnN0YW50cyB1c2VkIGJ5IHRoZSBUeXBlT1JNIGFkYXB0ZXIuXG4gKiBAc3VtbWFyeSBDb2xsZWN0aW9uIG9mIHN0cmluZyBjb25zdGFudHMgdGhhdCBpZGVudGlmeSBjb21tb24gZGF0YWJhc2UgcHJvcGVydGllcyBhbmQgYWRhcHRlci1zcGVjaWZpYyBrZXlzLlxuICogQGNvbnN0IFR5cGVPUk1LZXlzXG4gKiBAdHlwZSB7VHlwZU9STUtleXNEZWZ9XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci10eXBlb3JtXG4gKi9cbmV4cG9ydCBjb25zdCBUeXBlT1JNS2V5cyA9IHtcbiAgU0VQQVJBVE9SOiBcIi5cIixcbiAgSUQ6IFwiaWRcIixcbiAgVkVSU0lPTjogXCJ2ZXJzaW9uXCIsXG4gIERFTEVURUQ6IFwiZGVsZXRlZF9hdFwiLFxuICBUQUJMRTogXCJ0YWJsZV9uYW1lXCIsXG4gIFNDSEVNQTogXCJzY2hlbWFfbmFtZVwiLFxuICBTRVFVRU5DRTogXCJzZXF1ZW5jZV9uYW1lXCIsXG4gIElOREVYOiBcImluZGV4XCIsXG59O1xuIiwiaW1wb3J0IHsgQmFzZUVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEVycm9yIHRocm93biB3aGVuIHRoZXJlIGlzIGFuIGlzc3VlIHdpdGggVHlwZU9STSBpbmRleGVzLlxuICogQHN1bW1hcnkgUmVwcmVzZW50cyBhbiBlcnJvciByZWxhdGVkIHRvIGluZGV4IGdlbmVyYXRpb24gb3IgaGFuZGxpbmcgd2l0aGluIHRoZSBUeXBlT1JNIGFkYXB0ZXIuXG4gKiBAcGFyYW0ge3N0cmluZ3xFcnJvcn0gbXNnIFRoZSBlcnJvciBtZXNzYWdlIG9yIEVycm9yIG9iamVjdC5cbiAqIEBjbGFzc1xuICogQGNhdGVnb3J5IEVycm9yc1xuICogQGV4YW1wbGVcbiAqIC8vIEV4YW1wbGUgb2YgdXNpbmcgSW5kZXhFcnJvclxuICogdHJ5IHtcbiAqICAgLy8gU29tZSBjb2RlIHRoYXQgbWlnaHQgdGhyb3cgYW4gaW5kZXggZXJyb3JcbiAqICAgdGhyb3cgbmV3IEluZGV4RXJyb3IoXCJJbmRleCBub3QgZm91bmRcIik7XG4gKiB9IGNhdGNoIChlcnJvcikge1xuICogICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBJbmRleEVycm9yKSB7XG4gKiAgICAgY29uc29sZS5lcnJvcihcIkluZGV4IGVycm9yIG9jY3VycmVkOlwiLCBlcnJvci5tZXNzYWdlKTtcbiAqICAgfVxuICogfVxuICovXG5leHBvcnQgY2xhc3MgSW5kZXhFcnJvciBleHRlbmRzIEJhc2VFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nIHwgRXJyb3IpIHtcbiAgICBzdXBlcihJbmRleEVycm9yLm5hbWUsIG1zZywgNDA0KTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgUmVwb3NpdG9yeUZsYWdzIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBTZWxlY3RRdWVyeUJ1aWxkZXIgfSBmcm9tIFwidHlwZW9ybVwiO1xuaW1wb3J0IHsgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFNRTCBvcGVyYXRvcnMgYXZhaWxhYmxlIGZvciBidWlsZGluZyBUeXBlT1JNIHF1ZXJpZXMuXG4gKiBAc3VtbWFyeSBFbnVtZXJhdGlvbiBvZiBjb21tb24gU1FMIG9wZXJhdG9ycyBpbnRlbmRlZCBmb3IgdXNlIHdpdGhpbiBUeXBlT1JNIHF1ZXJ5IGNvbnN0cnVjdGlvbiBhbmQgdHJhbnNsYXRpb24gbGF5ZXJzLlxuICogQGVudW0ge3N0cmluZ31cbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLXR5cGVvcm1cbiAqL1xuZXhwb3J0IGVudW0gU1FMT3BlcmF0b3Ige1xuICBFUVVBTCA9IFwiPVwiLFxuICBOT1RfRVFVQUwgPSBcIjw+XCIsXG4gIExFU1NfVEhBTiA9IFwiPFwiLFxuICBMRVNTX1RIQU5fT1JfRVFVQUwgPSBcIjw9XCIsXG4gIEdSRUFURVJfVEhBTiA9IFwiPlwiLFxuICBHUkVBVEVSX1RIQU5fT1JfRVFVQUwgPSBcIj49XCIsXG4gIElOID0gXCJJTlwiLFxuICBOT1RfSU4gPSBcIk5PVCBJTlwiLFxuICBMSUtFID0gXCJMSUtFXCIsXG4gIElMSUtFID0gXCJJTElLRVwiLFxuICBCRVRXRUVOID0gXCJCRVRXRUVOXCIsXG4gIElTX05VTEwgPSBcIklTIE5VTExcIixcbiAgSVNfTk9UX05VTEwgPSBcIklTIE5PVCBOVUxMXCIsXG4gIEVYSVNUUyA9IFwiRVhJU1RTXCIsXG4gIE5PVF9FWElTVFMgPSBcIk5PVCBFWElTVFNcIixcbiAgQU5ZID0gXCJBTllcIixcbiAgQUxMID0gXCJBTExcIixcbiAgU09NRSA9IFwiU09NRVwiLFxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBRdWVyeSBjb250YWluZXIgdXNlZCBieSB0aGUgVHlwZU9STSBhZGFwdGVyLlxuICogQHN1bW1hcnkgUmVwcmVzZW50cyBlaXRoZXIgYSByYXcgU1FMIHN0cmluZyBvciBhIFR5cGVPUk0gU2VsZWN0UXVlcnlCdWlsZGVyIGFsb25nIHdpdGggb3B0aW9uYWwgYm91bmQgdmFsdWVzIHRvIGJlIGV4ZWN1dGVkIGJ5IHRoZSBhZGFwdGVyLlxuICogQHRlbXBsYXRlIE0gVGhlIE1vZGVsIHR5cGUgZm9yIHdoaWNoIHRoZSBTZWxlY3RRdWVyeUJ1aWxkZXIgaXMgcGFyYW1ldGVyaXplZC5cbiAqIEB0ZW1wbGF0ZSBUIFRoZSB1bmRlcmx5aW5nIHF1ZXJ5IHR5cGUsIGVpdGhlciBhIHN0cmluZyBvciBhIFNlbGVjdFF1ZXJ5QnVpbGRlcjxNPi5cbiAqIEBpbnRlcmZhY2UgVHlwZU9STVF1ZXJ5XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci10eXBlb3JtXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVHlwZU9STVF1ZXJ5PFxuICBNIGV4dGVuZHMgTW9kZWwgPSBNb2RlbCxcbiAgVCBleHRlbmRzIHN0cmluZyB8IFNlbGVjdFF1ZXJ5QnVpbGRlcjxNPiA9IHN0cmluZyxcbj4ge1xuICBxdWVyeTogVDtcbiAgdmFsdWVzPzogYW55W107XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbmZpZ3VyYXRpb24gZmxhZ3MgZm9yIFR5cGVPUk0gb3BlcmF0aW9ucy5cbiAqIEBzdW1tYXJ5IEV4dGVuZGVkIHJlcG9zaXRvcnkgZmxhZ3MgaW5jbHVkaW5nIGNvbm5lY3Rpb24vdXNlciBjb250ZXh0IHRoYXQgY2FuIGJlIGxldmVyYWdlZCBieSB0aGUgVHlwZU9STSBhZGFwdGVyLlxuICogQGludGVyZmFjZSBUeXBlT1JNRmxhZ3NcbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLXR5cGVvcm1cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUeXBlT1JNRmxhZ3MgZXh0ZW5kcyBSZXBvc2l0b3J5RmxhZ3Mge1xuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFVzZXIgYXV0aGVudGljYXRpb24gaW5mb3JtYXRpb24gZm9yIFBvc3RncmVzIGRhdGFiYXNlIGNvbm5lY3Rpb25zXG4gICAqL1xuICB1c2VyOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFNwZWNpZmljYXRpb24gZm9yIGEgdGFibGUgY3JlYXRpb24vY2hhbmdlIHN0YXRlbWVudCB1c2VkIGJ5IHRoZSBUeXBlT1JNIGFkYXB0ZXIuXG4gKiBAc3VtbWFyeSBFeHRlbmRzIGEgVHlwZU9STVF1ZXJ5IHdpdGggdGFibGUgbWV0YWRhdGEgc3VjaCBhcyBwcmltYXJ5IGtleSBmbGFnLCBjb25zdHJhaW50cywgYW5kIGZvcmVpZ24ga2V5cy5cbiAqIEB0eXBlZGVmIFR5cGVPUk1UYWJsZVNwZWNcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gcHJpbWFyeUtleSBJbmRpY2F0ZXMgaWYgdGhlIHRhcmdldCBjb2x1bW4gaXMgcGFydCBvZiB0aGUgcHJpbWFyeSBrZXkuXG4gKiBAcHJvcGVydHkge3N0cmluZ1tdfSBjb25zdHJhaW50cyBBIGxpc3Qgb2YgcmF3IFNRTCBjb25zdHJhaW50cyB0byBhcHBseSB0byB0aGUgdGFibGUvY29sdW1uLlxuICogQHByb3BlcnR5IHtzdHJpbmdbXX0gZm9yZWlnbktleXMgQSBsaXN0IG9mIGZvcmVpZ24ga2V5IGNvbnN0cmFpbnQgZGVmaW5pdGlvbnMuXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci10eXBlb3JtXG4gKi9cbmV4cG9ydCB0eXBlIFR5cGVPUk1UYWJsZVNwZWMgPSBUeXBlT1JNUXVlcnkgJiB7XG4gIHByaW1hcnlLZXk6IGJvb2xlYW47XG4gIGNvbnN0cmFpbnRzOiBzdHJpbmdbXTtcbiAgZm9yZWlnbktleXM6IHN0cmluZ1tdO1xufTtcbiIsImltcG9ydCB7IFNRTE9wZXJhdG9yIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERlZmF1bHQgcXVlcnkgbGltaXQgZm9yIFR5cGVPUk0tYmFja2VkIHF1ZXJpZXMuXG4gKiBAc3VtbWFyeSBNYXhpbXVtIG51bWJlciBvZiByZWNvcmRzIHRvIHJldHVybiBpbiBhIHNpbmdsZSBwYWdlIHdoZW4gcGFnaW5hdGluZyByZXN1bHRzLlxuICogQGNvbnN0IFR5cGVPUk1RdWVyeUxpbWl0XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci10eXBlb3JtXG4gKi9cbmV4cG9ydCBjb25zdCBUeXBlT1JNUXVlcnlMaW1pdCA9IDI1MDtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gTWFwcGluZyBvZiBvcGVyYXRvciBuYW1lcyB0byBTUUwgb3BlcmF0b3JzLlxuICogQHN1bW1hcnkgQ29uc3RhbnRzIGZvciBjb21wYXJpc29uIG9wZXJhdG9ycyB1c2VkIHdoZW4gdHJhbnNsYXRpbmcgaGlnaC1sZXZlbCBmaWx0ZXJzIGludG8gU1FMIHZpYSBUeXBlT1JNLlxuICogQHR5cGVkZWYge09iamVjdH0gUG9zdGdyZVNRTE9wZXJhdG9yVHlwZVxuICogQHByb3BlcnR5IHtzdHJpbmd9IEVRVUFMIEVxdWFsaXR5IG9wZXJhdG9yICg9KVxuICogQHByb3BlcnR5IHtzdHJpbmd9IERJRkZFUkVOVCBJbmVxdWFsaXR5IG9wZXJhdG9yICg8PilcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBCSUdHRVIgR3JlYXRlciB0aGFuIG9wZXJhdG9yICg+KVxuICogQHByb3BlcnR5IHtzdHJpbmd9IEJJR0dFUl9FUSBHcmVhdGVyIHRoYW4gb3IgZXF1YWwgb3BlcmF0b3IgKD49KVxuICogQHByb3BlcnR5IHtzdHJpbmd9IFNNQUxMRVIgTGVzcyB0aGFuIG9wZXJhdG9yICg8KVxuICogQHByb3BlcnR5IHtzdHJpbmd9IFNNQUxMRVJfRVEgTGVzcyB0aGFuIG9yIGVxdWFsIG9wZXJhdG9yICg8PSlcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBOT1QgTmVnYXRpb24gb3BlcmF0b3IgKE5PVClcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBJTiBJbiBhcnJheSBvcGVyYXRvciAoSU4pXG4gKiBAcHJvcGVydHkge3N0cmluZ30gUkVHRVhQIFJlZ3VsYXIgZXhwcmVzc2lvbiBvcGVyYXRvciAofilcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBJUkVHRVhQIENhc2UtaW5zZW5zaXRpdmUgcmVndWxhciBleHByZXNzaW9uIG9wZXJhdG9yICh+KilcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBMSUtFIFBhdHRlcm4gbWF0Y2hpbmcgb3BlcmF0b3IgKExJS0UpXG4gKiBAcHJvcGVydHkge3N0cmluZ30gSUxJS0UgQ2FzZS1pbnNlbnNpdGl2ZSBwYXR0ZXJuIG1hdGNoaW5nIG9wZXJhdG9yIChJTElLRSlcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBCRVRXRUVOIFJhbmdlIG9wZXJhdG9yIChCRVRXRUVOKVxuICogQHByb3BlcnR5IHtzdHJpbmd9IElTX05VTEwgTlVMTCBjaGVjayBvcGVyYXRvciAoSVMgTlVMTClcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBJU19OT1RfTlVMTCBOT1QgTlVMTCBjaGVjayBvcGVyYXRvciAoSVMgTk9UIE5VTEwpXG4gKiBAY29uc3QgVHlwZU9STU9wZXJhdG9yXG4gKiBAdHlwZSB7UG9zdGdyZVNRTE9wZXJhdG9yVHlwZX1cbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLXR5cGVvcm1cbiAqL1xuZXhwb3J0IGNvbnN0IFR5cGVPUk1PcGVyYXRvcjogUmVjb3JkPHN0cmluZywgU1FMT3BlcmF0b3IgfCBzdHJpbmc+ID0ge1xuICBFUVVBTDogU1FMT3BlcmF0b3IuRVFVQUwsXG4gIERJRkZFUkVOVDogU1FMT3BlcmF0b3IuTk9UX0VRVUFMLFxuICBCSUdHRVI6IFNRTE9wZXJhdG9yLkdSRUFURVJfVEhBTixcbiAgQklHR0VSX0VROiBTUUxPcGVyYXRvci5HUkVBVEVSX1RIQU5fT1JfRVFVQUwsXG4gIFNNQUxMRVI6IFNRTE9wZXJhdG9yLkxFU1NfVEhBTixcbiAgU01BTExFUl9FUTogU1FMT3BlcmF0b3IuTEVTU19USEFOX09SX0VRVUFMLFxuICBCRVRXRUVOOiBTUUxPcGVyYXRvci5CRVRXRUVOLFxuICBOT1Q6IFwiTk9UXCIsXG4gIElOOiBTUUxPcGVyYXRvci5JTixcbiAgSVNfTlVMTDogU1FMT3BlcmF0b3IuSVNfTlVMTCxcbiAgSVNfTk9UX05VTEw6IFNRTE9wZXJhdG9yLklTX05PVF9OVUxMLFxuICBSRUdFWFA6IFwiflwiLFxuICBJUkVHRVhQOiBcIn4qXCIsXG4gIExJS0U6IFNRTE9wZXJhdG9yLkxJS0UsXG4gIElMSUtFOiBTUUxPcGVyYXRvci5JTElLRSxcbn07XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIE1hcHBpbmcgb2YgbG9naWNhbCBvcGVyYXRvciBuYW1lcyB0byBTUUwgb3BlcmF0b3JzLlxuICogQHN1bW1hcnkgQ29uc3RhbnRzIGZvciBsb2dpY2FsIG9wZXJhdG9ycyB1c2VkIHdoZW4gYnVpbGRpbmcgV0hFUkUgY2xhdXNlIGdyb3VwcyBpbiBUeXBlT1JNIHF1ZXJpZXMuXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBQb3N0Z3JlU1FMR3JvdXBPcGVyYXRvclR5cGVcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBBTkQgTG9naWNhbCBBTkQgb3BlcmF0b3IgKEFORClcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBPUiBMb2dpY2FsIE9SIG9wZXJhdG9yIChPUilcbiAqIEBjb25zdCBUeXBlT1JNR3JvdXBPcGVyYXRvclxuICogQHR5cGUge1Bvc3RncmVTUUxHcm91cE9wZXJhdG9yVHlwZX1cbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLXR5cGVvcm1cbiAqL1xuZXhwb3J0IGNvbnN0IFR5cGVPUk1Hcm91cE9wZXJhdG9yOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICBBTkQ6IFwiQU5EXCIsXG4gIE9SOiBcIk9SXCIsXG59O1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBTcGVjaWFsIGNvbnN0YW50IHZhbHVlcyB1c2VkIGluIHF1ZXJpZXMuXG4gKiBAc3VtbWFyeSBTdHJpbmcgY29uc3RhbnRzIHJlcHJlc2VudGluZyBzcGVjaWFsIHZhbHVlcyB1c2VkIHdoaWxlIGNvbXBvc2luZyBTUUwgd2l0aCBUeXBlT1JNLlxuICogQHR5cGVkZWYge09iamVjdH0gUG9zdGdyZVNRTENvbnN0VHlwZVxuICogQHByb3BlcnR5IHtzdHJpbmd9IE5VTEwgU3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIG51bGwgdmFsdWUuXG4gKiBAY29uc3QgVHlwZU9STUNvbnN0XG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci10eXBlb3JtXG4gKi9cbmV4cG9ydCBjb25zdCBUeXBlT1JNQ29uc3Q6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gIE5VTEw6IFwiTlVMTFwiLFxufTtcbiIsImltcG9ydCB7IFBhZ2luYXRvciwgUGFnaW5nRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IFR5cGVPUk1RdWVyeSB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IsIE1vZGVsLCBNb2RlbEtleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBUeXBlT1JNQWRhcHRlciB9IGZyb20gXCIuLi9UeXBlT1JNQWRhcHRlclwiO1xuaW1wb3J0IHsgRmluZE1hbnlPcHRpb25zLCBSZXBvc2l0b3J5IGFzIFJlcG8gfSBmcm9tIFwidHlwZW9ybVwiO1xuaW1wb3J0IHsgZmluZFByaW1hcnlLZXkgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUGFnaW5hdG9yIGZvciBUeXBlT1JNIHF1ZXJ5IHJlc3VsdHMuXG4gKiBAc3VtbWFyeSBJbXBsZW1lbnRzIHBhZ2luYXRpb24gZm9yIFR5cGVPUk0tYnVpbHQgcXVlcmllcyB1c2luZyB0YWtlL3NraXAgZm9yIGVmZmljaWVudCBuYXZpZ2F0aW9uIHRocm91Z2ggcmVzdWx0IHNldHMuXG4gKiBAdGVtcGxhdGUgTSBUaGUgbW9kZWwgdHlwZSB0aGF0IGV4dGVuZHMgTW9kZWwuXG4gKiBAdGVtcGxhdGUgUiBUaGUgcmVzdWx0IHR5cGUuXG4gKiBAcGFyYW0ge1R5cGVPUk1BZGFwdGVyfSBhZGFwdGVyIFRoZSBUeXBlT1JNIGFkYXB0ZXIuXG4gKiBAcGFyYW0ge1R5cGVPUk1RdWVyeX0gcXVlcnkgVGhlIHF1ZXJ5IGNvbnRhaW5lciB0byBwYWdpbmF0ZS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBzaXplIFRoZSBwYWdlIHNpemUuXG4gKiBAcGFyYW0ge0NvbnN0cnVjdG9yPE0+fSBjbGF6eiBUaGUgbW9kZWwgY29uc3RydWN0b3IuXG4gKiBAY2xhc3MgVHlwZU9STVBhZ2luYXRvclxuICogQGV4YW1wbGVcbiAqIC8vIEV4YW1wbGUgb2YgdXNpbmcgVHlwZU9STVBhZ2luYXRvclxuICogY29uc3QgcGFnaW5hdG9yID0gbmV3IFR5cGVPUk1QYWdpbmF0b3IoYWRhcHRlciwgeyBxdWVyeTogcWIgfSwgMTAsIFVzZXIpO1xuICogY29uc3QgcGFnZTEgPSBhd2FpdCBwYWdpbmF0b3IucGFnZSgxKTtcbiAqIGNvbnN0IHBhZ2UyID0gYXdhaXQgcGFnaW5hdG9yLnBhZ2UoMik7XG4gKi9cbmV4cG9ydCBjbGFzcyBUeXBlT1JNUGFnaW5hdG9yPE0gZXh0ZW5kcyBNb2RlbCwgUj4gZXh0ZW5kcyBQYWdpbmF0b3I8XG4gIE0sXG4gIFIsXG4gIFR5cGVPUk1RdWVyeVxuPiB7XG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2V0cyB0aGUgdG90YWwgbnVtYmVyIG9mIHBhZ2VzXG4gICAqIEBzdW1tYXJ5IFJldHVybnMgdGhlIHRvdGFsIG51bWJlciBvZiBwYWdlcyBiYXNlZCBvbiB0aGUgcmVjb3JkIGNvdW50IGFuZCBwYWdlIHNpemVcbiAgICogQHJldHVybiB7bnVtYmVyfSBUaGUgdG90YWwgbnVtYmVyIG9mIHBhZ2VzXG4gICAqL1xuICBvdmVycmlkZSBnZXQgdG90YWwoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5fdG90YWxQYWdlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gR2V0cyB0aGUgdG90YWwgcmVjb3JkIGNvdW50XG4gICAqIEBzdW1tYXJ5IFJldHVybnMgdGhlIHRvdGFsIG51bWJlciBvZiByZWNvcmRzIG1hdGNoaW5nIHRoZSBxdWVyeVxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IFRoZSB0b3RhbCByZWNvcmQgY291bnRcbiAgICovXG4gIG92ZXJyaWRlIGdldCBjb3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLl9yZWNvcmRDb3VudDtcbiAgfVxuXG4gIHByaXZhdGUgX19yZXBvPzogUmVwbzxhbnk+O1xuXG4gIHByb3RlY3RlZCBnZXQgcmVwbygpIHtcbiAgICBpZiAoIXRoaXMuX19yZXBvKSB7XG4gICAgICB0aGlzLl9fcmVwbyA9ICh0aGlzLmFkYXB0ZXIgYXMgVHlwZU9STUFkYXB0ZXIpLmRhdGFTb3VyY2UuZ2V0UmVwb3NpdG9yeShcbiAgICAgICAgdGhpcy5jbGF6eltNb2RlbEtleXMuQU5DSE9SIGFzIGtleW9mIHR5cGVvZiB0aGlzLmNsYXp6XVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX19yZXBvO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgbmV3IFR5cGVPUk1QYWdpbmF0b3IgaW5zdGFuY2UuXG4gICAqIEBzdW1tYXJ5IEluaXRpYWxpemVzIGEgcGFnaW5hdG9yIGZvciBUeXBlT1JNIHF1ZXJ5IHJlc3VsdHMuXG4gICAqIEBwYXJhbSB7VHlwZU9STUFkYXB0ZXJ9IGFkYXB0ZXIgVGhlIFR5cGVPUk0gYWRhcHRlci5cbiAgICogQHBhcmFtIHtUeXBlT1JNUXVlcnl9IHF1ZXJ5IFRoZSBUeXBlT1JNIHF1ZXJ5IGNvbnRhaW5lciB0byBwYWdpbmF0ZS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IHNpemUgVGhlIHBhZ2Ugc2l6ZS5cbiAgICogQHBhcmFtIHtDb25zdHJ1Y3RvcjxNPn0gY2xhenogVGhlIG1vZGVsIGNvbnN0cnVjdG9yLlxuICAgKi9cbiAgY29uc3RydWN0b3IoXG4gICAgYWRhcHRlcjogVHlwZU9STUFkYXB0ZXIsXG4gICAgcXVlcnk6IFR5cGVPUk1RdWVyeSxcbiAgICBzaXplOiBudW1iZXIsXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE0+XG4gICkge1xuICAgIHN1cGVyKGFkYXB0ZXIsIHF1ZXJ5LCBzaXplLCBjbGF6eik7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIGEgcXVlcnkgZm9yIHBhZ2luYXRpb25cbiAgICogQHN1bW1hcnkgTW9kaWZpZXMgdGhlIHJhdyBxdWVyeSB0byBpbmNsdWRlIHBhZ2luYXRpb24gcGFyYW1ldGVyc1xuICAgKiBAcGFyYW0ge1R5cGVPUk1RdWVyeX0gcmF3U3RhdGVtZW50IC0gVGhlIG9yaWdpbmFsIFBvc3RncmVTUUwgcXVlcnlcbiAgICogQHJldHVybiB7VHlwZU9STVF1ZXJ5fSBUaGUgcHJlcGFyZWQgcXVlcnkgd2l0aCBwYWdpbmF0aW9uIHBhcmFtZXRlcnNcbiAgICovXG4gIHByb3RlY3RlZCBwcmVwYXJlKHJhd1N0YXRlbWVudDogVHlwZU9STVF1ZXJ5KTogVHlwZU9STVF1ZXJ5IHtcbiAgICBjb25zdCBxdWVyeTogVHlwZU9STVF1ZXJ5ID0geyAuLi5yYXdTdGF0ZW1lbnQgfTtcbiAgICByZXR1cm4gcXVlcnk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJldHJpZXZlcyBhIHNwZWNpZmljIHBhZ2Ugb2YgcmVzdWx0cy5cbiAgICogQHN1bW1hcnkgRXhlY3V0ZXMgdGhlIHF1ZXJ5IHdpdGggcGFnaW5hdGlvbiBhbmQgcHJvY2Vzc2VzIHRoZSByZXN1bHRzLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW3BhZ2U9MV0gVGhlIHBhZ2UgbnVtYmVyIHRvIHJldHJpZXZlLlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJbXT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIGFycmF5IG9mIHJlc3VsdHMuXG4gICAqIEB0aHJvd3Mge1BhZ2luZ0Vycm9yfSBJZiB0cnlpbmcgdG8gYWNjZXNzIGFuIGludmFsaWQgcGFnZSBvciBpZiBubyBjbGFzcyBpcyBkZWZpbmVkLlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBDbGllbnRcbiAgICogICBwYXJ0aWNpcGFudCBQYWdpbmF0b3IgYXMgVHlwZU9STVBhZ2luYXRvclxuICAgKiAgIHBhcnRpY2lwYW50IEFkYXB0ZXJcbiAgICogICBwYXJ0aWNpcGFudCBEQiBhcyBEYXRhYmFzZVxuICAgKlxuICAgKiAgIENsaWVudC0+PlBhZ2luYXRvcjogcGFnZShwYWdlTnVtYmVyKVxuICAgKiAgIE5vdGUgb3ZlciBQYWdpbmF0b3I6IFByZXBhcmUgb3B0aW9ucyAoc2tpcC90YWtlKVxuICAgKlxuICAgKiAgIGFsdCBGaXJzdCB0aW1lIG9yIG5lZWQgY291bnRcbiAgICogICAgIFBhZ2luYXRvci0+PkFkYXB0ZXI6IEdldCBjb3VudFxuICAgKiAgICAgQWRhcHRlci0+PkRCOiBFeGVjdXRlIENPVU5UXG4gICAqICAgICBEQi0tPj5BZGFwdGVyOiBjb3VudFxuICAgKiAgICAgQWRhcHRlci0tPj5QYWdpbmF0b3I6IGNvdW50XG4gICAqICAgICBQYWdpbmF0b3ItPj5QYWdpbmF0b3I6IENhbGN1bGF0ZSB0b3RhbCBwYWdlc1xuICAgKiAgIGVuZFxuICAgKlxuICAgKiAgIFBhZ2luYXRvci0+PkFkYXB0ZXI6IEV4ZWN1dGUgcXVlcnlcbiAgICogICBBZGFwdGVyLT4+REI6IGZpbmRBbmRDb3VudChvcHRpb25zKVxuICAgKiAgIERCLS0+PkFkYXB0ZXI6IHJvd3MsIGNvdW50XG4gICAqICAgQWRhcHRlci0tPj5QYWdpbmF0b3I6IHJvd3MsIGNvdW50XG4gICAqXG4gICAqICAgUGFnaW5hdG9yLT4+UGFnaW5hdG9yOiBNYXAgcm93cyB0byBtb2RlbHNcbiAgICogICBQYWdpbmF0b3ItLT4+Q2xpZW50OiByZXN1bHRzXG4gICAqL1xuXG4gIGFzeW5jIHBhZ2UocGFnZTogbnVtYmVyID0gMSk6IFByb21pc2U8UltdPiB7XG4gICAgY29uc3Qgc3RhdGVtZW50ID0geyAuLi50aGlzLnN0YXRlbWVudCB9O1xuXG4gICAgLy8gR2V0IHRvdGFsIGNvdW50IGlmIG5vdCBhbHJlYWR5IGNhbGN1bGF0ZWRcbiAgICBpZiAoIXRoaXMuX3JlY29yZENvdW50IHx8ICF0aGlzLl90b3RhbFBhZ2VzKSB7XG4gICAgICB0aGlzLl90b3RhbFBhZ2VzID0gdGhpcy5fcmVjb3JkQ291bnQgPSAwO1xuICAgIH1cblxuICAgIGNvbnN0IG9wdHM6IEZpbmRNYW55T3B0aW9uczxNPiA9IE9iamVjdC5hc3NpZ24oc3RhdGVtZW50LCB7XG4gICAgICBza2lwOiAodGhpcy5jdXJyZW50IHx8IDApICogdGhpcy5zaXplLFxuICAgICAgdGFrZTogdGhpcy5zaXplLFxuICAgIH0pO1xuXG4gICAgLy8gdGhpcy52YWxpZGF0ZVBhZ2UocGFnZSk7XG5cbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnJlcG8uZmluZEFuZENvdW50KG9wdHMpO1xuXG4gICAgdGhpcy5fcmVjb3JkQ291bnQgPSByZXN1bHRbMV07XG4gICAgdGhpcy5fdG90YWxQYWdlcyA9IE1hdGguY2VpbCh0aGlzLl9yZWNvcmRDb3VudCAvIHRoaXMuc2l6ZSk7XG5cbiAgICBpZiAoIXRoaXMuY2xhenopIHRocm93IG5ldyBQYWdpbmdFcnJvcihcIk5vIHN0YXRlbWVudCB0YXJnZXQgZGVmaW5lZFwiKTtcblxuICAgIGNvbnN0IHBrRGVmID0gZmluZFByaW1hcnlLZXkobmV3IHRoaXMuY2xhenooKSk7XG4gICAgY29uc3Qgcm93cyA9IHJlc3VsdFswXSB8fCBbXTtcblxuICAgIGNvbnN0IHJlc3VsdHMgPVxuICAgICAgLy8gc3RhdGVtZW50LmNvbHVtbnMgJiYgc3RhdGVtZW50LmNvbHVtbnMubGVuZ3RoXG4gICAgICAvLyAgID8gcm93cyAvLyBoYXMgY29sdW1ucyBtZWFucyBpdCdzIG5vdCBmdWxsIG1vZGVsXG4gICAgICByb3dzLm1hcCgocm93OiBhbnkpID0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRhcHRlci5yZXZlcnQocm93LCB0aGlzLmNsYXp6LCBwa0RlZi5pZCwgcm93W3BrRGVmLmlkXSk7XG4gICAgICB9KTtcblxuICAgIHRoaXMuX2N1cnJlbnRQYWdlID0gcGFnZTtcbiAgICByZXR1cm4gcmVzdWx0cyBhcyB1bmtub3duIGFzIFJbXTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgR3JvdXBPcGVyYXRvciwgT3BlcmF0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IFR5cGVPUk1Hcm91cE9wZXJhdG9yLCBUeXBlT1JNT3BlcmF0b3IgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IFF1ZXJ5RXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IFNRTE9wZXJhdG9yIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFRyYW5zbGF0ZXMgY29yZSBvcGVyYXRvcnMgdG8gVHlwZU9STSBTUUwgb3BlcmF0b3JzLlxuICogQHN1bW1hcnkgQ29udmVydHMgRGVjYWYudHMgY29yZSBvcGVyYXRvcnMgdG8gdGhlaXIgZXF1aXZhbGVudCBTUUwgb3BlcmF0b3JzIHVzZWQgYnkgdGhlIFR5cGVPUk0gYWRhcHRlci5cbiAqIEBwYXJhbSB7R3JvdXBPcGVyYXRvciB8IE9wZXJhdG9yfSBvcGVyYXRvciBUaGUgY29yZSBvcGVyYXRvciB0byB0cmFuc2xhdGUuXG4gKiBAcmV0dXJuIHtTUUxPcGVyYXRvciB8IHN0cmluZ30gVGhlIGVxdWl2YWxlbnQgU1FMIG9wZXJhdG9yLlxuICogQHRocm93cyB7UXVlcnlFcnJvcn0gSWYgbm8gdHJhbnNsYXRpb24gZXhpc3RzIGZvciB0aGUgZ2l2ZW4gb3BlcmF0b3IuXG4gKiBAZnVuY3Rpb24gdHJhbnNsYXRlT3BlcmF0b3JzXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci10eXBlb3JtXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IENhbGxlclxuICogICBwYXJ0aWNpcGFudCB0cmFuc2xhdGVPcGVyYXRvcnNcbiAqICAgcGFydGljaXBhbnQgUG9zdGdyZVNRTE9wZXJhdG9yXG4gKiAgIHBhcnRpY2lwYW50IFBvc3RncmVTUUxHcm91cE9wZXJhdG9yXG4gKlxuICogICBDYWxsZXItPj50cmFuc2xhdGVPcGVyYXRvcnM6IG9wZXJhdG9yXG4gKlxuICogICB0cmFuc2xhdGVPcGVyYXRvcnMtPj5Qb3N0Z3JlU1FMT3BlcmF0b3I6IENoZWNrIGZvciBtYXRjaFxuICogICBhbHQgRm91bmQgaW4gUG9zdGdyZVNRTE9wZXJhdG9yXG4gKiAgICAgUG9zdGdyZVNRTE9wZXJhdG9yLS0+PnRyYW5zbGF0ZU9wZXJhdG9yczogUmV0dXJuIG1hdGNoaW5nIG9wZXJhdG9yXG4gKiAgICAgdHJhbnNsYXRlT3BlcmF0b3JzLS0+PkNhbGxlcjogUmV0dXJuIFNRTE9wZXJhdG9yXG4gKiAgIGVsc2UgTm90IGZvdW5kXG4gKiAgICAgdHJhbnNsYXRlT3BlcmF0b3JzLT4+UG9zdGdyZVNRTEdyb3VwT3BlcmF0b3I6IENoZWNrIGZvciBtYXRjaFxuICogICAgIGFsdCBGb3VuZCBpbiBQb3N0Z3JlU1FMR3JvdXBPcGVyYXRvclxuICogICAgICAgUG9zdGdyZVNRTEdyb3VwT3BlcmF0b3ItLT4+dHJhbnNsYXRlT3BlcmF0b3JzOiBSZXR1cm4gbWF0Y2hpbmcgb3BlcmF0b3JcbiAqICAgICAgIHRyYW5zbGF0ZU9wZXJhdG9ycy0tPj5DYWxsZXI6IFJldHVybiBzdHJpbmdcbiAqICAgICBlbHNlIE5vdCBmb3VuZFxuICogICAgICAgdHJhbnNsYXRlT3BlcmF0b3JzLS0+PkNhbGxlcjogVGhyb3cgUXVlcnlFcnJvclxuICogICAgIGVuZFxuICogICBlbmRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zbGF0ZU9wZXJhdG9ycyhcbiAgb3BlcmF0b3I6IEdyb3VwT3BlcmF0b3IgfCBPcGVyYXRvclxuKTogU1FMT3BlcmF0b3IgfCBzdHJpbmcge1xuICBmb3IgKGNvbnN0IG9wZXJhdG9ycyBvZiBbVHlwZU9STU9wZXJhdG9yLCBUeXBlT1JNR3JvdXBPcGVyYXRvcl0pIHtcbiAgICBjb25zdCBlbCA9IE9iamVjdC5rZXlzKG9wZXJhdG9ycykuZmluZCgoaykgPT4gayA9PT0gb3BlcmF0b3IpO1xuICAgIGlmIChlbCkgcmV0dXJuIG9wZXJhdG9yc1tlbF07XG4gIH1cbiAgdGhyb3cgbmV3IFF1ZXJ5RXJyb3IoXG4gICAgYENvdWxkIG5vdCBmaW5kIGFkYXB0ZXIgdHJhbnNsYXRpb24gZm9yIG9wZXJhdG9yICR7b3BlcmF0b3J9YFxuICApO1xufVxuIiwiaW1wb3J0IHtcbiAgQ29uZGl0aW9uLFxuICBHcm91cE9wZXJhdG9yLFxuICBPcGVyYXRvcixcbiAgT3JkZXJEaXJlY3Rpb24sXG4gIFBhZ2luYXRvcixcbiAgUmVwb3NpdG9yeSxcbiAgU3RhdGVtZW50LFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IE1vZGVsLCBNb2RlbEtleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyB0cmFuc2xhdGVPcGVyYXRvcnMgfSBmcm9tIFwiLi90cmFuc2xhdGVcIjtcbmltcG9ydCB7IFR5cGVPUk1RdWVyeUxpbWl0IH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBUeXBlT1JNUGFnaW5hdG9yIH0gZnJvbSBcIi4vUGFnaW5hdG9yXCI7XG5pbXBvcnQgeyBmaW5kUHJpbWFyeUtleSwgSW50ZXJuYWxFcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgVHlwZU9STVF1ZXJ5IH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5pbXBvcnQgeyBUeXBlT1JNQWRhcHRlciB9IGZyb20gXCIuLi9UeXBlT1JNQWRhcHRlclwiO1xuaW1wb3J0IHsgRmluZE1hbnlPcHRpb25zLCBTZWxlY3RRdWVyeUJ1aWxkZXIgfSBmcm9tIFwidHlwZW9ybVwiO1xuaW1wb3J0IHsgRmluZE9wdGlvbnNXaGVyZSB9IGZyb20gXCJ0eXBlb3JtL2ZpbmQtb3B0aW9ucy9GaW5kT3B0aW9uc1doZXJlXCI7XG5pbXBvcnQgeyBGaW5kT3B0aW9uc09yZGVyIH0gZnJvbSBcInR5cGVvcm0vZmluZC1vcHRpb25zL0ZpbmRPcHRpb25zT3JkZXJcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gU3RhdGVtZW50IGJ1aWxkZXIgZm9yIFR5cGVPUk0tYmFja2VkIHF1ZXJpZXMuXG4gKiBAc3VtbWFyeSBQcm92aWRlcyBhIGZsdWVudCBpbnRlcmZhY2UgZm9yIGJ1aWxkaW5nIFNRTCBxdWVyaWVzIHZpYSBUeXBlT1JNJ3MgU2VsZWN0UXVlcnlCdWlsZGVyIHdpdGggdHlwZSBzYWZldHkgYW5kIERlY2FmLnRzIGFic3RyYWN0aW9ucy5cbiAqIEB0ZW1wbGF0ZSBNIFRoZSBtb2RlbCB0eXBlIHRoYXQgZXh0ZW5kcyBNb2RlbC5cbiAqIEB0ZW1wbGF0ZSBSIFRoZSByZXN1bHQgdHlwZSByZXR1cm5lZCBmcm9tIGV4ZWN1dGlvbi5cbiAqIEBwYXJhbSB7VHlwZU9STUFkYXB0ZXJ9IGFkYXB0ZXIgVGhlIFR5cGVPUk0gYWRhcHRlci5cbiAqIEBjbGFzcyBUeXBlT1JNU3RhdGVtZW50XG4gKiBAZXhhbXBsZVxuICogLy8gRXhhbXBsZSB1c2luZyBUeXBlT1JNU3RhdGVtZW50XG4gKiBjb25zdCBzdGF0ZW1lbnQgPSBuZXcgVHlwZU9STVN0YXRlbWVudDxVc2VyLCBVc2VyW10+KGFkYXB0ZXIpO1xuICogY29uc3QgdXNlcnMgPSBhd2FpdCBzdGF0ZW1lbnRcbiAqICAgLmZyb20oVXNlcilcbiAqICAgLndoZXJlKENvbmRpdGlvbi5hdHRyaWJ1dGU8VXNlcj4oJ2FnZScpLmd0KDE4KSlcbiAqICAgLm9yZGVyQnkoJ2xhc3ROYW1lJywgJ2FzYycpXG4gKiAgIC5saW1pdCgxMClcbiAqICAgLmV4ZWN1dGUoKTtcbiAqL1xuZXhwb3J0IGNsYXNzIFR5cGVPUk1TdGF0ZW1lbnQ8TSBleHRlbmRzIE1vZGVsLCBSPiBleHRlbmRzIFN0YXRlbWVudDxcbiAgVHlwZU9STVF1ZXJ5PE0+LFxuICBNLFxuICBSXG4+IHtcbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGFkYXB0ZXIhOiBUeXBlT1JNQWRhcHRlcjtcblxuICBjb25zdHJ1Y3RvcihhZGFwdGVyOiBUeXBlT1JNQWRhcHRlcikge1xuICAgIHN1cGVyKGFkYXB0ZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBCdWlsZHMgYSBUeXBlT1JNIFNlbGVjdFF1ZXJ5QnVpbGRlciBmcm9tIHRoZSBzdGF0ZW1lbnQuXG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIHRoZSBzdGF0ZW1lbnQncyBjb25kaXRpb25zLCBzZWxlY3RvcnMsIGFuZCBvcHRpb25zIGludG8gYSBUeXBlT1JNLWJhY2tlZCBxdWVyeSBvYmplY3QuXG4gICAqIEByZXR1cm4ge1R5cGVPUk1RdWVyeX0gVGhlIGJ1aWx0IFR5cGVPUk0gcXVlcnkgY29udGFpbmVyLlxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlcmUgYXJlIGludmFsaWQgcXVlcnkgY29uZGl0aW9ucy5cbiAgICogQG1lcm1haWRcbiAgICogc2VxdWVuY2VEaWFncmFtXG4gICAqICAgcGFydGljaXBhbnQgU3RhdGVtZW50XG4gICAqICAgcGFydGljaXBhbnQgUmVwb3NpdG9yeVxuICAgKiAgIHBhcnRpY2lwYW50IHBhcnNlQ29uZGl0aW9uXG4gICAqXG4gICAqICAgU3RhdGVtZW50LT4+U3RhdGVtZW50OiBidWlsZCgpXG4gICAqICAgTm90ZSBvdmVyIFN0YXRlbWVudDogSW5pdGlhbGl6ZSBxdWVyeVxuICAgKiAgIFN0YXRlbWVudC0+PlJlcG9zaXRvcnk6IEdldCB0YWJsZSBuYW1lXG4gICAqICAgUmVwb3NpdG9yeS0tPj5TdGF0ZW1lbnQ6IFJldHVybiB0YWJsZSBuYW1lXG4gICAqICAgU3RhdGVtZW50LT4+U3RhdGVtZW50OiBDcmVhdGUgYmFzZSBxdWVyeVxuICAgKlxuICAgKiAgIGFsdCBIYXMgc2VsZWN0U2VsZWN0b3JcbiAgICogICAgIFN0YXRlbWVudC0+PlN0YXRlbWVudDogQWRkIGNvbHVtbnMgdG8gcXVlcnlcbiAgICogICBlbmRcbiAgICpcbiAgICogICBhbHQgSGFzIHdoZXJlQ29uZGl0aW9uXG4gICAqICAgICBTdGF0ZW1lbnQtPj5TdGF0ZW1lbnQ6IENyZWF0ZSBjb21iaW5lZCBjb25kaXRpb24gd2l0aCB0YWJsZVxuICAgKiAgICAgU3RhdGVtZW50LT4+cGFyc2VDb25kaXRpb246IFBhcnNlIGNvbmRpdGlvblxuICAgKiAgICAgcGFyc2VDb25kaXRpb24tLT4+U3RhdGVtZW50OiBSZXR1cm4gcGFyc2VkIGNvbmRpdGlvbnNcbiAgICogICAgIFN0YXRlbWVudC0+PlN0YXRlbWVudDogQWRkIGNvbmRpdGlvbnMgdG8gcXVlcnlcbiAgICogICBlbmRcbiAgICpcbiAgICogICBhbHQgSGFzIG9yZGVyQnlTZWxlY3RvclxuICAgKiAgICAgU3RhdGVtZW50LT4+U3RhdGVtZW50OiBBZGQgb3JkZXJCeSB0byBxdWVyeVxuICAgKiAgIGVuZFxuICAgKlxuICAgKiAgIGFsdCBIYXMgbGltaXRTZWxlY3RvclxuICAgKiAgICAgU3RhdGVtZW50LT4+U3RhdGVtZW50OiBTZXQgbGltaXRcbiAgICogICBlbHNlXG4gICAqICAgICBTdGF0ZW1lbnQtPj5TdGF0ZW1lbnQ6IFVzZSBkZWZhdWx0IGxpbWl0XG4gICAqICAgZW5kXG4gICAqXG4gICAqICAgYWx0IEhhcyBvZmZzZXRTZWxlY3RvclxuICAgKiAgICAgU3RhdGVtZW50LT4+U3RhdGVtZW50OiBTZXQgb2Zmc2V0XG4gICAqICAgZW5kXG4gICAqXG4gICAqICAgU3RhdGVtZW50LS0+PlN0YXRlbWVudDogUmV0dXJuIHF1ZXJ5XG4gICAqL1xuICBwcm90ZWN0ZWQgYnVpbGQoKTogVHlwZU9STVF1ZXJ5PE0+IHtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5idWlsZCk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gUmVwb3NpdG9yeS50YWJsZSh0aGlzLmZyb21TZWxlY3Rvcik7XG4gICAgY29uc3QgbSA9IG5ldyB0aGlzLmZyb21TZWxlY3RvcigpO1xuXG4gICAgY29uc3QgcTogVHlwZU9STVF1ZXJ5PE0sIFNlbGVjdFF1ZXJ5QnVpbGRlcjxNPj4gPSB7XG4gICAgICBxdWVyeTogdGhpcy5hZGFwdGVyLmRhdGFTb3VyY2VcbiAgICAgICAgLmdldFJlcG9zaXRvcnkoXG4gICAgICAgICAgdGhpcy5mcm9tU2VsZWN0b3JbTW9kZWxLZXlzLkFOQ0hPUiBhcyBrZXlvZiB0eXBlb2YgdGhpcy5mcm9tU2VsZWN0b3JdXG4gICAgICAgIClcbiAgICAgICAgLmNyZWF0ZVF1ZXJ5QnVpbGRlcih0YWJsZU5hbWUpIGFzIFNlbGVjdFF1ZXJ5QnVpbGRlcjxNPixcbiAgICB9O1xuXG4gICAgaWYgKHRoaXMuc2VsZWN0U2VsZWN0b3IpXG4gICAgICBxLnF1ZXJ5ID0gcS5xdWVyeS5zZWxlY3QoXG4gICAgICAgIHRoaXMuc2VsZWN0U2VsZWN0b3IubWFwKChzKSA9PiBgJHt0YWJsZU5hbWV9LiR7cyBhcyBzdHJpbmd9YClcbiAgICAgICk7XG4gICAgZWxzZSBxLnF1ZXJ5ID0gcS5xdWVyeS5zZWxlY3QoKTtcbiAgICAvL1xuICAgIC8vIHEucXVlcnkgPSAocS5xdWVyeSBhcyBTZWxlY3RRdWVyeUJ1aWxkZXI8YW55PikuZnJvbShcbiAgICAvLyAgIHRoaXMuZnJvbVNlbGVjdG9yW01vZGVsS2V5cy5BTkNIT1IgYXMga2V5b2YgdHlwZW9mIHRoaXMuZnJvbVNlbGVjdG9yXSxcbiAgICAvLyAgIHRhYmxlTmFtZVxuICAgIC8vICk7XG5cbiAgICBpZiAodGhpcy53aGVyZUNvbmRpdGlvbilcbiAgICAgIHEucXVlcnkgPSB0aGlzLnBhcnNlQ29uZGl0aW9uKFxuICAgICAgICB0aGlzLndoZXJlQ29uZGl0aW9uLFxuICAgICAgICB0YWJsZU5hbWUsXG4gICAgICAgIHEucXVlcnkgYXMgU2VsZWN0UXVlcnlCdWlsZGVyPGFueT5cbiAgICAgICkucXVlcnkgYXMgdW5rbm93biBhcyBTZWxlY3RRdWVyeUJ1aWxkZXI8TT47XG5cbiAgICBsZXQgb3JkZXJCeUFyZ3M6IFtzdHJpbmcsIFwiREVTQ1wiIHwgXCJBU0NcIl07XG4gICAgaWYgKCF0aGlzLm9yZGVyQnlTZWxlY3RvcilcbiAgICAgIG9yZGVyQnlBcmdzID0gW1xuICAgICAgICBgJHt0YWJsZU5hbWV9LiR7ZmluZFByaW1hcnlLZXkobSkuaWQgYXMgc3RyaW5nfWAsXG4gICAgICAgIE9yZGVyRGlyZWN0aW9uLkFTQy50b1VwcGVyQ2FzZSgpIGFzIFwiQVNDXCIsXG4gICAgICBdO1xuICAgIGVsc2VcbiAgICAgIG9yZGVyQnlBcmdzID0gW1xuICAgICAgICBgJHt0YWJsZU5hbWV9LiR7dGhpcy5vcmRlckJ5U2VsZWN0b3JbMF0gYXMgc3RyaW5nfWAsXG4gICAgICAgIHRoaXMub3JkZXJCeVNlbGVjdG9yWzFdLnRvVXBwZXJDYXNlKCkgYXMgXCJERVNDXCIgfCBcIkFTQ1wiLFxuICAgICAgXTtcblxuICAgIHEucXVlcnkgPSAocS5xdWVyeSBhcyBTZWxlY3RRdWVyeUJ1aWxkZXI8YW55Pikub3JkZXJCeSguLi5vcmRlckJ5QXJncyk7XG4gICAgaWYgKHRoaXMubGltaXRTZWxlY3Rvcikge1xuICAgICAgcS5xdWVyeSA9IChxLnF1ZXJ5IGFzIFNlbGVjdFF1ZXJ5QnVpbGRlcjxhbnk+KS5saW1pdCh0aGlzLmxpbWl0U2VsZWN0b3IpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGBObyBsaW1pdCBzZWxlY3RvciBkZWZpbmVkLiBVc2luZyBkZWZhdWx0IGxpbWl0IG9mICR7VHlwZU9STVF1ZXJ5TGltaXR9YFxuICAgICAgKTtcbiAgICAgIHEucXVlcnkgPSAocS5xdWVyeSBhcyBTZWxlY3RRdWVyeUJ1aWxkZXI8YW55PikubGltaXQoVHlwZU9STVF1ZXJ5TGltaXQpO1xuICAgIH1cblxuICAgIC8vIEFkZCBvZmZzZXRcbiAgICBpZiAodGhpcy5vZmZzZXRTZWxlY3RvcilcbiAgICAgIHEucXVlcnkgPSAocS5xdWVyeSBhcyBTZWxlY3RRdWVyeUJ1aWxkZXI8YW55Pikuc2tpcCh0aGlzLm9mZnNldFNlbGVjdG9yKTtcblxuICAgIHJldHVybiBxIGFzIGFueTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIHBhZ2luYXRvciBmb3IgdGhlIHN0YXRlbWVudC5cbiAgICogQHN1bW1hcnkgQnVpbGRzIHRoZSBxdWVyeSBhbmQgcmV0dXJucyBhIFR5cGVPUk1QYWdpbmF0b3IgZm9yIHBhZ2luYXRlZCByZXN1bHRzLlxuICAgKiBAdGVtcGxhdGUgUiBUaGUgcmVzdWx0IHR5cGUuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzaXplIFRoZSBwYWdlIHNpemUuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8UGFnaW5hdG9yPE0sIFIsIFR5cGVPUk1RdWVyeT4+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIHBhZ2luYXRvci5cbiAgICogQHRocm93cyB7SW50ZXJuYWxFcnJvcn0gSWYgdGhlcmUncyBhbiBlcnJvciBidWlsZGluZyB0aGUgcXVlcnkuXG4gICAqL1xuICBhc3luYyBwYWdpbmF0ZTxSPihzaXplOiBudW1iZXIpOiBQcm9taXNlPFBhZ2luYXRvcjxNLCBSLCBUeXBlT1JNUXVlcnk+PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHF1ZXJ5OiBUeXBlT1JNUXVlcnkgPSB0aGlzLmJ1aWxkKCk7XG4gICAgICBjb25zdCB0cmFuc2Zvcm1lZFF1ZXJ5OiBGaW5kTWFueU9wdGlvbnM8TT4gPSB7fTtcbiAgICAgIGNvbnN0IGEgPSBxdWVyeS5xdWVyeSBhcyB1bmtub3duIGFzIFNlbGVjdFF1ZXJ5QnVpbGRlcjxNPjtcbiAgICAgIGlmICh0aGlzLndoZXJlQ29uZGl0aW9uKVxuICAgICAgICB0cmFuc2Zvcm1lZFF1ZXJ5LndoZXJlID0gdGhpcy5wYXJzZUNvbmRpdGlvbkZvclBhZ2luYXRpb24oXG4gICAgICAgICAgdGhpcy53aGVyZUNvbmRpdGlvbixcbiAgICAgICAgICBSZXBvc2l0b3J5LnRhYmxlKHRoaXMuZnJvbVNlbGVjdG9yKVxuICAgICAgICApO1xuXG4gICAgICBpZiAodGhpcy5vcmRlckJ5U2VsZWN0b3IpXG4gICAgICAgIHRyYW5zZm9ybWVkUXVlcnkub3JkZXIgPSB7XG4gICAgICAgICAgW3RoaXMub3JkZXJCeVNlbGVjdG9yWzBdXTogdGhpcy5vcmRlckJ5U2VsZWN0b3JbMV0udG9TdHJpbmcoKSxcbiAgICAgICAgfSBhcyBhbnk7XG5cbiAgICAgIHJldHVybiBuZXcgVHlwZU9STVBhZ2luYXRvcihcbiAgICAgICAgdGhpcy5hZGFwdGVyIGFzIGFueSxcbiAgICAgICAgdHJhbnNmb3JtZWRRdWVyeSBhcyBhbnksXG4gICAgICAgIHNpemUsXG4gICAgICAgIHRoaXMuZnJvbVNlbGVjdG9yXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcm9jZXNzZXMgYSByZWNvcmQuXG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIGEgcmF3IHJlc3VsdCByb3cgdG8gYSBtb2RlbCBpbnN0YW5jZSB1c2luZyB0aGUgYWRhcHRlci5cbiAgICogQHBhcmFtIHthbnl9IHIgVGhlIHJhdyByZWNvcmQuXG4gICAqIEBwYXJhbSB7a2V5b2YgTX0gcGtBdHRyIFRoZSBwcmltYXJ5IGtleSBhdHRyaWJ1dGUgb2YgdGhlIG1vZGVsLlxuICAgKiBAcGFyYW0ge1wiTnVtYmVyXCIgfCBcIkJpZ0ludFwiIHwgdW5kZWZpbmVkfSBzZXF1ZW5jZVR5cGUgVGhlIHR5cGUgb2YgdGhlIHNlcXVlbmNlLlxuICAgKiBAcmV0dXJuIHthbnl9IFRoZSBwcm9jZXNzZWQgcmVjb3JkLlxuICAgKi9cbiAgcHJpdmF0ZSBwcm9jZXNzUmVjb3JkKHI6IGFueSwgcGtBdHRyOiBrZXlvZiBNKSB7XG4gICAgaWYgKHR5cGVvZiByW3BrQXR0cl0gIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgIHJldHVybiB0aGlzLmFkYXB0ZXIucmV2ZXJ0KHIsIHRoaXMuZnJvbVNlbGVjdG9yLCBwa0F0dHIsIHJbcGtBdHRyXSk7XG4gICAgfVxuICAgIHJldHVybiByO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBFeGVjdXRlcyBhIHJhdyBUeXBlT1JNIHF1ZXJ5IGJ1aWxkZXIuXG4gICAqIEBzdW1tYXJ5IFNlbmRzIHRoZSBidWlsdCBTZWxlY3RRdWVyeUJ1aWxkZXIgdG8gdGhlIGRhdGFiYXNlIHZpYSBUeXBlT1JNIGFuZCByZXR1cm5zIHRoZSByZXN1bHRzLlxuICAgKiBAdGVtcGxhdGUgUiBUaGUgcmVzdWx0IHR5cGUuXG4gICAqIEBwYXJhbSB7VHlwZU9STVF1ZXJ5fSByYXdJbnB1dCBUaGUgcXVlcnkgY29udGFpbmVyIHRvIGV4ZWN1dGUuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Uj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBxdWVyeSByZXN1bHRzLlxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgcmF3PFI+KHJhd0lucHV0OiBUeXBlT1JNUXVlcnk8TT4pOiBQcm9taXNlPFI+IHtcbiAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5yYXcpO1xuICAgIGxvZy5kZWJ1ZyhcbiAgICAgIGBFeGVjdXRpbmcgcmF3IHF1ZXJ5OiAkeyhyYXdJbnB1dC5xdWVyeSBhcyB1bmtub3duIGFzIFNlbGVjdFF1ZXJ5QnVpbGRlcjxNPikuZ2V0U3FsKCl9YFxuICAgICk7XG4gICAgcmV0dXJuIChhd2FpdCAoXG4gICAgICByYXdJbnB1dC5xdWVyeSBhcyB1bmtub3duIGFzIFNlbGVjdFF1ZXJ5QnVpbGRlcjxNPlxuICAgICkuZ2V0TWFueSgpKSBhcyBSO1xuICB9XG5cbiAgcHJvdGVjdGVkIHBhcnNlQ29uZGl0aW9uRm9yUGFnaW5hdGlvbihcbiAgICBjb25kaXRpb246IENvbmRpdGlvbjxNPixcbiAgICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICBjb3VudGVyID0gMCxcbiAgICBjb25kaXRpb25hbE9wPzogR3JvdXBPcGVyYXRvciB8IE9wZXJhdG9yXG4gICk6IEZpbmRPcHRpb25zV2hlcmU8TT5bXSB8IEZpbmRPcHRpb25zV2hlcmU8TT4ge1xuICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiTm90IGltcGxlbWVudGVkXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQYXJzZXMgYSBjb25kaXRpb24gaW50byBQb3N0Z3JlU1FMIGNvbmRpdGlvbnNcbiAgICogQHN1bW1hcnkgQ29udmVydHMgYSBDb25kaXRpb24gb2JqZWN0IGludG8gUG9zdGdyZVNRTCBjb25kaXRpb24gc3RydWN0dXJlc1xuICAgKiBAcGFyYW0ge0NvbmRpdGlvbjxNPn0gY29uZGl0aW9uIC0gVGhlIGNvbmRpdGlvbiB0byBwYXJzZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3RhYmxlTmFtZV0gLSB0aGUgcG9zaXRpb25hbCBpbmRleCBvZiB0aGUgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1R5cGVPUk1RdWVyeX0gVGhlIFBvc3RncmVzU1FMIGNvbmRpdGlvblxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBTdGF0ZW1lbnRcbiAgICogICBwYXJ0aWNpcGFudCB0cmFuc2xhdGVPcGVyYXRvcnNcbiAgICogICBwYXJ0aWNpcGFudCBwYXJzZUNvbmRpdGlvblxuICAgKlxuICAgKiAgIFN0YXRlbWVudC0+PlN0YXRlbWVudDogcGFyc2VDb25kaXRpb24oY29uZGl0aW9uKVxuICAgKlxuICAgKiAgIE5vdGUgb3ZlciBTdGF0ZW1lbnQ6IEV4dHJhY3QgY29uZGl0aW9uIHBhcnRzXG4gICAqXG4gICAqICAgYWx0IFNpbXBsZSBjb21wYXJpc29uIG9wZXJhdG9yXG4gICAqICAgICBTdGF0ZW1lbnQtPj50cmFuc2xhdGVPcGVyYXRvcnM6IHRyYW5zbGF0ZU9wZXJhdG9ycyhvcGVyYXRvcilcbiAgICogICAgIHRyYW5zbGF0ZU9wZXJhdG9ycy0tPj5TdGF0ZW1lbnQ6IFJldHVybiBQb3N0Z3JlU1FMIG9wZXJhdG9yXG4gICAqICAgICBTdGF0ZW1lbnQtPj5TdGF0ZW1lbnQ6IENyZWF0ZSBjb25kaXRpb24gd2l0aCBjb2x1bW4sIG9wZXJhdG9yLCBhbmQgdmFsdWVcbiAgICogICBlbHNlIE5PVCBvcGVyYXRvclxuICAgKiAgICAgU3RhdGVtZW50LT4+U3RhdGVtZW50OiBwYXJzZUNvbmRpdGlvbihhdHRyMSlcbiAgICogICAgIFN0YXRlbWVudC0+PlN0YXRlbWVudDogQWRkIE5PVCB0byBjb25kaXRpb25zXG4gICAqICAgZWxzZSBBTkQvT1Igb3BlcmF0b3JcbiAgICogICAgIFN0YXRlbWVudC0+PlN0YXRlbWVudDogcGFyc2VDb25kaXRpb24oYXR0cjEpXG4gICAqICAgICBTdGF0ZW1lbnQtPj5TdGF0ZW1lbnQ6IHBhcnNlQ29uZGl0aW9uKGNvbXBhcmlzb24pXG4gICAqICAgICBTdGF0ZW1lbnQtPj5TdGF0ZW1lbnQ6IENvbWJpbmUgY29uZGl0aW9ucyB3aXRoIEFORC9PUlxuICAgKiAgIGVuZFxuICAgKlxuICAgKiAgIFN0YXRlbWVudC0tPj5TdGF0ZW1lbnQ6IFJldHVybiBjb25kaXRpb25zIGFycmF5XG4gICAqL1xuICBwcm90ZWN0ZWQgcGFyc2VDb25kaXRpb24oXG4gICAgY29uZGl0aW9uOiBDb25kaXRpb248TT4sXG4gICAgdGFibGVOYW1lOiBzdHJpbmcsXG4gICAgcWI6IFNlbGVjdFF1ZXJ5QnVpbGRlcjxhbnk+LFxuICAgIGNvdW50ZXIgPSAwLFxuICAgIGNvbmRpdGlvbmFsT3A/OiBHcm91cE9wZXJhdG9yIHwgT3BlcmF0b3JcbiAgKTogVHlwZU9STVF1ZXJ5PE0+IHtcbiAgICBjb25zdCB7IGF0dHIxLCBvcGVyYXRvciwgY29tcGFyaXNvbiB9ID0gY29uZGl0aW9uIGFzIHVua25vd24gYXMge1xuICAgICAgYXR0cjE6IHN0cmluZyB8IENvbmRpdGlvbjxNPjtcbiAgICAgIG9wZXJhdG9yOiBPcGVyYXRvciB8IEdyb3VwT3BlcmF0b3I7XG4gICAgICBjb21wYXJpc29uOiBhbnk7XG4gICAgfTtcblxuICAgIGZ1bmN0aW9uIHBhcnNlKCk6IFR5cGVPUk1RdWVyeTxNPiB7XG4gICAgICBjb25zdCBzcWxPcGVyYXRvciA9IHRyYW5zbGF0ZU9wZXJhdG9ycyhvcGVyYXRvcik7XG4gICAgICBjb25zdCBhdHRyUmVmID0gYCR7YXR0cjF9JHtjb3VudGVyfWA7XG4gICAgICBjb25zdCBxdWVyeVN0ciA9IGAke3RhYmxlTmFtZX0uJHthdHRyMX0gJHtzcWxPcGVyYXRvcn0gOiR7YXR0clJlZn1gO1xuICAgICAgY29uc3QgdmFsdWVzID0ge1xuICAgICAgICBbYXR0clJlZl06IGNvbXBhcmlzb24sXG4gICAgICB9O1xuICAgICAgc3dpdGNoIChjb25kaXRpb25hbE9wKSB7XG4gICAgICAgIGNhc2UgR3JvdXBPcGVyYXRvci5BTkQ6XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHF1ZXJ5OiBxYi5hbmRXaGVyZShxdWVyeVN0ciwgdmFsdWVzKSBhcyBhbnksXG4gICAgICAgICAgfTtcbiAgICAgICAgY2FzZSBHcm91cE9wZXJhdG9yLk9SOlxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBxdWVyeTogcWIub3JXaGVyZShxdWVyeVN0ciwgdmFsdWVzKSBhcyBhbnksXG4gICAgICAgICAgfTtcbiAgICAgICAgY2FzZSBPcGVyYXRvci5OT1Q6XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTk9UIG9wZXJhdG9yIG5vdCBpbXBsZW1lbnRlZFwiKTtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgcXVlcnk6IHFiLndoZXJlKHF1ZXJ5U3RyLCB2YWx1ZXMpIGFzIGFueSxcbiAgICAgICAgICB9O1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChcbiAgICAgIFtHcm91cE9wZXJhdG9yLkFORCwgR3JvdXBPcGVyYXRvci5PUiwgT3BlcmF0b3IuTk9UXS5pbmRleE9mKFxuICAgICAgICBvcGVyYXRvciBhcyBHcm91cE9wZXJhdG9yXG4gICAgICApID09PSAtMVxuICAgICkge1xuICAgICAgcmV0dXJuIHBhcnNlKCk7XG4gICAgfVxuICAgIC8vIEZvciBOT1Qgb3BlcmF0b3JcbiAgICBlbHNlIGlmIChvcGVyYXRvciA9PT0gT3BlcmF0b3IuTk9UKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJOT1Qgb3BlcmF0b3Igbm90IGltcGxlbWVudGVkXCIpO1xuICAgIH1cbiAgICAvLyBGb3IgQU5EL09SIG9wZXJhdG9yc1xuICAgIGVsc2Uge1xuICAgICAgcWIgPSB0aGlzLnBhcnNlQ29uZGl0aW9uKGF0dHIxIGFzIENvbmRpdGlvbjxNPiwgdGFibGVOYW1lLCBxYiwgKytjb3VudGVyKVxuICAgICAgICAucXVlcnkgYXMgdW5rbm93biBhcyBTZWxlY3RRdWVyeUJ1aWxkZXI8TT47XG4gICAgICByZXR1cm4gdGhpcy5wYXJzZUNvbmRpdGlvbihcbiAgICAgICAgY29tcGFyaXNvbixcbiAgICAgICAgdGFibGVOYW1lLFxuICAgICAgICBxYixcbiAgICAgICAgKytjb3VudGVyLFxuICAgICAgICBvcGVyYXRvclxuICAgICAgKTtcbiAgICB9XG4gIH1cbn1cbiIsImltcG9ydCB7IEludGVybmFsRXJyb3IsIE5vdEZvdW5kRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IFNlcXVlbmNlT3B0aW9ucyB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgU2VxdWVuY2UgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IFR5cGVPUk1BZGFwdGVyIH0gZnJvbSBcIi4uL1R5cGVPUk1BZGFwdGVyXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEFic3RyYWN0IGltcGxlbWVudGF0aW9uIG9mIGEgZGF0YWJhc2Ugc2VxdWVuY2UgZm9yIFR5cGVPUk0uXG4gKiBAc3VtbWFyeSBQcm92aWRlcyB0aGUgYmFzaWMgZnVuY3Rpb25hbGl0eSBmb3Ige0BsaW5rIFNlcXVlbmNlfXMsIGRlbGVnYXRpbmcgdG8gdGhlIHtAbGluayBUeXBlT1JNQWRhcHRlcn0gdG8gZmV0Y2ggYW5kIGluY3JlbWVudCB2YWx1ZXMgd2hpbGUgaGFuZGxpbmcgdHlwZSBwYXJzaW5nIGFuZCBlcnJvciB0cmFuc2xhdGlvbi5cbiAqIEBwYXJhbSB7U2VxdWVuY2VPcHRpb25zfSBvcHRpb25zIFRoZSBzZXF1ZW5jZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgKG5hbWUsIHR5cGUsIHN0YXJ0V2l0aCwgaW5jcmVtZW50QnksIGV0Yy4pLlxuICogQHBhcmFtIHtUeXBlT1JNQWRhcHRlcn0gYWRhcHRlciBUaGUgVHlwZU9STSBhZGFwdGVyIHVzZWQgdG8gZXhlY3V0ZSBzZXF1ZW5jZSBvcGVyYXRpb25zLlxuICogQGNsYXNzIFR5cGVPUk1TZXF1ZW5jZVxuICogQGltcGxlbWVudHMgU2VxdWVuY2VcbiAqIEBleGFtcGxlXG4gKiAvLyBDcmVhdGUgYW5kIHVzZSBhIFR5cGVPUk0tYmFja2VkIHNlcXVlbmNlXG4gKiBjb25zdCBzZXEgPSBuZXcgVHlwZU9STVNlcXVlbmNlKHsgbmFtZTogXCJ1c2VyX2lkX3NlcVwiLCB0eXBlOiBcIk51bWJlclwiLCBzdGFydFdpdGg6IDEsIGluY3JlbWVudEJ5OiAxIH0sIGFkYXB0ZXIpO1xuICogY29uc3QgbmV4dElkID0gYXdhaXQgc2VxLm5leHQoKTtcbiAqXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBTZXEgYXMgVHlwZU9STVNlcXVlbmNlXG4gKiAgIHBhcnRpY2lwYW50IEFkYXB0ZXIgYXMgVHlwZU9STUFkYXB0ZXJcbiAqICAgcGFydGljaXBhbnQgREIgYXMgRGF0YWJhc2VcbiAqICAgQXBwLT4+U2VxOiBuZXh0KClcbiAqICAgU2VxLT4+U2VxOiBjdXJyZW50KClcbiAqICAgU2VxLT4+QWRhcHRlcjogcmF3KFNFTEVDVCBjdXJyZW50X3ZhbHVlIC4uLilcbiAqICAgQWRhcHRlci0+PkRCOiBRdWVyeSBjdXJyZW50IHZhbHVlXG4gKiAgIERCLS0+PkFkYXB0ZXI6IGN1cnJlbnRfdmFsdWVcbiAqICAgQWRhcHRlci0tPj5TZXE6IHZhbHVlXG4gKiAgIFNlcS0+PlNlcTogaW5jcmVtZW50KGN1cnJlbnQpXG4gKiAgIFNlcS0+PkFkYXB0ZXI6IHJhdyhuZXh0dmFsKG5hbWUpKVxuICogICBBZGFwdGVyLT4+REI6IG5leHR2YWwoKVxuICogICBEQi0tPj5BZGFwdGVyOiBuZXh0IHZhbHVlXG4gKiAgIEFkYXB0ZXItLT4+U2VxOiB2YWx1ZVxuICogICBTZXEtLT4+QXBwOiBwYXJzZWQgbmV4dCB2YWx1ZVxuICovXG5leHBvcnQgY2xhc3MgVHlwZU9STVNlcXVlbmNlIGV4dGVuZHMgU2VxdWVuY2Uge1xuICBjb25zdHJ1Y3RvcihcbiAgICBvcHRpb25zOiBTZXF1ZW5jZU9wdGlvbnMsXG4gICAgcHJvdGVjdGVkIGFkYXB0ZXI6IFR5cGVPUk1BZGFwdGVyXG4gICkge1xuICAgIHN1cGVyKG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFJldHJpZXZlcyB0aGUgY3VycmVudCB2YWx1ZSBmb3IgdGhlIHNlcXVlbmNlXG4gICAqIEBwcm90ZWN0ZWRcbiAgICovXG4gIGFzeW5jIGN1cnJlbnQoKTogUHJvbWlzZTxzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnQ+IHtcbiAgICBjb25zdCB7IG5hbWUgfSA9IHRoaXMub3B0aW9ucztcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc2VxOiBhbnkgPSBhd2FpdCB0aGlzLmFkYXB0ZXIucmF3KHtcbiAgICAgICAgcXVlcnk6IGBTRUxFQ1QgY3VycmVudF92YWx1ZSBGUk9NIGluZm9ybWF0aW9uX3NjaGVtYS5zZXF1ZW5jZXMgV0hFUkUgc2VxdWVuY2VfbmFtZSA9ICQxYCxcbiAgICAgICAgdmFsdWVzOiBbbmFtZV0sXG4gICAgICB9KTtcbiAgICAgIHJldHVybiB0aGlzLnBhcnNlKHNlcS5jdXJyZW50X3ZhbHVlIGFzIHN0cmluZyB8IG51bWJlcik7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgdGhpcy5hZGFwdGVyLnBhcnNlRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFBhcnNlcyB0aGUge0BsaW5rIFNlcXVlbmNlfSB2YWx1ZVxuICAgKlxuICAgKiBAcHJvdGVjdGVkXG4gICAqIEBwYXJhbSB2YWx1ZVxuICAgKi9cbiAgcHJpdmF0ZSBwYXJzZSh2YWx1ZTogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50KTogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50IHtcbiAgICByZXR1cm4gU2VxdWVuY2UucGFyc2VWYWx1ZSh0aGlzLm9wdGlvbnMudHlwZSwgdmFsdWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IGluY3JlbWVudHMgdGhlIHNlcXVlbmNlXG4gICAqIEBkZXNjcmlwdGlvbiBTZXF1ZW5jZSBzcGVjaWZpYyBpbXBsZW1lbnRhdGlvblxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZyB8IG51bWJlciB8IGJpZ2ludH0gY3VycmVudFxuICAgKiBAcGFyYW0gY291bnRcbiAgICogQHByb3RlY3RlZFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBpbmNyZW1lbnQoXG4gICAgY3VycmVudDogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50LFxuICAgIGNvdW50PzogbnVtYmVyXG4gICk6IFByb21pc2U8c3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50PiB7XG4gICAgY29uc3QgeyB0eXBlLCBpbmNyZW1lbnRCeSwgbmFtZSwgc3RhcnRXaXRoIH0gPSB0aGlzLm9wdGlvbnM7XG4gICAgaWYgKHR5cGUgIT09IFwiTnVtYmVyXCIgJiYgdHlwZSAhPT0gXCJCaWdJbnRcIilcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICBgQ2Fubm90IGluY3JlbWVudCBzZXF1ZW5jZSBvZiB0eXBlICR7dHlwZX0gd2l0aCAke2NvdW50fWBcbiAgICAgICk7XG4gICAgbGV0IG5leHQ6IHN0cmluZyB8IG51bWJlciB8IGJpZ2ludDtcbiAgICB0cnkge1xuICAgICAgbmV4dCA9IGF3YWl0IHRoaXMuYWRhcHRlci5yYXcoe1xuICAgICAgICBxdWVyeTogYFNFTEVDVCBuZXh0dmFsKCQxKTtgLFxuICAgICAgICB2YWx1ZXM6IFtuYW1lXSxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGlmICghKGUgaW5zdGFuY2VvZiBOb3RGb3VuZEVycm9yKSkgdGhyb3cgZTtcbiAgICAgIG5leHQgPSBhd2FpdCB0aGlzLmFkYXB0ZXIucmF3KHtcbiAgICAgICAgcXVlcnk6IGBDUkVBVEUgU0VRVUVOQ0UgSUYgTk9UIEVYSVNUUyAkMSBTVEFSVCBXSVRIICQyIElOQ1JFTUVOVCBCWSAkMyBOTyBDWUNMRTtgLFxuICAgICAgICB2YWx1ZXM6IFtuYW1lLCBzdGFydFdpdGgsIGluY3JlbWVudEJ5XSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBuZXh0IGFzIHN0cmluZyB8IG51bWJlciB8IGJpZ2ludDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAc3VtbWFyeSBHZW5lcmF0ZXMgdGhlIG5leHQgdmFsdWUgaW4gdGggc2VxdWVuY2VcbiAgICogQGRlc2NyaXB0aW9uIGNhbGxzIHtAbGluayBTZXF1ZW5jZSNwYXJzZX0gb24gdGhlIGN1cnJlbnQgdmFsdWVcbiAgICogZm9sbG93ZWQgYnkge0BsaW5rIFNlcXVlbmNlI2luY3JlbWVudH1cbiAgICpcbiAgICovXG4gIGFzeW5jIG5leHQoKTogUHJvbWlzZTxudW1iZXIgfCBzdHJpbmcgfCBiaWdpbnQ+IHtcbiAgICBjb25zdCBjdXJyZW50ID0gYXdhaXQgdGhpcy5jdXJyZW50KCk7XG4gICAgcmV0dXJuIHRoaXMuaW5jcmVtZW50KGN1cnJlbnQpO1xuICB9XG5cbiAgYXN5bmMgcmFuZ2UoY291bnQ6IG51bWJlcik6IFByb21pc2U8KG51bWJlciB8IHN0cmluZyB8IGJpZ2ludClbXT4ge1xuICAgIGNvbnN0IGN1cnJlbnQgPSAoYXdhaXQgdGhpcy5jdXJyZW50KCkpIGFzIG51bWJlcjtcbiAgICBjb25zdCBpbmNyZW1lbnRCeSA9IHRoaXMucGFyc2UodGhpcy5vcHRpb25zLmluY3JlbWVudEJ5KSBhcyBudW1iZXI7XG4gICAgY29uc3QgbmV4dDogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50ID0gYXdhaXQgdGhpcy5pbmNyZW1lbnQoXG4gICAgICBjdXJyZW50LFxuICAgICAgKHRoaXMucGFyc2UoY291bnQpIGFzIG51bWJlcikgKiBpbmNyZW1lbnRCeVxuICAgICk7XG4gICAgY29uc3QgcmFuZ2U6IChudW1iZXIgfCBzdHJpbmcgfCBiaWdpbnQpW10gPSBbXTtcbiAgICBmb3IgKGxldCBpOiBudW1iZXIgPSAxOyBpIDw9IGNvdW50OyBpKyspIHtcbiAgICAgIHJhbmdlLnB1c2goY3VycmVudCArIGluY3JlbWVudEJ5ICogKHRoaXMucGFyc2UoaSkgYXMgbnVtYmVyKSk7XG4gICAgfVxuICAgIGlmIChyYW5nZVtyYW5nZS5sZW5ndGggLSAxXSAhPT0gbmV4dClcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiTWlzY2FsY3VsYXRpb24gb2YgcmFuZ2VcIik7XG4gICAgcmV0dXJuIHJhbmdlO1xuICB9XG59XG4iLCJpbXBvcnQge1xuICBJbmRleE1ldGFkYXRhLFxuICBPcmRlckRpcmVjdGlvbixcbiAgUGVyc2lzdGVuY2VLZXlzLFxuICBSZXBvc2l0b3J5LFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IFR5cGVPUk1LZXlzIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgRGVmYXVsdFNlcGFyYXRvciB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IsIE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgVHlwZU9STVF1ZXJ5IH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEdlbmVyYXRlcyBhIG5hbWUgZm9yIGEgQ291Y2hEQiBpbmRleFxuICogQHN1bW1hcnkgQ3JlYXRlcyBhIHN0YW5kYXJkaXplZCBuYW1lIGZvciBhIENvdWNoREIgaW5kZXggYnkgY29tYmluaW5nIG5hbWUgcGFydHMsIGNvbXBvc2l0aW9ucywgYW5kIGRpcmVjdGlvblxuICogQHBhcmFtIHtzdHJpbmdbXX0gbmFtZSAtIEFycmF5IG9mIG5hbWUgcGFydHMgZm9yIHRoZSBpbmRleFxuICogQHBhcmFtIHtPcmRlckRpcmVjdGlvbn0gW2RpcmVjdGlvbl0gLSBPcHRpb25hbCBzb3J0IGRpcmVjdGlvbiBmb3IgdGhlIGluZGV4XG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBbY29tcG9zaXRpb25zXSAtIE9wdGlvbmFsIGFkZGl0aW9uYWwgYXR0cmlidXRlcyB0byBpbmNsdWRlIGluIHRoZSBpbmRleCBuYW1lXG4gKiBAcGFyYW0ge3N0cmluZ30gW3NlcGFyYXRvcj1EZWZhdWx0U2VwYXJhdG9yXSAtIFRoZSBzZXBhcmF0b3IgdG8gdXNlIGJldHdlZW4gcGFydHMgb2YgdGhlIGluZGV4IG5hbWVcbiAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGdlbmVyYXRlZCBpbmRleCBuYW1lXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci1jb3VjaGRiXG4gKi9cbmZ1bmN0aW9uIGdlbmVyYXRlSW5kZXhOYW1lKFxuICBuYW1lOiBzdHJpbmdbXSxcbiAgZGlyZWN0aW9uPzogT3JkZXJEaXJlY3Rpb24sXG4gIGNvbXBvc2l0aW9ucz86IHN0cmluZ1tdLFxuICBzZXBhcmF0b3IgPSBEZWZhdWx0U2VwYXJhdG9yXG4pIHtcbiAgcmV0dXJuIFtcbiAgICAuLi5uYW1lLm1hcCgobikgPT4gKG4gPT09IFR5cGVPUk1LZXlzLlRBQkxFID8gXCJ0YWJsZVwiIDogbikpLFxuICAgIC4uLihjb21wb3NpdGlvbnMgfHwgW10pLFxuICAgIC4uLihkaXJlY3Rpb24gPyBbZGlyZWN0aW9uXSA6IFtdKSxcbiAgICBUeXBlT1JNS2V5cy5JTkRFWCxcbiAgXS5qb2luKHNlcGFyYXRvcik7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEdlbmVyYXRlcyBDb3VjaERCIGluZGV4IGNvbmZpZ3VyYXRpb25zIGZvciBtb2RlbHNcbiAqIEBzdW1tYXJ5IENyZWF0ZXMgYSBzZXQgb2YgQ291Y2hEQiBpbmRleCBjb25maWd1cmF0aW9ucyBiYXNlZCBvbiB0aGUgbWV0YWRhdGEgb2YgdGhlIHByb3ZpZGVkIG1vZGVsc1xuICogQHRlbXBsYXRlIE0gLSBUaGUgbW9kZWwgdHlwZSB0aGF0IGV4dGVuZHMgTW9kZWxcbiAqIEBwYXJhbSBtb2RlbHMgLSBBcnJheSBvZiBtb2RlbCBjb25zdHJ1Y3RvcnMgdG8gZ2VuZXJhdGUgaW5kZXhlcyBmb3JcbiAqIEByZXR1cm4ge1R5cGVPUk1RdWVyeX0gQXJyYXkgb2YgQ291Y2hEQiBpbmRleCBjb25maWd1cmF0aW9uc1xuICogQGZ1bmN0aW9uIGdlbmVyYXRlSW5kZXhlc1xuICogQG1lbWJlck9mIG1vZHVsZTpmb3ItY291Y2hkYlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAqICAgcGFydGljaXBhbnQgZ2VuZXJhdGVJbmRleGVzXG4gKiAgIHBhcnRpY2lwYW50IGdlbmVyYXRlSW5kZXhOYW1lXG4gKiAgIHBhcnRpY2lwYW50IFJlcG9zaXRvcnlcbiAqXG4gKiAgIENhbGxlci0+PmdlbmVyYXRlSW5kZXhlczogbW9kZWxzXG4gKlxuICogICBOb3RlIG92ZXIgZ2VuZXJhdGVJbmRleGVzOiBDcmVhdGUgYmFzZSB0YWJsZSBpbmRleFxuICogICBnZW5lcmF0ZUluZGV4ZXMtPj5nZW5lcmF0ZUluZGV4TmFtZTogW0NvdWNoREJLZXlzLlRBQkxFXVxuICogICBnZW5lcmF0ZUluZGV4TmFtZS0tPj5nZW5lcmF0ZUluZGV4ZXM6IHRhYmxlTmFtZVxuICogICBnZW5lcmF0ZUluZGV4ZXMtPj5nZW5lcmF0ZUluZGV4ZXM6IENyZWF0ZSB0YWJsZSBpbmRleCBjb25maWdcbiAqXG4gKiAgIGxvb3AgRm9yIGVhY2ggbW9kZWxcbiAqICAgICBnZW5lcmF0ZUluZGV4ZXMtPj5SZXBvc2l0b3J5OiBHZXQgaW5kZXhlcyBtZXRhZGF0YVxuICogICAgIFJlcG9zaXRvcnktLT4+Z2VuZXJhdGVJbmRleGVzOiBpbmRleCBtZXRhZGF0YVxuICpcbiAqICAgICBsb29wIEZvciBlYWNoIGluZGV4IGluIG1ldGFkYXRhXG4gKiAgICAgICBOb3RlIG92ZXIgZ2VuZXJhdGVJbmRleGVzOiBFeHRyYWN0IGluZGV4IHByb3BlcnRpZXNcbiAqICAgICAgIGdlbmVyYXRlSW5kZXhlcy0+PlJlcG9zaXRvcnk6IEdldCB0YWJsZSBuYW1lXG4gKiAgICAgICBSZXBvc2l0b3J5LS0+PmdlbmVyYXRlSW5kZXhlczogdGFibGVOYW1lXG4gKlxuICogICAgICAgTm90ZSBvdmVyIGdlbmVyYXRlSW5kZXhlczogRGVmaW5lIG5lc3RlZCBnZW5lcmF0ZSBmdW5jdGlvblxuICpcbiAqICAgICAgIGdlbmVyYXRlSW5kZXhlcy0+PmdlbmVyYXRlSW5kZXhlczogQ2FsbCBnZW5lcmF0ZSgpIGZvciBkZWZhdWx0IG9yZGVyXG4gKiAgICAgICBOb3RlIG92ZXIgZ2VuZXJhdGVJbmRleGVzOiBDcmVhdGUgaW5kZXggbmFtZSBhbmQgY29uZmlnXG4gKlxuICogICAgICAgYWx0IEhhcyBkaXJlY3Rpb25zXG4gKiAgICAgICAgIGxvb3AgRm9yIGVhY2ggZGlyZWN0aW9uXG4gKiAgICAgICAgICAgZ2VuZXJhdGVJbmRleGVzLT4+Z2VuZXJhdGVJbmRleGVzOiBDYWxsIGdlbmVyYXRlKGRpcmVjdGlvbilcbiAqICAgICAgICAgICBOb3RlIG92ZXIgZ2VuZXJhdGVJbmRleGVzOiBDcmVhdGUgb3JkZXJlZCBpbmRleCBjb25maWdcbiAqICAgICAgICAgZW5kXG4gKiAgICAgICBlbmRcbiAqICAgICBlbmRcbiAqICAgZW5kXG4gKlxuICogICBnZW5lcmF0ZUluZGV4ZXMtLT4+Q2FsbGVyOiBBcnJheSBvZiBpbmRleCBjb25maWd1cmF0aW9uc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVJbmRleGVzPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG1vZGVsczogQ29uc3RydWN0b3I8TT5bXVxuKTogVHlwZU9STVF1ZXJ5W10ge1xuICBjb25zdCB0YWJsZU5hbWUgPSBnZW5lcmF0ZUluZGV4TmFtZShbVHlwZU9STUtleXMuVEFCTEVdKTtcbiAgY29uc3QgaW5kZXhlczogUmVjb3JkPHN0cmluZywgVHlwZU9STVF1ZXJ5PiA9IHt9O1xuICBpbmRleGVzW3RhYmxlTmFtZV0gPSB7XG4gICAgcXVlcnk6IGBgLFxuICAgIHZhbHVlczogW10sXG4gIH07XG5cbiAgbW9kZWxzLmZvckVhY2goKG0pID0+IHtcbiAgICBjb25zdCBpbmQ6IFJlY29yZDxzdHJpbmcsIEluZGV4TWV0YWRhdGE+ID0gUmVwb3NpdG9yeS5pbmRleGVzKG0pO1xuICAgIE9iamVjdC5lbnRyaWVzKGluZCkuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICBjb25zdCBrID0gT2JqZWN0LmtleXModmFsdWUpWzBdO1xuXG4gICAgICBsZXQgeyBjb21wb3NpdGlvbnMgfSA9ICh2YWx1ZSBhcyBhbnkpW2tdO1xuICAgICAgY29uc3QgdGFibGVOYW1lID0gUmVwb3NpdG9yeS50YWJsZShtKTtcbiAgICAgIGNvbXBvc2l0aW9ucyA9IGNvbXBvc2l0aW9ucyB8fCBbXTtcblxuICAgICAgZnVuY3Rpb24gZ2VuZXJhdGUoKSB7XG4gICAgICAgIGNvbnN0IG5hbWUgPSBba2V5LCAuLi4oY29tcG9zaXRpb25zIGFzIFtdKSwgUGVyc2lzdGVuY2VLZXlzLklOREVYXS5qb2luKFxuICAgICAgICAgIERlZmF1bHRTZXBhcmF0b3JcbiAgICAgICAgKTtcblxuICAgICAgICBpbmRleGVzW25hbWVdID0ge1xuICAgICAgICAgIHF1ZXJ5OiBgQ1JFQVRFIElOREVYICQxIE9OICQyICgkMyk7YCxcbiAgICAgICAgICB2YWx1ZXM6IFtuYW1lLCB0YWJsZU5hbWUsIGtleV0sXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGdlbmVyYXRlKCk7XG4gICAgfSk7XG4gIH0pO1xuICByZXR1cm4gT2JqZWN0LnZhbHVlcyhpbmRleGVzKTtcbn1cbiIsImltcG9ydCB7XG4gIHR5cGUgQ29uc3RydWN0b3IsXG4gIE1vZGVsLFxuICBNb2RlbEtleXMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IFJlcG9zaXRvcnksIHVzZXMgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7XG4gIENvbnRleHQsXG4gIGVuZm9yY2VEQkRlY29yYXRvcnMsXG4gIE9wZXJhdGlvbktleXMsXG4gIFZhbGlkYXRpb25FcnJvcixcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBUeXBlT1JNRmxhZ3MsIFR5cGVPUk1RdWVyeSB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBUeXBlT1JNQWRhcHRlciB9IGZyb20gXCIuL1R5cGVPUk1BZGFwdGVyXCI7XG5pbXBvcnQgeyBUeXBlT1JNRmxhdm91ciB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXBvc2l0b3J5IGltcGxlbWVudGF0aW9uIGJhY2tlZCBieSBUeXBlT1JNLlxuICogQHN1bW1hcnkgUHJvdmlkZXMgQ1JVRCBvcGVyYXRpb25zIGZvciBhIGdpdmVuIE1vZGVsIHVzaW5nIHRoZSB7QGxpbmsgVHlwZU9STUFkYXB0ZXJ9LCBpbmNsdWRpbmcgYnVsayBvcGVyYXRpb25zIGFuZCBxdWVyeSBidWlsZGVyIGFjY2VzcyB3aGlsZSBwcmVzZXJ2aW5nIERlY2FmLnRzIHJlcG9zaXRvcnkgc2VtYW50aWNzLlxuICogQHRlbXBsYXRlIE0gVHlwZSBleHRlbmRpbmcgTW9kZWwgdGhhdCB0aGlzIHJlcG9zaXRvcnkgd2lsbCBtYW5hZ2UuXG4gKiBAcGFyYW0ge1R5cGVPUk1BZGFwdGVyfSBhZGFwdGVyIFRoZSBhZGFwdGVyIHVzZWQgdG8gZXhlY3V0ZSBwZXJzaXN0ZW5jZSBvcGVyYXRpb25zLlxuICogQHBhcmFtIHtDb25zdHJ1Y3RvcjxNPn0gbW9kZWwgVGhlIE1vZGVsIGNvbnN0cnVjdG9yIGFzc29jaWF0ZWQgd2l0aCB0aGlzIHJlcG9zaXRvcnkuXG4gKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIE9wdGlvbmFsIGFyZ3VtZW50cyBmb3J3YXJkZWQgdG8gdGhlIGJhc2UgUmVwb3NpdG9yeS5cbiAqIEBjbGFzcyBUeXBlT1JNUmVwb3NpdG9yeVxuICogQGV4YW1wbGVcbiAqIC8vIENyZWF0aW5nIGEgcmVwb3NpdG9yeVxuICogY29uc3QgcmVwbyA9IG5ldyBUeXBlT1JNUmVwb3NpdG9yeTxVc2VyPihhZGFwdGVyLCBVc2VyKTtcbiAqIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCByZXBvLmNyZWF0ZShuZXcgVXNlcih7IG5hbWU6IFwiQWxpY2VcIiB9KSk7XG4gKiBjb25zdCByZWFkID0gYXdhaXQgcmVwby5yZWFkKGNyZWF0ZWQuaWQpO1xuICpcbiAqIC8vIEJ1bGsgY3JlYXRlXG4gKiBhd2FpdCByZXBvLmNyZWF0ZUFsbChbbmV3IFVzZXIoeyBuYW1lOiBcIkFcIiB9KSwgbmV3IFVzZXIoeyBuYW1lOiBcIkJcIiB9KV0pO1xuICpcbiAqIC8vIFVzaW5nIHRoZSBxdWVyeSBidWlsZGVyXG4gKiBjb25zdCBxYiA9IHJlcG8ucXVlcnlCdWlsZGVyKCk7XG4gKiBjb25zdCByb3dzID0gYXdhaXQgcWIud2hlcmUoXCJuYW1lID0gOm5hbWVcIiwgeyBuYW1lOiBcIkFsaWNlXCIgfSkuZ2V0TWFueSgpO1xuICpcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgcGFydGljaXBhbnQgQXBwXG4gKiAgIHBhcnRpY2lwYW50IFJlcG8gYXMgVHlwZU9STVJlcG9zaXRvcnlcbiAqICAgcGFydGljaXBhbnQgQWRhcHRlciBhcyBUeXBlT1JNQWRhcHRlclxuICogICBwYXJ0aWNpcGFudCBEQiBhcyBUeXBlT1JNL0RhdGFTb3VyY2VcbiAqXG4gKiAgIEFwcC0+PlJlcG86IGNyZWF0ZShtb2RlbClcbiAqICAgUmVwby0+PkFkYXB0ZXI6IHByZXBhcmUobW9kZWwsIHBrKVxuICogICBBZGFwdGVyLS0+PlJlcG86IHsgcmVjb3JkLCBpZCwgdHJhbnNpZW50IH1cbiAqICAgUmVwby0+PkFkYXB0ZXI6IGNyZWF0ZSh0YWJsZSwgaWQsIG1vZGVsLCAuLi5hcmdzKVxuICogICBBZGFwdGVyLT4+REI6IElOU0VSVCAuLi5cbiAqICAgREItLT4+QWRhcHRlcjogcm93XG4gKiAgIEFkYXB0ZXItLT4+UmVwbzogcm93XG4gKiAgIFJlcG8tPj5BZGFwdGVyOiByZXZlcnQocm93LCBjbGF6eiwgcGssIGlkKVxuICogICBBZGFwdGVyLS0+PlJlcG86IG1vZGVsXG4gKiAgIFJlcG8tLT4+QXBwOiBtb2RlbFxuICovXG5AdXNlcyhUeXBlT1JNRmxhdm91cilcbmV4cG9ydCBjbGFzcyBUeXBlT1JNUmVwb3NpdG9yeTxNIGV4dGVuZHMgTW9kZWw+IGV4dGVuZHMgUmVwb3NpdG9yeTxcbiAgTSxcbiAgVHlwZU9STVF1ZXJ5PE0sIGFueT4sXG4gIFR5cGVPUk1BZGFwdGVyLFxuICBUeXBlT1JNRmxhZ3MsXG4gIENvbnRleHQ8VHlwZU9STUZsYWdzPlxuPiB7XG4gIGNvbnN0cnVjdG9yKGFkYXB0ZXI6IFR5cGVPUk1BZGFwdGVyLCBtb2RlbDogQ29uc3RydWN0b3I8TT4sIC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgc3VwZXIoYWRhcHRlciwgbW9kZWwsIC4uLmFyZ3MpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgVHlwZU9STSBxdWVyeSBidWlsZGVyIGZvciB0aGUgcmVwb3NpdG9yeSBlbnRpdHkuXG4gICAqIEBzdW1tYXJ5IFJldHVybnMgYSBTZWxlY3RRdWVyeUJ1aWxkZXIgYm91bmQgdG8gdGhpcyByZXBvc2l0b3J5J3MgZW50aXR5IGZvciBhZHZhbmNlZCBxdWVyeWluZy5cbiAgICogQHJldHVybiB7aW1wb3J0KFwidHlwZW9ybVwiKS5TZWxlY3RRdWVyeUJ1aWxkZXI8YW55Pn0gQSBUeXBlT1JNIFNlbGVjdFF1ZXJ5QnVpbGRlciBpbnN0YW5jZS5cbiAgICovXG4gIHF1ZXJ5QnVpbGRlcigpIHtcbiAgICBjb25zdCByZXBvID0gdGhpcy5hZGFwdGVyLmRhdGFTb3VyY2UuZ2V0UmVwb3NpdG9yeShcbiAgICAgIHRoaXMuY2xhc3NbTW9kZWxLZXlzLkFOQ0hPUiBhcyBrZXlvZiB0eXBlb2YgdGhpcy5jbGFzc11cbiAgICApO1xuICAgIHJldHVybiByZXBvLmNyZWF0ZVF1ZXJ5QnVpbGRlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGFuZCBwZXJzaXN0cyBhIG1vZGVsIGluc3RhbmNlLlxuICAgKiBAc3VtbWFyeSBQcmVwYXJlcyB0aGUgbW9kZWwsIGRlbGVnYXRlcyBpbnNlcnRpb24gdG8gdGhlIGFkYXB0ZXIsIGFuZCByZWh5ZHJhdGVzIHRoZSBwZXJzaXN0ZWQgc3RhdGUgYmFjayBpbnRvIGEgTW9kZWwgaW5zdGFuY2UuXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgVGhlIG1vZGVsIHRvIGNyZWF0ZS5cbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyBPcHRpb25hbCBhcmd1bWVudHMvY29udGV4dC5cbiAgICogQHJldHVybiB7UHJvbWlzZTxNPn0gVGhlIGNyZWF0ZWQgbW9kZWwgaW5zdGFuY2UuXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyBjcmVhdGUobW9kZWw6IE0sIC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTxNPiB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHByZWZlci1jb25zdFxuICAgIGxldCB7IHJlY29yZCwgaWQsIHRyYW5zaWVudCB9ID0gdGhpcy5hZGFwdGVyLnByZXBhcmUobW9kZWwsIHRoaXMucGspO1xuICAgIHJlY29yZCA9IGF3YWl0IHRoaXMuYWRhcHRlci5jcmVhdGUoXG4gICAgICAodGhpcy5jbGFzcyBhcyBhbnkpW01vZGVsS2V5cy5BTkNIT1JdIGFzIGFueSxcbiAgICAgIGlkLFxuICAgICAgbW9kZWwgYXMgYW55LFxuICAgICAgLi4uYXJnc1xuICAgICk7XG4gICAgbGV0IGM6IENvbnRleHQ8VHlwZU9STUZsYWdzPiB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICBpZiAoYXJncy5sZW5ndGgpIGMgPSBhcmdzW2FyZ3MubGVuZ3RoIC0gMV0gYXMgQ29udGV4dDxUeXBlT1JNRmxhZ3M+O1xuICAgIHJldHVybiB0aGlzLmFkYXB0ZXIucmV2ZXJ0PE0+KFxuICAgICAgcmVjb3JkLFxuICAgICAgdGhpcy5jbGFzcyxcbiAgICAgIHRoaXMucGssXG4gICAgICBpZCxcbiAgICAgIGMgJiYgYy5nZXQoXCJyZWJ1aWxkV2l0aFRyYW5zaWVudFwiKSA/IHRyYW5zaWVudCA6IHVuZGVmaW5lZFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlYWRzIGEgbW9kZWwgZnJvbSB0aGUgZGF0YWJhc2UgYnkgSUQuXG4gICAqIEBzdW1tYXJ5IFJldHJpZXZlcyBhIG1vZGVsIGluc3RhbmNlIGZyb20gdGhlIGRhdGFiYXNlIHVzaW5nIGl0cyBwcmltYXJ5IGtleS5cbiAgICogQHBhcmFtIHtzdHJpbmd8bnVtYmVyfGJpZ2ludH0gaWQgLSBUaGUgcHJpbWFyeSBrZXkgb2YgdGhlIG1vZGVsIHRvIHJlYWQuXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cy5cbiAgICogQHJldHVybiB7UHJvbWlzZTxNPn0gVGhlIHJldHJpZXZlZCBtb2RlbCBpbnN0YW5jZS5cbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIHJlYWQoXG4gICAgaWQ6IHN0cmluZyB8IG51bWJlciB8IGJpZ2ludCxcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxNPiB7XG4gICAgY29uc3QgbSA9IGF3YWl0IHRoaXMuYWRhcHRlci5yZWFkKFxuICAgICAgKHRoaXMuY2xhc3MgYXMgYW55KVtNb2RlbEtleXMuQU5DSE9SXSBhcyBhbnksXG4gICAgICBpZCBhcyBzdHJpbmcsXG4gICAgICB0aGlzLnBrIGFzIHN0cmluZ1xuICAgICk7XG4gICAgcmV0dXJuIHRoaXMuYWRhcHRlci5yZXZlcnQ8TT4obSwgdGhpcy5jbGFzcywgdGhpcy5waywgaWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIGFuZCBwZXJzaXN0cyBhIG1vZGVsIGluc3RhbmNlLlxuICAgKiBAc3VtbWFyeSBQcmVwYXJlcyB0aGUgbW9kZWwsIGRlbGVnYXRlcyB1cGRhdGUgdG8gdGhlIGFkYXB0ZXIsIGFuZCByZWh5ZHJhdGVzIHRoZSBwZXJzaXN0ZWQgc3RhdGUgYmFjayBpbnRvIGEgTW9kZWwgaW5zdGFuY2UuXG4gICAqIEBwYXJhbSB7TX0gbW9kZWwgVGhlIG1vZGVsIHRvIHVwZGF0ZS5cbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyBPcHRpb25hbCBhcmd1bWVudHMvY29udGV4dC5cbiAgICogQHJldHVybiB7UHJvbWlzZTxNPn0gVGhlIHVwZGF0ZWQgbW9kZWwgaW5zdGFuY2UuXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyB1cGRhdGUobW9kZWw6IE0sIC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTxNPiB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHByZWZlci1jb25zdFxuICAgIGxldCB7IHJlY29yZCwgaWQsIHRyYW5zaWVudCB9ID0gdGhpcy5hZGFwdGVyLnByZXBhcmUobW9kZWwsIHRoaXMucGspO1xuICAgIHJlY29yZCA9IGF3YWl0IHRoaXMuYWRhcHRlci51cGRhdGUoXG4gICAgICAodGhpcy5jbGFzcyBhcyBhbnkpW01vZGVsS2V5cy5BTkNIT1JdIGFzIGFueSxcbiAgICAgIGlkLFxuICAgICAgbW9kZWwsXG4gICAgICAuLi5hcmdzXG4gICAgKTtcbiAgICByZXR1cm4gdGhpcy5hZGFwdGVyLnJldmVydDxNPihyZWNvcmQsIHRoaXMuY2xhc3MsIHRoaXMucGssIGlkLCB0cmFuc2llbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBEZWxldGVzIGEgbW9kZWwgZnJvbSB0aGUgZGF0YWJhc2UgYnkgSUQuXG4gICAqIEBzdW1tYXJ5IFJlbW92ZXMgYSBtb2RlbCBpbnN0YW5jZSBmcm9tIHRoZSBkYXRhYmFzZSB1c2luZyBpdHMgcHJpbWFyeSBrZXkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfG51bWJlcnxiaWdpbnR9IGlkIC0gVGhlIHByaW1hcnkga2V5IG9mIHRoZSBtb2RlbCB0byBkZWxldGUuXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cy5cbiAgICogQHJldHVybiB7UHJvbWlzZTxNPn0gVGhlIGRlbGV0ZWQgbW9kZWwgaW5zdGFuY2UuXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyBkZWxldGUoXG4gICAgaWQ6IHN0cmluZyB8IG51bWJlciB8IGJpZ2ludCxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPE0+IHtcbiAgICBjb25zdCBtID0gYXdhaXQgdGhpcy5hZGFwdGVyLmRlbGV0ZShcbiAgICAgICh0aGlzLmNsYXNzIGFzIGFueSlbTW9kZWxLZXlzLkFOQ0hPUl0gYXMgYW55LFxuICAgICAgaWQgYXMgc3RyaW5nLFxuICAgICAgdGhpcy5wayBhcyBzdHJpbmcsXG4gICAgICAuLi5hcmdzXG4gICAgKTtcbiAgICByZXR1cm4gdGhpcy5hZGFwdGVyLnJldmVydDxNPihtLCB0aGlzLmNsYXNzLCB0aGlzLnBrLCBpZCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFZhbGlkYXRlcyBhbmQgcHJlcGFyZXMgbW9kZWxzIGZvciBidWxrIGNyZWF0aW9uLlxuICAgKiBAc3VtbWFyeSBBcHBsaWVzIGRlY29yYXRvci1iYXNlZCB2YWxpZGF0aW9ucyBhbmQgcmV0dXJucyB0cmFuc2Zvcm1lZCBtb2RlbHMgd2l0aCBjb250ZXh0IGFyZ3MgZm9yIGNyZWF0ZUFsbC5cbiAgICogQHBhcmFtIHtNW119IG1vZGVscyBUaGUgbW9kZWxzIHRvIGJlIGNyZWF0ZWQuXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgT3B0aW9uYWwgYXJndW1lbnRzL2NvbnRleHQuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8W01bXSwgLi4uYW55W11dPn0gVGhlIHByZXBhcmVkIG1vZGVscyBhbmQgZm9yd2FyZGVkIGFyZ3MgdHVwbGUuXG4gICAqL1xuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlQWxsUHJlZml4KG1vZGVsczogTVtdLCAuLi5hcmdzOiBhbnlbXSkge1xuICAgIGNvbnN0IGNvbnRleHRBcmdzID0gYXdhaXQgQ29udGV4dC5hcmdzKFxuICAgICAgT3BlcmF0aW9uS2V5cy5DUkVBVEUsXG4gICAgICB0aGlzLmNsYXNzLFxuICAgICAgYXJncyxcbiAgICAgIHRoaXMuYWRhcHRlcixcbiAgICAgIHRoaXMuX292ZXJyaWRlcyB8fCB7fVxuICAgICk7XG4gICAgaWYgKCFtb2RlbHMubGVuZ3RoKSByZXR1cm4gW21vZGVscywgLi4uY29udGV4dEFyZ3MuYXJnc107XG5cbiAgICBtb2RlbHMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgIG1vZGVscy5tYXAoYXN5bmMgKG0pID0+IHtcbiAgICAgICAgbSA9IG5ldyB0aGlzLmNsYXNzKG0pO1xuICAgICAgICBhd2FpdCBlbmZvcmNlREJEZWNvcmF0b3JzKFxuICAgICAgICAgIHRoaXMsXG4gICAgICAgICAgY29udGV4dEFyZ3MuY29udGV4dCxcbiAgICAgICAgICBtLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuQ1JFQVRFLFxuICAgICAgICAgIE9wZXJhdGlvbktleXMuT05cbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIG07XG4gICAgICB9KVxuICAgICk7XG4gICAgY29uc3QgZXJyb3JzID0gbW9kZWxzXG4gICAgICAubWFwKChtKSA9PlxuICAgICAgICBtLmhhc0Vycm9ycyhcbiAgICAgICAgICAuLi4oY29udGV4dEFyZ3MuY29udGV4dC5nZXQoXCJpZ25vcmVkVmFsaWRhdGlvblByb3BlcnRpZXNcIikgfHwgW10pXG4gICAgICAgIClcbiAgICAgIClcbiAgICAgIC5yZWR1Y2UoKGFjY3VtOiBzdHJpbmcgfCB1bmRlZmluZWQsIGUsIGkpID0+IHtcbiAgICAgICAgaWYgKGUpXG4gICAgICAgICAgYWNjdW0gPVxuICAgICAgICAgICAgdHlwZW9mIGFjY3VtID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAgID8gYWNjdW0gKyBgXFxuIC0gJHtpfTogJHtlLnRvU3RyaW5nKCl9YFxuICAgICAgICAgICAgICA6IGAgLSAke2l9OiAke2UudG9TdHJpbmcoKX1gO1xuICAgICAgICByZXR1cm4gYWNjdW07XG4gICAgICB9LCB1bmRlZmluZWQpO1xuICAgIGlmIChlcnJvcnMpIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoZXJyb3JzKTtcbiAgICByZXR1cm4gW21vZGVscywgLi4uY29udGV4dEFyZ3MuYXJnc107XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgbXVsdGlwbGUgbW9kZWxzIGF0IG9uY2UuXG4gICAqIEBzdW1tYXJ5IFByZXBhcmVzLCBwZXJzaXN0cywgYW5kIHJlaHlkcmF0ZXMgYSBiYXRjaCBvZiBtb2RlbHMuXG4gICAqIEBwYXJhbSB7TVtdfSBtb2RlbHMgVGhlIG1vZGVscyB0byBjcmVhdGUuXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgT3B0aW9uYWwgYXJndW1lbnRzL2NvbnRleHQuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TVtdPn0gVGhlIGNyZWF0ZWQgbW9kZWxzLlxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlQWxsKG1vZGVsczogTVtdLCAuLi5hcmdzOiBhbnlbXSk6IFByb21pc2U8TVtdPiB7XG4gICAgaWYgKCFtb2RlbHMubGVuZ3RoKSByZXR1cm4gbW9kZWxzO1xuICAgIGNvbnN0IHByZXBhcmVkID0gbW9kZWxzLm1hcCgobSkgPT4gdGhpcy5hZGFwdGVyLnByZXBhcmUobSwgdGhpcy5waykpO1xuICAgIGNvbnN0IGlkcyA9IHByZXBhcmVkLm1hcCgocCkgPT4gcC5pZCk7XG4gICAgbGV0IHJlY29yZHMgPSBwcmVwYXJlZC5tYXAoKHApID0+IHAucmVjb3JkKTtcbiAgICByZWNvcmRzID0gYXdhaXQgdGhpcy5hZGFwdGVyLmNyZWF0ZUFsbChcbiAgICAgICh0aGlzLmNsYXNzIGFzIGFueSlbTW9kZWxLZXlzLkFOQ0hPUl0gYXMgYW55LFxuICAgICAgaWRzIGFzIChzdHJpbmcgfCBudW1iZXIpW10sXG4gICAgICBtb2RlbHMsXG4gICAgICAuLi5hcmdzXG4gICAgKTtcbiAgICByZXR1cm4gcmVjb3Jkcy5tYXAoKHIsIGkpID0+XG4gICAgICB0aGlzLmFkYXB0ZXIucmV2ZXJ0KHIsIHRoaXMuY2xhc3MsIHRoaXMucGssIGlkc1tpXSBhcyBzdHJpbmcgfCBudW1iZXIpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVhZHMgbXVsdGlwbGUgbW9kZWxzIGJ5IHRoZWlyIHByaW1hcnkga2V5cy5cbiAgICogQHN1bW1hcnkgUmV0cmlldmVzIGEgbGlzdCBvZiBtb2RlbHMgY29ycmVzcG9uZGluZyB0byB0aGUgcHJvdmlkZWQga2V5cy5cbiAgICogQHBhcmFtIHsoc3RyaW5nW118bnVtYmVyW10pfSBrZXlzIFRoZSBwcmltYXJ5IGtleXMgdG8gcmVhZC5cbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyBPcHRpb25hbCBhcmd1bWVudHMvY29udGV4dC5cbiAgICogQHJldHVybiB7UHJvbWlzZTxNW10+fSBUaGUgcmV0cmlldmVkIG1vZGVscy5cbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIHJlYWRBbGwoXG4gICAga2V5czogc3RyaW5nW10gfCBudW1iZXJbXSxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPE1bXT4ge1xuICAgIGNvbnN0IHJlY29yZHMgPSBhd2FpdCB0aGlzLmFkYXB0ZXIucmVhZEFsbChcbiAgICAgICh0aGlzLmNsYXNzIGFzIGFueSlbTW9kZWxLZXlzLkFOQ0hPUl0gYXMgYW55LFxuICAgICAga2V5cyxcbiAgICAgIHRoaXMucGsgYXMgc3RyaW5nLFxuICAgICAgLi4uYXJnc1xuICAgICk7XG4gICAgcmV0dXJuIHJlY29yZHMubWFwKChyOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBpOiBudW1iZXIpID0+XG4gICAgICB0aGlzLmFkYXB0ZXIucmV2ZXJ0KHIsIHRoaXMuY2xhc3MsIHRoaXMucGssIGtleXNbaV0pXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gVXBkYXRlcyBtdWx0aXBsZSBtb2RlbHMgYXQgb25jZS5cbiAgICogQHN1bW1hcnkgUGVyc2lzdHMgYSBiYXRjaCBvZiBtb2RlbCB1cGRhdGVzIGFuZCByZXR1cm5zIHRoZWlyIHJlaHlkcmF0ZWQgaW5zdGFuY2VzLlxuICAgKiBAcGFyYW0ge01bXX0gbW9kZWxzIFRoZSBtb2RlbHMgdG8gdXBkYXRlLlxuICAgKiBAcGFyYW0gey4uLmFueVtdfSBhcmdzIE9wdGlvbmFsIGFyZ3VtZW50cy9jb250ZXh0LlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1bXT59IFRoZSB1cGRhdGVkIG1vZGVscy5cbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIHVwZGF0ZUFsbChtb2RlbHM6IE1bXSwgLi4uYXJnczogYW55W10pOiBQcm9taXNlPE1bXT4ge1xuICAgIGNvbnN0IHJlY29yZHMgPSBtb2RlbHMubWFwKChtKSA9PiB0aGlzLmFkYXB0ZXIucHJlcGFyZShtLCB0aGlzLnBrKSk7XG4gICAgY29uc3QgdXBkYXRlZCA9IGF3YWl0IHRoaXMuYWRhcHRlci51cGRhdGVBbGwoXG4gICAgICAodGhpcy5jbGFzcyBhcyBhbnkpW01vZGVsS2V5cy5BTkNIT1JdIGFzIGFueSxcbiAgICAgIHJlY29yZHMubWFwKChyKSA9PiByLmlkKSxcbiAgICAgIG1vZGVscyxcbiAgICAgIHRoaXMucGsgYXMgc3RyaW5nLFxuICAgICAgLi4uYXJnc1xuICAgICk7XG4gICAgcmV0dXJuIHVwZGF0ZWQubWFwKCh1OiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCBpOiBudW1iZXIpID0+XG4gICAgICB0aGlzLmFkYXB0ZXIucmV2ZXJ0KHUsIHRoaXMuY2xhc3MsIHRoaXMucGssIHJlY29yZHNbaV0uaWQpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVsZXRlcyBtdWx0aXBsZSBtb2RlbHMgYXQgb25jZS5cbiAgICogQHN1bW1hcnkgUmVtb3ZlcyBhIGxpc3Qgb2YgbW9kZWxzIGJ5IHRoZWlyIHByaW1hcnkga2V5cyBhbmQgcmV0dXJucyB0aGVpciBsYXN0IHBlcnNpc3RlZCBzdGF0ZXMuXG4gICAqIEBwYXJhbSB7KHN0cmluZ1tdfG51bWJlcltdKX0ga2V5cyBUaGUgcHJpbWFyeSBrZXlzIHRvIGRlbGV0ZS5cbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyBPcHRpb25hbCBhcmd1bWVudHMvY29udGV4dC5cbiAgICogQHJldHVybiB7UHJvbWlzZTxNW10+fSBUaGUgZGVsZXRlZCBtb2RlbHMuXG4gICAqL1xuICBvdmVycmlkZSBhc3luYyBkZWxldGVBbGwoXG4gICAga2V5czogc3RyaW5nW10gfCBudW1iZXJbXSxcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPE1bXT4ge1xuICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCB0aGlzLmFkYXB0ZXIuZGVsZXRlQWxsKFxuICAgICAgKHRoaXMuY2xhc3MgYXMgYW55KVtNb2RlbEtleXMuQU5DSE9SXSBhcyBhbnksXG4gICAgICBrZXlzLFxuICAgICAgdGhpcy5wayBhcyBzdHJpbmcsXG4gICAgICAuLi5hcmdzXG4gICAgKTtcbiAgICByZXR1cm4gcmVzdWx0cy5tYXAoKHI6IFJlY29yZDxzdHJpbmcsIGFueT4sIGk6IG51bWJlcikgPT5cbiAgICAgIHRoaXMuYWRhcHRlci5yZXZlcnQociwgdGhpcy5jbGFzcywgdGhpcy5waywga2V5c1tpXSlcbiAgICApO1xuICB9XG59XG4iLCJpbXBvcnQge1xuICBFbnRpdHlTdWJzY3JpYmVySW50ZXJmYWNlLFxuICBFdmVudFN1YnNjcmliZXIsXG4gIEluc2VydEV2ZW50LFxuICBSZW1vdmVFdmVudCxcbiAgVXBkYXRlRXZlbnQsXG59IGZyb20gXCJ0eXBlb3JtXCI7XG5pbXBvcnQgeyBFdmVudElkcywgUmVwb3NpdG9yeSB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgSW50ZXJuYWxFcnJvciwgT3BlcmF0aW9uS2V5cyB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIFR5cGVPUk0gZXZlbnQgc3Vic2NyaWJlciB0aGF0IGZvcndhcmRzIGVudGl0eSBsaWZlY3ljbGUgZXZlbnRzIHRvIHRoZSBhZGFwdGVyLlxuICogQHN1bW1hcnkgTGlzdGVucyBmb3IgaW5zZXJ0LCB1cGRhdGUsIGFuZCByZW1vdmUgZXZlbnRzIGVtaXR0ZWQgYnkgVHlwZU9STSBhbmQgbm90aWZpZXMgdGhlIERlY2FmLnRzIGFkYXB0ZXIgc28gdGhhdCBvYnNlcnZlcnMgY2FuIGJlIHVwZGF0ZWQgYWNjb3JkaW5nbHkuXG4gKiBAcGFyYW0ge1R5cGVPUk1BZGFwdGVyfSBhZGFwdGVyIFRoZSBUeXBlT1JNIGFkYXB0ZXIgdXNlZCB0byBwcm9wYWdhdGUgZXZlbnRzIGFuZCBsb29rIHVwIG1ldGFkYXRhLlxuICogQGNsYXNzXG4gKiBAZXhhbXBsZVxuICogLy8gUmVnaXN0ZXJpbmcgdGhlIHN1YnNjcmliZXIgd2hlbiBjcmVhdGluZyBhIERhdGFTb3VyY2VcbiAqIC8vIGRhdGFTb3VyY2VPcHRpb25zLnN1YnNjcmliZXJzID0gW25ldyBUeXBlT1JNRXZlbnRTdWJzY3JpYmVyKGFkYXB0ZXIpXTtcbiAqXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IFR5cGVPUk1cbiAqICAgcGFydGljaXBhbnQgU3Vic2NyaWJlciBhcyBUeXBlT1JNRXZlbnRTdWJzY3JpYmVyXG4gKiAgIHBhcnRpY2lwYW50IEFkYXB0ZXIgYXMgVHlwZU9STUFkYXB0ZXJcbiAqICAgcGFydGljaXBhbnQgT2JzZXJ2ZXJzXG4gKlxuICogICBUeXBlT1JNLT4+U3Vic2NyaWJlcjogYWZ0ZXJJbnNlcnQoZW50aXR5KVxuICogICBTdWJzY3JpYmVyLT4+QWRhcHRlcjogdXBkYXRlT2JzZXJ2ZXJzKHRhYmxlLCBDUkVBVEUsIFtpZF0pXG4gKiAgIEFkYXB0ZXItPj5PYnNlcnZlcnM6IG5vdGlmeSh0YWJsZSwgQ1JFQVRFLCBbaWRdKVxuICpcbiAqICAgVHlwZU9STS0+PlN1YnNjcmliZXI6IGFmdGVyVXBkYXRlKGV2ZW50KVxuICogICBTdWJzY3JpYmVyLT4+QWRhcHRlcjogdXBkYXRlT2JzZXJ2ZXJzKHRhYmxlLCBVUERBVEUsIFtpZF0pXG4gKiAgIEFkYXB0ZXItPj5PYnNlcnZlcnM6IG5vdGlmeSh0YWJsZSwgVVBEQVRFLCBbaWRdKVxuICpcbiAqICAgVHlwZU9STS0+PlN1YnNjcmliZXI6IGFmdGVyUmVtb3ZlKGV2ZW50KVxuICogICBTdWJzY3JpYmVyLT4+QWRhcHRlcjogdXBkYXRlT2JzZXJ2ZXJzKHRhYmxlLCBERUxFVEUsIFtpZF0pXG4gKiAgIEFkYXB0ZXItPj5PYnNlcnZlcnM6IG5vdGlmeSh0YWJsZSwgREVMRVRFLCBbaWRdKVxuICovXG5ARXZlbnRTdWJzY3JpYmVyKClcbmV4cG9ydCBjbGFzcyBUeXBlT1JNRXZlbnRTdWJzY3JpYmVyIGltcGxlbWVudHMgRW50aXR5U3Vic2NyaWJlckludGVyZmFjZSB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHByb3RlY3RlZCByZWFkb25seSBoYW5kbGVyOiAoXG4gICAgICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICAgIG9wZXJhdGlvbjogT3BlcmF0aW9uS2V5cyxcbiAgICAgIGlkczogRXZlbnRJZHNcbiAgICApID0+IHZvaWRcbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSGFuZGxlcyBwb3N0LWluc2VydCBldmVudHMuXG4gICAqIEBzdW1tYXJ5IE5vdGlmaWVzIG9ic2VydmVycyBhYm91dCBhIGNyZWF0ZSBvcGVyYXRpb24gZm9yIHRoZSBpbnNlcnRlZCBlbnRpdHkuXG4gICAqIEBwYXJhbSB7SW5zZXJ0RXZlbnQ8YW55Pn0gZXZlbnQgVGhlIFR5cGVPUk0gaW5zZXJ0IGV2ZW50LlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPGFueT58dm9pZH0gQSBwcm9taXNlIHdoZW4gYXN5bmMgb3Igdm9pZCBvdGhlcndpc2UuXG4gICAqL1xuICBhZnRlckluc2VydChldmVudDogSW5zZXJ0RXZlbnQ8YW55Pik6IFByb21pc2U8YW55PiB8IHZvaWQge1xuICAgIGNvbnN0IGNvbnN0cnVjdG9yID0gTW9kZWwuZ2V0KGV2ZW50LmVudGl0eS5jb25zdHJ1Y3Rvci5uYW1lKTtcbiAgICBpZiAoIWNvbnN0cnVjdG9yKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBObyByZWdpc3RlcmVkIG1vZGVsIGZvdW5kIGZvciAke2V2ZW50LmVudGl0eS5jb25zdHJ1Y3Rvci5uYW1lfWBcbiAgICAgICk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gUmVwb3NpdG9yeS50YWJsZShjb25zdHJ1Y3Rvcik7XG5cbiAgICB0aGlzLmhhbmRsZXIodGFibGVOYW1lLCBPcGVyYXRpb25LZXlzLkNSRUFURSwgW2V2ZW50LmVudGl0eUlkIGFzIGFueV0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBIYW5kbGVzIHBvc3QtcmVtb3ZlIGV2ZW50cy5cbiAgICogQHN1bW1hcnkgTm90aWZpZXMgb2JzZXJ2ZXJzIGFib3V0IGEgZGVsZXRlIG9wZXJhdGlvbiBmb3IgdGhlIHJlbW92ZWQgZW50aXR5LlxuICAgKiBAcGFyYW0ge1JlbW92ZUV2ZW50PGFueT59IGV2ZW50IFRoZSBUeXBlT1JNIHJlbW92ZSBldmVudC5cbiAgICogQHJldHVybiB7UHJvbWlzZTxhbnk+fHZvaWR9IEEgcHJvbWlzZSB3aGVuIGFzeW5jIG9yIHZvaWQgb3RoZXJ3aXNlLlxuICAgKi9cbiAgYWZ0ZXJSZW1vdmUoZXZlbnQ6IFJlbW92ZUV2ZW50PGFueT4pOiBQcm9taXNlPGFueT4gfCB2b2lkIHtcbiAgICBjb25zdCBjb25zdHJ1Y3RvciA9IE1vZGVsLmdldChldmVudC5lbnRpdHkuY29uc3RydWN0b3IubmFtZSk7XG4gICAgaWYgKCFjb25zdHJ1Y3RvcilcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICBgTm8gcmVnaXN0ZXJlZCBtb2RlbCBmb3VuZCBmb3IgJHtldmVudC5lbnRpdHkuY29uc3RydWN0b3IubmFtZX1gXG4gICAgICApO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IFJlcG9zaXRvcnkudGFibGUoY29uc3RydWN0b3IpO1xuXG4gICAgdGhpcy5oYW5kbGVyKHRhYmxlTmFtZSwgT3BlcmF0aW9uS2V5cy5ERUxFVEUsIFtldmVudC5lbnRpdHlJZCBhcyBhbnldKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSGFuZGxlcyBwb3N0LXVwZGF0ZSBldmVudHMuXG4gICAqIEBzdW1tYXJ5IE5vdGlmaWVzIG9ic2VydmVycyBhYm91dCBhbiB1cGRhdGUgb3BlcmF0aW9uIGZvciB0aGUgbW9kaWZpZWQgZW50aXR5LlxuICAgKiBAcGFyYW0ge1VwZGF0ZUV2ZW50PGFueT59IGV2ZW50IFRoZSBUeXBlT1JNIHVwZGF0ZSBldmVudC5cbiAgICogQHJldHVybiB7UHJvbWlzZTxhbnk+fHZvaWR9IEEgcHJvbWlzZSB3aGVuIGFzeW5jIG9yIHZvaWQgb3RoZXJ3aXNlLlxuICAgKi9cbiAgYWZ0ZXJVcGRhdGUoZXZlbnQ6IFVwZGF0ZUV2ZW50PGFueT4pOiBQcm9taXNlPGFueT4gfCB2b2lkIHtcbiAgICBjb25zdCBjb25zdHJ1Y3RvciA9IE1vZGVsLmdldChldmVudC5kYXRhYmFzZUVudGl0eS5jb25zdHJ1Y3Rvci5uYW1lKTtcbiAgICBpZiAoIWNvbnN0cnVjdG9yKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBObyByZWdpc3RlcmVkIG1vZGVsIGZvdW5kIGZvciAke2V2ZW50LmRhdGFiYXNlRW50aXR5LmNvbnN0cnVjdG9yLm5hbWV9YFxuICAgICAgKTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBSZXBvc2l0b3J5LnRhYmxlKGNvbnN0cnVjdG9yKTtcblxuICAgIHJldHVybiB0aGlzLmhhbmRsZXIodGFibGVOYW1lLCBPcGVyYXRpb25LZXlzLlVQREFURSwgW1xuICAgICAgKGV2ZW50LmVudGl0eSBhcyBhbnkpW1wiaWRcIl0gYXMgYW55LFxuICAgIF0pO1xuICB9XG59XG4iLCJpbXBvcnQgeyBEaXNwYXRjaCwgRXZlbnRJZHMgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IEludGVybmFsRXJyb3IsIE9wZXJhdGlvbktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IERhdGFTb3VyY2VPcHRpb25zIH0gZnJvbSBcInR5cGVvcm0vZGF0YS1zb3VyY2UvRGF0YVNvdXJjZU9wdGlvbnNcIjtcbmltcG9ydCB7IFR5cGVPUk1BZGFwdGVyIH0gZnJvbSBcIi4vVHlwZU9STUFkYXB0ZXJcIjtcbmltcG9ydCB7IFR5cGVPUk1FdmVudFN1YnNjcmliZXIgfSBmcm9tIFwiLi9UeXBlT1JNRXZlbnRTdWJzY3JpYmVyXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERpc3BhdGNoZXIgZm9yIFR5cGVPUk0tZHJpdmVuIGNoYW5nZSBldmVudHMuXG4gKiBAc3VtbWFyeSBTdWJzY3JpYmVzIGEgVHlwZU9STSBEYXRhU291cmNlIHdpdGggYSBjdXN0b20gRW50aXR5U3Vic2NyaWJlciB0byBub3RpZnkgb2JzZXJ2ZXJzIHdoZW4gcmVjb3JkcyBhcmUgY3JlYXRlZCwgdXBkYXRlZCwgb3IgZGVsZXRlZC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBbdGltZW91dD01MDAwXSBUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgaW5pdGlhbGl6YXRpb24gcmV0cmllcy5cbiAqIEBjbGFzcyBUeXBlT1JNRGlzcGF0Y2hcbiAqIEBleGFtcGxlXG4gKiAvLyBDcmVhdGUgYSBkaXNwYXRjaGVyIGZvciBhIFR5cGVPUk0gRGF0YVNvdXJjZVxuICogY29uc3QgZGlzcGF0Y2ggPSBuZXcgVHlwZU9STURpc3BhdGNoKCk7XG4gKiBhd2FpdCBkaXNwYXRjaC5vYnNlcnZlKGFkYXB0ZXIsIGFkYXB0ZXIuZGF0YVNvdXJjZS5vcHRpb25zKTtcbiAqXG4gKiAvLyBUaGUgZGlzcGF0Y2hlciByZWdpc3RlcnMgYSBUeXBlT1JNRXZlbnRTdWJzY3JpYmVyIGFuZCBub3RpZmllcyBvYnNlcnZlcnMgd2hlbiBlbnRpdGllcyBjaGFuZ2UuXG4gKiBAbWVybWFpZFxuICogY2xhc3NEaWFncmFtXG4gKiAgIGNsYXNzIERpc3BhdGNoIHtcbiAqICAgICAraW5pdGlhbGl6ZSgpXG4gKiAgICAgK3VwZGF0ZU9ic2VydmVycygpXG4gKiAgIH1cbiAqICAgY2xhc3MgVHlwZU9STURpc3BhdGNoIHtcbiAqICAgICAtb2JzZXJ2ZXJMYXN0VXBkYXRlPzogc3RyaW5nXG4gKiAgICAgLWF0dGVtcHRDb3VudGVyOiBudW1iZXJcbiAqICAgICAtdGltZW91dDogbnVtYmVyXG4gKiAgICAgK2NvbnN0cnVjdG9yKHRpbWVvdXQpXG4gKiAgICAgI25vdGlmaWNhdGlvbkhhbmRsZXIoKVxuICogICAgICNpbml0aWFsaXplKClcbiAqICAgfVxuICogICBEaXNwYXRjaCA8fC0tIFR5cGVPUk1EaXNwYXRjaFxuICovXG5leHBvcnQgY2xhc3MgVHlwZU9STURpc3BhdGNoIGV4dGVuZHMgRGlzcGF0Y2g8RGF0YVNvdXJjZU9wdGlvbnM+IHtcbiAgcHJpdmF0ZSBvYnNlcnZlckxhc3RVcGRhdGU/OiBzdHJpbmc7XG4gIHByaXZhdGUgYXR0ZW1wdENvdW50ZXI6IG51bWJlciA9IDA7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSB0aW1lb3V0ID0gNTAwMCkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByb2Nlc3NlcyBUeXBlT1JNIG5vdGlmaWNhdGlvbiBldmVudHMuXG4gICAqIEBzdW1tYXJ5IEhhbmRsZXMgY2hhbmdlIG5vdGlmaWNhdGlvbnMgKHRyYW5zbGF0ZWQgZnJvbSBUeXBlT1JNIGV2ZW50cykgYW5kIG5vdGlmaWVzIG9ic2VydmVycyBhYm91dCByZWNvcmQgY2hhbmdlcy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlIFRoZSBub3RpZmljYXRpb24gcGF5bG9hZC5cbiAgICogQHBhcmFtIHtPcGVyYXRpb25LZXlzfSBvcGVyYXRpb24gVGhlIG5vdGlmaWNhdGlvbiBwYXlsb2FkLlxuICAgKiBAcGFyYW0ge0V2ZW50SWRzfSBpZHMgVGhlIG5vdGlmaWNhdGlvbiBwYXlsb2FkLlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBub3RpZmljYXRpb25zIGhhdmUgYmVlbiBwcm9jZXNzZWQuXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEQgYXMgUG9zdGdyZVNRTERpc3BhdGNoXG4gICAqICAgcGFydGljaXBhbnQgTCBhcyBMb2dnZXJcbiAgICogICBwYXJ0aWNpcGFudCBPIGFzIE9ic2VydmVyc1xuICAgKiAgIE5vdGUgb3ZlciBEOiBSZWNlaXZlIG5vdGlmaWNhdGlvbiBmcm9tIFBvc3RncmVTUUxcbiAgICogICBELT4+RDogUGFyc2Ugbm90aWZpY2F0aW9uIHBheWxvYWRcbiAgICogICBELT4+RDogRXh0cmFjdCB0YWJsZSwgb3BlcmF0aW9uLCBhbmQgaWRzXG4gICAqICAgRC0+Pk86IHVwZGF0ZU9ic2VydmVycyh0YWJsZSwgb3BlcmF0aW9uLCBpZHMpXG4gICAqICAgRC0+PkQ6IFVwZGF0ZSBvYnNlcnZlckxhc3RVcGRhdGVcbiAgICogICBELT4+TDogTG9nIHN1Y2Nlc3NmdWwgZGlzcGF0Y2hcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBub3RpZmljYXRpb25IYW5kbGVyKFxuICAgIHRhYmxlOiBzdHJpbmcsXG4gICAgb3BlcmF0aW9uOiBPcGVyYXRpb25LZXlzLFxuICAgIGlkczogRXZlbnRJZHNcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMubm90aWZpY2F0aW9uSGFuZGxlcik7XG4gICAgdHJ5IHtcbiAgICAgIC8vIE5vdGlmeSBvYnNlcnZlcnNcbiAgICAgIGF3YWl0IHRoaXMudXBkYXRlT2JzZXJ2ZXJzKHRhYmxlLCBvcGVyYXRpb24sIGlkcyk7XG4gICAgICB0aGlzLm9ic2VydmVyTGFzdFVwZGF0ZSA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcbiAgICAgIGxvZy52ZXJib3NlKGBPYnNlcnZlciByZWZyZXNoIGRpc3BhdGNoZWQgYnkgJHtvcGVyYXRpb259IGZvciAke3RhYmxlfWApO1xuICAgICAgbG9nLmRlYnVnKGBwa3M6ICR7aWRzfWApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGxvZy5lcnJvcihgRmFpbGVkIHRvIHByb2Nlc3Mgbm90aWZpY2F0aW9uOiAke2V9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBJbml0aWFsaXplcyB0aGUgZGlzcGF0Y2hlciBhbmQgc3Vic2NyaWJlcyB0byBUeXBlT1JNIG5vdGlmaWNhdGlvbnMuXG4gICAqIEBzdW1tYXJ5IFJlZ2lzdGVycyB0aGUgVHlwZU9STUV2ZW50U3Vic2NyaWJlciBvbiB0aGUgRGF0YVNvdXJjZSBhbmQgbG9ncyB0aGUgc3Vic2NyaXB0aW9uIGxpZmVjeWNsZS5cbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgc3Vic2NyaXB0aW9uIGlzIGVzdGFibGlzaGVkLlxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBEIGFzIFR5cGVPUk1EaXNwYXRjaFxuICAgKiAgIHBhcnRpY2lwYW50IFMgYXMgc3Vic2NyaWJlVG9UeXBlT1JNXG4gICAqICAgcGFydGljaXBhbnQgRFMgYXMgVHlwZU9STSBEYXRhU291cmNlXG4gICAqICAgcGFydGljaXBhbnQgTCBhcyBMb2dnZXJcbiAgICogICBELT4+UzogQ2FsbCBzdWJzY3JpYmVUb1R5cGVPUk1cbiAgICogICBTLT4+UzogQ2hlY2sgYWRhcHRlciBhbmQgbmF0aXZlXG4gICAqICAgYWx0IE5vIGFkYXB0ZXIgb3IgbmF0aXZlXG4gICAqICAgICBTLS0+PlM6IHRocm93IEludGVybmFsRXJyb3JcbiAgICogICBlbmRcbiAgICogICBTLT4+RFM6IGluaXRpYWxpemUoKVxuICAgKiAgIFMtPj5EUzogc3Vic2NyaWJlcnMucHVzaChUeXBlT1JNRXZlbnRTdWJzY3JpYmVyKVxuICAgKiAgIGFsdCBTdWNjZXNzXG4gICAqICAgICBEUy0tPj5TOiBTdWJzY3JpcHRpb24gZXN0YWJsaXNoZWRcbiAgICogICAgIFMtLT4+RDogUHJvbWlzZSByZXNvbHZlc1xuICAgKiAgICAgRC0+Pkw6IExvZyBzdWNjZXNzZnVsIHN1YnNjcmlwdGlvblxuICAgKiAgIGVsc2UgRXJyb3JcbiAgICogICAgIERTLS0+PlM6IEVycm9yXG4gICAqICAgICBTLS0+PkQ6IFByb21pc2UgcmVqZWN0c1xuICAgKiAgIGVuZFxuICAgKi9cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGFzeW5jIGluaXRpYWxpemUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXN5bmMgZnVuY3Rpb24gc3Vic2NyaWJlVG9UeXBlT1JNKHRoaXM6IFR5cGVPUk1EaXNwYXRjaCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgaWYgKCF0aGlzLmFkYXB0ZXIgfHwgIXRoaXMubmF0aXZlKSB7XG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBObyBhZGFwdGVyL25hdGl2ZSBvYnNlcnZlZCBmb3IgZGlzcGF0Y2hgKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgYWRhcHRlciA9IHRoaXMuYWRhcHRlciBhcyBUeXBlT1JNQWRhcHRlcjtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKCFhZGFwdGVyLmRhdGFTb3VyY2UuaXNJbml0aWFsaXplZClcbiAgICAgICAgICBhd2FpdCBhZGFwdGVyLmRhdGFTb3VyY2UuaW5pdGlhbGl6ZSgpO1xuXG4gICAgICAgIGFkYXB0ZXIuZGF0YVNvdXJjZS5zdWJzY3JpYmVycy5wdXNoKFxuICAgICAgICAgIG5ldyBUeXBlT1JNRXZlbnRTdWJzY3JpYmVyKHRoaXMubm90aWZpY2F0aW9uSGFuZGxlci5iaW5kKHRoaXMpKVxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihlIGFzIEVycm9yKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBzdWJzY3JpYmVUb1R5cGVPUk1cbiAgICAgIC5jYWxsKHRoaXMpXG4gICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgIHRoaXMubG9nLmluZm8oYFN1YnNjcmliZWQgdG8gVHlwZU9STSBub3RpZmljYXRpb25zYCk7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKChlOiB1bmtub3duKSA9PiB7XG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgIGBGYWlsZWQgdG8gc3Vic2NyaWJlIHRvIFR5cGVPUk0gbm90aWZpY2F0aW9uczogJHtlfWBcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENsZWFudXAgbWV0aG9kIHRvIHJlbGVhc2UgcmVzb3VyY2VzIHdoZW4gdGhlIGRpc3BhdGNoZXIgaXMgbm8gbG9uZ2VyIG5lZWRlZFxuICAgKi9cbiAgcHVibGljIGNsZWFudXAoKTogdm9pZCB7XG4gICAgLy8gaWYgKHRoaXMuYWRhcHRlcikge1xuICAgIC8vXG4gICAgLy8gICBjb25zdCBhZGFwdGVyID0gdGhpcy5hZGFwdGVyIGFzIFR5cGVPUk1BZGFwdGVyO1xuICAgIC8vICAgYXdhaXQgYWRhcHRlci5kYXRhU291cmNlLmRlc3Ryb3koKTtcbiAgICAvLyB9XG4gIH1cbn1cbiIsIi8qKlxuICogQGRlc2NyaXB0aW9uIENvbnZlcnRzIGEgSmF2YVNjcmlwdCBSZWdFeHAgcGF0dGVybiB0byBhIFBvc3RncmVTUUwgUE9TSVggcGF0dGVybiBzdHJpbmcuXG4gKiBAc3VtbWFyeSBBY2NlcHRzIGVpdGhlciBhIFJlZ0V4cCBvYmplY3Qgb3IgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gKC9wYXR0ZXJuL2ZsYWdzKSBhbmQgcmV0dXJucyB0aGUgcmF3IHBhdHRlcm4gY29tcGF0aWJsZSB3aXRoIFBvc3RncmVTUUwncyB+IGFuZCB+KiBvcGVyYXRvcnMuXG4gKiBAcGFyYW0ge1JlZ0V4cHxzdHJpbmd9IGpzUmVnZXggSmF2YVNjcmlwdCBSZWdFeHAgb2JqZWN0IG9yIHBhdHRlcm4gc3RyaW5nLlxuICogQHJldHVybiB7c3RyaW5nfSBQb3N0Z3JlU1FMLWNvbXBhdGlibGUgcmVnZXggcGF0dGVybiBzdHJpbmcuXG4gKiBAZnVuY3Rpb24gY29udmVydEpzUmVnZXhUb1Bvc3RncmVzXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgIHBhcnRpY2lwYW50IEFwcFxuICogICBwYXJ0aWNpcGFudCBVdGlscyBhcyBjb252ZXJ0SnNSZWdleFRvUG9zdGdyZXNcbiAqICAgQXBwLT4+VXRpbHM6IGNvbnZlcnRKc1JlZ2V4VG9Qb3N0Z3JlcyhSZWdFeHAoXCJmb28uKlwiLFwiaVwiKSlcbiAqICAgVXRpbHMtPj5VdGlsczogUGFyc2Ugc3RyaW5nIG9yIHVzZSBSZWdFeHAuc291cmNlXG4gKiAgIFV0aWxzLS0+PkFwcDogXCJmb28uKlwiXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmZvci10eXBlb3JtXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb252ZXJ0SnNSZWdleFRvUG9zdGdyZXMoanNSZWdleDogUmVnRXhwIHwgc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgcnhwID0gbmV3IFJlZ0V4cCgvXlxcLyguKylcXC8oXFx3KykkL2cpO1xuICBpZiAodHlwZW9mIGpzUmVnZXggPT09IFwic3RyaW5nXCIpIHtcbiAgICBjb25zdCBtYXRjaCA9IHJ4cC5leGVjKGpzUmVnZXgpO1xuICAgIGlmIChtYXRjaCkge1xuICAgICAgY29uc3QgWywgcF0gPSBtYXRjaDtcbiAgICAgIGpzUmVnZXggPSBwO1xuICAgIH1cbiAgfVxuICBjb25zdCByZWdleCA9IHR5cGVvZiBqc1JlZ2V4ID09PSBcInN0cmluZ1wiID8gbmV3IFJlZ0V4cChqc1JlZ2V4KSA6IGpzUmVnZXg7XG5cbiAgY29uc3QgcGF0dGVybiA9IHJlZ2V4LnNvdXJjZTtcblxuICByZXR1cm4gcGF0dGVybjtcbn1cbiIsImltcG9ydCB7IENvbHVtbk1ldGFkYXRhQXJncyB9IGZyb20gXCJ0eXBlb3JtL21ldGFkYXRhLWFyZ3MvQ29sdW1uTWV0YWRhdGFBcmdzXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBhZ2dyZWdhdGVPck5ld0NvbHVtbihcbiAgdGFyZ2V0OiBhbnksXG4gIHByb3BlcnR5OiBzdHJpbmcsXG4gIGNvbHVtbnM6IENvbHVtbk1ldGFkYXRhQXJnc1tdLFxuICBvcHRpb25zOiBhbnkgPSB7fSxcbiAgbW9kZTogc3RyaW5nID0gXCJyZWd1bGFyXCJcbikge1xuICBjb25zdCBjb2xzID0gY29sdW1ucy5maWx0ZXIoXG4gICAgKGM6IENvbHVtbk1ldGFkYXRhQXJncykgPT5cbiAgICAgIGMudGFyZ2V0ID09PSB0YXJnZXQgJiYgYy5wcm9wZXJ0eU5hbWUgPT09IHByb3BlcnR5XG4gICk7XG5cbiAgaWYgKGNvbHMubGVuZ3RoID4gMSlcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgTXVsdGlwbGUgY29sdW1ucyBmb3IgJHtwcm9wZXJ0eX0gZm91bmQgZm9yIGdpdmVuIHRhcmdldDogJHtjb2x1bW5zLm1hcCgoYykgPT4gYy5wcm9wZXJ0eU5hbWUpLmpvaW4oXCIsIFwiKX1gXG4gICAgKTtcblxuICBpZiAoY29scy5sZW5ndGggPT09IDApIHtcbiAgICBjb2x1bW5zLnB1c2goe1xuICAgICAgdGFyZ2V0OiB0YXJnZXQsXG4gICAgICBwcm9wZXJ0eU5hbWU6IHByb3BlcnR5LFxuICAgICAgbW9kZTogbW9kZSxcbiAgICAgIG9wdGlvbnM6IG9wdGlvbnMsXG4gICAgfSBhcyBDb2x1bW5NZXRhZGF0YUFyZ3MpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGNvbHVtbiA9IGNvbHNbMF07XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjb2x1bW4sIFwib3B0aW9uc1wiLCB7XG4gICAgdmFsdWU6IHsgLi4uY29sdW1uLm9wdGlvbnMsIC4uLm9wdGlvbnMgfSxcbiAgICB3cml0YWJsZTogdHJ1ZSxcbiAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgfSk7XG5cbiAgaWYgKG1vZGUgIT09IFwicmVndWxhclwiKVxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjb2x1bW4sIFwibW9kZVwiLCB7XG4gICAgICB2YWx1ZTogbW9kZSxcbiAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICB9KTtcbn1cbiIsImltcG9ydCB7IEdlbmVyYXRlZE1ldGFkYXRhQXJncyB9IGZyb20gXCJ0eXBlb3JtL21ldGFkYXRhLWFyZ3MvR2VuZXJhdGVkTWV0YWRhdGFBcmdzXCI7XG5pbXBvcnQge1xuICBDb2x1bW5PcHRpb25zLFxuICBDb2x1bW5UeXBlLFxuICBDb2x1bW5UeXBlVW5kZWZpbmVkRXJyb3IsXG4gIGdldE1ldGFkYXRhQXJnc1N0b3JhZ2UsXG59IGZyb20gXCJ0eXBlb3JtXCI7XG5pbXBvcnQge1xuICBTaW1wbGVDb2x1bW5UeXBlLFxuICBTcGF0aWFsQ29sdW1uVHlwZSxcbiAgV2l0aExlbmd0aENvbHVtblR5cGUsXG4gIFdpdGhQcmVjaXNpb25Db2x1bW5UeXBlLFxuICBXaXRoV2lkdGhDb2x1bW5UeXBlLFxufSBmcm9tIFwidHlwZW9ybS9kcml2ZXIvdHlwZXMvQ29sdW1uVHlwZXNcIjtcbmltcG9ydCB7IENvbHVtbkNvbW1vbk9wdGlvbnMgfSBmcm9tIFwidHlwZW9ybS9kZWNvcmF0b3Ivb3B0aW9ucy9Db2x1bW5Db21tb25PcHRpb25zXCI7XG5pbXBvcnQgeyBTcGF0aWFsQ29sdW1uT3B0aW9ucyB9IGZyb20gXCJ0eXBlb3JtL2RlY29yYXRvci9vcHRpb25zL1NwYXRpYWxDb2x1bW5PcHRpb25zXCI7XG5pbXBvcnQgeyBDb2x1bW5XaXRoTGVuZ3RoT3B0aW9ucyB9IGZyb20gXCJ0eXBlb3JtL2RlY29yYXRvci9vcHRpb25zL0NvbHVtbldpdGhMZW5ndGhPcHRpb25zXCI7XG5pbXBvcnQgeyBDb2x1bW5XaXRoV2lkdGhPcHRpb25zIH0gZnJvbSBcInR5cGVvcm0vZGVjb3JhdG9yL29wdGlvbnMvQ29sdW1uV2l0aFdpZHRoT3B0aW9uc1wiO1xuaW1wb3J0IHsgQ29sdW1uTnVtZXJpY09wdGlvbnMgfSBmcm9tIFwidHlwZW9ybS9kZWNvcmF0b3Ivb3B0aW9ucy9Db2x1bW5OdW1lcmljT3B0aW9uc1wiO1xuaW1wb3J0IHsgQ29sdW1uRW51bU9wdGlvbnMgfSBmcm9tIFwidHlwZW9ybS9kZWNvcmF0b3Ivb3B0aW9ucy9Db2x1bW5FbnVtT3B0aW9uc1wiO1xuaW1wb3J0IHsgQ29sdW1uSHN0b3JlT3B0aW9ucyB9IGZyb20gXCJ0eXBlb3JtL2RlY29yYXRvci9vcHRpb25zL0NvbHVtbkhzdG9yZU9wdGlvbnNcIjtcbmltcG9ydCB7IENvbHVtbkVtYmVkZGVkT3B0aW9ucyB9IGZyb20gXCJ0eXBlb3JtL2RlY29yYXRvci9vcHRpb25zL0NvbHVtbkVtYmVkZGVkT3B0aW9uc1wiO1xuaW1wb3J0IHsgRW1iZWRkZWRNZXRhZGF0YUFyZ3MgfSBmcm9tIFwidHlwZW9ybS9tZXRhZGF0YS1hcmdzL0VtYmVkZGVkTWV0YWRhdGFBcmdzXCI7XG5pbXBvcnQgeyBDb2x1bW5NZXRhZGF0YUFyZ3MgfSBmcm9tIFwidHlwZW9ybS9tZXRhZGF0YS1hcmdzL0NvbHVtbk1ldGFkYXRhQXJnc1wiO1xuaW1wb3J0IHsgYWdncmVnYXRlT3JOZXdDb2x1bW4gfSBmcm9tIFwiLi91dGlsc1wiO1xuXG4vKipcbiAqIENvbHVtbiBkZWNvcmF0b3IgaXMgdXNlZCB0byBtYXJrIGEgc3BlY2lmaWMgY2xhc3MgcHJvcGVydHkgYXMgYSB0YWJsZSBjb2x1bW4uIE9ubHkgcHJvcGVydGllcyBkZWNvcmF0ZWQgd2l0aCB0aGlzXG4gKiBkZWNvcmF0b3Igd2lsbCBiZSBwZXJzaXN0ZWQgdG8gdGhlIGRhdGFiYXNlIHdoZW4gZW50aXR5IGJlIHNhdmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gQ29sdW1uKCk6IFByb3BlcnR5RGVjb3JhdG9yO1xuXG4vKipcbiAqIENvbHVtbiBkZWNvcmF0b3IgaXMgdXNlZCB0byBtYXJrIGEgc3BlY2lmaWMgY2xhc3MgcHJvcGVydHkgYXMgYSB0YWJsZSBjb2x1bW4uXG4gKiBPbmx5IHByb3BlcnRpZXMgZGVjb3JhdGVkIHdpdGggdGhpcyBkZWNvcmF0b3Igd2lsbCBiZSBwZXJzaXN0ZWQgdG8gdGhlIGRhdGFiYXNlIHdoZW4gZW50aXR5IGJlIHNhdmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gQ29sdW1uKG9wdGlvbnM6IENvbHVtbk9wdGlvbnMpOiBQcm9wZXJ0eURlY29yYXRvcjtcblxuLyoqXG4gKiBDb2x1bW4gZGVjb3JhdG9yIGlzIHVzZWQgdG8gbWFyayBhIHNwZWNpZmljIGNsYXNzIHByb3BlcnR5IGFzIGEgdGFibGUgY29sdW1uLlxuICogT25seSBwcm9wZXJ0aWVzIGRlY29yYXRlZCB3aXRoIHRoaXMgZGVjb3JhdG9yIHdpbGwgYmUgcGVyc2lzdGVkIHRvIHRoZSBkYXRhYmFzZSB3aGVuIGVudGl0eSBiZSBzYXZlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIENvbHVtbihcbiAgdHlwZTogU2ltcGxlQ29sdW1uVHlwZSxcbiAgb3B0aW9ucz86IENvbHVtbkNvbW1vbk9wdGlvbnNcbik6IFByb3BlcnR5RGVjb3JhdG9yO1xuXG4vKipcbiAqIENvbHVtbiBkZWNvcmF0b3IgaXMgdXNlZCB0byBtYXJrIGEgc3BlY2lmaWMgY2xhc3MgcHJvcGVydHkgYXMgYSB0YWJsZSBjb2x1bW4uXG4gKiBPbmx5IHByb3BlcnRpZXMgZGVjb3JhdGVkIHdpdGggdGhpcyBkZWNvcmF0b3Igd2lsbCBiZSBwZXJzaXN0ZWQgdG8gdGhlIGRhdGFiYXNlIHdoZW4gZW50aXR5IGJlIHNhdmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gQ29sdW1uKFxuICB0eXBlOiBTcGF0aWFsQ29sdW1uVHlwZSxcbiAgb3B0aW9ucz86IENvbHVtbkNvbW1vbk9wdGlvbnMgJiBTcGF0aWFsQ29sdW1uT3B0aW9uc1xuKTogUHJvcGVydHlEZWNvcmF0b3I7XG5cbi8qKlxuICogQ29sdW1uIGRlY29yYXRvciBpcyB1c2VkIHRvIG1hcmsgYSBzcGVjaWZpYyBjbGFzcyBwcm9wZXJ0eSBhcyBhIHRhYmxlIGNvbHVtbi5cbiAqIE9ubHkgcHJvcGVydGllcyBkZWNvcmF0ZWQgd2l0aCB0aGlzIGRlY29yYXRvciB3aWxsIGJlIHBlcnNpc3RlZCB0byB0aGUgZGF0YWJhc2Ugd2hlbiBlbnRpdHkgYmUgc2F2ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBDb2x1bW4oXG4gIHR5cGU6IFdpdGhMZW5ndGhDb2x1bW5UeXBlLFxuICBvcHRpb25zPzogQ29sdW1uQ29tbW9uT3B0aW9ucyAmIENvbHVtbldpdGhMZW5ndGhPcHRpb25zXG4pOiBQcm9wZXJ0eURlY29yYXRvcjtcblxuLyoqXG4gKiBDb2x1bW4gZGVjb3JhdG9yIGlzIHVzZWQgdG8gbWFyayBhIHNwZWNpZmljIGNsYXNzIHByb3BlcnR5IGFzIGEgdGFibGUgY29sdW1uLlxuICogT25seSBwcm9wZXJ0aWVzIGRlY29yYXRlZCB3aXRoIHRoaXMgZGVjb3JhdG9yIHdpbGwgYmUgcGVyc2lzdGVkIHRvIHRoZSBkYXRhYmFzZSB3aGVuIGVudGl0eSBiZSBzYXZlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIENvbHVtbihcbiAgdHlwZTogV2l0aFdpZHRoQ29sdW1uVHlwZSxcbiAgb3B0aW9ucz86IENvbHVtbkNvbW1vbk9wdGlvbnMgJiBDb2x1bW5XaXRoV2lkdGhPcHRpb25zXG4pOiBQcm9wZXJ0eURlY29yYXRvcjtcblxuLyoqXG4gKiBDb2x1bW4gZGVjb3JhdG9yIGlzIHVzZWQgdG8gbWFyayBhIHNwZWNpZmljIGNsYXNzIHByb3BlcnR5IGFzIGEgdGFibGUgY29sdW1uLlxuICogT25seSBwcm9wZXJ0aWVzIGRlY29yYXRlZCB3aXRoIHRoaXMgZGVjb3JhdG9yIHdpbGwgYmUgcGVyc2lzdGVkIHRvIHRoZSBkYXRhYmFzZSB3aGVuIGVudGl0eSBiZSBzYXZlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIENvbHVtbihcbiAgdHlwZTogV2l0aFByZWNpc2lvbkNvbHVtblR5cGUsXG4gIG9wdGlvbnM/OiBDb2x1bW5Db21tb25PcHRpb25zICYgQ29sdW1uTnVtZXJpY09wdGlvbnNcbik6IFByb3BlcnR5RGVjb3JhdG9yO1xuXG4vKipcbiAqIENvbHVtbiBkZWNvcmF0b3IgaXMgdXNlZCB0byBtYXJrIGEgc3BlY2lmaWMgY2xhc3MgcHJvcGVydHkgYXMgYSB0YWJsZSBjb2x1bW4uXG4gKiBPbmx5IHByb3BlcnRpZXMgZGVjb3JhdGVkIHdpdGggdGhpcyBkZWNvcmF0b3Igd2lsbCBiZSBwZXJzaXN0ZWQgdG8gdGhlIGRhdGFiYXNlIHdoZW4gZW50aXR5IGJlIHNhdmVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gQ29sdW1uKFxuICB0eXBlOiBcImVudW1cIixcbiAgb3B0aW9ucz86IENvbHVtbkNvbW1vbk9wdGlvbnMgJiBDb2x1bW5FbnVtT3B0aW9uc1xuKTogUHJvcGVydHlEZWNvcmF0b3I7XG5cbi8qKlxuICogQ29sdW1uIGRlY29yYXRvciBpcyB1c2VkIHRvIG1hcmsgYSBzcGVjaWZpYyBjbGFzcyBwcm9wZXJ0eSBhcyBhIHRhYmxlIGNvbHVtbi5cbiAqIE9ubHkgcHJvcGVydGllcyBkZWNvcmF0ZWQgd2l0aCB0aGlzIGRlY29yYXRvciB3aWxsIGJlIHBlcnNpc3RlZCB0byB0aGUgZGF0YWJhc2Ugd2hlbiBlbnRpdHkgYmUgc2F2ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBDb2x1bW4oXG4gIHR5cGU6IFwic2ltcGxlLWVudW1cIixcbiAgb3B0aW9ucz86IENvbHVtbkNvbW1vbk9wdGlvbnMgJiBDb2x1bW5FbnVtT3B0aW9uc1xuKTogUHJvcGVydHlEZWNvcmF0b3I7XG5cbi8qKlxuICogQ29sdW1uIGRlY29yYXRvciBpcyB1c2VkIHRvIG1hcmsgYSBzcGVjaWZpYyBjbGFzcyBwcm9wZXJ0eSBhcyBhIHRhYmxlIGNvbHVtbi5cbiAqIE9ubHkgcHJvcGVydGllcyBkZWNvcmF0ZWQgd2l0aCB0aGlzIGRlY29yYXRvciB3aWxsIGJlIHBlcnNpc3RlZCB0byB0aGUgZGF0YWJhc2Ugd2hlbiBlbnRpdHkgYmUgc2F2ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBDb2x1bW4oXG4gIHR5cGU6IFwic2V0XCIsXG4gIG9wdGlvbnM/OiBDb2x1bW5Db21tb25PcHRpb25zICYgQ29sdW1uRW51bU9wdGlvbnNcbik6IFByb3BlcnR5RGVjb3JhdG9yO1xuXG4vKipcbiAqIENvbHVtbiBkZWNvcmF0b3IgaXMgdXNlZCB0byBtYXJrIGEgc3BlY2lmaWMgY2xhc3MgcHJvcGVydHkgYXMgYSB0YWJsZSBjb2x1bW4uXG4gKiBPbmx5IHByb3BlcnRpZXMgZGVjb3JhdGVkIHdpdGggdGhpcyBkZWNvcmF0b3Igd2lsbCBiZSBwZXJzaXN0ZWQgdG8gdGhlIGRhdGFiYXNlIHdoZW4gZW50aXR5IGJlIHNhdmVkLlxuICovXG4vLyBAdHMtZXhwZWN0LWVycm9yIHNvbWUgdHlwZW9ybSB0aGluZ1xuZXhwb3J0IGZ1bmN0aW9uIENvbHVtbihcbiAgdHlwZTogXCJoc3RvcmVcIixcbiAgb3B0aW9ucz86IENvbHVtbkNvbW1vbk9wdGlvbnMgJiBDb2x1bW5Ic3RvcmVPcHRpb25zXG4pOiBQcm9wZXJ0eURlY29yYXRvcjtcblxuLyoqXG4gKiBDb2x1bW4gZGVjb3JhdG9yIGlzIHVzZWQgdG8gbWFyayBhIHNwZWNpZmljIGNsYXNzIHByb3BlcnR5IGFzIGEgdGFibGUgY29sdW1uLlxuICogT25seSBwcm9wZXJ0aWVzIGRlY29yYXRlZCB3aXRoIHRoaXMgZGVjb3JhdG9yIHdpbGwgYmUgcGVyc2lzdGVkIHRvIHRoZSBkYXRhYmFzZSB3aGVuIGVudGl0eSBiZSBzYXZlZC5cbiAqXG4gKiBQcm9wZXJ0eSBpbiBlbnRpdHkgY2FuIGJlIG1hcmtlZCBhcyBFbWJlZGRlZCwgYW5kIG9uIHBlcnNpc3QgYWxsIGNvbHVtbnMgZnJvbSB0aGUgZW1iZWRkZWQgYXJlIG1hcHBlZCB0byB0aGVcbiAqIHNpbmdsZSB0YWJsZSBvZiB0aGUgZW50aXR5IHdoZXJlIEVtYmVkZGVkIGlzIHVzZWQuIEFuZCBvbiBoeWRyYXRpb24gYWxsIGNvbHVtbnMgd2hpY2ggc3VwcG9zZWQgdG8gYmUgaW4gdGhlXG4gKiBlbWJlZGRlZCB3aWxsIGJlIG1hcHBlZCB0byBpdCBmcm9tIHRoZSBzaW5nbGUgdGFibGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBDb2x1bW4oXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5zYWZlLWZ1bmN0aW9uLXR5cGVcbiAgdHlwZTogKHR5cGU/OiBhbnkpID0+IEZ1bmN0aW9uLFxuICBvcHRpb25zPzogQ29sdW1uRW1iZWRkZWRPcHRpb25zXG4pOiBQcm9wZXJ0eURlY29yYXRvcjtcblxuLyoqXG4gKiBDb2x1bW4gZGVjb3JhdG9yIGlzIHVzZWQgdG8gbWFyayBhIHNwZWNpZmljIGNsYXNzIHByb3BlcnR5IGFzIGEgdGFibGUgY29sdW1uLlxuICogT25seSBwcm9wZXJ0aWVzIGRlY29yYXRlZCB3aXRoIHRoaXMgZGVjb3JhdG9yIHdpbGwgYmUgcGVyc2lzdGVkIHRvIHRoZSBkYXRhYmFzZSB3aGVuIGVudGl0eSBiZSBzYXZlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIENvbHVtbihcbiAgdHlwZU9yT3B0aW9ucz86IC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5zYWZlLWZ1bmN0aW9uLXR5cGVcbiAgfCAoKHR5cGU/OiBhbnkpID0+IEZ1bmN0aW9uKVxuICAgIHwgQ29sdW1uVHlwZVxuICAgIHwgKENvbHVtbk9wdGlvbnMgJiBDb2x1bW5FbWJlZGRlZE9wdGlvbnMpLFxuICBvcHRpb25zPzogQ29sdW1uT3B0aW9ucyAmIENvbHVtbkVtYmVkZGVkT3B0aW9uc1xuKTogUHJvcGVydHlEZWNvcmF0b3Ige1xuICByZXR1cm4gZnVuY3Rpb24gKG9iamVjdDogb2JqZWN0LCBwcm9wZXJ0eU5hbWU6IGFueSkge1xuICAgIC8vIG5vcm1hbGl6ZSBwYXJhbWV0ZXJzXG4gICAgbGV0IHR5cGU6IENvbHVtblR5cGUgfCB1bmRlZmluZWQ7XG4gICAgaWYgKFxuICAgICAgdHlwZW9mIHR5cGVPck9wdGlvbnMgPT09IFwic3RyaW5nXCIgfHxcbiAgICAgIHR5cGVvZiB0eXBlT3JPcHRpb25zID09PSBcImZ1bmN0aW9uXCJcbiAgICApIHtcbiAgICAgIHR5cGUgPSA8Q29sdW1uVHlwZT50eXBlT3JPcHRpb25zO1xuICAgIH0gZWxzZSBpZiAodHlwZU9yT3B0aW9ucykge1xuICAgICAgb3B0aW9ucyA9IDxDb2x1bW5PcHRpb25zPnR5cGVPck9wdGlvbnM7XG4gICAgICB0eXBlID0gdHlwZU9yT3B0aW9ucy50eXBlO1xuICAgIH1cbiAgICBpZiAoIW9wdGlvbnMpIG9wdGlvbnMgPSB7fSBhcyBDb2x1bW5PcHRpb25zO1xuXG4gICAgLy8gaWYgdHlwZSBpcyBub3QgZ2l2ZW4gZXhwbGljaXRseSB0aGVuIHRyeSB0byBndWVzcyBpdFxuICAgIGNvbnN0IHJlZmxlY3RNZXRhZGF0YVR5cGUgPVxuICAgICAgUmVmbGVjdCAmJiAoUmVmbGVjdCBhcyBhbnkpLmdldE1ldGFkYXRhXG4gICAgICAgID8gKFJlZmxlY3QgYXMgYW55KS5nZXRNZXRhZGF0YShcImRlc2lnbjp0eXBlXCIsIG9iamVjdCwgcHJvcGVydHlOYW1lKVxuICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICBpZiAoIXR5cGUgJiYgcmVmbGVjdE1ldGFkYXRhVHlwZSlcbiAgICAgIC8vIGlmIHR5cGUgaXMgbm90IGdpdmVuIGV4cGxpY2l0bHkgdGhlbiB0cnkgdG8gZ3Vlc3MgaXRcbiAgICAgIHR5cGUgPSByZWZsZWN0TWV0YWRhdGFUeXBlO1xuXG4gICAgLy8gY2hlY2sgaWYgdGhlcmUgaXMgbm8gdHlwZSBpbiBjb2x1bW4gb3B0aW9ucyB0aGVuIHNldCB0eXBlIGZyb20gZmlyc3QgZnVuY3Rpb24gYXJndW1lbnQsIG9yIGd1ZXNzZWQgb25lXG4gICAgaWYgKCFvcHRpb25zLnR5cGUgJiYgdHlwZSkgb3B0aW9ucy50eXBlID0gdHlwZTtcblxuICAgIC8vIHNwZWNpZnkgSFNUT1JFIHR5cGUgaWYgY29sdW1uIGlzIEhTVE9SRVxuICAgIGlmIChvcHRpb25zLnR5cGUgPT09IFwiaHN0b3JlXCIgJiYgIW9wdGlvbnMuaHN0b3JlVHlwZSlcbiAgICAgIG9wdGlvbnMuaHN0b3JlVHlwZSA9IHJlZmxlY3RNZXRhZGF0YVR5cGUgPT09IE9iamVjdCA/IFwib2JqZWN0XCIgOiBcInN0cmluZ1wiO1xuXG4gICAgaWYgKHR5cGVvZiB0eXBlT3JPcHRpb25zID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIC8vIHJlZ2lzdGVyIGFuIGVtYmVkZGVkXG4gICAgICBnZXRNZXRhZGF0YUFyZ3NTdG9yYWdlKCkuZW1iZWRkZWRzLnB1c2goe1xuICAgICAgICB0YXJnZXQ6IG9iamVjdC5jb25zdHJ1Y3RvcixcbiAgICAgICAgcHJvcGVydHlOYW1lOiBwcm9wZXJ0eU5hbWUsXG4gICAgICAgIGlzQXJyYXk6IHJlZmxlY3RNZXRhZGF0YVR5cGUgPT09IEFycmF5IHx8IG9wdGlvbnMuYXJyYXkgPT09IHRydWUsXG4gICAgICAgIHByZWZpeDogb3B0aW9ucy5wcmVmaXggIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMucHJlZml4IDogdW5kZWZpbmVkLFxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1mdW5jdGlvbi10eXBlXG4gICAgICAgIHR5cGU6IHR5cGVPck9wdGlvbnMgYXMgKHR5cGU/OiBhbnkpID0+IEZ1bmN0aW9uLFxuICAgICAgfSBhcyBFbWJlZGRlZE1ldGFkYXRhQXJncyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIHJlZ2lzdGVyIGEgcmVndWxhciBjb2x1bW5cblxuICAgICAgLy8gaWYgd2Ugc3RpbGwgZG9uJ3QgaGF2ZSBhIHR5cGUgdGhlbiB3ZSBuZWVkIHRvIGdpdmUgZXJyb3IgdG8gdXNlciB0aGF0IHR5cGUgaXMgcmVxdWlyZWRcbiAgICAgIGlmICghb3B0aW9ucy50eXBlKVxuICAgICAgICB0aHJvdyBuZXcgQ29sdW1uVHlwZVVuZGVmaW5lZEVycm9yKG9iamVjdCwgcHJvcGVydHlOYW1lKTtcblxuICAgICAgLy8gY3JlYXRlIHVuaXF1ZVxuICAgICAgaWYgKG9wdGlvbnMudW5pcXVlID09PSB0cnVlKVxuICAgICAgICBnZXRNZXRhZGF0YUFyZ3NTdG9yYWdlKCkudW5pcXVlcy5wdXNoKHtcbiAgICAgICAgICB0YXJnZXQ6IG9iamVjdC5jb25zdHJ1Y3RvcixcbiAgICAgICAgICBjb2x1bW5zOiBbcHJvcGVydHlOYW1lXSxcbiAgICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IGNvbHVtbnMgPSBnZXRNZXRhZGF0YUFyZ3NTdG9yYWdlKCkuY29sdW1ucztcbiAgICAgIGFnZ3JlZ2F0ZU9yTmV3Q29sdW1uKG9iamVjdC5jb25zdHJ1Y3RvciwgcHJvcGVydHlOYW1lLCBjb2x1bW5zLCBvcHRpb25zKTtcblxuICAgICAgaWYgKG9wdGlvbnMuZ2VuZXJhdGVkKSB7XG4gICAgICAgIGdldE1ldGFkYXRhQXJnc1N0b3JhZ2UoKS5nZW5lcmF0aW9ucy5wdXNoKHtcbiAgICAgICAgICB0YXJnZXQ6IG9iamVjdC5jb25zdHJ1Y3RvcixcbiAgICAgICAgICBwcm9wZXJ0eU5hbWU6IHByb3BlcnR5TmFtZSxcbiAgICAgICAgICBzdHJhdGVneTpcbiAgICAgICAgICAgIHR5cGVvZiBvcHRpb25zLmdlbmVyYXRlZCA9PT0gXCJzdHJpbmdcIlxuICAgICAgICAgICAgICA/IG9wdGlvbnMuZ2VuZXJhdGVkXG4gICAgICAgICAgICAgIDogXCJpbmNyZW1lbnRcIixcbiAgICAgICAgfSBhcyBHZW5lcmF0ZWRNZXRhZGF0YUFyZ3MpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcbn1cbiIsImltcG9ydCB7IENvbHVtbk9wdGlvbnMsIGdldE1ldGFkYXRhQXJnc1N0b3JhZ2UgfSBmcm9tIFwidHlwZW9ybVwiO1xuaW1wb3J0IHsgYWdncmVnYXRlT3JOZXdDb2x1bW4gfSBmcm9tIFwiLi91dGlsc1wiO1xuXG5leHBvcnQgZnVuY3Rpb24gVXBkYXRlRGF0ZUNvbHVtbihvcHRpb25zPzogQ29sdW1uT3B0aW9ucyk6IFByb3BlcnR5RGVjb3JhdG9yIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChvYmplY3Q6IGFueSwgcHJvcGVydHlOYW1lOiBhbnkpIHtcbiAgICBjb25zdCBjb2x1bW5zID0gZ2V0TWV0YWRhdGFBcmdzU3RvcmFnZSgpLmNvbHVtbnM7XG4gICAgYWdncmVnYXRlT3JOZXdDb2x1bW4oXG4gICAgICBvYmplY3QuY29uc3RydWN0b3IsXG4gICAgICBwcm9wZXJ0eU5hbWUsXG4gICAgICBjb2x1bW5zLFxuICAgICAgb3B0aW9ucyB8fCB7fSxcbiAgICAgIFwidXBkYXRlRGF0ZVwiXG4gICAgKTtcbiAgfTtcbn1cbiIsImltcG9ydCB7IENvbHVtbk9wdGlvbnMsIGdldE1ldGFkYXRhQXJnc1N0b3JhZ2UgfSBmcm9tIFwidHlwZW9ybVwiO1xuaW1wb3J0IHsgYWdncmVnYXRlT3JOZXdDb2x1bW4gfSBmcm9tIFwiLi91dGlsc1wiO1xuXG5leHBvcnQgZnVuY3Rpb24gQ3JlYXRlRGF0ZUNvbHVtbihvcHRpb25zPzogQ29sdW1uT3B0aW9ucyk6IFByb3BlcnR5RGVjb3JhdG9yIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChvYmplY3Q6IGFueSwgcHJvcGVydHlOYW1lOiBhbnkpIHtcbiAgICBjb25zdCBjb2x1bW5zID0gZ2V0TWV0YWRhdGFBcmdzU3RvcmFnZSgpLmNvbHVtbnM7XG4gICAgYWdncmVnYXRlT3JOZXdDb2x1bW4oXG4gICAgICBvYmplY3QuY29uc3RydWN0b3IsXG4gICAgICBwcm9wZXJ0eU5hbWUsXG4gICAgICBjb2x1bW5zLFxuICAgICAgb3B0aW9ucyB8fCB7fSxcbiAgICAgIFwiY3JlYXRlRGF0ZVwiXG4gICAgKTtcbiAgfTtcbn1cbiIsImltcG9ydCB7IE9iamVjdFV0aWxzIH0gZnJvbSBcInR5cGVvcm0vdXRpbC9PYmplY3RVdGlsc1wiO1xuaW1wb3J0IHsgUHJpbWFyeUdlbmVyYXRlZENvbHVtbk51bWVyaWNPcHRpb25zIH0gZnJvbSBcInR5cGVvcm0vZGVjb3JhdG9yL29wdGlvbnMvUHJpbWFyeUdlbmVyYXRlZENvbHVtbk51bWVyaWNPcHRpb25zXCI7XG5pbXBvcnQgeyBQcmltYXJ5R2VuZXJhdGVkQ29sdW1uVVVJRE9wdGlvbnMgfSBmcm9tIFwidHlwZW9ybS9kZWNvcmF0b3Ivb3B0aW9ucy9QcmltYXJ5R2VuZXJhdGVkQ29sdW1uVVVJRE9wdGlvbnNcIjtcbmltcG9ydCB7IFByaW1hcnlHZW5lcmF0ZWRDb2x1bW5JZGVudGl0eU9wdGlvbnMgfSBmcm9tIFwidHlwZW9ybS9kZWNvcmF0b3Ivb3B0aW9ucy9QcmltYXJ5R2VuZXJhdGVkQ29sdW1uSWRlbnRpdHlPcHRpb25zXCI7XG5pbXBvcnQgeyBDb2x1bW5PcHRpb25zLCBnZXRNZXRhZGF0YUFyZ3NTdG9yYWdlIH0gZnJvbSBcInR5cGVvcm1cIjtcbmltcG9ydCB7IEdlbmVyYXRlZE1ldGFkYXRhQXJncyB9IGZyb20gXCJ0eXBlb3JtL21ldGFkYXRhLWFyZ3MvR2VuZXJhdGVkTWV0YWRhdGFBcmdzXCI7XG5pbXBvcnQgeyBhZ2dyZWdhdGVPck5ld0NvbHVtbiB9IGZyb20gXCIuL3V0aWxzXCI7XG5cbi8qKlxuICogQ29sdW1uIGRlY29yYXRvciBpcyB1c2VkIHRvIG1hcmsgYSBzcGVjaWZpYyBjbGFzcyBwcm9wZXJ0eSBhcyBhIHRhYmxlIGNvbHVtbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFByaW1hcnlHZW5lcmF0ZWRDb2x1bW4oKTogUHJvcGVydHlEZWNvcmF0b3I7XG5cbi8qKlxuICogQ29sdW1uIGRlY29yYXRvciBpcyB1c2VkIHRvIG1hcmsgYSBzcGVjaWZpYyBjbGFzcyBwcm9wZXJ0eSBhcyBhIHRhYmxlIGNvbHVtbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFByaW1hcnlHZW5lcmF0ZWRDb2x1bW4oXG4gIG9wdGlvbnM6IFByaW1hcnlHZW5lcmF0ZWRDb2x1bW5OdW1lcmljT3B0aW9uc1xuKTogUHJvcGVydHlEZWNvcmF0b3I7XG5cbi8qKlxuICogQ29sdW1uIGRlY29yYXRvciBpcyB1c2VkIHRvIG1hcmsgYSBzcGVjaWZpYyBjbGFzcyBwcm9wZXJ0eSBhcyBhIHRhYmxlIGNvbHVtbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFByaW1hcnlHZW5lcmF0ZWRDb2x1bW4oXG4gIHN0cmF0ZWd5OiBcImluY3JlbWVudFwiLFxuICBvcHRpb25zPzogUHJpbWFyeUdlbmVyYXRlZENvbHVtbk51bWVyaWNPcHRpb25zXG4pOiBQcm9wZXJ0eURlY29yYXRvcjtcblxuLyoqXG4gKiBDb2x1bW4gZGVjb3JhdG9yIGlzIHVzZWQgdG8gbWFyayBhIHNwZWNpZmljIGNsYXNzIHByb3BlcnR5IGFzIGEgdGFibGUgY29sdW1uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gUHJpbWFyeUdlbmVyYXRlZENvbHVtbihcbiAgc3RyYXRlZ3k6IFwidXVpZFwiLFxuICBvcHRpb25zPzogUHJpbWFyeUdlbmVyYXRlZENvbHVtblVVSURPcHRpb25zXG4pOiBQcm9wZXJ0eURlY29yYXRvcjtcblxuLyoqXG4gKiBDb2x1bW4gZGVjb3JhdG9yIGlzIHVzZWQgdG8gbWFyayBhIHNwZWNpZmljIGNsYXNzIHByb3BlcnR5IGFzIGEgdGFibGUgY29sdW1uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gUHJpbWFyeUdlbmVyYXRlZENvbHVtbihcbiAgc3RyYXRlZ3k6IFwicm93aWRcIixcbiAgb3B0aW9ucz86IFByaW1hcnlHZW5lcmF0ZWRDb2x1bW5VVUlET3B0aW9uc1xuKTogUHJvcGVydHlEZWNvcmF0b3I7XG5cbmV4cG9ydCBmdW5jdGlvbiBQcmltYXJ5R2VuZXJhdGVkQ29sdW1uKFxuICBzdHJhdGVneTogXCJpZGVudGl0eVwiLFxuICBvcHRpb25zPzogUHJpbWFyeUdlbmVyYXRlZENvbHVtbklkZW50aXR5T3B0aW9uc1xuKTogUHJvcGVydHlEZWNvcmF0b3I7XG5cbi8qKlxuICogQ29sdW1uIGRlY29yYXRvciBpcyB1c2VkIHRvIG1hcmsgYSBzcGVjaWZpYyBjbGFzcyBwcm9wZXJ0eSBhcyBhIHRhYmxlIGNvbHVtbi5cbiAqIE9ubHkgcHJvcGVydGllcyBkZWNvcmF0ZWQgd2l0aCB0aGlzIGRlY29yYXRvciB3aWxsIGJlIHBlcnNpc3RlZCB0byB0aGUgZGF0YWJhc2Ugd2hlbiBlbnRpdHkgYmUgc2F2ZWQuXG4gKiBUaGlzIGNvbHVtbiBjcmVhdGVzIGFuIGludGVnZXIgUFJJTUFSWSBDT0xVTU4gd2l0aCBnZW5lcmF0ZWQgc2V0IHRvIHRydWUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBQcmltYXJ5R2VuZXJhdGVkQ29sdW1uKFxuICBzdHJhdGVneU9yT3B0aW9ucz86XG4gICAgfCBcImluY3JlbWVudFwiXG4gICAgfCBcInV1aWRcIlxuICAgIHwgXCJyb3dpZFwiXG4gICAgfCBcImlkZW50aXR5XCJcbiAgICB8IFByaW1hcnlHZW5lcmF0ZWRDb2x1bW5OdW1lcmljT3B0aW9uc1xuICAgIHwgUHJpbWFyeUdlbmVyYXRlZENvbHVtblVVSURPcHRpb25zXG4gICAgfCBQcmltYXJ5R2VuZXJhdGVkQ29sdW1uSWRlbnRpdHlPcHRpb25zLFxuICBtYXliZU9wdGlvbnM/OlxuICAgIHwgUHJpbWFyeUdlbmVyYXRlZENvbHVtbk51bWVyaWNPcHRpb25zXG4gICAgfCBQcmltYXJ5R2VuZXJhdGVkQ29sdW1uVVVJRE9wdGlvbnNcbiAgICB8IFByaW1hcnlHZW5lcmF0ZWRDb2x1bW5JZGVudGl0eU9wdGlvbnNcbik6IFByb3BlcnR5RGVjb3JhdG9yIHtcbiAgLy8gbm9ybWFsaXplIHBhcmFtZXRlcnNcbiAgY29uc3Qgb3B0aW9uczogQ29sdW1uT3B0aW9ucyA9IHt9O1xuICBsZXQgc3RyYXRlZ3k6IFwiaW5jcmVtZW50XCIgfCBcInV1aWRcIiB8IFwicm93aWRcIiB8IFwiaWRlbnRpdHlcIjtcbiAgaWYgKHN0cmF0ZWd5T3JPcHRpb25zKSB7XG4gICAgaWYgKHR5cGVvZiBzdHJhdGVneU9yT3B0aW9ucyA9PT0gXCJzdHJpbmdcIilcbiAgICAgIHN0cmF0ZWd5ID0gc3RyYXRlZ3lPck9wdGlvbnMgYXNcbiAgICAgICAgfCBcImluY3JlbWVudFwiXG4gICAgICAgIHwgXCJ1dWlkXCJcbiAgICAgICAgfCBcInJvd2lkXCJcbiAgICAgICAgfCBcImlkZW50aXR5XCI7XG5cbiAgICBpZiAoT2JqZWN0VXRpbHMuaXNPYmplY3Qoc3RyYXRlZ3lPck9wdGlvbnMpKSB7XG4gICAgICBzdHJhdGVneSA9IFwiaW5jcmVtZW50XCI7XG4gICAgICBPYmplY3QuYXNzaWduKG9wdGlvbnMsIHN0cmF0ZWd5T3JPcHRpb25zKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgc3RyYXRlZ3kgPSBcImluY3JlbWVudFwiO1xuICB9XG4gIGlmIChPYmplY3RVdGlscy5pc09iamVjdChtYXliZU9wdGlvbnMpKSBPYmplY3QuYXNzaWduKG9wdGlvbnMsIG1heWJlT3B0aW9ucyk7XG5cbiAgcmV0dXJuIGZ1bmN0aW9uIChvYmplY3Q6IGFueSwgcHJvcGVydHlOYW1lOiBhbnkpIHtcbiAgICAvLyBpZiBjb2x1bW4gdHlwZSBpcyBub3QgZXhwbGljaXRseSBzZXQgdGhlbiBkZXRlcm1pbmUgaXQgYmFzZWQgb24gZ2VuZXJhdGlvbiBzdHJhdGVneVxuICAgIGlmICghb3B0aW9ucy50eXBlKSB7XG4gICAgICBpZiAoc3RyYXRlZ3kgPT09IFwiaW5jcmVtZW50XCIgfHwgc3RyYXRlZ3kgPT09IFwiaWRlbnRpdHlcIikge1xuICAgICAgICBvcHRpb25zLnR5cGUgPSBOdW1iZXI7XG4gICAgICB9IGVsc2UgaWYgKHN0cmF0ZWd5ID09PSBcInV1aWRcIikge1xuICAgICAgICBvcHRpb25zLnR5cGUgPSBcInV1aWRcIjtcbiAgICAgIH0gZWxzZSBpZiAoc3RyYXRlZ3kgPT09IFwicm93aWRcIikge1xuICAgICAgICBvcHRpb25zLnR5cGUgPSBcImludFwiO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGV4cGxpY2l0bHkgc2V0IGEgcHJpbWFyeSBhbmQgZ2VuZXJhdGVkIHRvIGNvbHVtbiBvcHRpb25zXG4gICAgb3B0aW9ucy5wcmltYXJ5ID0gdHJ1ZTtcblxuICAgIGNvbnN0IGNvbHVtbnMgPSBnZXRNZXRhZGF0YUFyZ3NTdG9yYWdlKCkuY29sdW1ucztcbiAgICBhZ2dyZWdhdGVPck5ld0NvbHVtbihvYmplY3QuY29uc3RydWN0b3IsIHByb3BlcnR5TmFtZSwgY29sdW1ucywgb3B0aW9ucyk7XG4gICAgLy8gcmVnaXN0ZXIgZ2VuZXJhdGVkIG1ldGFkYXRhIGFyZ3NcbiAgICBnZXRNZXRhZGF0YUFyZ3NTdG9yYWdlKCkuZ2VuZXJhdGlvbnMucHVzaCh7XG4gICAgICB0YXJnZXQ6IG9iamVjdC5jb25zdHJ1Y3RvcixcbiAgICAgIHByb3BlcnR5TmFtZTogcHJvcGVydHlOYW1lLFxuICAgICAgc3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgIH0gYXMgR2VuZXJhdGVkTWV0YWRhdGFBcmdzKTtcbiAgfTtcbn1cbiIsImltcG9ydCB7XG4gIENvbHVtbk9wdGlvbnMsXG4gIENvbHVtblR5cGUsXG4gIENvbHVtblR5cGVVbmRlZmluZWRFcnJvcixcbiAgZ2V0TWV0YWRhdGFBcmdzU3RvcmFnZSxcbiAgUHJpbWFyeUNvbHVtbkNhbm5vdEJlTnVsbGFibGVFcnJvcixcbn0gZnJvbSBcInR5cGVvcm1cIjtcbmltcG9ydCB7IENvbHVtbk1ldGFkYXRhQXJncyB9IGZyb20gXCJ0eXBlb3JtL21ldGFkYXRhLWFyZ3MvQ29sdW1uTWV0YWRhdGFBcmdzXCI7XG5pbXBvcnQgeyBHZW5lcmF0ZWRNZXRhZGF0YUFyZ3MgfSBmcm9tIFwidHlwZW9ybS9tZXRhZGF0YS1hcmdzL0dlbmVyYXRlZE1ldGFkYXRhQXJnc1wiO1xuaW1wb3J0IHsgYWdncmVnYXRlT3JOZXdDb2x1bW4gfSBmcm9tIFwiLi91dGlsc1wiO1xuXG4vKipcbiAqIERlc2NyaWJlcyBhbGwgcHJpbWFyeSBrZXkgY29sdW1uJ3Mgb3B0aW9ucy5cbiAqIElmIHNwZWNpZmllZCwgdGhlIG51bGxhYmxlIGZpZWxkIG11c3QgYmUgc2V0IHRvIGZhbHNlLlxuICovXG5leHBvcnQgdHlwZSBQcmltYXJ5Q29sdW1uT3B0aW9ucyA9IENvbHVtbk9wdGlvbnMgJiB7IG51bGxhYmxlPzogZmFsc2UgfTtcblxuLyoqXG4gKiBDb2x1bW4gZGVjb3JhdG9yIGlzIHVzZWQgdG8gbWFyayBhIHNwZWNpZmljIGNsYXNzIHByb3BlcnR5IGFzIGEgdGFibGUgY29sdW1uLlxuICogT25seSBwcm9wZXJ0aWVzIGRlY29yYXRlZCB3aXRoIHRoaXMgZGVjb3JhdG9yIHdpbGwgYmUgcGVyc2lzdGVkIHRvIHRoZSBkYXRhYmFzZSB3aGVuIGVudGl0eSBiZSBzYXZlZC5cbiAqIFByaW1hcnkgY29sdW1ucyBhbHNvIGNyZWF0ZXMgYSBQUklNQVJZIEtFWSBmb3IgdGhpcyBjb2x1bW4gaW4gYSBkYi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFByaW1hcnlDb2x1bW4oXG4gIG9wdGlvbnM/OiBQcmltYXJ5Q29sdW1uT3B0aW9uc1xuKTogUHJvcGVydHlEZWNvcmF0b3I7XG5cbi8qKlxuICogQ29sdW1uIGRlY29yYXRvciBpcyB1c2VkIHRvIG1hcmsgYSBzcGVjaWZpYyBjbGFzcyBwcm9wZXJ0eSBhcyBhIHRhYmxlIGNvbHVtbi5cbiAqIE9ubHkgcHJvcGVydGllcyBkZWNvcmF0ZWQgd2l0aCB0aGlzIGRlY29yYXRvciB3aWxsIGJlIHBlcnNpc3RlZCB0byB0aGUgZGF0YWJhc2Ugd2hlbiBlbnRpdHkgYmUgc2F2ZWQuXG4gKiBQcmltYXJ5IGNvbHVtbnMgYWxzbyBjcmVhdGVzIGEgUFJJTUFSWSBLRVkgZm9yIHRoaXMgY29sdW1uIGluIGEgZGIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBQcmltYXJ5Q29sdW1uKFxuICB0eXBlPzogQ29sdW1uVHlwZSxcbiAgb3B0aW9ucz86IFByaW1hcnlDb2x1bW5PcHRpb25zXG4pOiBQcm9wZXJ0eURlY29yYXRvcjtcblxuLyoqXG4gKiBDb2x1bW4gZGVjb3JhdG9yIGlzIHVzZWQgdG8gbWFyayBhIHNwZWNpZmljIGNsYXNzIHByb3BlcnR5IGFzIGEgdGFibGUgY29sdW1uLlxuICogT25seSBwcm9wZXJ0aWVzIGRlY29yYXRlZCB3aXRoIHRoaXMgZGVjb3JhdG9yIHdpbGwgYmUgcGVyc2lzdGVkIHRvIHRoZSBkYXRhYmFzZSB3aGVuIGVudGl0eSBiZSBzYXZlZC5cbiAqIFByaW1hcnkgY29sdW1ucyBhbHNvIGNyZWF0ZXMgYSBQUklNQVJZIEtFWSBmb3IgdGhpcyBjb2x1bW4gaW4gYSBkYi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFByaW1hcnlDb2x1bW4oXG4gIHR5cGVPck9wdGlvbnM/OiBDb2x1bW5UeXBlIHwgUHJpbWFyeUNvbHVtbk9wdGlvbnMsXG4gIG9wdGlvbnM/OiBQcmltYXJ5Q29sdW1uT3B0aW9uc1xuKTogUHJvcGVydHlEZWNvcmF0b3Ige1xuICByZXR1cm4gZnVuY3Rpb24gKG9iamVjdDogYW55LCBwcm9wZXJ0eU5hbWU6IGFueSkge1xuICAgIC8vIG5vcm1hbGl6ZSBwYXJhbWV0ZXJzXG4gICAgbGV0IHR5cGU6IENvbHVtblR5cGUgfCB1bmRlZmluZWQ7XG4gICAgaWYgKFxuICAgICAgdHlwZW9mIHR5cGVPck9wdGlvbnMgPT09IFwic3RyaW5nXCIgfHxcbiAgICAgIHR5cGVPck9wdGlvbnMgPT09IFN0cmluZyB8fFxuICAgICAgdHlwZU9yT3B0aW9ucyA9PT0gQm9vbGVhbiB8fFxuICAgICAgdHlwZU9yT3B0aW9ucyA9PT0gTnVtYmVyXG4gICAgKSB7XG4gICAgICB0eXBlID0gdHlwZU9yT3B0aW9ucyBhcyBDb2x1bW5UeXBlO1xuICAgIH0gZWxzZSB7XG4gICAgICBvcHRpb25zID0gT2JqZWN0LmFzc2lnbih7fSwgPFByaW1hcnlDb2x1bW5PcHRpb25zPnR5cGVPck9wdGlvbnMpO1xuICAgIH1cbiAgICBpZiAoIW9wdGlvbnMpIG9wdGlvbnMgPSB7fSBhcyBQcmltYXJ5Q29sdW1uT3B0aW9ucztcblxuICAgIC8vIGlmIHR5cGUgaXMgbm90IGdpdmVuIGV4cGxpY2l0bHkgdGhlbiB0cnkgdG8gZ3Vlc3MgaXRcbiAgICBjb25zdCByZWZsZWN0TWV0YWRhdGFUeXBlID1cbiAgICAgIFJlZmxlY3QgJiYgKFJlZmxlY3QgYXMgYW55KS5nZXRNZXRhZGF0YVxuICAgICAgICA/IChSZWZsZWN0IGFzIGFueSkuZ2V0TWV0YWRhdGEoXCJkZXNpZ246dHlwZVwiLCBvYmplY3QsIHByb3BlcnR5TmFtZSlcbiAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgaWYgKCF0eXBlICYmIHJlZmxlY3RNZXRhZGF0YVR5cGUpIHR5cGUgPSByZWZsZWN0TWV0YWRhdGFUeXBlO1xuXG4gICAgLy8gY2hlY2sgaWYgdGhlcmUgaXMgbm8gdHlwZSBpbiBjb2x1bW4gb3B0aW9ucyB0aGVuIHNldCB0eXBlIGZyb20gZmlyc3QgZnVuY3Rpb24gYXJndW1lbnQsIG9yIGd1ZXNzZWQgb25lXG4gICAgaWYgKCFvcHRpb25zLnR5cGUgJiYgdHlwZSkgb3B0aW9ucy50eXBlID0gdHlwZTtcblxuICAgIC8vIGlmIHdlIHN0aWxsIGRvbid0IGhhdmUgYSB0eXBlIHRoZW4gd2UgbmVlZCB0byBnaXZlIGVycm9yIHRvIHVzZXIgdGhhdCB0eXBlIGlzIHJlcXVpcmVkXG4gICAgaWYgKCFvcHRpb25zLnR5cGUpIHRocm93IG5ldyBDb2x1bW5UeXBlVW5kZWZpbmVkRXJyb3Iob2JqZWN0LCBwcm9wZXJ0eU5hbWUpO1xuXG4gICAgLy8gY2hlY2sgaWYgY29sdW1uIGlzIG5vdCBudWxsYWJsZSwgYmVjYXVzZSB3ZSBjYW5ub3QgYWxsb3cgYSBwcmltYXJ5IGtleSB0byBiZSBudWxsYWJsZVxuICAgIGlmIChvcHRpb25zLm51bGxhYmxlKVxuICAgICAgdGhyb3cgbmV3IFByaW1hcnlDb2x1bW5DYW5ub3RCZU51bGxhYmxlRXJyb3Iob2JqZWN0LCBwcm9wZXJ0eU5hbWUpO1xuXG4gICAgLy8gZXhwbGljaXRseSBzZXQgYSBwcmltYXJ5IHRvIGNvbHVtbiBvcHRpb25zXG4gICAgb3B0aW9ucy5wcmltYXJ5ID0gdHJ1ZTtcblxuICAgIGNvbnN0IGNvbHVtbnMgPSBnZXRNZXRhZGF0YUFyZ3NTdG9yYWdlKCkuY29sdW1ucztcbiAgICBhZ2dyZWdhdGVPck5ld0NvbHVtbihvYmplY3QuY29uc3RydWN0b3IsIHByb3BlcnR5TmFtZSwgY29sdW1ucywgb3B0aW9ucyk7XG5cbiAgICBpZiAob3B0aW9ucy5nZW5lcmF0ZWQpIHtcbiAgICAgIGdldE1ldGFkYXRhQXJnc1N0b3JhZ2UoKS5nZW5lcmF0aW9ucy5wdXNoKHtcbiAgICAgICAgdGFyZ2V0OiBvYmplY3QuY29uc3RydWN0b3IsXG4gICAgICAgIHByb3BlcnR5TmFtZTogcHJvcGVydHlOYW1lLFxuICAgICAgICBzdHJhdGVneTpcbiAgICAgICAgICB0eXBlb2Ygb3B0aW9ucy5nZW5lcmF0ZWQgPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgID8gb3B0aW9ucy5nZW5lcmF0ZWRcbiAgICAgICAgICAgIDogXCJpbmNyZW1lbnRcIixcbiAgICAgIH0gYXMgR2VuZXJhdGVkTWV0YWRhdGFBcmdzKTtcbiAgICB9XG4gIH07XG59XG4iLCJpbXBvcnQgeyBFbnRpdHlPcHRpb25zLCBnZXRNZXRhZGF0YUFyZ3NTdG9yYWdlIH0gZnJvbSBcInR5cGVvcm1cIjtcbmltcG9ydCB7IE9iamVjdFV0aWxzIH0gZnJvbSBcInR5cGVvcm0vdXRpbC9PYmplY3RVdGlsc1wiO1xuaW1wb3J0IHsgVGFibGVNZXRhZGF0YUFyZ3MgfSBmcm9tIFwidHlwZW9ybS9tZXRhZGF0YS1hcmdzL1RhYmxlTWV0YWRhdGFBcmdzXCI7XG5cbi8qKlxuICogVGhpcyBkZWNvcmF0b3IgaXMgdXNlZCB0byBtYXJrIGNsYXNzZXMgdGhhdCB3aWxsIGJlIGFuIGVudGl0eSAodGFibGUgb3IgZG9jdW1lbnQgZGVwZW5kIG9uIGRhdGFiYXNlIHR5cGUpLlxuICogRGF0YWJhc2Ugc2NoZW1hIHdpbGwgYmUgY3JlYXRlZCBmb3IgYWxsIGNsYXNzZXMgZGVjb3JhdGVkIHdpdGggaXQsIGFuZCBSZXBvc2l0b3J5IGNhbiBiZSByZXRyaWV2ZWQgYW5kIHVzZWQgZm9yIGl0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gRW50aXR5KG9wdGlvbnM/OiBFbnRpdHlPcHRpb25zKTogQ2xhc3NEZWNvcmF0b3I7XG5cbi8qKlxuICogVGhpcyBkZWNvcmF0b3IgaXMgdXNlZCB0byBtYXJrIGNsYXNzZXMgdGhhdCB3aWxsIGJlIGFuIGVudGl0eSAodGFibGUgb3IgZG9jdW1lbnQgZGVwZW5kIG9uIGRhdGFiYXNlIHR5cGUpLlxuICogRGF0YWJhc2Ugc2NoZW1hIHdpbGwgYmUgY3JlYXRlZCBmb3IgYWxsIGNsYXNzZXMgZGVjb3JhdGVkIHdpdGggaXQsIGFuZCBSZXBvc2l0b3J5IGNhbiBiZSByZXRyaWV2ZWQgYW5kIHVzZWQgZm9yIGl0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gRW50aXR5KG5hbWU/OiBzdHJpbmcsIG9wdGlvbnM/OiBFbnRpdHlPcHRpb25zKTogQ2xhc3NEZWNvcmF0b3I7XG5cbi8qKlxuICogVGhpcyBkZWNvcmF0b3IgaXMgdXNlZCB0byBtYXJrIGNsYXNzZXMgdGhhdCB3aWxsIGJlIGFuIGVudGl0eSAodGFibGUgb3IgZG9jdW1lbnQgZGVwZW5kIG9uIGRhdGFiYXNlIHR5cGUpLlxuICogRGF0YWJhc2Ugc2NoZW1hIHdpbGwgYmUgY3JlYXRlZCBmb3IgYWxsIGNsYXNzZXMgZGVjb3JhdGVkIHdpdGggaXQsIGFuZCBSZXBvc2l0b3J5IGNhbiBiZSByZXRyaWV2ZWQgYW5kIHVzZWQgZm9yIGl0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gRW50aXR5KFxuICBuYW1lT3JPcHRpb25zPzogc3RyaW5nIHwgRW50aXR5T3B0aW9ucyxcbiAgbWF5YmVPcHRpb25zPzogRW50aXR5T3B0aW9uc1xuKTogQ2xhc3NEZWNvcmF0b3Ige1xuICBjb25zdCBvcHRpb25zID1cbiAgICAoT2JqZWN0VXRpbHMuaXNPYmplY3QobmFtZU9yT3B0aW9ucylcbiAgICAgID8gKG5hbWVPck9wdGlvbnMgYXMgRW50aXR5T3B0aW9ucylcbiAgICAgIDogbWF5YmVPcHRpb25zKSB8fCB7fTtcbiAgY29uc3QgbmFtZSA9IHR5cGVvZiBuYW1lT3JPcHRpb25zID09PSBcInN0cmluZ1wiID8gbmFtZU9yT3B0aW9ucyA6IG9wdGlvbnMubmFtZTtcblxuICByZXR1cm4gZnVuY3Rpb24gKHRhcmdldCkge1xuICAgIGNvbnN0IHRhYmxlcyA9IGdldE1ldGFkYXRhQXJnc1N0b3JhZ2UoKS50YWJsZXM7XG4gICAgdGFibGVzLnB1c2goe1xuICAgICAgdGFyZ2V0OiB0YXJnZXQsXG4gICAgICBuYW1lOiBuYW1lLFxuICAgICAgdHlwZTogXCJyZWd1bGFyXCIsXG4gICAgICBvcmRlckJ5OiBvcHRpb25zLm9yZGVyQnkgPyBvcHRpb25zLm9yZGVyQnkgOiB1bmRlZmluZWQsXG4gICAgICBlbmdpbmU6IG9wdGlvbnMuZW5naW5lID8gb3B0aW9ucy5lbmdpbmUgOiB1bmRlZmluZWQsXG4gICAgICBkYXRhYmFzZTogb3B0aW9ucy5kYXRhYmFzZSA/IG9wdGlvbnMuZGF0YWJhc2UgOiB1bmRlZmluZWQsXG4gICAgICBzY2hlbWE6IG9wdGlvbnMuc2NoZW1hID8gb3B0aW9ucy5zY2hlbWEgOiB1bmRlZmluZWQsXG4gICAgICBzeW5jaHJvbml6ZTogb3B0aW9ucy5zeW5jaHJvbml6ZSxcbiAgICAgIHdpdGhvdXRSb3dpZDogb3B0aW9ucy53aXRob3V0Um93aWQsXG4gICAgICBjb21tZW50OiBvcHRpb25zLmNvbW1lbnQgPyBvcHRpb25zLmNvbW1lbnQgOiB1bmRlZmluZWQsXG4gICAgfSBhcyBUYWJsZU1ldGFkYXRhQXJncyk7XG4gIH07XG59XG4iLCJpbXBvcnQge1xuICBBZGFwdGVyLFxuICBDYXNjYWRlLFxuICBDYXNjYWRlTWV0YWRhdGEsXG4gIENvbm5lY3Rpb25FcnJvcixcbiAgZmluYWwsXG4gIFBlcnNpc3RlbmNlS2V5cyxcbiAgUmVsYXRpb25zTWV0YWRhdGEsXG4gIFJlcG9zaXRvcnksXG4gIFNlcXVlbmNlLFxuICB0eXBlIFNlcXVlbmNlT3B0aW9ucyxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyByZXNlcnZlZEF0dHJpYnV0ZXMsIFR5cGVPUk1GbGF2b3VyIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQge1xuICBCYXNlRXJyb3IsXG4gIENvbmZsaWN0RXJyb3IsXG4gIENvbnRleHQsXG4gIERCS2V5cyxcbiAgREVGQVVMVF9FUlJPUl9NRVNTQUdFUyBhcyBEQl9ERUZBVUxUX0VSUk9SX01FU1NBR0VTLFxuICBmaW5kUHJpbWFyeUtleSxcbiAgSW50ZXJuYWxFcnJvcixcbiAgTm90Rm91bmRFcnJvcixcbiAgT3BlcmF0aW9uS2V5cyxcbiAgcmVhZG9ubHksXG4gIFVwZGF0ZVZhbGlkYXRpb25LZXlzLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCBcInJlZmxlY3QtbWV0YWRhdGFcIjtcbmltcG9ydCB7XG4gIHR5cGUgQ29uc3RydWN0b3IsXG4gIGRhdGUsXG4gIERlY29yYXRpb24sXG4gIERFRkFVTFRfRVJST1JfTUVTU0FHRVMsXG4gIGxpc3QsXG4gIE1heExlbmd0aFZhbGlkYXRvck9wdGlvbnMsXG4gIE1heFZhbGlkYXRvck9wdGlvbnMsXG4gIE1pbkxlbmd0aFZhbGlkYXRvck9wdGlvbnMsXG4gIE1pblZhbGlkYXRvck9wdGlvbnMsXG4gIE1vZGVsLFxuICBNb2RlbEtleXMsXG4gIFBhdHRlcm5WYWxpZGF0b3JPcHRpb25zLFxuICBwcm9wLFxuICBwcm9wTWV0YWRhdGEsXG4gIHJlcXVpcmVkLFxuICB0eXBlLFxuICBUeXBlTWV0YWRhdGEsXG4gIFZhbGlkYXRpb24sXG4gIFZhbGlkYXRpb25LZXlzLFxuICBWYWxpZGF0b3JPcHRpb25zLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBJbmRleEVycm9yIH0gZnJvbSBcIi4vZXJyb3JzXCI7XG5pbXBvcnQgeyBUeXBlT1JNU3RhdGVtZW50IH0gZnJvbSBcIi4vcXVlcnlcIjtcbmltcG9ydCB7IFR5cGVPUk1TZXF1ZW5jZSB9IGZyb20gXCIuL3NlcXVlbmNlc1wiO1xuaW1wb3J0IHsgZ2VuZXJhdGVJbmRleGVzIH0gZnJvbSBcIi4vaW5kZXhlc1wiO1xuaW1wb3J0IHsgVHlwZU9STUZsYWdzLCBUeXBlT1JNUXVlcnksIFR5cGVPUk1UYWJsZVNwZWMgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgYXBwbHksIFJlZmxlY3Rpb24gfSBmcm9tIFwiQGRlY2FmLXRzL3JlZmxlY3Rpb25cIjtcbmltcG9ydCB7IFR5cGVPUk1SZXBvc2l0b3J5IH0gZnJvbSBcIi4vVHlwZU9STVJlcG9zaXRvcnlcIjtcbmltcG9ydCB7IExvZ2dpbmcgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7IFR5cGVPUk1EaXNwYXRjaCB9IGZyb20gXCIuL1R5cGVPUk1EaXNwYXRjaFwiO1xuaW1wb3J0IHsgY29udmVydEpzUmVnZXhUb1Bvc3RncmVzIH0gZnJvbSBcIi4vdXRpbHNcIjtcbmltcG9ydCB7XG4gIERhdGFTb3VyY2UsXG4gIEZpbmRPbmVPcHRpb25zLFxuICBJbixcbiAgSW5zZXJ0UmVzdWx0LFxuICBSZWxhdGlvbk9wdGlvbnMsXG4gIE9uZVRvT25lLFxuICBKb2luQ29sdW1uLFxuICBNYW55VG9NYW55LFxuICBTZWxlY3RRdWVyeUJ1aWxkZXIsXG4gIFZlcnNpb25Db2x1bW4sXG4gIE9uZVRvTWFueSxcbiAgTWFueVRvT25lLFxuICBKb2luVGFibGUsXG59IGZyb20gXCJ0eXBlb3JtXCI7XG5pbXBvcnQgeyBEYXRhU291cmNlT3B0aW9ucyB9IGZyb20gXCJ0eXBlb3JtL2RhdGEtc291cmNlL0RhdGFTb3VyY2VPcHRpb25zXCI7XG5pbXBvcnQgeyBDb2x1bW4gfSBmcm9tIFwiLi9vdmVycmlkZXMvQ29sdW1uXCI7XG5pbXBvcnQgeyBVcGRhdGVEYXRlQ29sdW1uIH0gZnJvbSBcIi4vb3ZlcnJpZGVzL1VwZGF0ZURhdGVDb2x1bW5cIjtcbmltcG9ydCB7IENyZWF0ZURhdGVDb2x1bW4gfSBmcm9tIFwiLi9vdmVycmlkZXMvQ3JlYXRlRGF0ZUNvbHVtblwiO1xuaW1wb3J0IHsgUHJpbWFyeUdlbmVyYXRlZENvbHVtbiB9IGZyb20gXCIuL292ZXJyaWRlcy9QcmltYXJ5R2VuZXJhdGVkQ29sdW1uXCI7XG5pbXBvcnQgeyBQcmltYXJ5Q29sdW1uIH0gZnJvbSBcIi4vb3ZlcnJpZGVzL1ByaW1hcnlDb2x1bW5cIjtcbmltcG9ydCB7IEVudGl0eSB9IGZyb20gXCIuL292ZXJyaWRlcy9FbnRpdHlcIjtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZWRCeU9uUG9zdGdyZXNDcmVhdGVVcGRhdGU8XG4gIE0gZXh0ZW5kcyBNb2RlbCxcbiAgUiBleHRlbmRzIFR5cGVPUk1SZXBvc2l0b3J5PE0+LFxuICBWIGV4dGVuZHMgUmVsYXRpb25zTWV0YWRhdGEsXG4+KFxuICB0aGlzOiBSLFxuICBjb250ZXh0OiBDb250ZXh0PFR5cGVPUk1GbGFncz4sXG4gIGRhdGE6IFYsXG4gIGtleToga2V5b2YgTSxcbiAgbW9kZWw6IE1cbik6IFByb21pc2U8dm9pZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHVzZXIgPSBjb250ZXh0LmdldChcInVzZXJcIik7XG4gICAgbW9kZWxba2V5XSA9IHVzZXIgYXMgTVt0eXBlb2Yga2V5XTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgIFwiTm8gVXNlciBmb3VuZCBpbiBjb250ZXh0LiBQbGVhc2UgcHJvdmlkZSBhIHVzZXIgaW4gdGhlIGNvbnRleHRcIlxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQWRhcHRlciBmb3IgVHlwZU9STS1iYWNrZWQgcGVyc2lzdGVuY2Ugb3BlcmF0aW9ucy5cbiAqIEBzdW1tYXJ5IEltcGxlbWVudHMgdGhlIERlY2FmLnRzIEFkYXB0ZXIgb3ZlciBhIFR5cGVPUk0gRGF0YVNvdXJjZSwgcHJvdmlkaW5nIENSVUQgb3BlcmF0aW9ucywgcXVlcnkvc3RhdGVtZW50IGZhY3Rvcmllcywgc2VxdWVuY2UgbWFuYWdlbWVudCwgZXJyb3IgcGFyc2luZywgYW5kIGRlY29yYXRpb24gaGVscGVycy5cbiAqIEB0ZW1wbGF0ZSBZIFRoZSBuYXRpdmUgY29uZmlndXJhdGlvbiB0eXBlIChUeXBlT1JNIERhdGFTb3VyY2VPcHRpb25zKS5cbiAqIEB0ZW1wbGF0ZSBGIFRoZSByZXBvc2l0b3J5IGZsYWdzIHR5cGUuXG4gKiBAdGVtcGxhdGUgQyBUaGUgY29udGV4dCB0eXBlLlxuICogQHBhcmFtIHtEYXRhU291cmNlT3B0aW9uc30gc2NvcGUgVGhlIERhdGFTb3VyY2Ugb3B0aW9ucyBmb3IgdGhlIGFkYXB0ZXIuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmxhdm91ciBUaGUgZmxhdm91ciBvZiB0aGUgYWRhcHRlci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbYWxpYXNdIE9wdGlvbmFsIGFsaWFzIGZvciB0aGUgYWRhcHRlci5cbiAqIEBjbGFzcyBUeXBlT1JNQWRhcHRlclxuICogQGV4YW1wbGVcbiAqIGNvbnN0IGFkYXB0ZXIgPSBuZXcgVHlwZU9STUFkYXB0ZXIoeyB0eXBlOiAncG9zdGdyZXMnLCAvKiAuLi4gKlxcLyB9KTtcbiAqIGF3YWl0IGFkYXB0ZXIuaW5pdGlhbGl6ZSgpO1xuICogY29uc3QgcmVwbyA9IG5ldyAoYWRhcHRlci5yZXBvc2l0b3J5PFVzZXI+KCkpKGFkYXB0ZXIsIFVzZXIpO1xuICogY29uc3QgY3JlYXRlZCA9IGF3YWl0IHJlcG8uY3JlYXRlKG5ldyBVc2VyKHsgbmFtZTogJ0FsaWNlJyB9KSk7XG4gKlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICBwYXJ0aWNpcGFudCBBcHBcbiAqICAgcGFydGljaXBhbnQgQWRhcHRlciBhcyBUeXBlT1JNQWRhcHRlclxuICogICBwYXJ0aWNpcGFudCBSZXBvIGFzIFR5cGVPUk1SZXBvc2l0b3J5XG4gKiAgIHBhcnRpY2lwYW50IERTIGFzIFR5cGVPUk0gRGF0YVNvdXJjZVxuICpcbiAqICAgQXBwLT4+QWRhcHRlcjogbmV3IFR5cGVPUk1BZGFwdGVyKG9wdHMpXG4gKiAgIEFkYXB0ZXItPj5EUzogaW5pdGlhbGl6ZSgpXG4gKiAgIEFwcC0+PkFkYXB0ZXI6IHJlcG9zaXRvcnkoKVxuICogICBBZGFwdGVyLS0+PkFwcDogVHlwZU9STVJlcG9zaXRvcnlcbiAqICAgQXBwLT4+UmVwbzogY3JlYXRlKG1vZGVsKVxuICogICBSZXBvLT4+QWRhcHRlcjogcHJlcGFyZS9jcmVhdGUvcmV2ZXJ0XG4gKiAgIEFkYXB0ZXItLT4+UmVwbzogTW9kZWxcbiAqICAgUmVwby0tPj5BcHA6IE1vZGVsXG4gKi9cbmV4cG9ydCBjbGFzcyBUeXBlT1JNQWRhcHRlciBleHRlbmRzIEFkYXB0ZXI8XG4gIERhdGFTb3VyY2VPcHRpb25zLFxuICBUeXBlT1JNUXVlcnksXG4gIFR5cGVPUk1GbGFncyxcbiAgQ29udGV4dDxUeXBlT1JNRmxhZ3M+XG4+IHtcbiAgcHJpdmF0ZSBfZGF0YVNvdXJjZT86IERhdGFTb3VyY2U7XG5cbiAgZ2V0IGRhdGFTb3VyY2UoKTogRGF0YVNvdXJjZSB7XG4gICAgaWYgKCF0aGlzLl9kYXRhU291cmNlKSB7XG4gICAgICBjb25zdCBtb2RlbHMgPSBBZGFwdGVyLm1vZGVscyh0aGlzLmZsYXZvdXIpO1xuICAgICAgdGhpcy5fZGF0YVNvdXJjZSA9IG5ldyBEYXRhU291cmNlKFxuICAgICAgICBPYmplY3QuYXNzaWduKHRoaXMubmF0aXZlLCB7XG4gICAgICAgICAgZW50aXRpZXM6IG1vZGVscy5tYXAoKGMpID0+IGNbTW9kZWxLZXlzLkFOQ0hPUiBhcyBrZXlvZiB0eXBlb2YgY10pLFxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX2RhdGFTb3VyY2U7XG4gIH1cbiAgLy8gcHJvdGVjdGVkIGRhdGFTb3VcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBEYXRhU291cmNlT3B0aW9ucywgYWxpYXM/OiBzdHJpbmcpIHtcbiAgICBzdXBlcihvcHRpb25zLCBUeXBlT1JNRmxhdm91ciwgYWxpYXMpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGFzeW5jIGZsYWdzPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgb3BlcmF0aW9uOiBPcGVyYXRpb25LZXlzLFxuICAgIG1vZGVsOiBDb25zdHJ1Y3RvcjxNPixcbiAgICBmbGFnczogUGFydGlhbDxUeXBlT1JNRmxhZ3M+XG4gICk6IFByb21pc2U8VHlwZU9STUZsYWdzPiB7XG4gICAgY29uc3QgZiA9IGF3YWl0IHN1cGVyLmZsYWdzKG9wZXJhdGlvbiwgbW9kZWwsIGZsYWdzKTtcbiAgICBjb25zdCBuZXdPYmo6IGFueSA9IHtcbiAgICAgIHVzZXI6IChhd2FpdCBUeXBlT1JNQWRhcHRlci5nZXRDdXJyZW50VXNlcih0aGlzLmRhdGFTb3VyY2UpKSBhcyBzdHJpbmcsXG4gICAgfTtcbiAgICBjb25zdCBtID0gbmV3IG1vZGVsKCk7XG5cbiAgICBjb25zdCBleGNlcHRpb25zOiBzdHJpbmdbXSA9IFtdO1xuICAgIGlmIChvcGVyYXRpb24gPT09IE9wZXJhdGlvbktleXMuQ1JFQVRFKSB7XG4gICAgICBjb25zdCBwayA9IGZpbmRQcmltYXJ5S2V5KG0pLmlkO1xuICAgICAgZXhjZXB0aW9ucy5wdXNoKHBrIGFzIHN0cmluZyk7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgb3BlcmF0aW9uID09PSBPcGVyYXRpb25LZXlzLkNSRUFURSB8fFxuICAgICAgb3BlcmF0aW9uID09PSBPcGVyYXRpb25LZXlzLlVQREFURVxuICAgICkge1xuICAgICAgY29uc3QgZGVjcyA9IE9iamVjdC5rZXlzKG0pLnJlZHVjZSgoYWNjdW06IFJlY29yZDxzdHJpbmcsIGFueT4sIGtleSkgPT4ge1xuICAgICAgICBjb25zdCBkZWNzID0gUmVmbGVjdGlvbi5nZXRQcm9wZXJ0eURlY29yYXRvcnMoXG4gICAgICAgICAgVmFsaWRhdGlvbktleXMuUkVGTEVDVCxcbiAgICAgICAgICBtLFxuICAgICAgICAgIGtleSxcbiAgICAgICAgICB0cnVlXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IGRlYyA9IGRlY3MuZGVjb3JhdG9ycy5maW5kKFxuICAgICAgICAgIChkZWM6IGFueSkgPT5cbiAgICAgICAgICAgIGRlYy5rZXkgPT09IERCS2V5cy5USU1FU1RBTVAgJiZcbiAgICAgICAgICAgIGRlYy5wcm9wcy5vcGVyYXRpb24uaW5kZXhPZihvcGVyYXRpb24pICE9PSAtMVxuICAgICAgICApO1xuICAgICAgICBpZiAoZGVjKSB7XG4gICAgICAgICAgYWNjdW1ba2V5XSA9IGRlYy5wcm9wcztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYWNjdW07XG4gICAgICB9LCB7fSk7XG5cbiAgICAgIGV4Y2VwdGlvbnMucHVzaCguLi5PYmplY3Qua2V5cyhkZWNzKSk7XG4gICAgfVxuXG4gICAgbmV3T2JqLmlnbm9yZWRWYWxpZGF0aW9uUHJvcGVydGllcyA9IChcbiAgICAgIGYuaWdub3JlZFZhbGlkYXRpb25Qcm9wZXJ0aWVzID8gZi5pZ25vcmVkVmFsaWRhdGlvblByb3BlcnRpZXMgOiBbXVxuICAgICkuY29uY2F0KC4uLmV4Y2VwdGlvbnMpO1xuICAgIHJldHVybiBPYmplY3QuYXNzaWduKGYsIG5ld09iaikgYXMgVHlwZU9STUZsYWdzO1xuICB9XG5cbiAgQGZpbmFsKClcbiAgcHJvdGVjdGVkIG92ZXJyaWRlIERpc3BhdGNoKCk6IFR5cGVPUk1EaXNwYXRjaCB7XG4gICAgcmV0dXJuIG5ldyBUeXBlT1JNRGlzcGF0Y2goKTtcbiAgfVxuXG4gIEBmaW5hbCgpXG4gIG92ZXJyaWRlIHJlcG9zaXRvcnk8TSBleHRlbmRzIE1vZGVsPigpOiBDb25zdHJ1Y3RvcjxUeXBlT1JNUmVwb3NpdG9yeTxNPj4ge1xuICAgIHJldHVybiBUeXBlT1JNUmVwb3NpdG9yeTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIG5ldyBQb3N0Z3JlcyBzdGF0ZW1lbnQgZm9yIHF1ZXJ5aW5nXG4gICAqIEBzdW1tYXJ5IEZhY3RvcnkgbWV0aG9kIHRoYXQgY3JlYXRlcyBhIG5ldyBQb3N0Z3Jlc1N0YXRlbWVudCBpbnN0YW5jZSBmb3IgYnVpbGRpbmcgcXVlcmllc1xuICAgKiBAdGVtcGxhdGUgTSAtIFRoZSBtb2RlbCB0eXBlXG4gICAqIEByZXR1cm4ge1R5cGVPUk1TdGF0ZW1lbnQ8TSwgYW55Pn0gQSBuZXcgUG9zdGdyZXNTdGF0ZW1lbnQgaW5zdGFuY2VcbiAgICovXG4gIEBmaW5hbCgpXG4gIFN0YXRlbWVudDxNIGV4dGVuZHMgTW9kZWw+KCk6IFR5cGVPUk1TdGF0ZW1lbnQ8TSwgYW55PiB7XG4gICAgcmV0dXJuIG5ldyBUeXBlT1JNU3RhdGVtZW50KHRoaXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgbmV3IFBvc3RncmVTUUwgc2VxdWVuY2VcbiAgICogQHN1bW1hcnkgRmFjdG9yeSBtZXRob2QgdGhhdCBjcmVhdGVzIGEgbmV3IFBvc3RncmVTUUxTZXF1ZW5jZSBpbnN0YW5jZSBmb3IgbWFuYWdpbmcgc2VxdWVuY2VzXG4gICAqIEBwYXJhbSB7U2VxdWVuY2VPcHRpb25zfSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgZm9yIHRoZSBzZXF1ZW5jZVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFNlcXVlbmNlPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSBuZXcgU2VxdWVuY2UgaW5zdGFuY2VcbiAgICovXG4gIEBmaW5hbCgpXG4gIGFzeW5jIFNlcXVlbmNlKG9wdGlvbnM6IFNlcXVlbmNlT3B0aW9ucyk6IFByb21pc2U8U2VxdWVuY2U+IHtcbiAgICByZXR1cm4gbmV3IFR5cGVPUk1TZXF1ZW5jZShvcHRpb25zLCB0aGlzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gSW5pdGlhbGl6ZXMgdGhlIGFkYXB0ZXIgYnkgY3JlYXRpbmcgaW5kZXhlcyBmb3IgYWxsIG1hbmFnZWQgbW9kZWxzXG4gICAqIEBzdW1tYXJ5IFNldHMgdXAgdGhlIG5lY2Vzc2FyeSBkYXRhYmFzZSBpbmRleGVzIGZvciBhbGwgbW9kZWxzIG1hbmFnZWQgYnkgdGhpcyBhZGFwdGVyXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gaW5pdGlhbGl6YXRpb24gaXMgY29tcGxldGVcbiAgICovXG4gIGFzeW5jIGluaXRpYWxpemUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZHMgPSB0aGlzLmRhdGFTb3VyY2U7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGRzLmluaXRpYWxpemUoKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmluaXRpYWxpemUpO1xuICAgIGxvZy52ZXJib3NlKGAke3RoaXMuZmxhdm91cn0gYWRhcHRlciBpbml0aWFsaXplZGApO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGluZGV4ZXMgZm9yIHRoZSBnaXZlbiBtb2RlbHNcbiAgICogQHN1bW1hcnkgQWJzdHJhY3QgbWV0aG9kIHRoYXQgbXVzdCBiZSBpbXBsZW1lbnRlZCB0byBjcmVhdGUgZGF0YWJhc2UgaW5kZXhlcyBmb3IgdGhlIHNwZWNpZmllZCBtb2RlbHNcbiAgICogQHRlbXBsYXRlIE0gLSBUaGUgbW9kZWwgdHlwZVxuICAgKiBAcGFyYW0gey4uLkNvbnN0cnVjdG9yPE0+fSBtb2RlbHMgLSBUaGUgbW9kZWwgY29uc3RydWN0b3JzIHRvIGNyZWF0ZSBpbmRleGVzIGZvclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBpbmRleGVzIGFyZSBjcmVhdGVkXG4gICAqL1xuICBAZmluYWwoKVxuICBwcm90ZWN0ZWQgYXN5bmMgaW5kZXg8TSBleHRlbmRzIE1vZGVsPihcbiAgICAuLi5tb2RlbHM6IENvbnN0cnVjdG9yPE0+W11cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgaW5kZXhlczogVHlwZU9STVF1ZXJ5W10gPSBnZW5lcmF0ZUluZGV4ZXMobW9kZWxzKTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmRhdGFTb3VyY2UucXVlcnkoXCJCRUdJTlwiKTtcblxuICAgICAgZm9yIChjb25zdCBpbmRleCBvZiBpbmRleGVzKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuZGF0YVNvdXJjZS5xdWVyeShpbmRleC5xdWVyeSwgaW5kZXgudmFsdWVzKTtcbiAgICAgIH1cblxuICAgICAgYXdhaXQgdGhpcy5kYXRhU291cmNlLnF1ZXJ5KFwiQ09NTUlUXCIpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGF3YWl0IHRoaXMuZGF0YVNvdXJjZS5xdWVyeShcIlJPTExCQUNLXCIpO1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRXhlY3V0ZXMgYSByYXcgU1FMIHF1ZXJ5IGFnYWluc3QgdGhlIGRhdGFiYXNlXG4gICAqIEBzdW1tYXJ5IEFic3RyYWN0IG1ldGhvZCB0aGF0IG11c3QgYmUgaW1wbGVtZW50ZWQgdG8gZXhlY3V0ZSByYXcgU1FMIHF1ZXJpZXNcbiAgICogQHRlbXBsYXRlIFIgLSBUaGUgcmVzdWx0IHR5cGVcbiAgICogQHBhcmFtIHtUeXBlT1JNUXVlcnl9IHEgLSBUaGUgcXVlcnkgdG8gZXhlY3V0ZVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFI+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcXVlcnkgcmVzdWx0XG4gICAqL1xuICBvdmVycmlkZSBhc3luYyByYXc8Uj4ocTogVHlwZU9STVF1ZXJ5KTogUHJvbWlzZTxSPiB7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMucmF3KTtcbiAgICB0cnkge1xuICAgICAgaWYgKCF0aGlzLmRhdGFTb3VyY2UuaXNJbml0aWFsaXplZCkgYXdhaXQgdGhpcy5kYXRhU291cmNlLmluaXRpYWxpemUoKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICBjb25zdCB7IHF1ZXJ5LCB2YWx1ZXMgfSA9IHE7XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGBleGVjdXRpbmcgcXVlcnk6ICR7KHF1ZXJ5IGFzIHVua25vd24gYXMgU2VsZWN0UXVlcnlCdWlsZGVyPGFueT4pLmdldFNxbCgpfWBcbiAgICAgICk7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZGF0YVNvdXJjZS5xdWVyeShxdWVyeSwgdmFsdWVzKTtcbiAgICAgIHJldHVybiByZXNwb25zZSBhcyBSO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG4gIH1cblxuICBvdmVycmlkZSBwcmVwYXJlPE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgbW9kZWw6IE0sXG4gICAgcGs6IGtleW9mIE0sXG4gICAgY2hpbGQgPSBmYWxzZVxuICApOiB7XG4gICAgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICAgIGlkOiBzdHJpbmc7XG4gICAgdHJhbnNpZW50PzogUmVjb3JkPHN0cmluZywgYW55PjtcbiAgfSB7XG4gICAgY29uc3QgcHJlcGFyZWQgPSBzdXBlci5wcmVwYXJlKG1vZGVsLCBwayk7XG5cbiAgICBwcmVwYXJlZC5yZWNvcmQgPSBPYmplY3QuZW50cmllcyhwcmVwYXJlZC5yZWNvcmQpLnJlZHVjZShcbiAgICAgIChhY2N1bTogUmVjb3JkPHN0cmluZywgYW55PiwgW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICAgIGlmIChrZXkgPT09IFBlcnNpc3RlbmNlS2V5cy5NRVRBREFUQSB8fCB0aGlzLmlzUmVzZXJ2ZWQoa2V5KSlcbiAgICAgICAgICByZXR1cm4gYWNjdW07XG4gICAgICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgcmV0dXJuIGFjY3VtO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgRGF0ZSkge1xuICAgICAgICAgIHZhbHVlID0gbmV3IERhdGUodmFsdWUuZ2V0VGltZSgpKTtcbiAgICAgICAgfSBlbHNlIGlmIChNb2RlbC5pc01vZGVsKHZhbHVlKSkge1xuICAgICAgICAgIHZhbHVlID0gdGhpcy5wcmVwYXJlKHZhbHVlLCBmaW5kUHJpbWFyeUtleSh2YWx1ZSkuaWQsIHRydWUpLnJlY29yZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzd2l0Y2ggKHR5cGVvZiB2YWx1ZSkge1xuICAgICAgICAgICAgY2FzZSBcInN0cmluZ1wiOlxuICAgICAgICAgICAgICB2YWx1ZSA9IGAke3ZhbHVlfWA7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIC8vZG8gbm90aGluZztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgYWNjdW1ba2V5XSA9IHZhbHVlO1xuICAgICAgICByZXR1cm4gYWNjdW07XG4gICAgICB9LFxuICAgICAge31cbiAgICApO1xuICAgIGNvbnN0IGNvbnN0cjogQ29uc3RydWN0b3I8YW55PiB8IHVuZGVmaW5lZCA9IE1vZGVsLmdldChcbiAgICAgIG1vZGVsLmNvbnN0cnVjdG9yLm5hbWVcbiAgICApO1xuICAgIGlmICghY29uc3RyKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBNb2RlbCAke21vZGVsLmNvbnN0cnVjdG9yLm5hbWV9IG5vdCBmb3VuZCBpbiByZWdpc3RyeWBcbiAgICAgICk7XG4gICAgY29uc3QgcmVzdWx0ID0gY2hpbGRcbiAgICAgID8gbmV3IChjb25zdHIgYXMgYW55KVtNb2RlbEtleXMuQU5DSE9SIGFzIGtleW9mIHR5cGVvZiBjb25zdHJdKClcbiAgICAgIDogbmV3IGNvbnN0cigpO1xuICAgIGlmIChjaGlsZClcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShyZXN1bHQsIFwiY29uc3RydWN0b3JcIiwge1xuICAgICAgICBjb25maWd1cmFibGU6IGZhbHNlLFxuICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgdmFsdWU6IChjb25zdHIgYXMgYW55KVtNb2RlbEtleXMuQU5DSE9SIGFzIGtleW9mIHR5cGVvZiBjb25zdHJdLFxuICAgICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgICB9KTtcbiAgICBPYmplY3QuZW50cmllcyhwcmVwYXJlZC5yZWNvcmQpLmZvckVhY2goXG4gICAgICAoW2tleSwgdmFsXSkgPT4gKHJlc3VsdFtrZXkgYXMga2V5b2YgdHlwZW9mIHJlc3VsdF0gPSB2YWwpXG4gICAgKTtcbiAgICBwcmVwYXJlZC5yZWNvcmQgPSByZXN1bHQ7XG4gICAgcmV0dXJuIHByZXBhcmVkO1xuICB9XG5cbiAgb3ZlcnJpZGUgcmV2ZXJ0PE0gZXh0ZW5kcyBNb2RlbD4oXG4gICAgb2JqOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIGNsYXp6OiBzdHJpbmcgfCBDb25zdHJ1Y3RvcjxNPixcbiAgICBwazoga2V5b2YgTSxcbiAgICBpZDogc3RyaW5nIHwgbnVtYmVyIHwgYmlnaW50LFxuICAgIHRyYW5zaWVudD86IFJlY29yZDxzdHJpbmcsIGFueT5cbiAgKTogTSB7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMucmV2ZXJ0KTtcbiAgICBpZiAodHJhbnNpZW50KSB7XG4gICAgICBsb2cudmVyYm9zZShcbiAgICAgICAgYHJlLWFkZGluZyB0cmFuc2llbnQgcHJvcGVydGllczogJHtPYmplY3Qua2V5cyh0cmFuc2llbnQpLmpvaW4oXCIsIFwiKX1gXG4gICAgICApO1xuICAgICAgT2JqZWN0LmVudHJpZXModHJhbnNpZW50KS5mb3JFYWNoKChba2V5LCB2YWxdKSA9PiB7XG4gICAgICAgIGlmIChrZXkgaW4gb2JqKVxuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgYFRyYW5zaWVudCBwcm9wZXJ0eSAke2tleX0gYWxyZWFkeSBleGlzdHMgb24gbW9kZWwgJHt0eXBlb2YgY2xhenogPT09IFwic3RyaW5nXCIgPyBjbGF6eiA6IGNsYXp6Lm5hbWV9LiBzaG91bGQgYmUgaW1wb3NzaWJsZWBcbiAgICAgICAgICApO1xuICAgICAgICAob2JqIGFzIE0pW2tleSBhcyBrZXlvZiBNXSA9IHZhbDtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgKGNsYXp6IGFzIENvbnN0cnVjdG9yPE0+KShvYmopO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgbmV3IHJlY29yZCBpbiB0aGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgQWJzdHJhY3QgbWV0aG9kIHRoYXQgbXVzdCBiZSBpbXBsZW1lbnRlZCB0byBjcmVhdGUgYSBuZXcgcmVjb3JkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdGFibGVcbiAgICogQHBhcmFtIHtzdHJpbmd8bnVtYmVyfSBpZCAtIFRoZSBJRCBvZiB0aGUgcmVjb3JkXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gbW9kZWwgLSBUaGUgbW9kZWwgdG8gY3JlYXRlXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgY3JlYXRlZCByZWNvcmRcbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIGNyZWF0ZShcbiAgICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICBpZDogc3RyaW5nIHwgbnVtYmVyLFxuICAgIG1vZGVsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+IHtcbiAgICBjb25zdCBtOiBDb25zdHJ1Y3RvcjxNb2RlbD4gPSB0YWJsZU5hbWUgYXMgdW5rbm93biBhcyBDb25zdHJ1Y3RvcjxNb2RlbD47XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlcG8gPSB0aGlzLmRhdGFTb3VyY2UuZ2V0UmVwb3NpdG9yeShtKTtcbiAgICAgIHJldHVybiBhd2FpdCByZXBvLnNhdmUobW9kZWwpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFJlYWRzIGEgcmVjb3JkIGZyb20gdGhlIGRhdGFiYXNlXG4gICAqIEBzdW1tYXJ5IEFic3RyYWN0IG1ldGhvZCB0aGF0IG11c3QgYmUgaW1wbGVtZW50ZWQgdG8gcmVhZCBhIHJlY29yZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlXG4gICAqIEBwYXJhbSB7c3RyaW5nfG51bWJlcn0gaWQgLSBUaGUgSUQgb2YgdGhlIHJlY29yZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGsgLSBwcmltYXJ5IGtleSBjb2x1bVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVhZCByZWNvcmRcbiAgICovXG4gIG92ZXJyaWRlIGFzeW5jIHJlYWQoXG4gICAgdGFibGVOYW1lOiBzdHJpbmcsXG4gICAgaWQ6IHN0cmluZyB8IG51bWJlcixcbiAgICBwazogc3RyaW5nXG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IG06IENvbnN0cnVjdG9yPE1vZGVsPiA9IHRhYmxlTmFtZSBhcyB1bmtub3duIGFzIENvbnN0cnVjdG9yPE1vZGVsPjtcbiAgICBsZXQgcmVzdWx0OiBhbnk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlcG8gPSB0aGlzLmRhdGFTb3VyY2UuZ2V0UmVwb3NpdG9yeShtKTtcbiAgICAgIGNvbnN0IHE6IEZpbmRPbmVPcHRpb25zID0ge1xuICAgICAgICB3aGVyZToge1xuICAgICAgICAgIFtwa106IGlkLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICAgIHJlc3VsdCA9IChhd2FpdCByZXBvLmZpbmRPbmUocSkpIGFzIFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgICBpZiAoIXJlc3VsdClcbiAgICAgIHRocm93IG5ldyBOb3RGb3VuZEVycm9yKFxuICAgICAgICBgUmVjb3JkIHdpdGggaWQ6ICR7aWR9IG5vdCBmb3VuZCBpbiB0YWJsZSAke3R5cGVvZiB0YWJsZU5hbWUgPT09IFwic3RyaW5nXCIgPyB0YWJsZU5hbWUgOiBSZXBvc2l0b3J5LnRhYmxlKHRhYmxlTmFtZSl9YFxuICAgICAgKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIGEgcmVjb3JkIGluIHRoZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBBYnN0cmFjdCBtZXRob2QgdGhhdCBtdXN0IGJlIGltcGxlbWVudGVkIHRvIHVwZGF0ZSBhIHJlY29yZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlXG4gICAqIEBwYXJhbSB7c3RyaW5nfG51bWJlcn0gaWQgLSBUaGUgSUQgb2YgdGhlIHJlY29yZFxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IG1vZGVsIC0gVGhlIG1vZGVsIHRvIHVwZGF0ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGsgLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xuICAgKiBAcmV0dXJuIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSB1cGRhdGVkIHJlY29yZFxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgdXBkYXRlKFxuICAgIHRhYmxlTmFtZTogc3RyaW5nLFxuICAgIGlkOiBzdHJpbmcgfCBudW1iZXIsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICAgIGNvbnN0IG06IENvbnN0cnVjdG9yPE1vZGVsPiA9IHRhYmxlTmFtZSBhcyB1bmtub3duIGFzIENvbnN0cnVjdG9yPE1vZGVsPjtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVwbyA9IHRoaXMuZGF0YVNvdXJjZS5nZXRSZXBvc2l0b3J5KG0pO1xuICAgICAgcmV0dXJuIHJlcG8uc2F2ZShtb2RlbCk7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVsZXRlcyBhIHJlY29yZCBmcm9tIHRoZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBBYnN0cmFjdCBtZXRob2QgdGhhdCBtdXN0IGJlIGltcGxlbWVudGVkIHRvIGRlbGV0ZSBhIHJlY29yZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlXG4gICAqIEBwYXJhbSB7c3RyaW5nfG51bWJlcn0gaWQgLSBUaGUgSUQgb2YgdGhlIHJlY29yZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGsgLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xuICAgKiBAcmV0dXJuIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBkZWxldGVkIHJlY29yZFxuICAgKi9cbiAgb3ZlcnJpZGUgYXN5bmMgZGVsZXRlKFxuICAgIHRhYmxlTmFtZTogc3RyaW5nLFxuICAgIGlkOiBzdHJpbmcgfCBudW1iZXIsXG4gICAgcGs6IHN0cmluZyxcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+PiB7XG4gICAgY29uc3QgbTogQ29uc3RydWN0b3I8TW9kZWw+ID0gdGFibGVOYW1lIGFzIHVua25vd24gYXMgQ29uc3RydWN0b3I8TW9kZWw+O1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXBvID0gdGhpcy5kYXRhU291cmNlLmdldFJlcG9zaXRvcnkobSk7XG4gICAgICBjb25zdCBtb2RlbCA9IGF3YWl0IHRoaXMucmVhZCh0YWJsZU5hbWUsIGlkLCBwayk7XG4gICAgICBjb25zdCByZXMgPSBhd2FpdCByZXBvLmRlbGV0ZShpZCk7XG4gICAgICByZXR1cm4gbW9kZWw7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGNyZWF0ZUFsbChcbiAgICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICBpZDogKHN0cmluZyB8IG51bWJlcilbXSxcbiAgICBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PltdLFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT5bXT4ge1xuICAgIGNvbnN0IG06IENvbnN0cnVjdG9yPE1vZGVsPiA9IHRhYmxlTmFtZSBhcyB1bmtub3duIGFzIENvbnN0cnVjdG9yPE1vZGVsPjtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVwbyA9IHRoaXMuZGF0YVNvdXJjZS5nZXRSZXBvc2l0b3J5KG0pO1xuICAgICAgY29uc3QgcmVzdWx0OiBJbnNlcnRSZXN1bHQgPSBhd2FpdCByZXBvLmluc2VydChtb2RlbCk7XG4gICAgICByZXR1cm4gdGhpcy5yZWFkQWxsKFxuICAgICAgICB0YWJsZU5hbWUsXG4gICAgICAgIHJlc3VsdC5pZGVudGlmaWVycy5tYXAoKGlkKSA9PiBpZC5pZCksXG4gICAgICAgIFwiaWRcIlxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgcmVhZEFsbChcbiAgICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICBpZDogKHN0cmluZyB8IG51bWJlciB8IGJpZ2ludClbXSxcbiAgICBwazogc3RyaW5nLFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICAuLi5hcmdzOiBhbnlbXVxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT5bXT4ge1xuICAgIGlmICghaWQubGVuZ3RoKSByZXR1cm4gW107XG5cbiAgICBjb25zdCBtOiBDb25zdHJ1Y3RvcjxNb2RlbD4gPSB0YWJsZU5hbWUgYXMgdW5rbm93biBhcyBDb25zdHJ1Y3RvcjxNb2RlbD47XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlcG8gPSB0aGlzLmRhdGFTb3VyY2UuZ2V0UmVwb3NpdG9yeShtKTtcbiAgICAgIHJldHVybiByZXBvLmZpbmRCeSh7IFtwa106IEluKGlkKSB9KTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgb3ZlcnJpZGUgYXN5bmMgdXBkYXRlQWxsKFxuICAgIHRhYmxlTmFtZTogc3RyaW5nLFxuICAgIGlkczogc3RyaW5nW10gfCBudW1iZXJbXSxcbiAgICBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PltdLFxuICAgIHBrOiBzdHJpbmcsXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+W10+IHtcbiAgICBjb25zdCByZXN1bHQgPSBbXTtcbiAgICBmb3IgKGNvbnN0IG0gb2YgbW9kZWwpIHtcbiAgICAgIHJlc3VsdC5wdXNoKGF3YWl0IHRoaXMudXBkYXRlKHRhYmxlTmFtZSwgbVtwa10sIG0sIC4uLmFyZ3MpKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIG92ZXJyaWRlIGFzeW5jIGRlbGV0ZUFsbChcbiAgICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICBpZHM6IChzdHJpbmcgfCBudW1iZXIgfCBiaWdpbnQpW10sXG4gICAgcGs6IHN0cmluZyxcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgLi4uYXJnczogYW55W11cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+W10+IHtcbiAgICBpZiAoIWlkcy5sZW5ndGgpIHJldHVybiBbXTtcbiAgICBjb25zdCBtOiBDb25zdHJ1Y3RvcjxNb2RlbD4gPSB0YWJsZU5hbWUgYXMgdW5rbm93biBhcyBDb25zdHJ1Y3RvcjxNb2RlbD47XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlcG8gPSB0aGlzLmRhdGFTb3VyY2UuZ2V0UmVwb3NpdG9yeShtKTtcbiAgICAgIGNvbnN0IG1vZGVscyA9IGF3YWl0IHRoaXMucmVhZEFsbCh0YWJsZU5hbWUsIGlkcywgcGspO1xuICAgICAgYXdhaXQgcmVwby5kZWxldGUoaWRzKTtcbiAgICAgIHJldHVybiBtb2RlbHM7XG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgdGhyb3cgdGhpcy5wYXJzZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUGFyc2VzIGFuIGVycm9yIGFuZCBjb252ZXJ0cyBpdCB0byBhIEJhc2VFcnJvclxuICAgKiBAc3VtbWFyeSBDb252ZXJ0cyB2YXJpb3VzIGVycm9yIHR5cGVzIHRvIGFwcHJvcHJpYXRlIEJhc2VFcnJvciBzdWJ0eXBlc1xuICAgKiBAcGFyYW0ge0Vycm9yfHN0cmluZ30gZXJyIC0gVGhlIGVycm9yIHRvIHBhcnNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcmVhc29uXSAtIE9wdGlvbmFsIHJlYXNvbiBmb3IgdGhlIGVycm9yXG4gICAqIEByZXR1cm4ge0Jhc2VFcnJvcn0gVGhlIHBhcnNlZCBlcnJvciBhcyBhIEJhc2VFcnJvclxuICAgKi9cbiAgcGFyc2VFcnJvcihlcnI6IEVycm9yIHwgc3RyaW5nLCByZWFzb24/OiBzdHJpbmcpOiBCYXNlRXJyb3Ige1xuICAgIHJldHVybiBUeXBlT1JNQWRhcHRlci5wYXJzZUVycm9yKGVyciwgcmVhc29uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ2hlY2tzIGlmIGFuIGF0dHJpYnV0ZSBpcyByZXNlcnZlZFxuICAgKiBAc3VtbWFyeSBEZXRlcm1pbmVzIGlmIGFuIGF0dHJpYnV0ZSBuYW1lIGlzIHJlc2VydmVkIGluIFBvc3RncmVTUUxcbiAgICogQHBhcmFtIHtzdHJpbmd9IGF0dHIgLSBUaGUgYXR0cmlidXRlIG5hbWUgdG8gY2hlY2tcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgYXR0cmlidXRlIGlzIHJlc2VydmVkLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIHByb3RlY3RlZCBvdmVycmlkZSBpc1Jlc2VydmVkKGF0dHI6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIWF0dHIubWF0Y2gocmVzZXJ2ZWRBdHRyaWJ1dGVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gU3RhdGljIG1ldGhvZCB0byBwYXJzZSBhbiBlcnJvciBhbmQgY29udmVydCBpdCB0byBhIEJhc2VFcnJvclxuICAgKiBAc3VtbWFyeSBDb252ZXJ0cyB2YXJpb3VzIGVycm9yIHR5cGVzIHRvIGFwcHJvcHJpYXRlIEJhc2VFcnJvciBzdWJ0eXBlcyBiYXNlZCBvbiBQb3N0Z3JlU1FMIGVycm9yIGNvZGVzIGFuZCBtZXNzYWdlc1xuICAgKiBAcGFyYW0ge0Vycm9yfHN0cmluZ30gZXJyIC0gVGhlIGVycm9yIHRvIHBhcnNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcmVhc29uXSAtIE9wdGlvbmFsIHJlYXNvbiBmb3IgdGhlIGVycm9yXG4gICAqIEByZXR1cm4ge0Jhc2VFcnJvcn0gVGhlIHBhcnNlZCBlcnJvciBhcyBhIEJhc2VFcnJvclxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAgICogICBwYXJ0aWNpcGFudCBwYXJzZUVycm9yXG4gICAqICAgcGFydGljaXBhbnQgRXJyb3JUeXBlc1xuICAgKlxuICAgKiAgIENhbGxlci0+PnBhcnNlRXJyb3I6IGVyciwgcmVhc29uXG4gICAqICAgTm90ZSBvdmVyIHBhcnNlRXJyb3I6IENoZWNrIGlmIGVyciBpcyBhbHJlYWR5IGEgQmFzZUVycm9yXG4gICAqICAgYWx0IGVyciBpcyBCYXNlRXJyb3JcbiAgICogICAgIHBhcnNlRXJyb3ItLT4+Q2FsbGVyOiByZXR1cm4gZXJyXG4gICAqICAgZWxzZSBlcnIgaXMgc3RyaW5nXG4gICAqICAgICBOb3RlIG92ZXIgcGFyc2VFcnJvcjogRXh0cmFjdCBjb2RlIGZyb20gc3RyaW5nXG4gICAqICAgICBhbHQgY29kZSBtYXRjaGVzIFwiZHVwbGljYXRlIGtleXxhbHJlYWR5IGV4aXN0c1wiXG4gICAqICAgICAgIHBhcnNlRXJyb3ItPj5FcnJvclR5cGVzOiBuZXcgQ29uZmxpY3RFcnJvcihjb2RlKVxuICAgKiAgICAgICBFcnJvclR5cGVzLS0+PkNhbGxlcjogQ29uZmxpY3RFcnJvclxuICAgKiAgICAgZWxzZSBjb2RlIG1hdGNoZXMgXCJkb2VzIG5vdCBleGlzdHxub3QgZm91bmRcIlxuICAgKiAgICAgICBwYXJzZUVycm9yLT4+RXJyb3JUeXBlczogbmV3IE5vdEZvdW5kRXJyb3IoY29kZSlcbiAgICogICAgICAgRXJyb3JUeXBlcy0tPj5DYWxsZXI6IE5vdEZvdW5kRXJyb3JcbiAgICogICAgIGVuZFxuICAgKiAgIGVsc2UgZXJyIGhhcyBjb2RlIHByb3BlcnR5XG4gICAqICAgICBOb3RlIG92ZXIgcGFyc2VFcnJvcjogRXh0cmFjdCBjb2RlIGFuZCByZWFzb25cbiAgICogICBlbHNlXG4gICAqICAgICBOb3RlIG92ZXIgcGFyc2VFcnJvcjogVXNlIGVyci5tZXNzYWdlIGFzIGNvZGVcbiAgICogICBlbmRcbiAgICpcbiAgICogICBOb3RlIG92ZXIgcGFyc2VFcnJvcjogU3dpdGNoIG9uIFBvc3RncmVTUUwgZXJyb3IgY29kZVxuICAgKiAgIGFsdCBjb2RlIGlzIDIzNTA1ICh1bmlxdWVfdmlvbGF0aW9uKVxuICAgKiAgICAgcGFyc2VFcnJvci0+PkVycm9yVHlwZXM6IG5ldyBDb25mbGljdEVycm9yKHJlYXNvbilcbiAgICogICAgIEVycm9yVHlwZXMtLT4+Q2FsbGVyOiBDb25mbGljdEVycm9yXG4gICAqICAgZWxzZSBjb2RlIGlzIDIzNTAzIChmb3JlaWduX2tleV92aW9sYXRpb24pXG4gICAqICAgICBwYXJzZUVycm9yLT4+RXJyb3JUeXBlczogbmV3IENvbmZsaWN0RXJyb3IocmVhc29uKVxuICAgKiAgICAgRXJyb3JUeXBlcy0tPj5DYWxsZXI6IENvbmZsaWN0RXJyb3JcbiAgICogICBlbHNlIGNvZGUgaXMgNDJQMDEgKHVuZGVmaW5lZF90YWJsZSlcbiAgICogICAgIHBhcnNlRXJyb3ItPj5FcnJvclR5cGVzOiBuZXcgTm90Rm91bmRFcnJvcihyZWFzb24pXG4gICAqICAgICBFcnJvclR5cGVzLS0+PkNhbGxlcjogTm90Rm91bmRFcnJvclxuICAgKiAgIGVsc2UgY29kZSBpcyA0MjcwMyAodW5kZWZpbmVkX2NvbHVtbilcbiAgICogICAgIHBhcnNlRXJyb3ItPj5FcnJvclR5cGVzOiBuZXcgTm90Rm91bmRFcnJvcihyZWFzb24pXG4gICAqICAgICBFcnJvclR5cGVzLS0+PkNhbGxlcjogTm90Rm91bmRFcnJvclxuICAgKiAgIGVsc2UgY29kZSBpcyA0MlAwNyAoZHVwbGljYXRlX3RhYmxlKVxuICAgKiAgICAgcGFyc2VFcnJvci0+PkVycm9yVHlwZXM6IG5ldyBDb25mbGljdEVycm9yKHJlYXNvbilcbiAgICogICAgIEVycm9yVHlwZXMtLT4+Q2FsbGVyOiBDb25mbGljdEVycm9yXG4gICAqICAgZWxzZSBjb2RlIGlzIDQyUDE2IChpbnZhbGlkX3RhYmxlX2RlZmluaXRpb24pXG4gICAqICAgICBwYXJzZUVycm9yLT4+RXJyb3JUeXBlczogbmV3IEluZGV4RXJyb3IoZXJyKVxuICAgKiAgICAgRXJyb3JUeXBlcy0tPj5DYWxsZXI6IEluZGV4RXJyb3JcbiAgICogICBlbHNlIGNvZGUgbWF0Y2hlcyBcIkVDT05OUkVGVVNFRFwiXG4gICAqICAgICBwYXJzZUVycm9yLT4+RXJyb3JUeXBlczogbmV3IENvbm5lY3Rpb25FcnJvcihlcnIpXG4gICAqICAgICBFcnJvclR5cGVzLS0+PkNhbGxlcjogQ29ubmVjdGlvbkVycm9yXG4gICAqICAgZWxzZVxuICAgKiAgICAgcGFyc2VFcnJvci0+PkVycm9yVHlwZXM6IG5ldyBJbnRlcm5hbEVycm9yKGVycilcbiAgICogICAgIEVycm9yVHlwZXMtLT4+Q2FsbGVyOiBJbnRlcm5hbEVycm9yXG4gICAqICAgZW5kXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIHBhcnNlRXJyb3IoZXJyOiBFcnJvciB8IHN0cmluZywgcmVhc29uPzogc3RyaW5nKTogQmFzZUVycm9yIHtcbiAgICBpZiAoZXJyIGluc3RhbmNlb2YgQmFzZUVycm9yKSByZXR1cm4gZXJyIGFzIGFueTtcbiAgICBjb25zdCBjb2RlOiBzdHJpbmcgPSB0eXBlb2YgZXJyID09PSBcInN0cmluZ1wiID8gZXJyIDogZXJyLm1lc3NhZ2U7XG5cbiAgICBpZiAoY29kZS5tYXRjaCgvZHVwbGljYXRlIGtleXxhbHJlYWR5IGV4aXN0cy9nKSlcbiAgICAgIHJldHVybiBuZXcgQ29uZmxpY3RFcnJvcihjb2RlKTtcbiAgICBpZiAoY29kZS5tYXRjaCgvZG9lcyBub3QgZXhpc3R8bm90IGZvdW5kL2cpKSByZXR1cm4gbmV3IE5vdEZvdW5kRXJyb3IoY29kZSk7XG5cbiAgICAvLyBQb3N0Z3JlU1FMIGVycm9yIGNvZGVzOiBodHRwczovL3d3dy5wb3N0Z3Jlc3FsLm9yZy9kb2NzL2N1cnJlbnQvZXJyY29kZXMtYXBwZW5kaXguaHRtbFxuICAgIHN3aXRjaCAoY29kZS50b1N0cmluZygpKSB7XG4gICAgICAvLyBJbnRlZ3JpdHkgY29uc3RyYWludCB2aW9sYXRpb25zXG4gICAgICBjYXNlIFwiMjM1MDVcIjogLy8gdW5pcXVlX3Zpb2xhdGlvblxuICAgICAgY2FzZSBcIjIzNTAzXCI6IC8vIGZvcmVpZ25fa2V5X3Zpb2xhdGlvblxuICAgICAgY2FzZSBcIjQyUDA3XCI6IC8vIGR1cGxpY2F0ZV90YWJsZVxuICAgICAgICByZXR1cm4gbmV3IENvbmZsaWN0RXJyb3IocmVhc29uIGFzIHN0cmluZyk7XG5cbiAgICAgIC8vIE9iamVjdCBub3QgZm91bmQgZXJyb3JzXG4gICAgICBjYXNlIFwiNDJQMDFcIjogLy8gdW5kZWZpbmVkX3RhYmxlXG4gICAgICBjYXNlIFwiNDI3MDNcIjogLy8gdW5kZWZpbmVkX2NvbHVtblxuICAgICAgICByZXR1cm4gbmV3IE5vdEZvdW5kRXJyb3IocmVhc29uIGFzIHN0cmluZyk7XG5cbiAgICAgIC8vIEludmFsaWQgb2JqZWN0IGRlZmluaXRpb25cbiAgICAgIGNhc2UgXCI0MlAxNlwiOiAvLyBpbnZhbGlkX3RhYmxlX2RlZmluaXRpb25cbiAgICAgICAgcmV0dXJuIG5ldyBJbmRleEVycm9yKGVycik7XG5cbiAgICAgIC8vIENvbm5lY3Rpb24gZXJyb3JzXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBpZiAoY29kZS50b1N0cmluZygpLm1hdGNoKC9FQ09OTlJFRlVTRUQvZykpXG4gICAgICAgICAgcmV0dXJuIG5ldyBDb25uZWN0aW9uRXJyb3IoZXJyKTtcbiAgICAgICAgcmV0dXJuIG5ldyBJbnRlcm5hbEVycm9yKGVycik7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIGFzeW5jIGNvbm5lY3QoY29uZmlnOiBEYXRhU291cmNlT3B0aW9ucyk6IFByb21pc2U8RGF0YVNvdXJjZT4ge1xuICAgIGNvbnN0IGNvbiA9IG5ldyBEYXRhU291cmNlKGNvbmZpZyk7XG4gICAgaWYgKCFjb24uaXNJbml0aWFsaXplZCkgYXdhaXQgY29uLmluaXRpYWxpemUoKTtcbiAgICByZXR1cm4gY29uO1xuICB9XG5cbiAgc3RhdGljIGFzeW5jIGNyZWF0ZURhdGFiYXNlKFxuICAgIGRhdGFTb3VyY2U6IERhdGFTb3VyY2UsXG4gICAgZGJOYW1lOiBzdHJpbmdcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbG9nID0gTG9nZ2luZy5mb3IodGhpcy5jcmVhdGVEYXRhYmFzZSk7XG4gICAgbG9nLnZlcmJvc2UoYENyZWF0aW5nIGRhdGFiYXNlICR7ZGJOYW1lfWApO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBkYXRhU291cmNlLnF1ZXJ5KGBDUkVBVEUgREFUQUJBU0UgJHtkYk5hbWV9YCk7XG4gICAgICBsb2cuaW5mbyhgQ3JlYXRlZCBkYXRhYmFzZSAke2RiTmFtZX1gKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0aHJvdyB0aGlzLnBhcnNlRXJyb3IoZSBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIGFzeW5jIGNyZWF0ZU5vdGlmeUZ1bmN0aW9uKFxuICAgIGRhdGFTb3VyY2U6IERhdGFTb3VyY2UsXG4gICAgdXNlcjogc3RyaW5nXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGxvZyA9IExvZ2dpbmcuZm9yKHRoaXMuY3JlYXRlTm90aWZ5RnVuY3Rpb24pO1xuICAgIGxvZy52ZXJib3NlKGBDcmVhdGluZyBub3RpZnkgZnVuY3Rpb25gKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgZGF0YVNvdXJjZS5xdWVyeShcbiAgICAgICAgYENSRUFURSBPUiBSRVBMQUNFIEZVTkNUSU9OIG5vdGlmeV90YWJsZV9jaGFuZ2VzKClcblJFVFVSTlMgdHJpZ2dlciBBUyAkJFxuQkVHSU5cbiAgICBQRVJGT1JNIHBnX25vdGlmeShcbiAgICAgICAgJ3RhYmxlX2NoYW5nZXMnLFxuICAgICAgICBqc29uX2J1aWxkX29iamVjdChcbiAgICAgICAgICAgICd0YWJsZScsIFRHX1RBQkxFX05BTUUsXG4gICAgICAgICAgICAnYWN0aW9uJywgVEdfT1AsXG4gICAgICAgICAgICAnZGF0YScsIHJvd190b19qc29uKE5FVyksXG4gICAgICAgICAgICAnb2xkX2RhdGEnLCByb3dfdG9fanNvbihPTEQpXG4gICAgICAgICk6OnRleHRcbiAgICApO1xuICAgIFJFVFVSTiBORVc7XG5FTkQ7XG4kJCBMQU5HVUFHRSBwbHBnc3FsIFNFQ1VSSVRZIERFRklORVJcbjtgXG4gICAgICApO1xuICAgICAgYXdhaXQgZGF0YVNvdXJjZS5xdWVyeShcbiAgICAgICAgYEFMVEVSIEZVTkNUSU9OIG5vdGlmeV90YWJsZV9jaGFuZ2VzKCkgT1dORVIgVE8gJHt1c2VyfTtgXG4gICAgICApO1xuICAgICAgYXdhaXQgZGF0YVNvdXJjZS5xdWVyeShgXG4gICAgICAgICAgICBHUkFOVCBFWEVDVVRFIE9OIEZVTkNUSU9OIG5vdGlmeV90YWJsZV9jaGFuZ2VzKCkgVE8gcHVibGljO1xuICAgICAgICBgKTtcbiAgICAgIGxvZy5pbmZvKGBDcmVhdGVkIG5vdGlmeSBmdW5jdGlvbmApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgZGVsZXRlRGF0YWJhc2UoXG4gICAgZGF0YVNvdXJjZTogRGF0YVNvdXJjZSxcbiAgICBkYk5hbWU6IHN0cmluZyxcbiAgICB1c2VyPzogc3RyaW5nXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBpZiAodXNlcikgYXdhaXQgZGF0YVNvdXJjZS5xdWVyeShgRFJPUCBPV05FRCBCWSAke3VzZXJ9IENBU0NBREU7YCk7XG4gICAgICBhd2FpdCBkYXRhU291cmNlLnF1ZXJ5KGBEUk9QIERBVEFCQVNFICR7ZGJOYW1lfWApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgY3JlYXRlVXNlcihcbiAgICBkYXRhU291cmNlOiBEYXRhU291cmNlLFxuICAgIGRiTmFtZTogc3RyaW5nLFxuICAgIHVzZXI6IHN0cmluZyxcbiAgICBwYXNzd29yZDogc3RyaW5nXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBkYXRhU291cmNlLnF1ZXJ5KGBDUkVBVEUgVVNFUiAke3VzZXJ9IFdJVEggUEFTU1dPUkQgJyR7cGFzc3dvcmR9J2ApO1xuICAgICAgYXdhaXQgZGF0YVNvdXJjZS5xdWVyeShgR1JBTlQgQ09OTkVDVCBPTiBEQVRBQkFTRSAke2RiTmFtZX0gVE8gJHt1c2VyfWApO1xuXG4gICAgICBhd2FpdCBkYXRhU291cmNlLnF1ZXJ5KGBHUkFOVCBVU0FHRSBPTiBTQ0hFTUEgcHVibGljIFRPICR7dXNlcn1gKTtcbiAgICAgIGF3YWl0IGRhdGFTb3VyY2UucXVlcnkoYEdSQU5UIENSRUFURSBPTiBTQ0hFTUEgcHVibGljIFRPICR7dXNlcn1gKTtcbiAgICAgIGF3YWl0IGRhdGFTb3VyY2UucXVlcnkoXG4gICAgICAgIGBHUkFOVCBBTEwgUFJJVklMRUdFUyBPTiBBTEwgVEFCTEVTIElOIFNDSEVNQSBwdWJsaWMgVE8gJHt1c2VyfWBcbiAgICAgICk7XG4gICAgICBhd2FpdCBkYXRhU291cmNlLnF1ZXJ5KFxuICAgICAgICBgR1JBTlQgQUxMIFBSSVZJTEVHRVMgT04gQUxMIFNFUVVFTkNFUyBJTiBTQ0hFTUEgcHVibGljIFRPICR7dXNlcn1gXG4gICAgICApO1xuICAgICAgYXdhaXQgZGF0YVNvdXJjZS5xdWVyeShcbiAgICAgICAgYEdSQU5UIEFMTCBQUklWSUxFR0VTIE9OIEFMTCBGVU5DVElPTlMgSU4gU0NIRU1BIHB1YmxpYyBUTyAke3VzZXJ9YFxuICAgICAgKTtcbiAgICAgIGF3YWl0IGRhdGFTb3VyY2UucXVlcnkoXG4gICAgICAgIGBBTFRFUiBERUZBVUxUIFBSSVZJTEVHRVMgSU4gU0NIRU1BIHB1YmxpYyBHUkFOVCBBTEwgUFJJVklMRUdFUyBPTiBUQUJMRVMgVE8gJHt1c2VyfWBcbiAgICAgICk7XG4gICAgICBhd2FpdCBkYXRhU291cmNlLnF1ZXJ5KFxuICAgICAgICBgQUxURVIgREVGQVVMVCBQUklWSUxFR0VTIElOIFNDSEVNQSBwdWJsaWMgR1JBTlQgQUxMIFBSSVZJTEVHRVMgT04gU0VRVUVOQ0VTIFRPICR7dXNlcn1gXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgZGVsZXRlVXNlcihcbiAgICBjbGllbnQ6IERhdGFTb3VyY2UsXG4gICAgdXNlcjogc3RyaW5nLFxuICAgIGFkbWluOiBzdHJpbmdcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShgUkVBU1NJR04gT1dORUQgQlkgJHt1c2VyfSBUTyAke2FkbWlufWApO1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KFxuICAgICAgICBgUkVWT0tFIEFMTCBPTiBBTEwgVEFCTEVTIElOIFNDSEVNQSBwdWJsaWMgRlJPTSAke3VzZXJ9YFxuICAgICAgKTtcbiAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShgUkVWT0tFIEFMTCBPTiBTQ0hFTUEgcHVibGljIEZST00gJHt1c2VyfWApO1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KFxuICAgICAgICBgUkVWT0tFIEFMTCBQUklWSUxFR0VTIE9OIEFMTCBTRVFVRU5DRVMgSU4gU0NIRU1BIHB1YmxpYyBGUk9NICR7dXNlcn1gXG4gICAgICApO1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KFxuICAgICAgICBgUkVWT0tFIEFMTCBQUklWSUxFR0VTIE9OIEFMTCBGVU5DVElPTlMgSU4gU0NIRU1BIHB1YmxpYyBGUk9NICR7dXNlcn1gXG4gICAgICApO1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KFxuICAgICAgICBgQUxURVIgREVGQVVMVCBQUklWSUxFR0VTIEZPUiBST0xFICR7YWRtaW59IElOIFNDSEVNQSBwdWJsaWMgUkVWT0tFIEFMTCBPTiBUQUJMRVMgRlJPTSAke3VzZXJ9YFxuICAgICAgKTtcbiAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShcbiAgICAgICAgYEFMVEVSIERFRkFVTFQgUFJJVklMRUdFUyBGT1IgUk9MRSAke2FkbWlufSBJTiBTQ0hFTUEgcHVibGljIFJFVk9LRSBBTEwgT04gU0VRVUVOQ0VTIEZST00gJHt1c2VyfTtgXG4gICAgICApO1xuICAgICAgYXdhaXQgY2xpZW50LnF1ZXJ5KFxuICAgICAgICBgQUxURVIgREVGQVVMVCBQUklWSUxFR0VTIEZPUiBST0xFICR7YWRtaW59IElOIFNDSEVNQSBwdWJsaWMgUkVWT0tFIEFMTCBPTiBGVU5DVElPTlMgRlJPTSAke3VzZXJ9YFxuICAgICAgKTtcbiAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShgRFJPUCBPV05FRCBCWSAke3VzZXJ9IENBU0NBREVgKTtcbiAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShgRFJPUCBVU0VSIElGIEVYSVNUUyBcIiR7dXNlcn1cImApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBwYXJzZVR5cGVUb1Bvc3RncmVzKFxuICAgIHR5cGU6IHN0cmluZyxcbiAgICBpc1BrOiBib29sZWFuLFxuICAgIGlzRmsgPSBmYWxzZVxuICApIHtcbiAgICBzd2l0Y2ggKHR5cGUudG9Mb3dlckNhc2UoKSkge1xuICAgICAgY2FzZSBcInN0cmluZ1wiOlxuICAgICAgICByZXR1cm4gaXNQayA/IFwiVEVYVCBQUklNQVJZIEtFWVwiIDogaXNGayA/IFwiVEVYVFwiIDogXCJWQVJDSEFSXCI7XG4gICAgICBjYXNlIFwibnVtYmVyXCI6XG4gICAgICAgIHJldHVybiBpc1BrID8gXCJTRVJJQUwgUFJJTUFSWSBLRVlcIiA6IFwiSU5URUdFUlwiO1xuICAgICAgY2FzZSBcImJvb2xlYW5cIjpcbiAgICAgICAgcmV0dXJuIFwiQk9PTEVBTlwiO1xuICAgICAgY2FzZSBcImRhdGVcIjpcbiAgICAgICAgcmV0dXJuIFwiVElNRVNUQU1QXCI7XG4gICAgICBjYXNlIFwiYmlnaW50XCI6XG4gICAgICAgIHJldHVybiBpc1BrID8gXCJCSUdJTlQgUFJJTUFSWSBLRVlcIiA6IFwiQklHSU5UXCI7XG4gICAgICBkZWZhdWx0OiB7XG4gICAgICAgIGNvbnN0IG0gPSBNb2RlbC5nZXQodHlwZSk7XG4gICAgICAgIGlmIChtKSB7XG4gICAgICAgICAgY29uc3QgbW0gPSBuZXcgbSgpO1xuICAgICAgICAgIGNvbnN0IHR5cGUgPSBSZWZsZWN0aW9uLmdldFR5cGVGcm9tRGVjb3JhdG9yKFxuICAgICAgICAgICAgbW0sXG4gICAgICAgICAgICBmaW5kUHJpbWFyeUtleShtbSkuaWRcbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBtb2RlbDogbSxcbiAgICAgICAgICAgIHBrVHlwZTogdHlwZSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBVbnN1cHBvcnRlZCB0eXBlOiAke3R5cGV9YCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgcGFyc2VWYWxpZGF0aW9uVG9Qb3N0Z3JlcyhcbiAgICBwcm9wOiBzdHJpbmcsXG4gICAgdHlwZTogc3RyaW5nLFxuICAgIGlzUGs6IGJvb2xlYW4sXG4gICAga2V5OiBzdHJpbmcsXG4gICAgb3B0aW9uczogVmFsaWRhdG9yT3B0aW9uc1xuICApIHtcbiAgICBzd2l0Y2ggKGtleSkge1xuICAgICAgY2FzZSBWYWxpZGF0aW9uS2V5cy5SRVFVSVJFRDpcbiAgICAgICAgcmV0dXJuIFwiTk9UIE5VTExcIjtcbiAgICAgIGNhc2UgVmFsaWRhdGlvbktleXMuTUFYX0xFTkdUSDpcbiAgICAgICAgaWYgKGlzUGsgfHwgIW9wdGlvbnMgfHwgdHlwZS50b0xvd2VyQ2FzZSgpICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGAoJHsob3B0aW9ucyBhcyBNYXhMZW5ndGhWYWxpZGF0b3JPcHRpb25zKVtWYWxpZGF0aW9uS2V5cy5NQVhfTEVOR1RIXX0pYDtcbiAgICAgIGNhc2UgVmFsaWRhdGlvbktleXMuTUlOX0xFTkdUSDpcbiAgICAgICAgcmV0dXJuIGBDT05TVFJBSU5UICR7cHJvcH1fbWluX2xlbmd0aF9jaGVjayBDSEVDSyAoTEVOR1RIKCR7cHJvcH0pID49ICR7KG9wdGlvbnMgYXMgTWluTGVuZ3RoVmFsaWRhdG9yT3B0aW9ucylbVmFsaWRhdGlvbktleXMuTUlOX0xFTkdUSF19KWA7XG4gICAgICBjYXNlIFZhbGlkYXRpb25LZXlzLlBBVFRFUk46XG4gICAgICBjYXNlIFZhbGlkYXRpb25LZXlzLlVSTDpcbiAgICAgIGNhc2UgVmFsaWRhdGlvbktleXMuRU1BSUw6XG4gICAgICAgIHJldHVybiBgQ09OU1RSQUlOVCAke3Byb3B9X3BhdHRlcm5fY2hlY2sgQ0hFQ0sgKCR7cHJvcH0gfiAnJHtjb252ZXJ0SnNSZWdleFRvUG9zdGdyZXMoKG9wdGlvbnMgYXMgUGF0dGVyblZhbGlkYXRvck9wdGlvbnMpW1ZhbGlkYXRpb25LZXlzLlBBVFRFUk5dIGFzIHN0cmluZyl9JylgO1xuICAgICAgY2FzZSBWYWxpZGF0aW9uS2V5cy5UWVBFOlxuICAgICAgY2FzZSBWYWxpZGF0aW9uS2V5cy5EQVRFOlxuICAgICAgICByZXR1cm4gXCJcIjtcbiAgICAgIGNhc2UgVmFsaWRhdGlvbktleXMuTUlOOlxuICAgICAgICByZXR1cm4gYENPTlNUUkFJTlQgJHtwcm9wfV8ke2tleX1fY2hlY2sgQ0hFQ0sgKCR7cHJvcH0gPj0gJHsob3B0aW9ucyBhcyBNaW5WYWxpZGF0b3JPcHRpb25zKVtWYWxpZGF0aW9uS2V5cy5NSU5dfSlgO1xuICAgICAgY2FzZSBWYWxpZGF0aW9uS2V5cy5NQVg6XG4gICAgICAgIHJldHVybiBgQ09OU1RSQUlOVCAke3Byb3B9XyR7a2V5fV9jaGVjayBDSEVDSyAoJHtwcm9wfSA8PSAkeyhvcHRpb25zIGFzIE1heFZhbGlkYXRvck9wdGlvbnMpW1ZhbGlkYXRpb25LZXlzLk1BWF19KWA7XG4gICAgICBjYXNlIFZhbGlkYXRpb25LZXlzLlBBU1NXT1JEOlxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYFVuc3VwcG9ydGVkIHR5cGU6ICR7a2V5fWApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIHBhcnNlUmVsYXRpb25zVG9Qb3N0Z3JlcyhcbiAgICBwcm9wOiBzdHJpbmcsXG4gICAgY2xheno6IENvbnN0cnVjdG9yPE1vZGVsPixcbiAgICBwazogc3RyaW5nLFxuICAgIGtleTogUGVyc2lzdGVuY2VLZXlzLFxuICAgIG9wdGlvbnM6IFJlbGF0aW9uc01ldGFkYXRhXG4gICkge1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IFJlcG9zaXRvcnkudGFibGUoY2xhenopO1xuICAgIGNvbnN0IHsgY2FzY2FkZSB9ID0gb3B0aW9ucztcbiAgICBjb25zdCBjYXNjYWRlU3RyID0gYCR7Y2FzY2FkZS51cGRhdGUgPyBcIiBPTiBVUERBVEUgQ0FTQ0FERVwiIDogXCJcIn0ke2Nhc2NhZGUuZGVsZXRlID8gXCIgT04gREVMRVRFIENBU0NBREVcIiA6IFwiXCJ9YDtcbiAgICBzd2l0Y2ggKGByZWxhdGlvbnMke2tleX1gKSB7XG4gICAgICBjYXNlIFBlcnNpc3RlbmNlS2V5cy5PTkVfVE9fT05FOlxuICAgICAgICByZXR1cm4gYEZPUkVJR04gS0VZICgke3Byb3B9KSBSRUZFUkVOQ0VTICR7dGFibGVOYW1lfSgke3BrfSkke2Nhc2NhZGVTdHJ9YDtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBVbnN1cHBvcnRlZCBvcGVyYXRpb246ICR7a2V5fWApO1xuICAgIH1cbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBjcmVhdGVUYWJsZTxNIGV4dGVuZHMgTW9kZWw+KFxuICAgIGNsaWVudDogRGF0YVNvdXJjZSxcbiAgICBtb2RlbDogQ29uc3RydWN0b3I8TT5cbiAgKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBUeXBlT1JNVGFibGVTcGVjPj4ge1xuICAgIGNvbnN0IHJlc3VsdDogUmVjb3JkPHN0cmluZywgVHlwZU9STVRhYmxlU3BlYz4gPSB7fTtcbiAgICBjb25zdCBtID0gbmV3IG1vZGVsKHt9KTtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBSZXBvc2l0b3J5LnRhYmxlKG1vZGVsKTtcbiAgICBjb25zdCB7IGlkIH0gPSBmaW5kUHJpbWFyeUtleShtKTtcblxuICAgIGxldCBpc1BrOiBib29sZWFuLCBjb2x1bW46IHN0cmluZztcbiAgICBjb25zdCBwcm9wZXJ0aWVzID0gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMobSkgYXMgKGtleW9mIE0pW107XG4gICAgZm9yIChjb25zdCBwcm9wIG9mIHByb3BlcnRpZXMpIHtcbiAgICAgIGlmIChcbiAgICAgICAgdHlwZW9mICh0aGlzIGFzIGFueSlbcHJvcF0gPT09IFwiZnVuY3Rpb25cIiB8fFxuICAgICAgICBwcm9wLnRvU3RyaW5nKCkuc3RhcnRzV2l0aChcIl9cIikgfHxcbiAgICAgICAgcHJvcCA9PT0gXCJjb25zdHJ1Y3RvclwiXG4gICAgICApIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGlzUGsgPSBwcm9wID09PSBpZDtcbiAgICAgIGNvbHVtbiA9IFJlcG9zaXRvcnkuY29sdW1uKG0sIHByb3AudG9TdHJpbmcoKSk7XG5cbiAgICAgIGNvbnN0IGFsbERlY3MgPSBSZWZsZWN0aW9uLmdldFByb3BlcnR5RGVjb3JhdG9ycyhcbiAgICAgICAgVmFsaWRhdGlvbktleXMuUkVGTEVDVCxcbiAgICAgICAgbSxcbiAgICAgICAgcHJvcC50b1N0cmluZygpLFxuICAgICAgICBmYWxzZSxcbiAgICAgICAgdHJ1ZVxuICAgICAgKTtcblxuICAgICAgY29uc3QgZGVjb3JhdG9yRGF0YSA9IGFsbERlY3MuZGVjb3JhdG9ycy5yZWR1Y2UoXG4gICAgICAgIChhY2N1bTogUmVjb3JkPHN0cmluZywgYW55PiwgZWwpID0+IHtcbiAgICAgICAgICBjb25zdCB7IGtleSwgcHJvcHMgfSA9IGVsO1xuICAgICAgICAgIGlmIChrZXkgPT09IE1vZGVsS2V5cy5UWVBFICYmICFhY2N1bVtWYWxpZGF0aW9uS2V5cy5UWVBFXSkge1xuICAgICAgICAgICAgYWNjdW1bVmFsaWRhdGlvbktleXMuVFlQRV0gPSB7XG4gICAgICAgICAgICAgIGN1c3RvbVR5cGVzOiBbcHJvcHMubmFtZSBhcyBzdHJpbmddLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBERUZBVUxUX0VSUk9SX01FU1NBR0VTLlRZUEUsXG4gICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcImRlZmluZXMgdGhlIGFjY2VwdGVkIHR5cGVzIGZvciB0aGUgYXR0cmlidXRlXCIsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0gZWxzZSBpZiAoa2V5ICE9PSBWYWxpZGF0aW9uS2V5cy5UWVBFKSB7XG4gICAgICAgICAgICAvLyBkbyBub3RoaW5nLiB3ZSBjYW4gb25seSBzdXBwb3J0IGJhc2lzIGN0eXBlcyBhdCB0aGlzIHRpbWVcbiAgICAgICAgICAgIGFjY3VtW2tleV0gPSBwcm9wcztcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGFjY3VtO1xuICAgICAgICB9LFxuICAgICAgICB7fVxuICAgICAgKTtcblxuICAgICAgY29uc3QgZGJEZWNzID0gUmVmbGVjdGlvbi5nZXRQcm9wZXJ0eURlY29yYXRvcnMoXG4gICAgICAgIFJlcG9zaXRvcnkua2V5KFwicmVsYXRpb25zXCIpLFxuICAgICAgICBtLFxuICAgICAgICBwcm9wLnRvU3RyaW5nKCksXG4gICAgICAgIHRydWUsXG4gICAgICAgIHRydWVcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IHF1ZXJ5OiBzdHJpbmdbXSA9IFtdO1xuICAgICAgY29uc3QgY29uc3RyYWludHM6IHN0cmluZ1tdID0gW107XG4gICAgICBjb25zdCBmb3JlaWduS2V5czogc3RyaW5nW10gPSBbXTtcbiAgICAgIGxldCB0eXBlRGF0YTogVHlwZU1ldGFkYXRhIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICAgICAgbGV0IGNoaWxkQ2xhc3M6IENvbnN0cnVjdG9yPE1vZGVsPiB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICAgIGxldCBjaGlsZFBrOiBhbnk7XG5cbiAgICAgIGlmIChPYmplY3Qua2V5cyhkZWNvcmF0b3JEYXRhKS5sZW5ndGgpIHtcbiAgICAgICAgdHlwZURhdGEgPSBkZWNvcmF0b3JEYXRhW1ZhbGlkYXRpb25LZXlzLlRZUEVdIGFzIFR5cGVNZXRhZGF0YTtcblxuICAgICAgICBpZiAoIXR5cGVEYXRhKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBNaXNzaW5nIHR5cGUgaW5mb3JtYXRpb25gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBwYXJzZWRUeXBlOlxuICAgICAgICAgIHwgc3RyaW5nXG4gICAgICAgICAgfCB7IG1vZGVsOiBDb25zdHJ1Y3RvcjxNb2RlbD4gfCBzdHJpbmc7IHBrVHlwZT86IHN0cmluZyB9ID1cbiAgICAgICAgICB0aGlzLnBhcnNlVHlwZVRvUG9zdGdyZXMoXG4gICAgICAgICAgICB0eXBlb2YgKHR5cGVEYXRhLmN1c3RvbVR5cGVzIGFzIGFueVtdKVswXSA9PT0gXCJmdW5jdGlvblwiXG4gICAgICAgICAgICAgID8gKHR5cGVEYXRhLmN1c3RvbVR5cGVzIGFzIGFueSlbMF0oKVxuICAgICAgICAgICAgICA6ICh0eXBlRGF0YS5jdXN0b21UeXBlcyBhcyBhbnkpWzBdLFxuICAgICAgICAgICAgaXNQa1xuICAgICAgICAgICk7XG4gICAgICAgIGlmICh0eXBlb2YgcGFyc2VkVHlwZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgIHBhcnNlZFR5cGUgPSB7IG1vZGVsOiBwYXJzZWRUeXBlIH07XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHR5cGVTdHI6XG4gICAgICAgICAgfCBzdHJpbmdcbiAgICAgICAgICB8IHsgbW9kZWw6IENvbnN0cnVjdG9yPE1vZGVsPiB8IHN0cmluZzsgcGtUeXBlPzogc3RyaW5nIH0gPVxuICAgICAgICAgIHBhcnNlZFR5cGUubW9kZWwgYXNcbiAgICAgICAgICAgIHwgc3RyaW5nXG4gICAgICAgICAgICB8IHsgbW9kZWw6IENvbnN0cnVjdG9yPE1vZGVsPiB8IHN0cmluZzsgcGtUeXBlPzogc3RyaW5nIH07XG5cbiAgICAgICAgaWYgKHR5cGVvZiB0eXBlU3RyICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkodHlwZVN0cikpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKHR5cGVTdHIpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIGNvbnRpbnVlO1xuICAgICAgICAgIC8vIGNvbnN0IHJlczogUmVjb3JkPHN0cmluZywgUG9zdGdyZXNUYWJsZVNwZWM+ID0gYXdhaXQgdGhpcy5jcmVhdGVUYWJsZShwb29sLCB0eXBlU3RyKTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgY2hpbGRDbGFzcyA9IHBhcnNlZFR5cGUubW9kZWwgYXMgQ29uc3RydWN0b3I8TW9kZWw+O1xuICAgICAgICAgICAgY29uc3QgbSA9IG5ldyBjaGlsZENsYXNzKCk7XG4gICAgICAgICAgICBjaGlsZFBrID0gZmluZFByaW1hcnlLZXkobSk7XG4gICAgICAgICAgICB0eXBlU3RyID0gdGhpcy5wYXJzZVR5cGVUb1Bvc3RncmVzKFxuICAgICAgICAgICAgICBwYXJzZWRUeXBlLnBrVHlwZSBhcyBzdHJpbmcsXG4gICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICB0cnVlXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5jcmVhdGVUYWJsZShjbGllbnQsIGNoaWxkQ2xhc3MpO1xuICAgICAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgICAgIGlmICghKGUgaW5zdGFuY2VvZiBDb25mbGljdEVycm9yKSkgdGhyb3cgZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgdHAgPSBBcnJheS5pc0FycmF5KHR5cGVEYXRhLmN1c3RvbVR5cGVzKVxuICAgICAgICAgID8gdHlwZURhdGEuY3VzdG9tVHlwZXNbMF1cbiAgICAgICAgICA6IHR5cGVEYXRhLmN1c3RvbVR5cGVzO1xuICAgICAgICB0cCA9IHR5cGVvZiB0cCA9PT0gXCJmdW5jdGlvblwiICYmICF0cC5uYW1lID8gdHAoKSA6IHRwO1xuICAgICAgICBjb25zdCB2YWxpZGF0aW9uU3RyID0gdGhpcy5wYXJzZVZhbGlkYXRpb25Ub1Bvc3RncmVzKFxuICAgICAgICAgIGNvbHVtbixcbiAgICAgICAgICB0cCBhcyBhbnksXG4gICAgICAgICAgaXNQayxcbiAgICAgICAgICBWYWxpZGF0aW9uS2V5cy5NQVhfTEVOR1RILFxuICAgICAgICAgIChkZWNvcmF0b3JEYXRhW1xuICAgICAgICAgICAgVmFsaWRhdGlvbktleXMuTUFYX0xFTkdUSFxuICAgICAgICAgIF0gYXMgTWF4TGVuZ3RoVmFsaWRhdG9yT3B0aW9ucykgfHwge1xuICAgICAgICAgICAgW1ZhbGlkYXRpb25LZXlzLk1BWF9MRU5HVEhdOiAyNTUsXG4gICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IHEgPSBgJHtjb2x1bW59ICR7dHlwZVN0cn0ke3ZhbGlkYXRpb25TdHJ9YDtcblxuICAgICAgICBpZiAoaXNQaykge1xuICAgICAgICAgIHF1ZXJ5LnVuc2hpZnQocSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcXVlcnkucHVzaChxKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAoY29uc3QgW2tleSwgcHJvcHNdIG9mIE9iamVjdC5lbnRyaWVzKGRlY29yYXRvckRhdGEpLmZpbHRlcihcbiAgICAgICAgICAoW2tdKSA9PlxuICAgICAgICAgICAgIVtWYWxpZGF0aW9uS2V5cy5UWVBFLCBWYWxpZGF0aW9uS2V5cy5NQVhfTEVOR1RIXS5pbmNsdWRlcyhrIGFzIGFueSlcbiAgICAgICAgKSkge1xuICAgICAgICAgIGNvbnN0IHZhbGlkYXRpb24gPSB0aGlzLnBhcnNlVmFsaWRhdGlvblRvUG9zdGdyZXMoXG4gICAgICAgICAgICBjb2x1bW4sXG4gICAgICAgICAgICB0cCBhcyBhbnksXG4gICAgICAgICAgICBpc1BrLFxuICAgICAgICAgICAga2V5LFxuICAgICAgICAgICAgcHJvcHNcbiAgICAgICAgICApO1xuICAgICAgICAgIGlmICh2YWxpZGF0aW9uLnN0YXJ0c1dpdGgoXCJDT05TVFJBSU5UXCIpKSB7XG4gICAgICAgICAgICBjb25zdHJhaW50cy5wdXNoKHZhbGlkYXRpb24pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAodmFsaWRhdGlvbikge1xuICAgICAgICAgICAgICBxdWVyeS5wdXNoKHZhbGlkYXRpb24pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBUT0RPIGlnbm9yZSBmb3Igbm93LiB0aGlzIGxlYXZlcyBmb3JlaWduIGtleXMgb3V0XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc3RhbnQtYmluYXJ5LWV4cHJlc3Npb25cbiAgICAgIGlmIChmYWxzZSB8fCAoZGJEZWNzICYmIGRiRGVjcy5kZWNvcmF0b3JzLmxlbmd0aCkpIHtcbiAgICAgICAgaWYgKCF0eXBlRGF0YSkgdGhyb3cgbmV3IEVycm9yKGBNaXNzaW5nIHR5cGUgaW5mb3JtYXRpb25gKTtcbiAgICAgICAgZm9yIChjb25zdCBkZWNvcmF0b3Igb2YgZGJEZWNzLmRlY29yYXRvcnMpIHtcbiAgICAgICAgICBjb25zdCB7IGtleSwgcHJvcHMgfSA9IGRlY29yYXRvcjtcbiAgICAgICAgICBjb25zdCB2YWxpZGF0aW9uID0gdGhpcy5wYXJzZVJlbGF0aW9uc1RvUG9zdGdyZXMoXG4gICAgICAgICAgICBjb2x1bW4sXG4gICAgICAgICAgICBjaGlsZENsYXNzIGFzIENvbnN0cnVjdG9yPE1vZGVsPixcbiAgICAgICAgICAgIGNoaWxkUGsuaWQsXG4gICAgICAgICAgICBrZXkgYXMgUGVyc2lzdGVuY2VLZXlzLFxuICAgICAgICAgICAgcHJvcHMgYXMgdW5rbm93biBhcyBSZWxhdGlvbnNNZXRhZGF0YVxuICAgICAgICAgICk7XG4gICAgICAgICAgaWYgKHZhbGlkYXRpb24uc3RhcnRzV2l0aChcIkZPUkVJR05cIikpIHtcbiAgICAgICAgICAgIGZvcmVpZ25LZXlzLnB1c2godmFsaWRhdGlvbik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBVbnN1cHBvcnRlZCByZWxhdGlvbjogJHtrZXl9YCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJlc3VsdFtwcm9wLnRvU3RyaW5nKCldID0ge1xuICAgICAgICBxdWVyeTogcXVlcnkuam9pbihcIiBcIiksXG4gICAgICAgIHZhbHVlczogW10sXG4gICAgICAgIHByaW1hcnlLZXk6IGlzUGssXG4gICAgICAgIGNvbnN0cmFpbnRzOiBjb25zdHJhaW50cyxcbiAgICAgICAgZm9yZWlnbktleXM6IGZvcmVpZ25LZXlzLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCB2YWx1ZXMgPSBPYmplY3QudmFsdWVzKHJlc3VsdCk7XG4gICAgY29uc3QgcXVlcnkgPSB2YWx1ZXMubWFwKChyKSA9PiByLnF1ZXJ5KS5qb2luKFwiLFxcblwiKTtcbiAgICBjb25zdCBjb25zdHJhaW50cyA9IHZhbHVlc1xuICAgICAgLmZpbHRlcigoYykgPT4gISFjLmNvbnN0cmFpbnRzLmxlbmd0aClcbiAgICAgIC5tYXAoKHIpID0+IHIuY29uc3RyYWludHMpXG4gICAgICAuam9pbihcIixcXG5cIik7XG4gICAgY29uc3QgZm9yZWlnbktleXMgPSB2YWx1ZXNcbiAgICAgIC5maWx0ZXIoKGMpID0+ICEhYy5mb3JlaWduS2V5cy5sZW5ndGgpXG4gICAgICAubWFwKChyKSA9PiByLmZvcmVpZ25LZXlzKVxuICAgICAgLmpvaW4oXCIsXFxuXCIpO1xuICAgIGNvbnN0IHZhbHMgPSBbcXVlcnksIGNvbnN0cmFpbnRzXTtcbiAgICBpZiAoZm9yZWlnbktleXMpIHtcbiAgICAgIHZhbHMucHVzaChmb3JlaWduS2V5cyk7XG4gICAgfVxuICAgIGNvbnN0IHF1ZXJ5U3RyaW5nID0gYENSRUFURSBUQUJMRSAke3RhYmxlTmFtZX0gKCR7dmFscy5maWx0ZXIoKHYpID0+ICEhdikuam9pbihcIixcXG5cIil9KWA7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGNsaWVudC5xdWVyeShxdWVyeVN0cmluZyk7XG4gICAgICBhd2FpdCBjbGllbnQucXVlcnkoXG4gICAgICAgIGBDUkVBVEUgVFJJR0dFUiBub3RpZnlfY2hhbmdlc18ke3RhYmxlTmFtZX1cbkFGVEVSIElOU0VSVCBPUiBVUERBVEUgT1IgREVMRVRFIE9OICR7dGFibGVOYW1lfVxuICAgIEZPUiBFQUNIIFJPV1xuICAgIEVYRUNVVEUgRlVOQ1RJT04gbm90aWZ5X3RhYmxlX2NoYW5nZXMoKTtgXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHN0YXRpYyBhc3luYyBnZXRDdXJyZW50VXNlcihjbGllbnQ6IERhdGFTb3VyY2UpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHF1ZXJ5U3RyaW5nID0gYFNFTEVDVCBDVVJSRU5UX1VTRVI7YDtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY2xpZW50LnF1ZXJ5KHF1ZXJ5U3RyaW5nKTtcbiAgICAgIHJldHVybiByZXN1bHRbMF0uY3VycmVudF91c2VyO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRocm93IHRoaXMucGFyc2VFcnJvcihlIGFzIEVycm9yKTtcbiAgICB9XG4gIH1cblxuICBzdGF0aWMgZGVjb3JhdGlvbigpIHtcbiAgICAvLyBAdGFibGUoKSA9PiBARW50aXR5KClcbiAgICBjb25zdCB0YWJsZUtleSA9IEFkYXB0ZXIua2V5KFBlcnNpc3RlbmNlS2V5cy5UQUJMRSk7XG4gICAgRGVjb3JhdGlvbi5mbGF2b3VyZWRBcyhUeXBlT1JNRmxhdm91cilcbiAgICAgIC5mb3IodGFibGVLZXkpXG4gICAgICAuZXh0ZW5kKChvcmlnaW5hbDogYW55KSA9PlxuICAgICAgICBFbnRpdHkoKShvcmlnaW5hbFtNb2RlbEtleXMuQU5DSE9SXSB8fCBvcmlnaW5hbClcbiAgICAgIClcbiAgICAgIC5hcHBseSgpO1xuXG4gICAgLy8gQHBrKCkgPT4gQFByaW1hcnlHZW5lcmF0ZWRDb2x1bW4oKSB8IEBQcmltYXJ5Q29sdW1uKClcbiAgICBjb25zdCBwa0tleSA9IFJlcG9zaXRvcnkua2V5KERCS2V5cy5JRCk7XG5cbiAgICBmdW5jdGlvbiBwa0RlYyhvcHRpb25zOiBTZXF1ZW5jZU9wdGlvbnMpIHtcbiAgICAgIGNvbnN0IGRlY29yYXRvcnM6IGFueVtdID0gW1xuICAgICAgICByZXF1aXJlZCgpLFxuICAgICAgICByZWFkb25seSgpLFxuICAgICAgICBwcm9wTWV0YWRhdGEocGtLZXksIG9wdGlvbnMpLFxuICAgICAgXTtcbiAgICAgIGlmIChvcHRpb25zLnR5cGUpIGRlY29yYXRvcnMucHVzaChQcmltYXJ5R2VuZXJhdGVkQ29sdW1uKCkpO1xuICAgICAgZWxzZSBkZWNvcmF0b3JzLnB1c2goUHJpbWFyeUNvbHVtbih7IHVuaXF1ZTogdHJ1ZSB9KSk7XG4gICAgICByZXR1cm4gYXBwbHkoLi4uZGVjb3JhdG9ycyk7XG4gICAgfVxuXG4gICAgRGVjb3JhdGlvbi5mbGF2b3VyZWRBcyhUeXBlT1JNRmxhdm91cilcbiAgICAgIC5mb3IocGtLZXkpXG4gICAgICAuZGVmaW5lKHtcbiAgICAgICAgZGVjb3JhdG9yOiBwa0RlYyxcbiAgICAgIH0pXG4gICAgICAuYXBwbHkoKTtcblxuICAgIC8vIEBjb2x1bW4oXCJjb2x1bW5OYW1lXCIpID0+IEBDb2x1bW4oe25hbWU6IFwiY29sdW1uTmFtZVwifSlcbiAgICBjb25zdCBjb2x1bW5LZXkgPSBBZGFwdGVyLmtleShQZXJzaXN0ZW5jZUtleXMuQ09MVU1OKTtcbiAgICBEZWNvcmF0aW9uLmZsYXZvdXJlZEFzKFR5cGVPUk1GbGF2b3VyKVxuICAgICAgLmZvcihjb2x1bW5LZXkpXG4gICAgICAuZXh0ZW5kKHtcbiAgICAgICAgZGVjb3JhdG9yOiBmdW5jdGlvbiBjb2x1bW0obmFtZTogc3RyaW5nKSB7XG4gICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIGNvbHVtbihvYmo6IGFueSwgcHJvcDogYW55KSB7XG4gICAgICAgICAgICByZXR1cm4gQ29sdW1uKHtcbiAgICAgICAgICAgICAgbmFtZTogbmFtZSB8fCBwcm9wLFxuICAgICAgICAgICAgICBudWxsYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIH0pKG9iaiwgcHJvcCk7XG4gICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgdHJhbnNmb3JtOiAoYXJnczogYW55W10pID0+IHtcbiAgICAgICAgICBjb25zdCBjb2x1bW5OYW1lID0gYXJnc1sxXTtcbiAgICAgICAgICByZXR1cm4gW2NvbHVtbk5hbWVdO1xuICAgICAgICB9LFxuICAgICAgfSlcbiAgICAgIC5hcHBseSgpO1xuXG4gICAgLy8gQHVuaXF1ZSA9PiBAQ29sdW1uKHt1bmlxdWU6IHRydWV9KVxuICAgIGNvbnN0IHVuaXF1ZUtleSA9IEFkYXB0ZXIua2V5KFBlcnNpc3RlbmNlS2V5cy5VTklRVUUpO1xuICAgIERlY29yYXRpb24uZmxhdm91cmVkQXMoVHlwZU9STUZsYXZvdXIpXG4gICAgICAuZm9yKHVuaXF1ZUtleSlcbiAgICAgIC5kZWZpbmUocHJvcE1ldGFkYXRhKHVuaXF1ZUtleSwge30pKVxuICAgICAgLmV4dGVuZChDb2x1bW4oeyB1bmlxdWU6IHRydWUgfSkpXG4gICAgICAuYXBwbHkoKTtcblxuICAgIC8vIEByZXF1aXJlZCA9PiBAQ29sdW1uKHsgbnVsbGFibGU6IGZhbHNlIH0pXG4gICAgY29uc3QgcmVxdWlyZWRLZXkgPSBWYWxpZGF0aW9uLmtleShWYWxpZGF0aW9uS2V5cy5SRVFVSVJFRCk7XG4gICAgRGVjb3JhdGlvbi5mbGF2b3VyZWRBcyhUeXBlT1JNRmxhdm91cilcbiAgICAgIC5mb3IocmVxdWlyZWRLZXkpXG4gICAgICAuZXh0ZW5kKENvbHVtbih7IG51bGxhYmxlOiBmYWxzZSB9KSlcbiAgICAgIC5hcHBseSgpO1xuXG4gICAgLy8gQHZlcnNpb24gPT4gQFZlcnNpb25Db2x1bW4oKVxuICAgIGNvbnN0IHZlcnNpb25LZXkgPSBSZXBvc2l0b3J5LmtleShEQktleXMuVkVSU0lPTik7XG4gICAgRGVjb3JhdGlvbi5mbGF2b3VyZWRBcyhUeXBlT1JNRmxhdm91cilcbiAgICAgIC5mb3IodmVyc2lvbktleSlcbiAgICAgIC5kZWZpbmUodHlwZShOdW1iZXIubmFtZSksIFZlcnNpb25Db2x1bW4oKSlcbiAgICAgIC5hcHBseSgpO1xuXG4gICAgZnVuY3Rpb24gVmFsaWRhdGlvblVwZGF0ZUtleShrZXk6IHN0cmluZykge1xuICAgICAgcmV0dXJuIFVwZGF0ZVZhbGlkYXRpb25LZXlzLlJFRkxFQ1QgKyBrZXk7XG4gICAgfVxuXG4gICAgLy8gQHRpbWVzdGFtcChvcCkgPT4gQENyZWF0ZURhdGVDb2x1bW4oKSB8fCBAVXBkYXRlRGF0ZUNvbHVtbigpXG4gICAgY29uc3QgdGltZXN0YW1wS2V5ID0gVmFsaWRhdGlvblVwZGF0ZUtleShEQktleXMuVElNRVNUQU1QKTtcblxuICAgIGZ1bmN0aW9uIHRzKG9wZXJhdGlvbjogT3BlcmF0aW9uS2V5c1tdLCBmb3JtYXQ6IHN0cmluZykge1xuICAgICAgY29uc3QgZGVjb3JhdG9yczogYW55W10gPSBbXG4gICAgICAgIGRhdGUoZm9ybWF0LCBEQl9ERUZBVUxUX0VSUk9SX01FU1NBR0VTLlRJTUVTVEFNUC5EQVRFKSxcbiAgICAgICAgcmVxdWlyZWQoREJfREVGQVVMVF9FUlJPUl9NRVNTQUdFUy5USU1FU1RBTVAuUkVRVUlSRUQpLFxuICAgICAgICBwcm9wTWV0YWRhdGEoVmFsaWRhdGlvbi5rZXkoREJLZXlzLlRJTUVTVEFNUCksIHtcbiAgICAgICAgICBvcGVyYXRpb246IG9wZXJhdGlvbixcbiAgICAgICAgICBmb3JtYXQ6IGZvcm1hdCxcbiAgICAgICAgfSksXG4gICAgICBdO1xuICAgICAgaWYgKG9wZXJhdGlvbi5pbmRleE9mKE9wZXJhdGlvbktleXMuVVBEQVRFKSAhPT0gLTEpXG4gICAgICAgIGRlY29yYXRvcnMucHVzaChcbiAgICAgICAgICBwcm9wTWV0YWRhdGEodGltZXN0YW1wS2V5LCB7XG4gICAgICAgICAgICBtZXNzYWdlOiBEQl9ERUZBVUxUX0VSUk9SX01FU1NBR0VTLlRJTUVTVEFNUC5JTlZBTElELFxuICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgICBlbHNlIGRlY29yYXRvcnMucHVzaChyZWFkb25seSgpKTtcbiAgICAgIHJldHVybiBhcHBseSguLi5kZWNvcmF0b3JzKTtcbiAgICB9XG5cbiAgICBEZWNvcmF0aW9uLmZsYXZvdXJlZEFzKFR5cGVPUk1GbGF2b3VyKVxuICAgICAgLmZvcih0aW1lc3RhbXBLZXkpXG4gICAgICAuZGVmaW5lKHtcbiAgICAgICAgZGVjb3JhdG9yOiB0cyxcbiAgICAgIH0pXG4gICAgICAuZXh0ZW5kKHtcbiAgICAgICAgZGVjb3JhdG9yOiBmdW5jdGlvbiB0aW1lc3RhbXAoLi4ub3BzOiBPcGVyYXRpb25LZXlzW10pIHtcbiAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gdGltZXN0YW1wKG9iajogYW55LCBwcm9wOiBhbnkpIHtcbiAgICAgICAgICAgIGlmIChvcHMuaW5kZXhPZihPcGVyYXRpb25LZXlzLlVQREFURSkgIT09IC0xKVxuICAgICAgICAgICAgICByZXR1cm4gVXBkYXRlRGF0ZUNvbHVtbigpKG9iaiwgcHJvcCk7XG4gICAgICAgICAgICByZXR1cm4gQ3JlYXRlRGF0ZUNvbHVtbigpKG9iaiwgcHJvcCk7XG4gICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgdHJhbnNmb3JtOiAoYXJnczogYW55W10pID0+IHtcbiAgICAgICAgICByZXR1cm4gYXJnc1swXTtcbiAgICAgICAgfSxcbiAgICAgIH0pXG4gICAgICAuYXBwbHkoKTtcblxuICAgIC8vIEBvbmVUb09uZShjbGF6eikgPT4gQE9uZVRvT25lKCgpID0+IGNsYXp6KVxuICAgIGNvbnN0IG9uZVRvT25lS2V5ID0gUmVwb3NpdG9yeS5rZXkoUGVyc2lzdGVuY2VLZXlzLk9ORV9UT19PTkUpO1xuICAgIERlY29yYXRpb24uZmxhdm91cmVkQXMoVHlwZU9STUZsYXZvdXIpXG4gICAgICAuZm9yKG9uZVRvT25lS2V5KVxuICAgICAgLmRlZmluZSh7XG4gICAgICAgIGRlY29yYXRvcjogZnVuY3Rpb24gb25lVG9PbmUoXG4gICAgICAgICAgY2xheno6IENvbnN0cnVjdG9yPGFueT4gfCAoKCkgPT4gQ29uc3RydWN0b3I8YW55PiksXG4gICAgICAgICAgY2FzY2FkZTogQ2FzY2FkZU1ldGFkYXRhLFxuICAgICAgICAgIHBvcHVsYXRlOiBib29sZWFuXG4gICAgICAgICkge1xuICAgICAgICAgIGNvbnN0IG1ldGFkYXRhOiBSZWxhdGlvbnNNZXRhZGF0YSA9IHtcbiAgICAgICAgICAgIGNsYXNzOiAoY2xhenoubmFtZSA/IGNsYXp6Lm5hbWUgOiBjbGF6eikgYXMgc3RyaW5nLFxuICAgICAgICAgICAgY2FzY2FkZTogY2FzY2FkZSxcbiAgICAgICAgICAgIHBvcHVsYXRlOiBwb3B1bGF0ZSxcbiAgICAgICAgICB9O1xuICAgICAgICAgIGNvbnN0IG9ybU1ldGE6IFJlbGF0aW9uT3B0aW9ucyA9IHtcbiAgICAgICAgICAgIGNhc2NhZGU6XG4gICAgICAgICAgICAgIGNhc2NhZGUudXBkYXRlID09PSBDYXNjYWRlLkNBU0NBREUgfHxcbiAgICAgICAgICAgICAgY2FzY2FkZS5kZWxldGUgPT09IENhc2NhZGUuQ0FTQ0FERSxcbiAgICAgICAgICAgIG9uRGVsZXRlOiBjYXNjYWRlLmRlbGV0ZSA/IFwiQ0FTQ0FERVwiIDogXCJERUZBVUxUXCIsXG4gICAgICAgICAgICBvblVwZGF0ZTogY2FzY2FkZS51cGRhdGUgPyBcIkNBU0NBREVcIiA6IFwiREVGQVVMVFwiLFxuICAgICAgICAgICAgbnVsbGFibGU6IHRydWUsXG4gICAgICAgICAgICBlYWdlcjogcG9wdWxhdGUsXG4gICAgICAgICAgfTtcbiAgICAgICAgICByZXR1cm4gYXBwbHkoXG4gICAgICAgICAgICBwcm9wKFBlcnNpc3RlbmNlS2V5cy5SRUxBVElPTlMpLFxuICAgICAgICAgICAgdHlwZShbXG4gICAgICAgICAgICAgICh0eXBlb2YgY2xhenogPT09IFwiZnVuY3Rpb25cIiAmJiAhY2xhenoubmFtZVxuICAgICAgICAgICAgICAgID8gY2xhenpcbiAgICAgICAgICAgICAgICA6IGNsYXp6Lm5hbWUpIGFzIGFueSxcbiAgICAgICAgICAgICAgU3RyaW5nLm5hbWUsXG4gICAgICAgICAgICAgIE51bWJlci5uYW1lLFxuICAgICAgICAgICAgICBCaWdJbnQubmFtZSxcbiAgICAgICAgICAgIF0pLFxuICAgICAgICAgICAgcHJvcE1ldGFkYXRhKG9uZVRvT25lS2V5LCBtZXRhZGF0YSksXG4gICAgICAgICAgICBPbmVUb09uZShcbiAgICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghY2xhenoubmFtZSkgY2xhenogPSAoY2xhenogYXMgYW55KSgpO1xuICAgICAgICAgICAgICAgIGlmICghY2xhenpbTW9kZWxLZXlzLkFOQ0hPUiBhcyBrZXlvZiB0eXBlb2YgY2xhenpdKVxuICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIFwiT3JpZ2luYWwgTW9kZWwgbm90IGZvdW5kIGluIGNvbnN0cnVjdG9yXCJcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNsYXp6W01vZGVsS2V5cy5BTkNIT1IgYXMga2V5b2YgdHlwZW9mIGNsYXp6XTtcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgKG1vZGVsOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBwayA9IGZpbmRQcmltYXJ5S2V5KG5ldyAoY2xhenogYXMgQ29uc3RydWN0b3I8YW55PikoKSkuaWQ7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1vZGVsW3BrXTtcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgb3JtTWV0YVxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIEpvaW5Db2x1bW4oKVxuICAgICAgICAgICk7XG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgICAgLmFwcGx5KCk7XG5cbiAgICAvLyBAb25lVG9NYW55KGNsYXp6KSA9PiBAT25lVG9NYW55KCgpID0+IGNsYXp6KVxuICAgIGNvbnN0IG9uZVRvTWFueUtleSA9IFJlcG9zaXRvcnkua2V5KFBlcnNpc3RlbmNlS2V5cy5PTkVfVE9fTUFOWSk7XG4gICAgRGVjb3JhdGlvbi5mbGF2b3VyZWRBcyhUeXBlT1JNRmxhdm91cilcbiAgICAgIC5mb3Iob25lVG9NYW55S2V5KVxuICAgICAgLmRlZmluZSh7XG4gICAgICAgIGRlY29yYXRvcjogZnVuY3Rpb24gb25lVG9NYW55KFxuICAgICAgICAgIGNsYXp6OiBDb25zdHJ1Y3Rvcjxhbnk+IHwgKCgpID0+IENvbnN0cnVjdG9yPGFueT4pLFxuICAgICAgICAgIGNhc2NhZGU6IENhc2NhZGVNZXRhZGF0YSxcbiAgICAgICAgICBwb3B1bGF0ZTogYm9vbGVhblxuICAgICAgICApIHtcbiAgICAgICAgICBjb25zdCBtZXRhZGF0YTogUmVsYXRpb25zTWV0YWRhdGEgPSB7XG4gICAgICAgICAgICBjbGFzczogKGNsYXp6Lm5hbWUgPyBjbGF6ei5uYW1lIDogY2xhenopIGFzIHN0cmluZyxcbiAgICAgICAgICAgIGNhc2NhZGU6IGNhc2NhZGUsXG4gICAgICAgICAgICBwb3B1bGF0ZTogcG9wdWxhdGUsXG4gICAgICAgICAgfTtcbiAgICAgICAgICByZXR1cm4gYXBwbHkoXG4gICAgICAgICAgICBwcm9wKFBlcnNpc3RlbmNlS2V5cy5SRUxBVElPTlMpLFxuICAgICAgICAgICAgbGlzdChjbGF6eiksXG4gICAgICAgICAgICBwcm9wTWV0YWRhdGEob25lVG9NYW55S2V5LCBtZXRhZGF0YSksXG4gICAgICAgICAgICBmdW5jdGlvbiBPbmVUb01hbnlXcmFwcGVyKG9iajogYW55LCBwcm9wOiBhbnkpOiBhbnkge1xuICAgICAgICAgICAgICBjb25zdCBvcm1NZXRhOiBSZWxhdGlvbk9wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgY2FzY2FkZTpcbiAgICAgICAgICAgICAgICAgIGNhc2NhZGUudXBkYXRlID09PSBDYXNjYWRlLkNBU0NBREUgfHxcbiAgICAgICAgICAgICAgICAgIGNhc2NhZGUuZGVsZXRlID09PSBDYXNjYWRlLkNBU0NBREUsXG4gICAgICAgICAgICAgICAgb25EZWxldGU6IGNhc2NhZGUuZGVsZXRlID8gXCJDQVNDQURFXCIgOiBcIkRFRkFVTFRcIixcbiAgICAgICAgICAgICAgICBvblVwZGF0ZTogY2FzY2FkZS51cGRhdGUgPyBcIkNBU0NBREVcIiA6IFwiREVGQVVMVFwiLFxuICAgICAgICAgICAgICAgIG51bGxhYmxlOiB0cnVlLFxuICAgICAgICAgICAgICAgIGVhZ2VyOiBwb3B1bGF0ZSxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgcmV0dXJuIE9uZVRvTWFueShcbiAgICAgICAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICBpZiAoIWNsYXp6Lm5hbWUpIGNsYXp6ID0gKGNsYXp6IGFzIGFueSkoKTtcbiAgICAgICAgICAgICAgICAgIGlmICghY2xhenpbTW9kZWxLZXlzLkFOQ0hPUiBhcyBrZXlvZiB0eXBlb2YgY2xhenpdKVxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICBcIk9yaWdpbmFsIE1vZGVsIG5vdCBmb3VuZCBpbiBjb25zdHJ1Y3RvclwiXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gY2xhenpbTW9kZWxLZXlzLkFOQ0hPUiBhcyBrZXlvZiB0eXBlb2YgY2xhenpdO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgKG1vZGVsOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICAgIGlmICghY2xhenoubmFtZSkgY2xhenogPSAoY2xhenogYXMgYW55KSgpO1xuICAgICAgICAgICAgICAgICAgY29uc3QgbSA9IG5ldyAoY2xhenogYXMgQ29uc3RydWN0b3I8YW55PikoKTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGNyb3NzUmVsYXRpb25LZXkgPSBPYmplY3Qua2V5cyhtKS5maW5kKChrKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGRlY3MgPSBSZWZsZWN0aW9uLmdldFByb3BlcnR5RGVjb3JhdG9ycyhcbiAgICAgICAgICAgICAgICAgICAgICBSZXBvc2l0b3J5LmtleShQZXJzaXN0ZW5jZUtleXMuTUFOWV9UT19PTkUpLFxuICAgICAgICAgICAgICAgICAgICAgIG0sXG4gICAgICAgICAgICAgICAgICAgICAgayxcbiAgICAgICAgICAgICAgICAgICAgICB0cnVlXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghZGVjcyB8fCAhZGVjcy5kZWNvcmF0b3JzIHx8ICFkZWNzLmRlY29yYXRvcnMubGVuZ3RoKVxuICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZGVzaWduVHlwZSA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEoXG4gICAgICAgICAgICAgICAgICAgICAgTW9kZWxLZXlzLlRZUEUsXG4gICAgICAgICAgICAgICAgICAgICAgbSxcbiAgICAgICAgICAgICAgICAgICAgICBrXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghZGVzaWduVHlwZSlcbiAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgIGBObyBUeXBlIERlZmluaXRpb24gZm91bmQgZm9yICR7a30gaW4gJHttLmNvbnN0cnVjdG9yLm5hbWV9YFxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBkZXNpZ25UeXBlLm5hbWUgPT09IG9iai5jb25zdHJ1Y3Rvci5uYW1lO1xuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICBpZiAoIWNyb3NzUmVsYXRpb25LZXkpXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgIGBDcm9zcyByZWxhdGlvbiBub3QgZm91bmQuIERpZCB5b3UgdXNlIEBtYW55VG9PbmUgb24gdGhlICR7Y2xhenoubmFtZX0/YFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIG1vZGVsW2Nyb3NzUmVsYXRpb25LZXldO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgb3JtTWV0YVxuICAgICAgICAgICAgICApKG9iaiwgcHJvcCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfSxcbiAgICAgIH0pXG4gICAgICAuYXBwbHkoKTtcblxuICAgIC8vIEBtYW55VG9PbmUoY2xhenopID0+IEBNYW55VG9PbmUoKCkgPT4gY2xhenopXG4gICAgY29uc3QgbWFueVRvT25lS2V5ID0gUmVwb3NpdG9yeS5rZXkoUGVyc2lzdGVuY2VLZXlzLk1BTllfVE9fT05FKTtcbiAgICBEZWNvcmF0aW9uLmZsYXZvdXJlZEFzKFR5cGVPUk1GbGF2b3VyKVxuICAgICAgLmZvcihtYW55VG9PbmVLZXkpXG4gICAgICAuZGVmaW5lKHtcbiAgICAgICAgZGVjb3JhdG9yOiBmdW5jdGlvbiBtYW55VG9PbmUoXG4gICAgICAgICAgY2xheno6IENvbnN0cnVjdG9yPGFueT4gfCAoKCkgPT4gQ29uc3RydWN0b3I8YW55PiksXG4gICAgICAgICAgY2FzY2FkZTogQ2FzY2FkZU1ldGFkYXRhLFxuICAgICAgICAgIHBvcHVsYXRlOiBib29sZWFuXG4gICAgICAgICkge1xuICAgICAgICAgIGNvbnN0IG1ldGFkYXRhOiBSZWxhdGlvbnNNZXRhZGF0YSA9IHtcbiAgICAgICAgICAgIGNsYXNzOiAoY2xhenoubmFtZSA/IGNsYXp6Lm5hbWUgOiBjbGF6eikgYXMgc3RyaW5nLFxuICAgICAgICAgICAgY2FzY2FkZTogY2FzY2FkZSxcbiAgICAgICAgICAgIHBvcHVsYXRlOiBwb3B1bGF0ZSxcbiAgICAgICAgICB9O1xuICAgICAgICAgIGNvbnN0IG9ybU1ldGE6IFJlbGF0aW9uT3B0aW9ucyA9IHtcbiAgICAgICAgICAgIGNhc2NhZGU6XG4gICAgICAgICAgICAgIGNhc2NhZGUudXBkYXRlID09PSBDYXNjYWRlLkNBU0NBREUgfHxcbiAgICAgICAgICAgICAgY2FzY2FkZS5kZWxldGUgPT09IENhc2NhZGUuQ0FTQ0FERSxcbiAgICAgICAgICAgIG9uRGVsZXRlOiBjYXNjYWRlLmRlbGV0ZSA/IFwiQ0FTQ0FERVwiIDogXCJERUZBVUxUXCIsXG4gICAgICAgICAgICBvblVwZGF0ZTogY2FzY2FkZS51cGRhdGUgPyBcIkNBU0NBREVcIiA6IFwiREVGQVVMVFwiLFxuICAgICAgICAgICAgbnVsbGFibGU6IHRydWUsXG4gICAgICAgICAgICBlYWdlcjogcG9wdWxhdGUsXG4gICAgICAgICAgfTtcbiAgICAgICAgICByZXR1cm4gYXBwbHkoXG4gICAgICAgICAgICBwcm9wKFBlcnNpc3RlbmNlS2V5cy5SRUxBVElPTlMpLFxuICAgICAgICAgICAgdHlwZShbXG4gICAgICAgICAgICAgICh0eXBlb2YgY2xhenogPT09IFwiZnVuY3Rpb25cIiAmJiAhY2xhenoubmFtZVxuICAgICAgICAgICAgICAgID8gY2xhenpcbiAgICAgICAgICAgICAgICA6IGNsYXp6Lm5hbWUpIGFzIGFueSxcbiAgICAgICAgICAgICAgU3RyaW5nLm5hbWUsXG4gICAgICAgICAgICAgIE51bWJlci5uYW1lLFxuICAgICAgICAgICAgICBCaWdJbnQubmFtZSxcbiAgICAgICAgICAgIF0pLFxuICAgICAgICAgICAgcHJvcE1ldGFkYXRhKG1hbnlUb09uZUtleSwgbWV0YWRhdGEpLFxuICAgICAgICAgICAgZnVuY3Rpb24gTWFueVRvT25lV3JhcHBlcihvYmo6IGFueSwgcHJvcDogYW55KTogYW55IHtcbiAgICAgICAgICAgICAgcmV0dXJuIE1hbnlUb09uZShcbiAgICAgICAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICBpZiAoIWNsYXp6Lm5hbWUpIGNsYXp6ID0gKGNsYXp6IGFzIGFueSkoKTtcbiAgICAgICAgICAgICAgICAgIGlmICghY2xhenpbTW9kZWxLZXlzLkFOQ0hPUiBhcyBrZXlvZiB0eXBlb2YgY2xhenpdKVxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICBcIk9yaWdpbmFsIE1vZGVsIG5vdCBmb3VuZCBpbiBjb25zdHJ1Y3RvclwiXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICByZXR1cm4gY2xhenpbTW9kZWxLZXlzLkFOQ0hPUiBhcyBrZXlvZiB0eXBlb2YgY2xhenpdO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgKG1vZGVsOiBhbnkpID0+IHtcbiAgICAgICAgICAgICAgICAgIGlmICghY2xhenoubmFtZSkgY2xhenogPSAoY2xhenogYXMgYW55KSgpO1xuICAgICAgICAgICAgICAgICAgY29uc3QgbSA9IG5ldyAoY2xhenogYXMgQ29uc3RydWN0b3I8YW55PikoKTtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGNyb3NzUmVsYXRpb25LZXkgPSBPYmplY3Qua2V5cyhtKS5maW5kKChrKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGRlY3MgPSBSZWZsZWN0aW9uLmdldFByb3BlcnR5RGVjb3JhdG9ycyhcbiAgICAgICAgICAgICAgICAgICAgICBSZXBvc2l0b3J5LmtleShQZXJzaXN0ZW5jZUtleXMuT05FX1RPX01BTlkpLFxuICAgICAgICAgICAgICAgICAgICAgIG0sXG4gICAgICAgICAgICAgICAgICAgICAgayxcbiAgICAgICAgICAgICAgICAgICAgICB0cnVlXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghZGVjcyB8fCAhZGVjcy5kZWNvcmF0b3JzIHx8ICFkZWNzLmRlY29yYXRvcnMubGVuZ3RoKVxuICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbGlzdERlYyA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEoXG4gICAgICAgICAgICAgICAgICAgICAgVmFsaWRhdGlvbi5rZXkoVmFsaWRhdGlvbktleXMuTElTVCksXG4gICAgICAgICAgICAgICAgICAgICAgbSxcbiAgICAgICAgICAgICAgICAgICAgICBrXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghbGlzdERlYylcbiAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgIGBObyBUeXBlIERlZmluaXRpb24gZm91bmQgZm9yICR7a30gaW4gJHttLmNvbnN0cnVjdG9yLm5hbWV9YFxuICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG5hbWUgPSBsaXN0RGVjLmNsYXp6WzBdKCkubmFtZTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5hbWUgPT09IG9iai5jb25zdHJ1Y3Rvci5uYW1lO1xuICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICBpZiAoIWNyb3NzUmVsYXRpb25LZXkpXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgIGBDcm9zcyByZWxhdGlvbiBub3QgZm91bmQuIERpZCB5b3UgdXNlIEBtYW55VG9PbmUgb24gdGhlICR7Y2xhenoubmFtZX0/YFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIG1vZGVsW2Nyb3NzUmVsYXRpb25LZXldO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgKShvYmosIHByb3ApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICk7XG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgICAgLmFwcGx5KCk7XG5cbiAgICAvLyBAbWFueVRvTWFueShjbGF6eikgPT4gQE1hbnlUb01hbnkoKCkgPT4gY2xhenopXG4gICAgY29uc3QgbWFueVRvTWFueUtleSA9IFJlcG9zaXRvcnkua2V5KFBlcnNpc3RlbmNlS2V5cy5NQU5ZX1RPX01BTlkpO1xuICAgIERlY29yYXRpb24uZmxhdm91cmVkQXMoVHlwZU9STUZsYXZvdXIpXG4gICAgICAuZm9yKG1hbnlUb01hbnlLZXkpXG4gICAgICAuZGVmaW5lKHtcbiAgICAgICAgZGVjb3JhdG9yOiBmdW5jdGlvbiBtYW55VG9NYW55KFxuICAgICAgICAgIGNsYXp6OiBDb25zdHJ1Y3Rvcjxhbnk+IHwgKCgpID0+IENvbnN0cnVjdG9yPGFueT4pLFxuICAgICAgICAgIGNhc2NhZGU6IENhc2NhZGVNZXRhZGF0YSxcbiAgICAgICAgICBwb3B1bGF0ZTogYm9vbGVhblxuICAgICAgICApIHtcbiAgICAgICAgICBjb25zdCBtZXRhZGF0YTogUmVsYXRpb25zTWV0YWRhdGEgPSB7XG4gICAgICAgICAgICBjbGFzczogY2xhenoubmFtZSxcbiAgICAgICAgICAgIGNhc2NhZGU6IGNhc2NhZGUsXG4gICAgICAgICAgICBwb3B1bGF0ZTogcG9wdWxhdGUsXG4gICAgICAgICAgfTtcbiAgICAgICAgICBjb25zdCBvcm1NZXRhOiBSZWxhdGlvbk9wdGlvbnMgPSB7XG4gICAgICAgICAgICBjYXNjYWRlOlxuICAgICAgICAgICAgICBjYXNjYWRlLnVwZGF0ZSA9PT0gQ2FzY2FkZS5DQVNDQURFIHx8XG4gICAgICAgICAgICAgIGNhc2NhZGUuZGVsZXRlID09PSBDYXNjYWRlLkNBU0NBREUsXG4gICAgICAgICAgICBvbkRlbGV0ZTogY2FzY2FkZS5kZWxldGUgPyBcIkNBU0NBREVcIiA6IFwiREVGQVVMVFwiLFxuICAgICAgICAgICAgb25VcGRhdGU6IGNhc2NhZGUudXBkYXRlID8gXCJDQVNDQURFXCIgOiBcIkRFRkFVTFRcIixcbiAgICAgICAgICAgIG51bGxhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZWFnZXI6IHBvcHVsYXRlLFxuICAgICAgICAgIH07XG4gICAgICAgICAgcmV0dXJuIGFwcGx5KFxuICAgICAgICAgICAgcHJvcChQZXJzaXN0ZW5jZUtleXMuUkVMQVRJT05TKSxcbiAgICAgICAgICAgIGxpc3QoY2xhenopLFxuICAgICAgICAgICAgcHJvcE1ldGFkYXRhKG1hbnlUb01hbnlLZXksIG1ldGFkYXRhKSxcbiAgICAgICAgICAgIE1hbnlUb01hbnkoXG4gICAgICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoIWNsYXp6Lm5hbWUpIGNsYXp6ID0gKGNsYXp6IGFzIGFueSkoKTtcbiAgICAgICAgICAgICAgICBpZiAoIWNsYXp6W01vZGVsS2V5cy5BTkNIT1IgYXMga2V5b2YgdHlwZW9mIGNsYXp6XSlcbiAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgICAgICAgICBcIk9yaWdpbmFsIE1vZGVsIG5vdCBmb3VuZCBpbiBjb25zdHJ1Y3RvclwiXG4gICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHJldHVybiBjbGF6eltNb2RlbEtleXMuQU5DSE9SIGFzIGtleW9mIHR5cGVvZiBjbGF6el07XG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIChtb2RlbDogYW55KSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKCFjbGF6ei5uYW1lKSBjbGF6eiA9IChjbGF6eiBhcyBhbnkpKCk7XG4gICAgICAgICAgICAgICAgY29uc3QgcGsgPSBmaW5kUHJpbWFyeUtleShuZXcgKGNsYXp6IGFzIENvbnN0cnVjdG9yPGFueT4pKCkpLmlkO1xuICAgICAgICAgICAgICAgIHJldHVybiBtb2RlbFtwa107XG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIG9ybU1ldGFcbiAgICAgICAgICAgICksXG4gICAgICAgICAgICBKb2luVGFibGUoKVxuICAgICAgICAgICk7XG4gICAgICAgIH0sXG4gICAgICB9KVxuICAgICAgLmFwcGx5KCk7XG4gIH1cbn1cbiIsImltcG9ydCB7IFR5cGVPUk1BZGFwdGVyIH0gZnJvbSBcIi4vVHlwZU9STUFkYXB0ZXJcIjtcblxuVHlwZU9STUFkYXB0ZXIuZGVjb3JhdGlvbigpO1xuXG5leHBvcnQgKiBmcm9tIFwiLi9pbmRleGVzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9xdWVyeVwiO1xuZXhwb3J0ICogZnJvbSBcIi4vc2VxdWVuY2VzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9UeXBlT1JNQWRhcHRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9lcnJvcnNcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1R5cGVPUk1EaXNwYXRjaFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vVHlwZU9STVJlcG9zaXRvcnlcIjtcbmV4cG9ydCAqIGZyb20gXCIuL3R5cGVzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi91dGlsc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBUeXBlT1JNIGludGVncmF0aW9uIGZvciBEZWNhZi50cy5cbiAqIEBzdW1tYXJ5IFByb3ZpZGVzIHRoZSBUeXBlT1JNLWJhY2tlZCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgRGVjYWYudHMgZGF0YSBhY2Nlc3MgYWJzdHJhY3Rpb25zLCBpbmNsdWRpbmcgdGhlIGFkYXB0ZXIsIHJlcG9zaXRvcnksIHN0YXRlbWVudCBidWlsZGVyLCBwYWdpbmF0aW9uIHV0aWxpdGllcywgaW5kZXggaGVscGVycywgYW5kIHR5cGUgZGVmaW5pdGlvbnMuIEtleSBleHBvcnRzIGluY2x1ZGUge0BsaW5rIFR5cGVPUk1BZGFwdGVyfSwge0BsaW5rIFR5cGVPUk1SZXBvc2l0b3J5fSwge0BsaW5rIFR5cGVPUk1TdGF0ZW1lbnR9LCB7QGxpbmsgVHlwZU9STVBhZ2luYXRvcn0sIGFuZCBpbmRleCBnZW5lcmF0aW9uIHV0aWxpdGllcy5cbiAqIEBtb2R1bGUgZm9yLXR5cGVvcm1cbiAqL1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBTdG9yZXMgdGhlIGN1cnJlbnQgcGFja2FnZSB2ZXJzaW9uLlxuICogQHN1bW1hcnkgVGhlIHZlcnNpb24gc3RyaW5nIG9mIHRoZSBmb3ItdHlwZW9ybSBwYWNrYWdlLlxuICogQGNvbnN0IFZFUlNJT05cbiAqIEBtZW1iZXJPZiBtb2R1bGU6Zm9yLXR5cGVvcm1cbiAqL1xuZXhwb3J0IGNvbnN0IFZFUlNJT04gPSBcIiMjVkVSU0lPTiMjXCI7XG4iXSwibmFtZXMiOlsiQmFzZUVycm9yIiwiU1FMT3BlcmF0b3IiLCJQYWdpbmF0b3IiLCJNb2RlbEtleXMiLCJQYWdpbmdFcnJvciIsImZpbmRQcmltYXJ5S2V5IiwiUXVlcnlFcnJvciIsIlN0YXRlbWVudCIsIlJlcG9zaXRvcnkiLCJPcmRlckRpcmVjdGlvbiIsIkludGVybmFsRXJyb3IiLCJHcm91cE9wZXJhdG9yIiwiT3BlcmF0b3IiLCJTZXF1ZW5jZSIsIk5vdEZvdW5kRXJyb3IiLCJEZWZhdWx0U2VwYXJhdG9yIiwiUGVyc2lzdGVuY2VLZXlzIiwiVHlwZU9STVJlcG9zaXRvcnkiLCJDb250ZXh0IiwiT3BlcmF0aW9uS2V5cyIsImVuZm9yY2VEQkRlY29yYXRvcnMiLCJWYWxpZGF0aW9uRXJyb3IiLCJfX2RlY29yYXRlIiwidXNlcyIsIk1vZGVsIiwiRXZlbnRTdWJzY3JpYmVyIiwiRGlzcGF0Y2giLCJnZXRNZXRhZGF0YUFyZ3NTdG9yYWdlIiwiQ29sdW1uVHlwZVVuZGVmaW5lZEVycm9yIiwiT2JqZWN0VXRpbHMiLCJQcmltYXJ5Q29sdW1uQ2Fubm90QmVOdWxsYWJsZUVycm9yIiwiQWRhcHRlciIsIkRhdGFTb3VyY2UiLCJSZWZsZWN0aW9uIiwiVmFsaWRhdGlvbktleXMiLCJEQktleXMiLCJJbiIsIkNvbmZsaWN0RXJyb3IiLCJDb25uZWN0aW9uRXJyb3IiLCJMb2dnaW5nIiwiREVGQVVMVF9FUlJPUl9NRVNTQUdFUyIsIkRlY29yYXRpb24iLCJyZXF1aXJlZCIsInJlYWRvbmx5IiwicHJvcE1ldGFkYXRhIiwiYXBwbHkiLCJWYWxpZGF0aW9uIiwidHlwZSIsIlZlcnNpb25Db2x1bW4iLCJVcGRhdGVWYWxpZGF0aW9uS2V5cyIsImRhdGUiLCJEQl9ERUZBVUxUX0VSUk9SX01FU1NBR0VTIiwiQ2FzY2FkZSIsInByb3AiLCJPbmVUb09uZSIsIkpvaW5Db2x1bW4iLCJsaXN0IiwiT25lVG9NYW55IiwiTWFueVRvT25lIiwiTWFueVRvTWFueSIsIkpvaW5UYWJsZSIsImZpbmFsIl0sIm1hcHBpbmdzIjoiOzs7Ozs7SUFBQTs7Ozs7SUFLRztBQUNJLFVBQU0sa0JBQWtCLEdBQzdCO0FBRUssVUFBTSxjQUFjLEdBQUc7SUFFOUI7Ozs7Ozs7Ozs7Ozs7SUFhRztJQUNIOzs7Ozs7SUFNRztBQUNJLFVBQU0sV0FBVyxHQUFHO0lBQ3pCLElBQUEsU0FBUyxFQUFFLEdBQUc7SUFDZCxJQUFBLEVBQUUsRUFB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
|