@pipeline-builder/pipeline-data 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,170 @@
1
+ import { SQL } from 'drizzle-orm';
2
+ import type { AnyColumn } from 'drizzle-orm/column';
3
+ import type { PgTable } from 'drizzle-orm/pg-core';
4
+ /**
5
+ * Cast Drizzle query results to a typed array.
6
+ * Drizzle's generic return type (`PgSelectBase<...>`) doesn't narrow to our
7
+ * entity generics, so an explicit cast is needed. Centralised here so every
8
+ * call-site stays one-liner clean and the cast is documented in one place.
9
+ */
10
+ export declare function drizzleRows<T>(rows: unknown): T[];
11
+ /** Cast a Drizzle aggregate result to extract `[{ count: number }]`. */
12
+ export declare function drizzleCount(rows: unknown): [{
13
+ count: number;
14
+ }];
15
+ /**
16
+ * Base interface for entities with common fields
17
+ */
18
+ export interface BaseEntity {
19
+ id: string;
20
+ orgId: string;
21
+ isDefault: boolean;
22
+ createdAt: Date;
23
+ updatedAt: Date;
24
+ createdBy: string;
25
+ updatedBy: string;
26
+ [key: string]: unknown;
27
+ }
28
+ /**
29
+ * Pagination and sorting options
30
+ */
31
+ export interface QueryOptions {
32
+ limit?: number;
33
+ offset?: number;
34
+ sortBy?: string;
35
+ sortOrder?: 'asc' | 'desc';
36
+ /** When true, runs a separate COUNT(*) query to include exact total. Default: false. */
37
+ includeTotal?: boolean;
38
+ /** Cursor-based pagination: fetch rows after this cursor value (uses sortBy column). */
39
+ cursor?: string;
40
+ /** Sparse fieldset: column names to select. Returns all columns when omitted. */
41
+ fields?: string[];
42
+ }
43
+ /**
44
+ * Paginated result with metadata
45
+ */
46
+ export interface PaginatedResult<T> {
47
+ data: T[];
48
+ /** Total count of matching entities. Only present when includeTotal is true. */
49
+ total?: number;
50
+ limit: number;
51
+ offset: number;
52
+ hasMore: boolean;
53
+ /** Cursor pointing to the last item, for cursor-based pagination. */
54
+ nextCursor?: string;
55
+ }
56
+ /**
57
+ * Abstract CRUD service with access control and common operations.
58
+ *
59
+ * @typeParam TEntity - Entity type extending BaseEntity
60
+ * @typeParam TFilter - Filter type for query parameters
61
+ * @typeParam TInsert - Insert DTO type
62
+ * @typeParam TUpdate - Update DTO type
63
+ *
64
+ * Type assertions (`as any`, `as unknown as T`) are used throughout for Drizzle ORM compatibility.
65
+ * This is safe because: access control filters by orgId, schema validation is at the DB level,
66
+ * and each subclass is tested for type correctness.
67
+ *
68
+ * Errors are not caught here — they propagate to the route-level error handler (`withRoute`)
69
+ * which provides consistent logging with request context.
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * class PipelineService extends CrudService<Pipeline, PipelineFilter, PipelineInsert, PipelineUpdate> {
74
+ * protected get schema() { return schema.pipeline; }
75
+ * protected buildConditions(filter, orgId) { return buildPipelineConditions(filter, orgId); }
76
+ * protected getSortColumn(sortBy) { return sortColumnMap[sortBy] ?? null; }
77
+ * protected getProjectColumn() { return schema.pipeline.project; }
78
+ * protected getOrgColumn() { return schema.pipeline.organization; }
79
+ * }
80
+ * ```
81
+ */
82
+ export declare abstract class CrudService<TEntity extends BaseEntity, TFilter, TInsert, TUpdate> {
83
+ /** Drizzle schema table for this entity */
84
+ protected abstract get schema(): PgTable;
85
+ /** Build SQL conditions for filtering entities */
86
+ protected abstract buildConditions(filter: Partial<TFilter>, orgId?: string): SQL[];
87
+ /** Get the schema column for sorting by field name */
88
+ protected abstract getSortColumn(sortBy: string): AnyColumn | null;
89
+ /** Get the project column for setDefault scoping (null if entity has no project scope) */
90
+ protected abstract getProjectColumn(): AnyColumn | null;
91
+ /** Get the organization column for setDefault scoping */
92
+ protected abstract getOrgColumn(): AnyColumn;
93
+ /** Get the unique constraint columns for onConflictDoUpdate */
94
+ protected abstract get conflictTarget(): AnyColumn[];
95
+ private readonly _logger;
96
+ /** Build conditions for a single entity by ID. */
97
+ private idConditions;
98
+ /** Called after a new entity is created */
99
+ protected onAfterCreate(_entity: TEntity, _userId: string): Promise<void>;
100
+ /** Called after an entity is updated */
101
+ protected onAfterUpdate(_id: string, _entity: TEntity, _userId: string): Promise<void>;
102
+ /** Called after an entity is soft-deleted */
103
+ protected onAfterDelete(_id: string, _entity: TEntity, _userId: string): Promise<void>;
104
+ /**
105
+ * Find entities matching filter criteria
106
+ *
107
+ * @param filter - Filter criteria
108
+ * @param orgId - User's organization ID (optional — omit for anonymous/system-public-only access)
109
+ */
110
+ find(filter: Partial<TFilter>, orgId?: string): Promise<TEntity[]>;
111
+ /**
112
+ * Find entities with pagination and sorting
113
+ *
114
+ * @param filter - Filter criteria
115
+ * @param orgId - User's organization ID (optional — omit for anonymous/system-public-only access)
116
+ * @param options - Pagination and sorting options
117
+ */
118
+ findPaginated(filter: Partial<TFilter>, orgId?: string, options?: QueryOptions): Promise<PaginatedResult<TEntity>>;
119
+ /**
120
+ * Build a column selection map for sparse fieldsets.
121
+ * Falls back to full select if no matching columns found.
122
+ */
123
+ private buildFieldSelect;
124
+ /**
125
+ * Count entities matching filter criteria
126
+ *
127
+ * @param filter - Filter criteria
128
+ * @param orgId - User's organization ID (optional — omit for anonymous/system-public-only access)
129
+ */
130
+ count(filter: Partial<TFilter>, orgId?: string): Promise<number>;
131
+ /**
132
+ * Find a single entity by ID
133
+ *
134
+ * @param id - Entity ID
135
+ * @param orgId - User's organization ID (optional — omit for anonymous/system-public-only access)
136
+ */
137
+ findById(id: string, orgId?: string): Promise<TEntity | null>;
138
+ /**
139
+ * Create a new entity
140
+ */
141
+ create(data: TInsert, userId: string): Promise<TEntity>;
142
+ /**
143
+ * Update an existing entity
144
+ */
145
+ update(id: string, data: Partial<TUpdate>, orgId: string, userId: string): Promise<TEntity | null>;
146
+ /**
147
+ * Delete an entity (soft delete by setting isActive = false)
148
+ */
149
+ delete(id: string, orgId: string, userId: string): Promise<TEntity | null>;
150
+ /**
151
+ * Set an entity as the default for a project/organization scope.
152
+ * Marks all other entities as non-default, then sets the specified entity.
153
+ * Uses a transaction to ensure atomicity.
154
+ */
155
+ setDefault(project: string, org: string, id: string, userId: string): Promise<TEntity>;
156
+ /**
157
+ * Update multiple entities matching filter
158
+ */
159
+ updateMany(filter: Partial<TFilter>, data: Partial<TUpdate>, orgId: string, userId: string): Promise<TEntity[]>;
160
+ /**
161
+ * Create multiple entities in a single batch insert.
162
+ * Uses upsert (onConflictDoUpdate) — all rows are inserted in one query per chunk.
163
+ * Chunks of 100 to stay within PostgreSQL parameter limits.
164
+ */
165
+ bulkCreate(items: TInsert[], userId: string): Promise<TEntity[]>;
166
+ /**
167
+ * Soft-delete multiple entities by IDs in a single batch operation.
168
+ */
169
+ bulkDelete(ids: string[], orgId: string, userId: string): Promise<TEntity[]>;
170
+ }
@@ -0,0 +1,387 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.CrudService = void 0;
6
+ exports.drizzleRows = drizzleRows;
7
+ exports.drizzleCount = drizzleCount;
8
+ const api_core_1 = require("@pipeline-builder/api-core");
9
+ const drizzle_orm_1 = require("drizzle-orm");
10
+ const postgres_connection_1 = require("../database/postgres-connection");
11
+ /** Pagination defaults — read from env to match CoreConstants in pipeline-core. */
12
+ const DEFAULT_PAGE_LIMIT = parseInt(process.env.DEFAULT_PAGE_LIMIT || '100', 10);
13
+ const MAX_PAGE_LIMIT = parseInt(process.env.MAX_PAGE_LIMIT || '1000', 10);
14
+ /**
15
+ * Cast Drizzle query results to a typed array.
16
+ * Drizzle's generic return type (`PgSelectBase<...>`) doesn't narrow to our
17
+ * entity generics, so an explicit cast is needed. Centralised here so every
18
+ * call-site stays one-liner clean and the cast is documented in one place.
19
+ */
20
+ function drizzleRows(rows) {
21
+ return rows;
22
+ }
23
+ /** Cast a Drizzle aggregate result to extract `[{ count: number }]`. */
24
+ function drizzleCount(rows) {
25
+ return rows;
26
+ }
27
+ /**
28
+ * Abstract CRUD service with access control and common operations.
29
+ *
30
+ * @typeParam TEntity - Entity type extending BaseEntity
31
+ * @typeParam TFilter - Filter type for query parameters
32
+ * @typeParam TInsert - Insert DTO type
33
+ * @typeParam TUpdate - Update DTO type
34
+ *
35
+ * Type assertions (`as any`, `as unknown as T`) are used throughout for Drizzle ORM compatibility.
36
+ * This is safe because: access control filters by orgId, schema validation is at the DB level,
37
+ * and each subclass is tested for type correctness.
38
+ *
39
+ * Errors are not caught here — they propagate to the route-level error handler (`withRoute`)
40
+ * which provides consistent logging with request context.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * class PipelineService extends CrudService<Pipeline, PipelineFilter, PipelineInsert, PipelineUpdate> {
45
+ * protected get schema() { return schema.pipeline; }
46
+ * protected buildConditions(filter, orgId) { return buildPipelineConditions(filter, orgId); }
47
+ * protected getSortColumn(sortBy) { return sortColumnMap[sortBy] ?? null; }
48
+ * protected getProjectColumn() { return schema.pipeline.project; }
49
+ * protected getOrgColumn() { return schema.pipeline.organization; }
50
+ * }
51
+ * ```
52
+ */
53
+ class CrudService {
54
+ _logger = (0, api_core_1.createLogger)('CrudService');
55
+ /** Build conditions for a single entity by ID. */
56
+ idConditions(id, orgId) {
57
+ return this.buildConditions({ id }, orgId);
58
+ }
59
+ // Lifecycle hooks — override in subclasses to react to mutations
60
+ // These are fire-and-forget: errors are logged but never block the caller.
61
+ /** Called after a new entity is created */
62
+ async onAfterCreate(_entity, _userId) { }
63
+ /** Called after an entity is updated */
64
+ async onAfterUpdate(_id, _entity, _userId) { }
65
+ /** Called after an entity is soft-deleted */
66
+ async onAfterDelete(_id, _entity, _userId) { }
67
+ /**
68
+ * Find entities matching filter criteria
69
+ *
70
+ * @param filter - Filter criteria
71
+ * @param orgId - User's organization ID (optional — omit for anonymous/system-public-only access)
72
+ */
73
+ async find(filter, orgId) {
74
+ const conditions = this.buildConditions(filter, orgId);
75
+ return postgres_connection_1.db
76
+ .select()
77
+ .from(this.schema)
78
+ .where((0, drizzle_orm_1.and)(...conditions)).then(r => drizzleRows(r));
79
+ }
80
+ /**
81
+ * Find entities with pagination and sorting
82
+ *
83
+ * @param filter - Filter criteria
84
+ * @param orgId - User's organization ID (optional — omit for anonymous/system-public-only access)
85
+ * @param options - Pagination and sorting options
86
+ */
87
+ async findPaginated(filter, orgId, options = {}) {
88
+ const { limit: rawLimit = DEFAULT_PAGE_LIMIT, offset = 0, sortBy, sortOrder = 'asc', includeTotal = false, cursor, fields } = options;
89
+ const limit = Math.min(Math.max(1, rawLimit), MAX_PAGE_LIMIT);
90
+ // Cursor and offset are mutually exclusive — cursor takes precedence
91
+ const useCursor = !!(cursor && sortBy);
92
+ const conditions = this.buildConditions(filter, orgId);
93
+ // Cursor-based pagination: add WHERE clause for keyset pagination
94
+ if (useCursor) {
95
+ const sortColumn = this.getSortColumn(sortBy);
96
+ if (sortColumn) {
97
+ const op = sortOrder === 'desc'
98
+ ? (0, drizzle_orm_1.sql) `${sortColumn} < ${cursor}`
99
+ : (0, drizzle_orm_1.sql) `${sortColumn} > ${cursor}`;
100
+ conditions.push(op);
101
+ }
102
+ }
103
+ // Build SELECT — sparse fieldset when fields are specified
104
+ const selectSpec = fields ? this.buildFieldSelect(fields) : undefined;
105
+ let query = selectSpec
106
+ ? postgres_connection_1.db.select(selectSpec).from(this.schema).where((0, drizzle_orm_1.and)(...conditions))
107
+ : postgres_connection_1.db.select().from(this.schema).where((0, drizzle_orm_1.and)(...conditions));
108
+ if (sortBy) {
109
+ const sortColumn = this.getSortColumn(sortBy);
110
+ if (sortColumn) {
111
+ query = query.orderBy(sortOrder === 'desc' ? (0, drizzle_orm_1.desc)(sortColumn) : (0, drizzle_orm_1.asc)(sortColumn));
112
+ }
113
+ }
114
+ // Fetch limit+1 to detect hasMore without COUNT(*)
115
+ const effectiveOffset = useCursor ? 0 : offset;
116
+ const rows = await query
117
+ .limit(limit + 1)
118
+ .offset(effectiveOffset).then(r => drizzleRows(r));
119
+ const hasMore = rows.length > limit;
120
+ const data = hasMore ? rows.slice(0, limit) : rows;
121
+ const result = { data, limit, offset: effectiveOffset, hasMore };
122
+ // Provide next cursor from last item's sort column value
123
+ if (data.length > 0 && sortBy) {
124
+ const lastItem = data[data.length - 1];
125
+ const cursorValue = lastItem[sortBy];
126
+ if (cursorValue !== undefined) {
127
+ result.nextCursor = cursorValue instanceof Date ? cursorValue.toISOString() : String(cursorValue);
128
+ }
129
+ }
130
+ // Only run the COUNT(*) query when the caller explicitly needs the total
131
+ if (includeTotal) {
132
+ const baseConditions = this.buildConditions(filter, orgId);
133
+ const [countResult] = await postgres_connection_1.db
134
+ .select({ count: (0, drizzle_orm_1.sql) `count(*)::int` })
135
+ .from(this.schema)
136
+ .where((0, drizzle_orm_1.and)(...baseConditions)).then(r => drizzleCount(r));
137
+ result.total = countResult?.count || 0;
138
+ }
139
+ return result;
140
+ }
141
+ /**
142
+ * Build a column selection map for sparse fieldsets.
143
+ * Falls back to full select if no matching columns found.
144
+ */
145
+ buildFieldSelect(fields) {
146
+ if (fields.length === 0)
147
+ return undefined;
148
+ const columns = {};
149
+ // Always include id for entity identity
150
+ columns.id = this.schema.id;
151
+ for (const field of fields) {
152
+ if (field === 'id')
153
+ continue; // Already included
154
+ const col = this.schema[field];
155
+ if (col)
156
+ columns[field] = col;
157
+ }
158
+ // At minimum we'll have { id }, which is valid
159
+ return columns;
160
+ }
161
+ /**
162
+ * Count entities matching filter criteria
163
+ *
164
+ * @param filter - Filter criteria
165
+ * @param orgId - User's organization ID (optional — omit for anonymous/system-public-only access)
166
+ */
167
+ async count(filter, orgId) {
168
+ const conditions = this.buildConditions(filter, orgId);
169
+ const [result] = await postgres_connection_1.db
170
+ .select({ count: (0, drizzle_orm_1.sql) `count(*)::int` })
171
+ .from(this.schema)
172
+ .where((0, drizzle_orm_1.and)(...conditions)).then(r => drizzleCount(r));
173
+ return result?.count || 0;
174
+ }
175
+ /**
176
+ * Find a single entity by ID
177
+ *
178
+ * @param id - Entity ID
179
+ * @param orgId - User's organization ID (optional — omit for anonymous/system-public-only access)
180
+ */
181
+ async findById(id, orgId) {
182
+ const conditions = this.idConditions(id, orgId);
183
+ const results = await postgres_connection_1.db
184
+ .select()
185
+ .from(this.schema)
186
+ .where((0, drizzle_orm_1.and)(...conditions))
187
+ .limit(1).then(r => drizzleRows(r));
188
+ return results[0] || null;
189
+ }
190
+ // Mutation operations
191
+ /**
192
+ * Create a new entity
193
+ */
194
+ async create(data, userId) {
195
+ const [created] = await postgres_connection_1.db
196
+ .insert(this.schema)
197
+ .values({
198
+ ...data,
199
+ createdBy: userId || 'system',
200
+ updatedBy: userId || 'system',
201
+ })
202
+ .onConflictDoUpdate({
203
+ target: this.conflictTarget,
204
+ set: {
205
+ ...data,
206
+ updatedAt: new Date(),
207
+ updatedBy: userId || 'system',
208
+ },
209
+ })
210
+ .returning().then(r => drizzleRows(r));
211
+ this.onAfterCreate(created, userId).catch(err => this._logger.warn('Lifecycle hook failed', { error: String(err) }));
212
+ return created;
213
+ }
214
+ /**
215
+ * Update an existing entity
216
+ */
217
+ async update(id, data, orgId, userId) {
218
+ const conditions = this.idConditions(id, orgId);
219
+ const [updated] = await postgres_connection_1.db
220
+ .update(this.schema)
221
+ .set({
222
+ ...data,
223
+ updatedAt: new Date(),
224
+ updatedBy: userId || 'system',
225
+ })
226
+ .where((0, drizzle_orm_1.and)(...conditions))
227
+ .returning().then(r => drizzleRows(r));
228
+ if (updated) {
229
+ this.onAfterUpdate(id, updated, userId).catch(err => this._logger.warn('Lifecycle hook failed', { error: String(err) }));
230
+ }
231
+ return updated || null;
232
+ }
233
+ /**
234
+ * Delete an entity (soft delete by setting isActive = false)
235
+ */
236
+ async delete(id, orgId, userId) {
237
+ const conditions = this.idConditions(id, orgId);
238
+ const [deleted] = await postgres_connection_1.db
239
+ .update(this.schema)
240
+ .set({
241
+ isActive: false,
242
+ updatedAt: new Date(),
243
+ updatedBy: userId || 'system',
244
+ deletedAt: new Date(),
245
+ deletedBy: userId || 'system',
246
+ })
247
+ .where((0, drizzle_orm_1.and)(...conditions))
248
+ .returning().then(r => drizzleRows(r));
249
+ if (deleted) {
250
+ this.onAfterDelete(id, deleted, userId).catch(err => this._logger.warn('Lifecycle hook failed', { error: String(err) }));
251
+ }
252
+ return deleted || null;
253
+ }
254
+ /**
255
+ * Set an entity as the default for a project/organization scope.
256
+ * Marks all other entities as non-default, then sets the specified entity.
257
+ * Uses a transaction to ensure atomicity.
258
+ */
259
+ async setDefault(project, org, id, userId) {
260
+ return postgres_connection_1.db.transaction(async (tx) => {
261
+ const orgColumn = this.getOrgColumn();
262
+ const projectColumn = this.getProjectColumn();
263
+ // Build scoping conditions for clearing defaults
264
+ const scopeConditions = [
265
+ (0, drizzle_orm_1.eq)(orgColumn, org),
266
+ (0, drizzle_orm_1.eq)(this.schema.isDefault, true),
267
+ ];
268
+ if (projectColumn) {
269
+ scopeConditions.push((0, drizzle_orm_1.eq)(projectColumn, project));
270
+ }
271
+ // Lock existing defaults with FOR UPDATE to prevent concurrent setDefault races
272
+ await tx.execute((0, drizzle_orm_1.sql) `SELECT id FROM ${this.schema}
273
+ WHERE ${orgColumn} = ${org}
274
+ AND ${this.schema.isDefault} = true
275
+ ${projectColumn ? (0, drizzle_orm_1.sql) `AND ${projectColumn} = ${project}` : (0, drizzle_orm_1.sql) ``}
276
+ FOR UPDATE`);
277
+ // Mark all entities in scope as non-default
278
+ await tx
279
+ .update(this.schema)
280
+ .set({
281
+ isDefault: false,
282
+ updatedAt: new Date(),
283
+ updatedBy: userId || 'system',
284
+ })
285
+ .where((0, drizzle_orm_1.and)(...scopeConditions));
286
+ // Set the specified entity as default
287
+ const [updated] = await tx
288
+ .update(this.schema)
289
+ .set({
290
+ isDefault: true,
291
+ updatedAt: new Date(),
292
+ updatedBy: userId || 'system',
293
+ })
294
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(this.schema.id, id), (0, drizzle_orm_1.eq)(orgColumn, org)))
295
+ .returning().then(r => drizzleRows(r));
296
+ if (!updated) {
297
+ throw new api_core_1.NotFoundError(`Entity with id ${id} not found`);
298
+ }
299
+ return updated;
300
+ });
301
+ }
302
+ /**
303
+ * Update multiple entities matching filter
304
+ */
305
+ async updateMany(filter, data, orgId, userId) {
306
+ const conditions = this.buildConditions(filter, orgId);
307
+ return postgres_connection_1.db
308
+ .update(this.schema)
309
+ .set({
310
+ ...data,
311
+ updatedAt: new Date(),
312
+ updatedBy: userId || 'system',
313
+ })
314
+ .where((0, drizzle_orm_1.and)(...conditions))
315
+ .returning().then(r => drizzleRows(r));
316
+ }
317
+ /**
318
+ * Create multiple entities in a single batch insert.
319
+ * Uses upsert (onConflictDoUpdate) — all rows are inserted in one query per chunk.
320
+ * Chunks of 100 to stay within PostgreSQL parameter limits.
321
+ */
322
+ async bulkCreate(items, userId) {
323
+ if (items.length === 0)
324
+ return [];
325
+ const CHUNK_SIZE = 100;
326
+ const now = new Date();
327
+ const user = userId || 'system';
328
+ const results = await postgres_connection_1.db.transaction(async (tx) => {
329
+ const allCreated = [];
330
+ for (let i = 0; i < items.length; i += CHUNK_SIZE) {
331
+ const chunk = items.slice(i, i + CHUNK_SIZE);
332
+ const values = chunk.map(data => ({
333
+ ...data,
334
+ createdBy: user,
335
+ updatedBy: user,
336
+ }));
337
+ const created = await tx
338
+ .insert(this.schema)
339
+ .values(values)
340
+ .onConflictDoUpdate({
341
+ target: this.conflictTarget,
342
+ set: {
343
+ updatedAt: now,
344
+ updatedBy: user,
345
+ },
346
+ })
347
+ .returning().then(r => drizzleRows(r));
348
+ allCreated.push(...created);
349
+ }
350
+ return allCreated;
351
+ });
352
+ for (const entity of results) {
353
+ this.onAfterCreate(entity, userId).catch(err => this._logger.warn('Lifecycle hook failed', { error: String(err) }));
354
+ }
355
+ return results;
356
+ }
357
+ /**
358
+ * Soft-delete multiple entities by IDs in a single batch operation.
359
+ */
360
+ async bulkDelete(ids, orgId, userId) {
361
+ if (ids.length === 0)
362
+ return [];
363
+ const now = new Date();
364
+ const user = userId || 'system';
365
+ const conditions = [
366
+ (0, drizzle_orm_1.inArray)(this.schema.id, ids),
367
+ ...this.buildConditions({}, orgId),
368
+ ];
369
+ const deleted = await postgres_connection_1.db
370
+ .update(this.schema)
371
+ .set({
372
+ isActive: false,
373
+ updatedAt: now,
374
+ updatedBy: user,
375
+ deletedAt: now,
376
+ deletedBy: user,
377
+ })
378
+ .where((0, drizzle_orm_1.and)(...conditions))
379
+ .returning().then(r => drizzleRows(r));
380
+ for (const entity of deleted) {
381
+ this.onAfterDelete(entity.id, entity, userId).catch(err => this._logger.warn('Lifecycle hook failed', { error: String(err) }));
382
+ }
383
+ return deleted;
384
+ }
385
+ }
386
+ exports.CrudService = CrudService;
387
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3J1ZC1zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9jcnVkLXNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7OztBQWtCdEMsa0NBRUM7QUFHRCxvQ0FFQztBQXZCRCx5REFBeUU7QUFDekUsNkNBQW9FO0FBR3BFLHlFQUFxRDtBQUVyRCxtRkFBbUY7QUFDbkYsTUFBTSxrQkFBa0IsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsSUFBSSxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDakYsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxJQUFJLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztBQUUxRTs7Ozs7R0FLRztBQUNILFNBQWdCLFdBQVcsQ0FBSSxJQUFhO0lBQzFDLE9BQU8sSUFBVyxDQUFDO0FBQ3JCLENBQUM7QUFFRCx3RUFBd0U7QUFDeEUsU0FBZ0IsWUFBWSxDQUFDLElBQWE7SUFDeEMsT0FBTyxJQUEyQixDQUFDO0FBQ3JDLENBQUM7QUE4Q0Q7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Qkc7QUFDSCxNQUFzQixXQUFXO0lBd0JkLE9BQU8sR0FBRyxJQUFBLHVCQUFZLEVBQUMsYUFBYSxDQUFDLENBQUM7SUFFdkQsa0RBQWtEO0lBQzFDLFlBQVksQ0FBQyxFQUFVLEVBQUUsS0FBYztRQUM3QyxPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsRUFBRSxFQUFFLEVBQWlDLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUVELGlFQUFpRTtJQUNqRSwyRUFBMkU7SUFFM0UsMkNBQTJDO0lBQ2pDLEtBQUssQ0FBQyxhQUFhLENBQUMsT0FBZ0IsRUFBRSxPQUFlLElBQWtCLENBQUM7SUFFbEYsd0NBQXdDO0lBQzlCLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FB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QixFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNqSSxDQUFDO1FBRUQsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztDQUNGO0FBNWJELGtDQTRiQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBOb3RGb3VuZEVycm9yLCBjcmVhdGVMb2dnZXIgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgeyBTUUwsIGVxLCBhbmQsIGFzYywgZGVzYywgc3FsLCBpbkFycmF5IH0gZnJvbSAnZHJpenpsZS1vcm0nO1xuaW1wb3J0IHR5cGUgeyBBbnlDb2x1bW4gfSBmcm9tICdkcml6emxlLW9ybS9jb2x1bW4nO1xuaW1wb3J0IHR5cGUgeyBQZ1RhYmxlIH0gZnJvbSAnZHJpenpsZS1vcm0vcGctY29yZSc7XG5pbXBvcnQgeyBkYiB9IGZyb20gJy4uL2RhdGFiYXNlL3Bvc3RncmVzLWNvbm5lY3Rpb24nO1xuXG4vKiogUGFnaW5hdGlvbiBkZWZhdWx0cyDigJQgcmVhZCBmcm9tIGVudiB0byBtYXRjaCBDb3JlQ29uc3RhbnRzIGluIHBpcGVsaW5lLWNvcmUuICovXG5jb25zdCBERUZBVUxUX1BBR0VfTElNSVQgPSBwYXJzZUludChwcm9jZXNzLmVudi5ERUZBVUxUX1BBR0VfTElNSVQgfHwgJzEwMCcsIDEwKTtcbmNvbnN0IE1BWF9QQUdFX0xJTUlUID0gcGFyc2VJbnQocHJvY2Vzcy5lbnYuTUFYX1BBR0VfTElNSVQgfHwgJzEwMDAnLCAxMCk7XG5cbi8qKlxuICogQ2FzdCBEcml6emxlIHF1ZXJ5IHJlc3VsdHMgdG8gYSB0eXBlZCBhcnJheS5cbiAqIERyaXp6bGUncyBnZW5lcmljIHJldHVybiB0eXBlIChgUGdTZWxlY3RCYXNlPC4uLj5gKSBkb2Vzbid0IG5hcnJvdyB0byBvdXJcbiAqIGVudGl0eSBnZW5lcmljcywgc28gYW4gZXhwbGljaXQgY2FzdCBpcyBuZWVkZWQuIENlbnRyYWxpc2VkIGhlcmUgc28gZXZlcnlcbiAqIGNhbGwtc2l0ZSBzdGF5cyBvbmUtbGluZXIgY2xlYW4gYW5kIHRoZSBjYXN0IGlzIGRvY3VtZW50ZWQgaW4gb25lIHBsYWNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZHJpenpsZVJvd3M8VD4ocm93czogdW5rbm93bik6IFRbXSB7XG4gIHJldHVybiByb3dzIGFzIFRbXTtcbn1cblxuLyoqIENhc3QgYSBEcml6emxlIGFnZ3JlZ2F0ZSByZXN1bHQgdG8gZXh0cmFjdCBgW3sgY291bnQ6IG51bWJlciB9XWAuICovXG5leHBvcnQgZnVuY3Rpb24gZHJpenpsZUNvdW50KHJvd3M6IHVua25vd24pOiBbeyBjb3VudDogbnVtYmVyIH1dIHtcbiAgcmV0dXJuIHJvd3MgYXMgW3sgY291bnQ6IG51bWJlciB9XTtcbn1cblxuLyoqXG4gKiBCYXNlIGludGVyZmFjZSBmb3IgZW50aXRpZXMgd2l0aCBjb21tb24gZmllbGRzXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQmFzZUVudGl0eSB7XG4gIGlkOiBzdHJpbmc7XG4gIG9yZ0lkOiBzdHJpbmc7XG4gIGlzRGVmYXVsdDogYm9vbGVhbjtcbiAgY3JlYXRlZEF0OiBEYXRlO1xuICB1cGRhdGVkQXQ6IERhdGU7XG4gIGNyZWF0ZWRCeTogc3RyaW5nO1xuICB1cGRhdGVkQnk6IHN0cmluZztcbiAgW2tleTogc3RyaW5nXTogdW5rbm93bjtcbn1cblxuLyoqXG4gKiBQYWdpbmF0aW9uIGFuZCBzb3J0aW5nIG9wdGlvbnNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBRdWVyeU9wdGlvbnMge1xuICBsaW1pdD86IG51bWJlcjtcbiAgb2Zmc2V0PzogbnVtYmVyO1xuICBzb3J0Qnk/OiBzdHJpbmc7XG4gIHNvcnRPcmRlcj86ICdhc2MnIHwgJ2Rlc2MnO1xuICAvKiogV2hlbiB0cnVlLCBydW5zIGEgc2VwYXJhdGUgQ09VTlQoKikgcXVlcnkgdG8gaW5jbHVkZSBleGFjdCB0b3RhbC4gRGVmYXVsdDogZmFsc2UuICovXG4gIGluY2x1ZGVUb3RhbD86IGJvb2xlYW47XG4gIC8qKiBDdXJzb3ItYmFzZWQgcGFnaW5hdGlvbjogZmV0Y2ggcm93cyBhZnRlciB0aGlzIGN1cnNvciB2YWx1ZSAodXNlcyBzb3J0QnkgY29sdW1uKS4gKi9cbiAgY3Vyc29yPzogc3RyaW5nO1xuICAvKiogU3BhcnNlIGZpZWxkc2V0OiBjb2x1bW4gbmFtZXMgdG8gc2VsZWN0LiBSZXR1cm5zIGFsbCBjb2x1bW5zIHdoZW4gb21pdHRlZC4gKi9cbiAgZmllbGRzPzogc3RyaW5nW107XG59XG5cbi8qKlxuICogUGFnaW5hdGVkIHJlc3VsdCB3aXRoIG1ldGFkYXRhXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGFnaW5hdGVkUmVzdWx0PFQ+IHtcbiAgZGF0YTogVFtdO1xuICAvKiogVG90YWwgY291bnQgb2YgbWF0Y2hpbmcgZW50aXRpZXMuIE9ubHkgcHJlc2VudCB3aGVuIGluY2x1ZGVUb3RhbCBpcyB0cnVlLiAqL1xuICB0b3RhbD86IG51bWJlcjtcbiAgbGltaXQ6IG51bWJlcjtcbiAgb2Zmc2V0OiBudW1iZXI7XG4gIGhhc01vcmU6IGJvb2xlYW47XG4gIC8qKiBDdXJzb3IgcG9pbnRpbmcgdG8gdGhlIGxhc3QgaXRlbSwgZm9yIGN1cnNvci1iYXNlZCBwYWdpbmF0aW9uLiAqL1xuICBuZXh0Q3Vyc29yPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEFic3RyYWN0IENSVUQgc2VydmljZSB3aXRoIGFjY2VzcyBjb250cm9sIGFuZCBjb21tb24gb3BlcmF0aW9ucy5cbiAqXG4gKiBAdHlwZVBhcmFtIFRFbnRpdHkgLSBFbnRpdHkgdHlwZSBleHRlbmRpbmcgQmFzZUVudGl0eVxuICogQHR5cGVQYXJhbSBURmlsdGVyIC0gRmlsdGVyIHR5cGUgZm9yIHF1ZXJ5IHBhcmFtZXRlcnNcbiAqIEB0eXBlUGFyYW0gVEluc2VydCAtIEluc2VydCBEVE8gdHlwZVxuICogQHR5cGVQYXJhbSBUVXBkYXRlIC0gVXBkYXRlIERUTyB0eXBlXG4gKlxuICogVHlwZSBhc3NlcnRpb25zIChgYXMgYW55YCwgYGFzIHVua25vd24gYXMgVGApIGFyZSB1c2VkIHRocm91Z2hvdXQgZm9yIERyaXp6bGUgT1JNIGNvbXBhdGliaWxpdHkuXG4gKiBUaGlzIGlzIHNhZmUgYmVjYXVzZTogYWNjZXNzIGNvbnRyb2wgZmlsdGVycyBieSBvcmdJZCwgc2NoZW1hIHZhbGlkYXRpb24gaXMgYXQgdGhlIERCIGxldmVsLFxuICogYW5kIGVhY2ggc3ViY2xhc3MgaXMgdGVzdGVkIGZvciB0eXBlIGNvcnJlY3RuZXNzLlxuICpcbiAqIEVycm9ycyBhcmUgbm90IGNhdWdodCBoZXJlIOKAlCB0aGV5IHByb3BhZ2F0ZSB0byB0aGUgcm91dGUtbGV2ZWwgZXJyb3IgaGFuZGxlciAoYHdpdGhSb3V0ZWApXG4gKiB3aGljaCBwcm92aWRlcyBjb25zaXN0ZW50IGxvZ2dpbmcgd2l0aCByZXF1ZXN0IGNvbnRleHQuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNsYXNzIFBpcGVsaW5lU2VydmljZSBleHRlbmRzIENydWRTZXJ2aWNlPFBpcGVsaW5lLCBQaXBlbGluZUZpbHRlciwgUGlwZWxpbmVJbnNlcnQsIFBpcGVsaW5lVXBkYXRlPiB7XG4gKiAgIHByb3RlY3RlZCBnZXQgc2NoZW1hKCkgeyByZXR1cm4gc2NoZW1hLnBpcGVsaW5lOyB9XG4gKiAgIHByb3RlY3RlZCBidWlsZENvbmRpdGlvbnMoZmlsdGVyLCBvcmdJZCkgeyByZXR1cm4gYnVpbGRQaXBlbGluZUNvbmRpdGlvbnMoZmlsdGVyLCBvcmdJZCk7IH1cbiAqICAgcHJvdGVjdGVkIGdldFNvcnRDb2x1bW4oc29ydEJ5KSB7IHJldHVybiBzb3J0Q29sdW1uTWFwW3NvcnRCeV0gPz8gbnVsbDsgfVxuICogICBwcm90ZWN0ZWQgZ2V0UHJvamVjdENvbHVtbigpIHsgcmV0dXJuIHNjaGVtYS5waXBlbGluZS5wcm9qZWN0OyB9XG4gKiAgIHByb3RlY3RlZCBnZXRPcmdDb2x1bW4oKSB7IHJldHVybiBzY2hlbWEucGlwZWxpbmUub3JnYW5pemF0aW9uOyB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIENydWRTZXJ2aWNlPFxuICBURW50aXR5IGV4dGVuZHMgQmFzZUVudGl0eSxcbiAgVEZpbHRlcixcbiAgVEluc2VydCxcbiAgVFVwZGF0ZSxcbj4ge1xuICAvKiogRHJpenpsZSBzY2hlbWEgdGFibGUgZm9yIHRoaXMgZW50aXR5ICovXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBnZXQgc2NoZW1hKCk6IFBnVGFibGU7XG5cbiAgLyoqIEJ1aWxkIFNRTCBjb25kaXRpb25zIGZvciBmaWx0ZXJpbmcgZW50aXRpZXMgKi9cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGJ1aWxkQ29uZGl0aW9ucyhmaWx0ZXI6IFBhcnRpYWw8VEZpbHRlcj4sIG9yZ0lkPzogc3RyaW5nKTogU1FMW107XG5cbiAgLyoqIEdldCB0aGUgc2NoZW1hIGNvbHVtbiBmb3Igc29ydGluZyBieSBmaWVsZCBuYW1lICovXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBnZXRTb3J0Q29sdW1uKHNvcnRCeTogc3RyaW5nKTogQW55Q29sdW1uIHwgbnVsbDtcblxuICAvKiogR2V0IHRoZSBwcm9qZWN0IGNvbHVtbiBmb3Igc2V0RGVmYXVsdCBzY29waW5nIChudWxsIGlmIGVudGl0eSBoYXMgbm8gcHJvamVjdCBzY29wZSkgKi9cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGdldFByb2plY3RDb2x1bW4oKTogQW55Q29sdW1uIHwgbnVsbDtcblxuICAvKiogR2V0IHRoZSBvcmdhbml6YXRpb24gY29sdW1uIGZvciBzZXREZWZhdWx0IHNjb3BpbmcgKi9cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGdldE9yZ0NvbHVtbigpOiBBbnlDb2x1bW47XG5cbiAgLyoqIEdldCB0aGUgdW5pcXVlIGNvbnN0cmFpbnQgY29sdW1ucyBmb3Igb25Db25mbGljdERvVXBkYXRlICovXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBnZXQgY29uZmxpY3RUYXJnZXQoKTogQW55Q29sdW1uW107XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdDcnVkU2VydmljZScpO1xuXG4gIC8qKiBCdWlsZCBjb25kaXRpb25zIGZvciBhIHNpbmdsZSBlbnRpdHkgYnkgSUQuICovXG4gIHByaXZhdGUgaWRDb25kaXRpb25zKGlkOiBzdHJpbmcsIG9yZ0lkPzogc3RyaW5nKTogU1FMW10ge1xuICAgIHJldHVybiB0aGlzLmJ1aWxkQ29uZGl0aW9ucyh7IGlkIH0gYXMgdW5rbm93biBhcyBQYXJ0aWFsPFRGaWx0ZXI+LCBvcmdJZCk7XG4gIH1cblxuICAvLyBMaWZlY3ljbGUgaG9va3Mg4oCUIG92ZXJyaWRlIGluIHN1YmNsYXNzZXMgdG8gcmVhY3QgdG8gbXV0YXRpb25zXG4gIC8vIFRoZXNlIGFyZSBmaXJlLWFuZC1mb3JnZXQ6IGVycm9ycyBhcmUgbG9nZ2VkIGJ1dCBuZXZlciBibG9jayB0aGUgY2FsbGVyLlxuXG4gIC8qKiBDYWxsZWQgYWZ0ZXIgYSBuZXcgZW50aXR5IGlzIGNyZWF0ZWQgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIG9uQWZ0ZXJDcmVhdGUoX2VudGl0eTogVEVudGl0eSwgX3VzZXJJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7fVxuXG4gIC8qKiBDYWxsZWQgYWZ0ZXIgYW4gZW50aXR5IGlzIHVwZGF0ZWQgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIG9uQWZ0ZXJVcGRhdGUoX2lkOiBzdHJpbmcsIF9lbnRpdHk6IFRFbnRpdHksIF91c2VySWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge31cblxuICAvKiogQ2FsbGVkIGFmdGVyIGFuIGVudGl0eSBpcyBzb2Z0LWRlbGV0ZWQgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIG9uQWZ0ZXJEZWxldGUoX2lkOiBzdHJpbmcsIF9lbnRpdHk6IFRFbnRpdHksIF91c2VySWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge31cblxuICAvKipcbiAgICogRmluZCBlbnRpdGllcyBtYXRjaGluZyBmaWx0ZXIgY3JpdGVyaWFcbiAgICpcbiAgICogQHBhcmFtIGZpbHRlciAtIEZpbHRlciBjcml0ZXJpYVxuICAgKiBAcGFyYW0gb3JnSWQgLSBVc2VyJ3Mgb3JnYW5pemF0aW9uIElEIChvcHRpb25hbCDigJQgb21pdCBmb3IgYW5vbnltb3VzL3N5c3RlbS1wdWJsaWMtb25seSBhY2Nlc3MpXG4gICAqL1xuICBhc3luYyBmaW5kKGZpbHRlcjogUGFydGlhbDxURmlsdGVyPiwgb3JnSWQ/OiBzdHJpbmcpOiBQcm9taXNlPFRFbnRpdHlbXT4ge1xuICAgIGNvbnN0IGNvbmRpdGlvbnMgPSB0aGlzLmJ1aWxkQ29uZGl0aW9ucyhmaWx0ZXIsIG9yZ0lkKTtcblxuICAgIHJldHVybiBkYlxuICAgICAgLnNlbGVjdCgpXG4gICAgICAuZnJvbSh0aGlzLnNjaGVtYSlcbiAgICAgIC53aGVyZShhbmQoLi4uY29uZGl0aW9ucykpLnRoZW4ociA9PiBkcml6emxlUm93czxURW50aXR5PihyKSk7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBlbnRpdGllcyB3aXRoIHBhZ2luYXRpb24gYW5kIHNvcnRpbmdcbiAgICpcbiAgICogQHBhcmFtIGZpbHRlciAtIEZpbHRlciBjcml0ZXJpYVxuICAgKiBAcGFyYW0gb3JnSWQgLSBVc2VyJ3Mgb3JnYW5pemF0aW9uIElEIChvcHRpb25hbCDigJQgb21pdCBmb3IgYW5vbnltb3VzL3N5c3RlbS1wdWJsaWMtb25seSBhY2Nlc3MpXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gUGFnaW5hdGlvbiBhbmQgc29ydGluZyBvcHRpb25zXG4gICAqL1xuICBhc3luYyBmaW5kUGFnaW5hdGVkKFxuICAgIGZpbHRlcjogUGFydGlhbDxURmlsdGVyPixcbiAgICBvcmdJZD86IHN0cmluZyxcbiAgICBvcHRpb25zOiBRdWVyeU9wdGlvbnMgPSB7fSxcbiAgKTogUHJvbWlzZTxQYWdpbmF0ZWRSZXN1bHQ8VEVudGl0eT4+IHtcbiAgICBjb25zdCB7IGxpbWl0OiByYXdMaW1pdCA9IERFRkFVTFRfUEFHRV9MSU1JVCwgb2Zmc2V0ID0gMCwgc29ydEJ5LCBzb3J0T3JkZXIgPSAnYXNjJywgaW5jbHVkZVRvdGFsID0gZmFsc2UsIGN1cnNvciwgZmllbGRzIH0gPSBvcHRpb25zO1xuICAgIGNvbnN0IGxpbWl0ID0gTWF0aC5taW4oTWF0aC5tYXgoMSwgcmF3TGltaXQpLCBNQVhfUEFHRV9MSU1JVCk7XG5cbiAgICAvLyBDdXJzb3IgYW5kIG9mZnNldCBhcmUgbXV0dWFsbHkgZXhjbHVzaXZlIOKAlCBjdXJzb3IgdGFrZXMgcHJlY2VkZW5jZVxuICAgIGNvbnN0IHVzZUN1cnNvciA9ICEhKGN1cnNvciAmJiBzb3J0QnkpO1xuXG4gICAgY29uc3QgY29uZGl0aW9ucyA9IHRoaXMuYnVpbGRDb25kaXRpb25zKGZpbHRlciwgb3JnSWQpO1xuXG4gICAgLy8gQ3Vyc29yLWJhc2VkIHBhZ2luYXRpb246IGFkZCBXSEVSRSBjbGF1c2UgZm9yIGtleXNldCBwYWdpbmF0aW9uXG4gICAgaWYgKHVzZUN1cnNvcikge1xuICAgICAgY29uc3Qgc29ydENvbHVtbiA9IHRoaXMuZ2V0U29ydENvbHVtbihzb3J0QnkpO1xuICAgICAgaWYgKHNvcnRDb2x1bW4pIHtcbiAgICAgICAgY29uc3Qgb3AgPSBzb3J0T3JkZXIgPT09ICdkZXNjJ1xuICAgICAgICAgID8gc3FsYCR7c29ydENvbHVtbn0gPCAke2N1cnNvcn1gXG4gICAgICAgICAgOiBzcWxgJHtzb3J0Q29sdW1ufSA+ICR7Y3Vyc29yfWA7XG4gICAgICAgIGNvbmRpdGlvbnMucHVzaChvcCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQnVpbGQgU0VMRUNUIOKAlCBzcGFyc2UgZmllbGRzZXQgd2hlbiBmaWVsZHMgYXJlIHNwZWNpZmllZFxuICAgIGNvbnN0IHNlbGVjdFNwZWMgPSBmaWVsZHMgPyB0aGlzLmJ1aWxkRmllbGRTZWxlY3QoZmllbGRzKSA6IHVuZGVmaW5lZDtcbiAgICBsZXQgcXVlcnkgPSBzZWxlY3RTcGVjXG4gICAgICA/IGRiLnNlbGVjdChzZWxlY3RTcGVjIGFzIGFueSkuZnJvbSh0aGlzLnNjaGVtYSkud2hlcmUoYW5kKC4uLmNvbmRpdGlvbnMpKVxuICAgICAgOiBkYi5zZWxlY3QoKS5mcm9tKHRoaXMuc2NoZW1hKS53aGVyZShhbmQoLi4uY29uZGl0aW9ucykpO1xuXG4gICAgaWYgKHNvcnRCeSkge1xuICAgICAgY29uc3Qgc29ydENvbHVtbiA9IHRoaXMuZ2V0U29ydENvbHVtbihzb3J0QnkpO1xuICAgICAgaWYgKHNvcnRDb2x1bW4pIHtcbiAgICAgICAgcXVlcnkgPSBxdWVyeS5vcmRlckJ5KHNvcnRPcmRlciA9PT0gJ2Rlc2MnID8gZGVzYyhzb3J0Q29sdW1uKSA6IGFzYyhzb3J0Q29sdW1uKSkgYXMgYW55O1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEZldGNoIGxpbWl0KzEgdG8gZGV0ZWN0IGhhc01vcmUgd2l0aG91dCBDT1VOVCgqKVxuICAgIGNvbnN0IGVmZmVjdGl2ZU9mZnNldCA9IHVzZUN1cnNvciA/IDAgOiBvZmZzZXQ7XG4gICAgY29uc3Qgcm93cyA9IGF3YWl0IHF1ZXJ5XG4gICAgICAubGltaXQobGltaXQgKyAxKVxuICAgICAgLm9mZnNldChlZmZlY3RpdmVPZmZzZXQpLnRoZW4ociA9PiBkcml6emxlUm93czxURW50aXR5PihyKSk7XG5cbiAgICBjb25zdCBoYXNNb3JlID0gcm93cy5sZW5ndGggPiBsaW1pdDtcbiAgICBjb25zdCBkYXRhID0gaGFzTW9yZSA/IHJvd3Muc2xpY2UoMCwgbGltaXQpIDogcm93cztcblxuICAgIGNvbnN0IHJlc3VsdDogUGFnaW5hdGVkUmVzdWx0PFRFbnRpdHk+ID0geyBkYXRhLCBsaW1pdCwgb2Zmc2V0OiBlZmZlY3RpdmVPZmZzZXQsIGhhc01vcmUgfTtcblxuICAgIC8vIFByb3ZpZGUgbmV4dCBjdXJzb3IgZnJvbSBsYXN0IGl0ZW0ncyBzb3J0IGNvbHVtbiB2YWx1ZVxuICAgIGlmIChkYXRhLmxlbmd0aCA+IDAgJiYgc29ydEJ5KSB7XG4gICAgICBjb25zdCBsYXN0SXRlbSA9IGRhdGFbZGF0YS5sZW5ndGggLSAxXSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAgIGNvbnN0IGN1cnNvclZhbHVlID0gbGFzdEl0ZW1bc29ydEJ5XTtcbiAgICAgIGlmIChjdXJzb3JWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJlc3VsdC5uZXh0Q3Vyc29yID0gY3Vyc29yVmFsdWUgaW5zdGFuY2VvZiBEYXRlID8gY3Vyc29yVmFsdWUudG9JU09TdHJpbmcoKSA6IFN0cmluZyhjdXJzb3JWYWx1ZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gT25seSBydW4gdGhlIENPVU5UKCopIHF1ZXJ5IHdoZW4gdGhlIGNhbGxlciBleHBsaWNpdGx5IG5lZWRzIHRoZSB0b3RhbFxuICAgIGlmIChpbmNsdWRlVG90YWwpIHtcbiAgICAgIGNvbnN0IGJhc2VDb25kaXRpb25zID0gdGhpcy5idWlsZENvbmRpdGlvbnMoZmlsdGVyLCBvcmdJZCk7XG4gICAgICBjb25zdCBbY291bnRSZXN1bHRdID0gYXdhaXQgZGJcbiAgICAgICAgLnNlbGVjdCh7IGNvdW50OiBzcWw8bnVtYmVyPmBjb3VudCgqKTo6aW50YCB9KVxuICAgICAgICAuZnJvbSh0aGlzLnNjaGVtYSlcbiAgICAgICAgLndoZXJlKGFuZCguLi5iYXNlQ29uZGl0aW9ucykpLnRoZW4ociA9PiBkcml6emxlQ291bnQocikpO1xuICAgICAgcmVzdWx0LnRvdGFsID0gY291bnRSZXN1bHQ/LmNvdW50IHx8IDA7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZCBhIGNvbHVtbiBzZWxlY3Rpb24gbWFwIGZvciBzcGFyc2UgZmllbGRzZXRzLlxuICAgKiBGYWxscyBiYWNrIHRvIGZ1bGwgc2VsZWN0IGlmIG5vIG1hdGNoaW5nIGNvbHVtbnMgZm91bmQuXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkRmllbGRTZWxlY3QoZmllbGRzOiBzdHJpbmdbXSk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoZmllbGRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IGNvbHVtbnM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gICAgLy8gQWx3YXlzIGluY2x1ZGUgaWQgZm9yIGVudGl0eSBpZGVudGl0eVxuICAgIGNvbHVtbnMuaWQgPSAodGhpcy5zY2hlbWEgYXMgYW55KS5pZDtcblxuICAgIGZvciAoY29uc3QgZmllbGQgb2YgZmllbGRzKSB7XG4gICAgICBpZiAoZmllbGQgPT09ICdpZCcpIGNvbnRpbnVlOyAvLyBBbHJlYWR5IGluY2x1ZGVkXG4gICAgICBjb25zdCBjb2wgPSAodGhpcy5zY2hlbWEgYXMgYW55KVtmaWVsZF07XG4gICAgICBpZiAoY29sKSBjb2x1bW5zW2ZpZWxkXSA9IGNvbDtcbiAgICB9XG5cbiAgICAvLyBBdCBtaW5pbXVtIHdlJ2xsIGhhdmUgeyBpZCB9LCB3aGljaCBpcyB2YWxpZFxuICAgIHJldHVybiBjb2x1bW5zO1xuICB9XG5cbiAgLyoqXG4gICAqIENvdW50IGVudGl0aWVzIG1hdGNoaW5nIGZpbHRlciBjcml0ZXJpYVxuICAgKlxuICAgKiBAcGFyYW0gZmlsdGVyIC0gRmlsdGVyIGNyaXRlcmlhXG4gICAqIEBwYXJhbSBvcmdJZCAtIFVzZXIncyBvcmdhbml6YXRpb24gSUQgKG9wdGlvbmFsIOKAlCBvbWl0IGZvciBhbm9ueW1vdXMvc3lzdGVtLXB1YmxpYy1vbmx5IGFjY2VzcylcbiAgICovXG4gIGFzeW5jIGNvdW50KGZpbHRlcjogUGFydGlhbDxURmlsdGVyPiwgb3JnSWQ/OiBzdHJpbmcpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGNvbnN0IGNvbmRpdGlvbnMgPSB0aGlzLmJ1aWxkQ29uZGl0aW9ucyhmaWx0ZXIsIG9yZ0lkKTtcblxuICAgIGNvbnN0IFtyZXN1bHRdID0gYXdhaXQgZGJcbiAgICAgIC5zZWxlY3QoeyBjb3VudDogc3FsPG51bWJlcj5gY291bnQoKik6OmludGAgfSlcbiAgICAgIC5mcm9tKHRoaXMuc2NoZW1hKVxuICAgICAgLndoZXJlKGFuZCguLi5jb25kaXRpb25zKSkudGhlbihyID0+IGRyaXp6bGVDb3VudChyKSk7XG5cbiAgICByZXR1cm4gcmVzdWx0Py5jb3VudCB8fCAwO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmQgYSBzaW5nbGUgZW50aXR5IGJ5IElEXG4gICAqXG4gICAqIEBwYXJhbSBpZCAtIEVudGl0eSBJRFxuICAgKiBAcGFyYW0gb3JnSWQgLSBVc2VyJ3Mgb3JnYW5pemF0aW9uIElEIChvcHRpb25hbCDigJQgb21pdCBmb3IgYW5vbnltb3VzL3N5c3RlbS1wdWJsaWMtb25seSBhY2Nlc3MpXG4gICAqL1xuICBhc3luYyBmaW5kQnlJZChpZDogc3RyaW5nLCBvcmdJZD86IHN0cmluZyk6IFByb21pc2U8VEVudGl0eSB8IG51bGw+IHtcbiAgICBjb25zdCBjb25kaXRpb25zID0gdGhpcy5pZENvbmRpdGlvbnMoaWQsIG9yZ0lkKTtcblxuICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBkYlxuICAgICAgLnNlbGVjdCgpXG4gICAgICAuZnJvbSh0aGlzLnNjaGVtYSlcbiAgICAgIC53aGVyZShhbmQoLi4uY29uZGl0aW9ucykpXG4gICAgICAubGltaXQoMSkudGhlbihyID0+IGRyaXp6bGVSb3dzPFRFbnRpdHk+KHIpKTtcblxuICAgIHJldHVybiByZXN1bHRzWzBdIHx8IG51bGw7XG4gIH1cblxuICAvLyBNdXRhdGlvbiBvcGVyYXRpb25zXG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIG5ldyBlbnRpdHlcbiAgICovXG4gIGFzeW5jIGNyZWF0ZShkYXRhOiBUSW5zZXJ0LCB1c2VySWQ6IHN0cmluZyk6IFByb21pc2U8VEVudGl0eT4ge1xuICAgIGNvbnN0IFtjcmVhdGVkXSA9IGF3YWl0IGRiXG4gICAgICAuaW5zZXJ0KHRoaXMuc2NoZW1hKVxuICAgICAgLnZhbHVlcyh7XG4gICAgICAgIC4uLmRhdGEsXG4gICAgICAgIGNyZWF0ZWRCeTogdXNlcklkIHx8ICdzeXN0ZW0nLFxuICAgICAgICB1cGRhdGVkQnk6IHVzZXJJZCB8fCAnc3lzdGVtJyxcbiAgICAgIH0gYXMgYW55KVxuICAgICAgLm9uQ29uZmxpY3REb1VwZGF0ZSh7XG4gICAgICAgIHRhcmdldDogdGhpcy5jb25mbGljdFRhcmdldCBhcyBhbnksXG4gICAgICAgIHNldDoge1xuICAgICAgICAgIC4uLmRhdGEsXG4gICAgICAgICAgdXBkYXRlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgIHVwZGF0ZWRCeTogdXNlcklkIHx8ICdzeXN0ZW0nLFxuICAgICAgICB9IGFzIGFueSxcbiAgICAgIH0pXG4gICAgICAucmV0dXJuaW5nKCkudGhlbihyID0+IGRyaXp6bGVSb3dzPFRFbnRpdHk+KHIpKTtcblxuICAgIHRoaXMub25BZnRlckNyZWF0ZShjcmVhdGVkLCB1c2VySWQpLmNhdGNoKGVyciA9PiB0aGlzLl9sb2dnZXIud2FybignTGlmZWN5Y2xlIGhvb2sgZmFpbGVkJywgeyBlcnJvcjogU3RyaW5nKGVycikgfSkpO1xuXG4gICAgcmV0dXJuIGNyZWF0ZWQ7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlIGFuIGV4aXN0aW5nIGVudGl0eVxuICAgKi9cbiAgYXN5bmMgdXBkYXRlKFxuICAgIGlkOiBzdHJpbmcsXG4gICAgZGF0YTogUGFydGlhbDxUVXBkYXRlPixcbiAgICBvcmdJZDogc3RyaW5nLFxuICAgIHVzZXJJZDogc3RyaW5nLFxuICApOiBQcm9taXNlPFRFbnRpdHkgfCBudWxsPiB7XG4gICAgY29uc3QgY29uZGl0aW9ucyA9IHRoaXMuaWRDb25kaXRpb25zKGlkLCBvcmdJZCk7XG5cbiAgICBjb25zdCBbdXBkYXRlZF0gPSBhd2FpdCBkYlxuICAgICAgLnVwZGF0ZSh0aGlzLnNjaGVtYSlcbiAgICAgIC5zZXQoe1xuICAgICAgICAuLi5kYXRhLFxuICAgICAgICB1cGRhdGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgICAgIHVwZGF0ZWRCeTogdXNlcklkIHx8ICdzeXN0ZW0nLFxuICAgICAgfSBhcyBhbnkpXG4gICAgICAud2hlcmUoYW5kKC4uLmNvbmRpdGlvbnMpKVxuICAgICAgLnJldHVybmluZygpLnRoZW4ociA9PiBkcml6emxlUm93czxURW50aXR5PihyKSk7XG5cbiAgICBpZiAodXBkYXRlZCkge1xuICAgICAgdGhpcy5vbkFmdGVyVXBkYXRlKGlkLCB1cGRhdGVkLCB1c2VySWQpLmNhdGNoKGVyciA9PiB0aGlzLl9sb2dnZXIud2FybignTGlmZWN5Y2xlIGhvb2sgZmFpbGVkJywgeyBlcnJvcjogU3RyaW5nKGVycikgfSkpO1xuICAgIH1cblxuICAgIHJldHVybiB1cGRhdGVkIHx8IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlIGFuIGVudGl0eSAoc29mdCBkZWxldGUgYnkgc2V0dGluZyBpc0FjdGl2ZSA9IGZhbHNlKVxuICAgKi9cbiAgYXN5bmMgZGVsZXRlKGlkOiBzdHJpbmcsIG9yZ0lkOiBzdHJpbmcsIHVzZXJJZDogc3RyaW5nKTogUHJvbWlzZTxURW50aXR5IHwgbnVsbD4ge1xuICAgIGNvbnN0IGNvbmRpdGlvbnMgPSB0aGlzLmlkQ29uZGl0aW9ucyhpZCwgb3JnSWQpO1xuXG4gICAgY29uc3QgW2RlbGV0ZWRdID0gYXdhaXQgZGJcbiAgICAgIC51cGRhdGUodGhpcy5zY2hlbWEpXG4gICAgICAuc2V0KHtcbiAgICAgICAgaXNBY3RpdmU6IGZhbHNlLFxuICAgICAgICB1cGRhdGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgICAgIHVwZGF0ZWRCeTogdXNlcklkIHx8ICdzeXN0ZW0nLFxuICAgICAgICBkZWxldGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgICAgIGRlbGV0ZWRCeTogdXNlcklkIHx8ICdzeXN0ZW0nLFxuICAgICAgfSBhcyBhbnkpXG4gICAgICAud2hlcmUoYW5kKC4uLmNvbmRpdGlvbnMpKVxuICAgICAgLnJldHVybmluZygpLnRoZW4ociA9PiBkcml6emxlUm93czxURW50aXR5PihyKSk7XG5cbiAgICBpZiAoZGVsZXRlZCkge1xuICAgICAgdGhpcy5vbkFmdGVyRGVsZXRlKGlkLCBkZWxldGVkLCB1c2VySWQpLmNhdGNoKGVyciA9PiB0aGlzLl9sb2dnZXIud2FybignTGlmZWN5Y2xlIGhvb2sgZmFpbGVkJywgeyBlcnJvcjogU3RyaW5nKGVycikgfSkpO1xuICAgIH1cblxuICAgIHJldHVybiBkZWxldGVkIHx8IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogU2V0IGFuIGVudGl0eSBhcyB0aGUgZGVmYXVsdCBmb3IgYSBwcm9qZWN0L29yZ2FuaXphdGlvbiBzY29wZS5cbiAgICogTWFya3MgYWxsIG90aGVyIGVudGl0aWVzIGFzIG5vbi1kZWZhdWx0LCB0aGVuIHNldHMgdGhlIHNwZWNpZmllZCBlbnRpdHkuXG4gICAqIFVzZXMgYSB0cmFuc2FjdGlvbiB0byBlbnN1cmUgYXRvbWljaXR5LlxuICAgKi9cbiAgYXN5bmMgc2V0RGVmYXVsdChcbiAgICBwcm9qZWN0OiBzdHJpbmcsXG4gICAgb3JnOiBzdHJpbmcsXG4gICAgaWQ6IHN0cmluZyxcbiAgICB1c2VySWQ6IHN0cmluZyxcbiAgKTogUHJvbWlzZTxURW50aXR5PiB7XG4gICAgcmV0dXJuIGRiLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgICAgY29uc3Qgb3JnQ29sdW1uID0gdGhpcy5nZXRPcmdDb2x1bW4oKTtcbiAgICAgIGNvbnN0IHByb2plY3RDb2x1bW4gPSB0aGlzLmdldFByb2plY3RDb2x1bW4oKTtcblxuICAgICAgLy8gQnVpbGQgc2NvcGluZyBjb25kaXRpb25zIGZvciBjbGVhcmluZyBkZWZhdWx0c1xuICAgICAgY29uc3Qgc2NvcGVDb25kaXRpb25zID0gW1xuICAgICAgICBlcShvcmdDb2x1bW4sIG9yZyksXG4gICAgICAgIGVxKCh0aGlzLnNjaGVtYSBhcyBhbnkpLmlzRGVmYXVsdCwgdHJ1ZSksXG4gICAgICBdO1xuICAgICAgaWYgKHByb2plY3RDb2x1bW4pIHtcbiAgICAgICAgc2NvcGVDb25kaXRpb25zLnB1c2goZXEocHJvamVjdENvbHVtbiwgcHJvamVjdCkpO1xuICAgICAgfVxuXG4gICAgICAvLyBMb2NrIGV4aXN0aW5nIGRlZmF1bHRzIHdpdGggRk9SIFVQREFURSB0byBwcmV2ZW50IGNvbmN1cnJlbnQgc2V0RGVmYXVsdCByYWNlc1xuICAgICAgYXdhaXQgdHguZXhlY3V0ZShcbiAgICAgICAgc3FsYFNFTEVDVCBpZCBGUk9NICR7dGhpcy5zY2hlbWF9XG4gICAgICAgICAgICBXSEVSRSAke29yZ0NvbHVtbn0gPSAke29yZ31cbiAgICAgICAgICAgICAgQU5EICR7KHRoaXMuc2NoZW1hIGFzIGFueSkuaXNEZWZhdWx0fSA9IHRydWVcbiAgICAgICAgICAgICR7cHJvamVjdENvbHVtbiA/IHNxbGBBTkQgJHtwcm9qZWN0Q29sdW1ufSA9ICR7cHJvamVjdH1gIDogc3FsYGB9XG4gICAgICAgICAgICBGT1IgVVBEQVRFYCxcbiAgICAgICk7XG5cbiAgICAgIC8vIE1hcmsgYWxsIGVudGl0aWVzIGluIHNjb3BlIGFzIG5vbi1kZWZhdWx0XG4gICAgICBhd2FpdCB0eFxuICAgICAgICAudXBkYXRlKHRoaXMuc2NoZW1hKVxuICAgICAgICAuc2V0KHtcbiAgICAgICAgICBpc0RlZmF1bHQ6IGZhbHNlLFxuICAgICAgICAgIHVwZGF0ZWRBdDogbmV3IERhdGUoKSxcbiAgICAgICAgICB1cGRhdGVkQnk6IHVzZXJJZCB8fCAnc3lzdGVtJyxcbiAgICAgICAgfSBhcyBhbnkpXG4gICAgICAgIC53aGVyZShhbmQoLi4uc2NvcGVDb25kaXRpb25zKSk7XG5cbiAgICAgIC8vIFNldCB0aGUgc3BlY2lmaWVkIGVudGl0eSBhcyBkZWZhdWx0XG4gICAgICBjb25zdCBbdXBkYXRlZF0gPSBhd2FpdCB0eFxuICAgICAgICAudXBkYXRlKHRoaXMuc2NoZW1hKVxuICAgICAgICAuc2V0KHtcbiAgICAgICAgICBpc0RlZmF1bHQ6IHRydWUsXG4gICAgICAgICAgdXBkYXRlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICAgIHVwZGF0ZWRCeTogdXNlcklkIHx8ICdzeXN0ZW0nLFxuICAgICAgICB9IGFzIGFueSlcbiAgICAgICAgLndoZXJlKFxuICAgICAgICAgIGFuZChcbiAgICAgICAgICAgIGVxKCh0aGlzLnNjaGVtYSBhcyBhbnkpLmlkLCBpZCksXG4gICAgICAgICAgICBlcShvcmdDb2x1bW4sIG9yZyksXG4gICAgICAgICAgKSxcbiAgICAgICAgKVxuICAgICAgICAucmV0dXJuaW5nKCkudGhlbihyID0+IGRyaXp6bGVSb3dzPFRFbnRpdHk+KHIpKTtcblxuICAgICAgaWYgKCF1cGRhdGVkKSB7XG4gICAgICAgIHRocm93IG5ldyBOb3RGb3VuZEVycm9yKGBFbnRpdHkgd2l0aCBpZCAke2lkfSBub3QgZm91bmRgKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHVwZGF0ZWQ7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlIG11bHRpcGxlIGVudGl0aWVzIG1hdGNoaW5nIGZpbHRlclxuICAgKi9cbiAgYXN5bmMgdXBkYXRlTWFueShcbiAgICBmaWx0ZXI6IFBhcnRpYWw8VEZpbHRlcj4sXG4gICAgZGF0YTogUGFydGlhbDxUVXBkYXRlPixcbiAgICBvcmdJZDogc3RyaW5nLFxuICAgIHVzZXJJZDogc3RyaW5nLFxuICApOiBQcm9taXNlPFRFbnRpdHlbXT4ge1xuICAgIGNvbnN0IGNvbmRpdGlvbnMgPSB0aGlzLmJ1aWxkQ29uZGl0aW9ucyhmaWx0ZXIsIG9yZ0lkKTtcblxuICAgIHJldHVybiBkYlxuICAgICAgLnVwZGF0ZSh0aGlzLnNjaGVtYSlcbiAgICAgIC5zZXQoe1xuICAgICAgICAuLi5kYXRhLFxuICAgICAgICB1cGRhdGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgICAgIHVwZGF0ZWRCeTogdXNlcklkIHx8ICdzeXN0ZW0nLFxuICAgICAgfSBhcyBhbnkpXG4gICAgICAud2hlcmUoYW5kKC4uLmNvbmRpdGlvbnMpKVxuICAgICAgLnJldHVybmluZygpLnRoZW4ociA9PiBkcml6emxlUm93czxURW50aXR5PihyKSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIG11bHRpcGxlIGVudGl0aWVzIGluIGEgc2luZ2xlIGJhdGNoIGluc2VydC5cbiAgICogVXNlcyB1cHNlcnQgKG9uQ29uZmxpY3REb1VwZGF0ZSkg4oCUIGFsbCByb3dzIGFyZSBpbnNlcnRlZCBpbiBvbmUgcXVlcnkgcGVyIGNodW5rLlxuICAgKiBDaHVua3Mgb2YgMTAwIHRvIHN0YXkgd2l0aGluIFBvc3RncmVTUUwgcGFyYW1ldGVyIGxpbWl0cy5cbiAgICovXG4gIGFzeW5jIGJ1bGtDcmVhdGUoaXRlbXM6IFRJbnNlcnRbXSwgdXNlcklkOiBzdHJpbmcpOiBQcm9taXNlPFRFbnRpdHlbXT4ge1xuICAgIGlmIChpdGVtcy5sZW5ndGggPT09IDApIHJldHVybiBbXTtcblxuICAgIGNvbnN0IENIVU5LX1NJWkUgPSAxMDA7XG4gICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcbiAgICBjb25zdCB1c2VyID0gdXNlcklkIHx8ICdzeXN0ZW0nO1xuXG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IGRiLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICAgICAgY29uc3QgYWxsQ3JlYXRlZDogVEVudGl0eVtdID0gW107XG5cbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaXRlbXMubGVuZ3RoOyBpICs9IENIVU5LX1NJWkUpIHtcbiAgICAgICAgY29uc3QgY2h1bmsgPSBpdGVtcy5zbGljZShpLCBpICsgQ0hVTktfU0laRSk7XG4gICAgICAgIGNvbnN0IHZhbHVlcyA9IGNodW5rLm1hcChkYXRhID0+ICh7XG4gICAgICAgICAgLi4uZGF0YSxcbiAgICAgICAgICBjcmVhdGVkQnk6IHVzZXIsXG4gICAgICAgICAgdXBkYXRlZEJ5OiB1c2VyLFxuICAgICAgICB9IGFzIGFueSkpO1xuXG4gICAgICAgIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCB0eFxuICAgICAgICAgIC5pbnNlcnQodGhpcy5zY2hlbWEpXG4gICAgICAgICAgLnZhbHVlcyh2YWx1ZXMpXG4gICAgICAgICAgLm9uQ29uZmxpY3REb1VwZGF0ZSh7XG4gICAgICAgICAgICB0YXJnZXQ6IHRoaXMuY29uZmxpY3RUYXJnZXQgYXMgYW55LFxuICAgICAgICAgICAgc2V0OiB7XG4gICAgICAgICAgICAgIHVwZGF0ZWRBdDogbm93LFxuICAgICAgICAgICAgICB1cGRhdGVkQnk6IHVzZXIsXG4gICAgICAgICAgICB9IGFzIGFueSxcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5yZXR1cm5pbmcoKS50aGVuKHIgPT4gZHJpenpsZVJvd3M8VEVudGl0eT4ocikpO1xuXG4gICAgICAgIGFsbENyZWF0ZWQucHVzaCguLi5jcmVhdGVkKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGFsbENyZWF0ZWQ7XG4gICAgfSk7XG5cbiAgICBmb3IgKGNvbnN0IGVudGl0eSBvZiByZXN1bHRzKSB7XG4gICAgICB0aGlzLm9uQWZ0ZXJDcmVhdGUoZW50aXR5LCB1c2VySWQpLmNhdGNoKGVyciA9PiB0aGlzLl9sb2dnZXIud2FybignTGlmZWN5Y2xlIGhvb2sgZmFpbGVkJywgeyBlcnJvcjogU3RyaW5nKGVycikgfSkpO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNvZnQtZGVsZXRlIG11bHRpcGxlIGVudGl0aWVzIGJ5IElEcyBpbiBhIHNpbmdsZSBiYXRjaCBvcGVyYXRpb24uXG4gICAqL1xuICBhc3luYyBidWxrRGVsZXRlKFxuICAgIGlkczogc3RyaW5nW10sXG4gICAgb3JnSWQ6IHN0cmluZyxcbiAgICB1c2VySWQ6IHN0cmluZyxcbiAgKTogUHJvbWlzZTxURW50aXR5W10+IHtcbiAgICBpZiAoaWRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFtdO1xuXG4gICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcbiAgICBjb25zdCB1c2VyID0gdXNlcklkIHx8ICdzeXN0ZW0nO1xuICAgIGNvbnN0IGNvbmRpdGlvbnMgPSBbXG4gICAgICBpbkFycmF5KCh0aGlzLnNjaGVtYSBhcyBhbnkpLmlkLCBpZHMpLFxuICAgICAgLi4udGhpcy5idWlsZENvbmRpdGlvbnMoe30gYXMgUGFydGlhbDxURmlsdGVyPiwgb3JnSWQpLFxuICAgIF07XG5cbiAgICBjb25zdCBkZWxldGVkID0gYXdhaXQgZGJcbiAgICAgIC51cGRhdGUodGhpcy5zY2hlbWEpXG4gICAgICAuc2V0KHtcbiAgICAgICAgaXNBY3RpdmU6IGZhbHNlLFxuICAgICAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgICAgICAgdXBkYXRlZEJ5OiB1c2VyLFxuICAgICAgICBkZWxldGVkQXQ6IG5vdyxcbiAgICAgICAgZGVsZXRlZEJ5OiB1c2VyLFxuICAgICAgfSBhcyBhbnkpXG4gICAgICAud2hlcmUoYW5kKC4uLmNvbmRpdGlvbnMpKVxuICAgICAgLnJldHVybmluZygpLnRoZW4ociA9PiBkcml6emxlUm93czxURW50aXR5PihyKSk7XG5cbiAgICBmb3IgKGNvbnN0IGVudGl0eSBvZiBkZWxldGVkKSB7XG4gICAgICB0aGlzLm9uQWZ0ZXJEZWxldGUoZW50aXR5LmlkLCBlbnRpdHksIHVzZXJJZCkuY2F0Y2goZXJyID0+IHRoaXMuX2xvZ2dlci53YXJuKCdMaWZlY3ljbGUgaG9vayBmYWlsZWQnLCB7IGVycm9yOiBTdHJpbmcoZXJyKSB9KSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlbGV0ZWQ7XG4gIH1cbn1cbiJdfQ==