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