@thinkhive/sdk 3.1.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,250 @@
1
+ /**
2
+ * ThinkHive SDK v3.0 - Evaluation Health API
3
+ *
4
+ * API for eval saturation monitoring, regression detection, and health reports
5
+ */
6
+ export type SaturationType = 'ceiling' | 'floor' | 'healthy';
7
+ export type HealthStatus = 'healthy' | 'warning' | 'critical';
8
+ export type RegressionSeverity = 'minor' | 'moderate' | 'severe';
9
+ export interface EvalHealthSnapshot {
10
+ id: string;
11
+ companyId: string;
12
+ agentId: string;
13
+ criterionId?: string;
14
+ snapshotDate: string;
15
+ passRate?: string;
16
+ evalCount?: number;
17
+ meanScore?: string;
18
+ saturationType?: SaturationType;
19
+ daysAtSaturation?: number;
20
+ trendDirection?: string;
21
+ trendStrength?: string;
22
+ healthStatus?: HealthStatus;
23
+ healthScore?: string;
24
+ createdAt: string;
25
+ }
26
+ export interface EvalRegression {
27
+ id: string;
28
+ companyId: string;
29
+ agentId: string;
30
+ criterionId?: string;
31
+ severity: RegressionSeverity;
32
+ baselinePassRate: string;
33
+ currentPassRate: string;
34
+ delta: string;
35
+ deltaPercent?: string;
36
+ baselinePeriodStart: string;
37
+ baselinePeriodEnd: string;
38
+ currentPeriodStart: string;
39
+ currentPeriodEnd: string;
40
+ baselineEvalCount?: number;
41
+ currentEvalCount?: number;
42
+ suspectedCauses?: unknown[];
43
+ isSignificant?: boolean;
44
+ isResolved: boolean;
45
+ isAcknowledged: boolean;
46
+ resolvedAt?: string;
47
+ resolvedBy?: string;
48
+ resolutionType?: string;
49
+ resolutionNotes?: string;
50
+ acknowledgedAt?: string;
51
+ acknowledgedBy?: string;
52
+ detectedAt: string;
53
+ createdAt: string;
54
+ }
55
+ export interface HealthReport {
56
+ agentId: string;
57
+ generatedAt: string;
58
+ overallHealth: HealthStatus;
59
+ overallScore: number;
60
+ passRate: number;
61
+ evalCount: number;
62
+ saturationStatus: {
63
+ type: SaturationType;
64
+ daysAtSaturation: number;
65
+ recommendation: string;
66
+ };
67
+ regressionCount: number;
68
+ activeRegressions: EvalRegression[];
69
+ trend: {
70
+ direction: 'improving' | 'stable' | 'declining';
71
+ strength: number;
72
+ description: string;
73
+ };
74
+ recommendations: string[];
75
+ }
76
+ export interface CreateSnapshotOptions {
77
+ agentId: string;
78
+ criterionId?: string;
79
+ snapshotDate: string;
80
+ passRate?: string;
81
+ evalCount?: number;
82
+ meanScore?: string;
83
+ saturationType?: SaturationType;
84
+ daysAtSaturation?: number;
85
+ trendDirection?: string;
86
+ trendStrength?: string;
87
+ healthStatus?: HealthStatus;
88
+ healthScore?: string;
89
+ }
90
+ export interface CreateRegressionOptions {
91
+ agentId: string;
92
+ criterionId?: string;
93
+ severity: RegressionSeverity;
94
+ baselinePassRate: string;
95
+ currentPassRate: string;
96
+ delta: string;
97
+ deltaPercent?: string;
98
+ baselinePeriodStart: string;
99
+ baselinePeriodEnd: string;
100
+ currentPeriodStart: string;
101
+ currentPeriodEnd: string;
102
+ baselineEvalCount?: number;
103
+ currentEvalCount?: number;
104
+ suspectedCauses?: unknown[];
105
+ isSignificant?: boolean;
106
+ detectedAt?: string;
107
+ }
108
+ export interface ResolveRegressionOptions {
109
+ resolutionType: string;
110
+ notes?: string;
111
+ }
112
+ export interface GetSnapshotsOptions {
113
+ agentId: string;
114
+ criterionId?: string;
115
+ startDate?: string;
116
+ endDate?: string;
117
+ }
118
+ /**
119
+ * Evaluation Health API client for monitoring eval quality and detecting regressions
120
+ */
121
+ export declare const evalHealth: {
122
+ /**
123
+ * Get comprehensive health report for an agent
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * const report = await evalHealth.getReport('agent_123');
128
+ * console.log(`Overall health: ${report.overallHealth}`);
129
+ * console.log(`Active regressions: ${report.regressionCount}`);
130
+ * ```
131
+ */
132
+ getReport(agentId: string): Promise<HealthReport>;
133
+ /**
134
+ * Get historical health snapshots
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * const snapshots = await evalHealth.getSnapshots({
139
+ * agentId: 'agent_123',
140
+ * startDate: '2024-01-01T00:00:00Z',
141
+ * endDate: '2024-01-31T23:59:59Z',
142
+ * });
143
+ * ```
144
+ */
145
+ getSnapshots(options: GetSnapshotsOptions): Promise<EvalHealthSnapshot[]>;
146
+ /**
147
+ * Get latest health snapshot
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * const snapshot = await evalHealth.getLatestSnapshot('agent_123');
152
+ * ```
153
+ */
154
+ getLatestSnapshot(agentId: string, criterionId?: string): Promise<EvalHealthSnapshot | null>;
155
+ /**
156
+ * Record a health snapshot
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * const snapshot = await evalHealth.recordSnapshot({
161
+ * agentId: 'agent_123',
162
+ * snapshotDate: new Date().toISOString(),
163
+ * passRate: '0.85',
164
+ * evalCount: 150,
165
+ * healthStatus: 'healthy',
166
+ * });
167
+ * ```
168
+ */
169
+ recordSnapshot(options: CreateSnapshotOptions): Promise<EvalHealthSnapshot>;
170
+ /**
171
+ * Get unresolved regressions for an agent
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * const regressions = await evalHealth.getRegressions('agent_123');
176
+ * for (const regression of regressions) {
177
+ * console.log(`${regression.severity}: ${regression.delta}% drop`);
178
+ * }
179
+ * ```
180
+ */
181
+ getRegressions(agentId: string): Promise<EvalRegression[]>;
182
+ /**
183
+ * Record a new regression
184
+ *
185
+ * @example
186
+ * ```typescript
187
+ * const regression = await evalHealth.recordRegression({
188
+ * agentId: 'agent_123',
189
+ * severity: 'moderate',
190
+ * baselinePassRate: '0.92',
191
+ * currentPassRate: '0.78',
192
+ * delta: '-0.14',
193
+ * baselinePeriodStart: '2024-01-01T00:00:00Z',
194
+ * baselinePeriodEnd: '2024-01-15T23:59:59Z',
195
+ * currentPeriodStart: '2024-01-16T00:00:00Z',
196
+ * currentPeriodEnd: '2024-01-31T23:59:59Z',
197
+ * });
198
+ * ```
199
+ */
200
+ recordRegression(options: CreateRegressionOptions): Promise<EvalRegression>;
201
+ /**
202
+ * Resolve a regression
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * await evalHealth.resolveRegression('regression_123', {
207
+ * resolutionType: 'fixed',
208
+ * notes: 'Updated prompt template to address quality issues',
209
+ * });
210
+ * ```
211
+ */
212
+ resolveRegression(regressionId: string, options: ResolveRegressionOptions): Promise<void>;
213
+ /**
214
+ * Acknowledge a regression
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * await evalHealth.acknowledgeRegression('regression_123');
219
+ * ```
220
+ */
221
+ acknowledgeRegression(regressionId: string): Promise<void>;
222
+ };
223
+ /**
224
+ * Check if health status indicates an issue
225
+ *
226
+ * @param status - Health status to check
227
+ * @returns Whether the status indicates a problem
228
+ */
229
+ export declare function hasHealthIssue(status: HealthStatus): boolean;
230
+ /**
231
+ * Get severity level as numeric value for sorting
232
+ *
233
+ * @param severity - Regression severity
234
+ * @returns Numeric severity (1-3, higher is worse)
235
+ */
236
+ export declare function getSeverityLevel(severity: RegressionSeverity): number;
237
+ /**
238
+ * Check if evaluation is saturated
239
+ *
240
+ * @param snapshot - Health snapshot to check
241
+ * @returns Whether evaluation is at ceiling or floor
242
+ */
243
+ export declare function isSaturated(snapshot: EvalHealthSnapshot): boolean;
244
+ /**
245
+ * Get recommendation for saturation type
246
+ *
247
+ * @param saturationType - Type of saturation
248
+ * @returns Recommendation string
249
+ */
250
+ export declare function getSaturationRecommendation(saturationType: SaturationType): string;
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ /**
3
+ * ThinkHive SDK v3.0 - Evaluation Health API
4
+ *
5
+ * API for eval saturation monitoring, regression detection, and health reports
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.evalHealth = void 0;
9
+ exports.hasHealthIssue = hasHealthIssue;
10
+ exports.getSeverityLevel = getSeverityLevel;
11
+ exports.isSaturated = isSaturated;
12
+ exports.getSaturationRecommendation = getSaturationRecommendation;
13
+ const client_1 = require("../core/client");
14
+ // ============================================================================
15
+ // EVAL HEALTH API CLIENT
16
+ // ============================================================================
17
+ /**
18
+ * Evaluation Health API client for monitoring eval quality and detecting regressions
19
+ */
20
+ exports.evalHealth = {
21
+ /**
22
+ * Get comprehensive health report for an agent
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const report = await evalHealth.getReport('agent_123');
27
+ * console.log(`Overall health: ${report.overallHealth}`);
28
+ * console.log(`Active regressions: ${report.regressionCount}`);
29
+ * ```
30
+ */
31
+ async getReport(agentId) {
32
+ return (0, client_1.apiRequestWithData)(`/eval-health/report?agentId=${agentId}`, { apiVersion: 'v1' });
33
+ },
34
+ // ---------------------------------------------------------------------------
35
+ // SNAPSHOTS
36
+ // ---------------------------------------------------------------------------
37
+ /**
38
+ * Get historical health snapshots
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const snapshots = await evalHealth.getSnapshots({
43
+ * agentId: 'agent_123',
44
+ * startDate: '2024-01-01T00:00:00Z',
45
+ * endDate: '2024-01-31T23:59:59Z',
46
+ * });
47
+ * ```
48
+ */
49
+ async getSnapshots(options) {
50
+ const params = new URLSearchParams();
51
+ params.set('agentId', options.agentId);
52
+ if (options.criterionId)
53
+ params.set('criterionId', options.criterionId);
54
+ if (options.startDate)
55
+ params.set('startDate', options.startDate);
56
+ if (options.endDate)
57
+ params.set('endDate', options.endDate);
58
+ return (0, client_1.apiRequestWithData)(`/eval-health/snapshots?${params.toString()}`, { apiVersion: 'v1' });
59
+ },
60
+ /**
61
+ * Get latest health snapshot
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * const snapshot = await evalHealth.getLatestSnapshot('agent_123');
66
+ * ```
67
+ */
68
+ async getLatestSnapshot(agentId, criterionId) {
69
+ const params = new URLSearchParams();
70
+ params.set('agentId', agentId);
71
+ if (criterionId)
72
+ params.set('criterionId', criterionId);
73
+ return (0, client_1.apiRequestWithData)(`/eval-health/snapshots/latest?${params.toString()}`, { apiVersion: 'v1' });
74
+ },
75
+ /**
76
+ * Record a health snapshot
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const snapshot = await evalHealth.recordSnapshot({
81
+ * agentId: 'agent_123',
82
+ * snapshotDate: new Date().toISOString(),
83
+ * passRate: '0.85',
84
+ * evalCount: 150,
85
+ * healthStatus: 'healthy',
86
+ * });
87
+ * ```
88
+ */
89
+ async recordSnapshot(options) {
90
+ return (0, client_1.apiRequestWithData)('/eval-health/snapshots', {
91
+ method: 'POST',
92
+ body: options,
93
+ apiVersion: 'v1',
94
+ });
95
+ },
96
+ // ---------------------------------------------------------------------------
97
+ // REGRESSIONS
98
+ // ---------------------------------------------------------------------------
99
+ /**
100
+ * Get unresolved regressions for an agent
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * const regressions = await evalHealth.getRegressions('agent_123');
105
+ * for (const regression of regressions) {
106
+ * console.log(`${regression.severity}: ${regression.delta}% drop`);
107
+ * }
108
+ * ```
109
+ */
110
+ async getRegressions(agentId) {
111
+ return (0, client_1.apiRequestWithData)(`/eval-health/regressions?agentId=${agentId}`, { apiVersion: 'v1' });
112
+ },
113
+ /**
114
+ * Record a new regression
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * const regression = await evalHealth.recordRegression({
119
+ * agentId: 'agent_123',
120
+ * severity: 'moderate',
121
+ * baselinePassRate: '0.92',
122
+ * currentPassRate: '0.78',
123
+ * delta: '-0.14',
124
+ * baselinePeriodStart: '2024-01-01T00:00:00Z',
125
+ * baselinePeriodEnd: '2024-01-15T23:59:59Z',
126
+ * currentPeriodStart: '2024-01-16T00:00:00Z',
127
+ * currentPeriodEnd: '2024-01-31T23:59:59Z',
128
+ * });
129
+ * ```
130
+ */
131
+ async recordRegression(options) {
132
+ return (0, client_1.apiRequestWithData)('/eval-health/regressions', {
133
+ method: 'POST',
134
+ body: options,
135
+ apiVersion: 'v1',
136
+ });
137
+ },
138
+ /**
139
+ * Resolve a regression
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * await evalHealth.resolveRegression('regression_123', {
144
+ * resolutionType: 'fixed',
145
+ * notes: 'Updated prompt template to address quality issues',
146
+ * });
147
+ * ```
148
+ */
149
+ async resolveRegression(regressionId, options) {
150
+ await (0, client_1.apiRequest)(`/eval-health/regressions/${regressionId}/resolve`, {
151
+ method: 'POST',
152
+ body: options,
153
+ apiVersion: 'v1',
154
+ });
155
+ },
156
+ /**
157
+ * Acknowledge a regression
158
+ *
159
+ * @example
160
+ * ```typescript
161
+ * await evalHealth.acknowledgeRegression('regression_123');
162
+ * ```
163
+ */
164
+ async acknowledgeRegression(regressionId) {
165
+ await (0, client_1.apiRequest)(`/eval-health/regressions/${regressionId}/acknowledge`, {
166
+ method: 'POST',
167
+ apiVersion: 'v1',
168
+ });
169
+ },
170
+ };
171
+ // ============================================================================
172
+ // HELPER FUNCTIONS
173
+ // ============================================================================
174
+ /**
175
+ * Check if health status indicates an issue
176
+ *
177
+ * @param status - Health status to check
178
+ * @returns Whether the status indicates a problem
179
+ */
180
+ function hasHealthIssue(status) {
181
+ return status === 'warning' || status === 'critical';
182
+ }
183
+ /**
184
+ * Get severity level as numeric value for sorting
185
+ *
186
+ * @param severity - Regression severity
187
+ * @returns Numeric severity (1-3, higher is worse)
188
+ */
189
+ function getSeverityLevel(severity) {
190
+ switch (severity) {
191
+ case 'minor': return 1;
192
+ case 'moderate': return 2;
193
+ case 'severe': return 3;
194
+ default: return 0;
195
+ }
196
+ }
197
+ /**
198
+ * Check if evaluation is saturated
199
+ *
200
+ * @param snapshot - Health snapshot to check
201
+ * @returns Whether evaluation is at ceiling or floor
202
+ */
203
+ function isSaturated(snapshot) {
204
+ return snapshot.saturationType === 'ceiling' || snapshot.saturationType === 'floor';
205
+ }
206
+ /**
207
+ * Get recommendation for saturation type
208
+ *
209
+ * @param saturationType - Type of saturation
210
+ * @returns Recommendation string
211
+ */
212
+ function getSaturationRecommendation(saturationType) {
213
+ switch (saturationType) {
214
+ case 'ceiling':
215
+ return 'Evaluation criteria may be too lenient. Consider adding stricter checks or more challenging test cases.';
216
+ case 'floor':
217
+ return 'Evaluation criteria may be too strict. Consider relaxing thresholds or reviewing criteria for accuracy.';
218
+ case 'healthy':
219
+ return 'Evaluation is operating within healthy parameters.';
220
+ default:
221
+ return 'Unable to determine saturation status.';
222
+ }
223
+ }
224
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZhbC1oZWFsdGguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL2V2YWwtaGVhbHRoLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7OztHQUlHOzs7QUE0VEgsd0NBRUM7QUFRRCw0Q0FPQztBQVFELGtDQUVDO0FBUUQsa0VBV0M7QUF4V0QsMkNBQWdFO0FBOEhoRSwrRUFBK0U7QUFDL0UseUJBQXlCO0FBQ3pCLCtFQUErRTtBQUUvRTs7R0FFRztBQUNVLFFBQUEsVUFBVSxHQUFHO0lBQ3hCOzs7Ozs7Ozs7T0FTRztJQUNILEtBQUssQ0FBQyxTQUFTLENBQUMsT0FBZTtRQUM3QixPQUFPLElBQUEsMkJBQWtCLEVBQ3ZCLCtCQUErQixPQUFPLEVBQUUsRUFDeEMsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLENBQ3JCLENBQUM7SUFDSixDQUFDO0lBRUQsOEVBQThFO0lBQzlFLFlBQVk7SUFDWiw4RUFBOEU7SUFFOUU7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxLQUFLLENBQUMsWUFBWSxDQUFDLE9BQTRCO1FBQzdDLE1BQU0sTUFBTSxHQUFHLElBQUksZUFBZSxFQUFFLENBQUM7UUFDckMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3ZDLElBQUksT0FBTyxDQUFDLFdBQVc7WUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDeEUsSUFBSSxPQUFPLENBQUMsU0FBUztZQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNsRSxJQUFJLE9BQU8sQ0FBQyxPQUFPO1lBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRTVELE9BQU8sSUFBQSwyQkFBa0IsRUFDdkIsMEJBQTBCLE1BQU0s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LFFBQVEsQ0FBQyxjQUFjLEtBQUssT0FBTyxDQUFDO0FBQ3RGLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILFNBQWdCLDJCQUEyQixDQUFDLGNBQThCO0lBQ3hFLFFBQVEsY0FBYyxFQUFFLENBQUM7UUFDdkIsS0FBSyxTQUFTO1lBQ1osT0FBTyx5R0FBeUcsQ0FBQztRQUNuSCxLQUFLLE9BQU87WUFDVixPQUFPLHlHQUF5RyxDQUFDO1FBQ25ILEtBQUssU0FBUztZQUNaLE9BQU8sb0RBQW9ELENBQUM7UUFDOUQ7WUFDRSxPQUFPLHdDQUF3QyxDQUFDO0lBQ3BELENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGlua0hpdmUgU0RLIHYzLjAgLSBFdmFsdWF0aW9uIEhlYWx0aCBBUElcbiAqXG4gKiBBUEkgZm9yIGV2YWwgc2F0dXJhdGlvbiBtb25pdG9yaW5nLCByZWdyZXNzaW9uIGRldGVjdGlvbiwgYW5kIGhlYWx0aCByZXBvcnRzXG4gKi9cblxuaW1wb3J0IHsgYXBpUmVxdWVzdCwgYXBpUmVxdWVzdFdpdGhEYXRhIH0gZnJvbSAnLi4vY29yZS9jbGllbnQnO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBUWVBFU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgdHlwZSBTYXR1cmF0aW9uVHlwZSA9ICdjZWlsaW5nJyB8ICdmbG9vcicgfCAnaGVhbHRoeSc7XG5leHBvcnQgdHlwZSBIZWFsdGhTdGF0dXMgPSAnaGVhbHRoeScgfCAnd2FybmluZycgfCAnY3JpdGljYWwnO1xuZXhwb3J0IHR5cGUgUmVncmVzc2lvblNldmVyaXR5ID0gJ21pbm9yJyB8ICdtb2RlcmF0ZScgfCAnc2V2ZXJlJztcblxuZXhwb3J0IGludGVyZmFjZSBFdmFsSGVhbHRoU25hcHNob3Qge1xuICBpZDogc3RyaW5nO1xuICBjb21wYW55SWQ6IHN0cmluZztcbiAgYWdlbnRJZDogc3RyaW5nO1xuICBjcml0ZXJpb25JZD86IHN0cmluZztcbiAgc25hcHNob3REYXRlOiBzdHJpbmc7XG4gIHBhc3NSYXRlPzogc3RyaW5nO1xuICBldmFsQ291bnQ/OiBudW1iZXI7XG4gIG1lYW5TY29yZT86IHN0cmluZztcbiAgc2F0dXJhdGlvblR5cGU/OiBTYXR1cmF0aW9uVHlwZTtcbiAgZGF5c0F0U2F0dXJhdGlvbj86IG51bWJlcjtcbiAgdHJlbmREaXJlY3Rpb24/OiBzdHJpbmc7XG4gIHRyZW5kU3RyZW5ndGg/OiBzdHJpbmc7XG4gIGhlYWx0aFN0YXR1cz86IEhlYWx0aFN0YXR1cztcbiAgaGVhbHRoU2NvcmU/OiBzdHJpbmc7XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEV2YWxSZWdyZXNzaW9uIHtcbiAgaWQ6IHN0cmluZztcbiAgY29tcGFueUlkOiBzdHJpbmc7XG4gIGFnZW50SWQ6IHN0cmluZztcbiAgY3JpdGVyaW9uSWQ/OiBzdHJpbmc7XG4gIHNldmVyaXR5OiBSZWdyZXNzaW9uU2V2ZXJpdHk7XG4gIGJhc2VsaW5lUGFzc1JhdGU6IHN0cmluZztcbiAgY3VycmVudFBhc3NSYXRlOiBzdHJpbmc7XG4gIGRlbHRhOiBzdHJpbmc7XG4gIGRlbHRhUGVyY2VudD86IHN0cmluZztcbiAgYmFzZWxpbmVQZXJpb2RTdGFydDogc3RyaW5nO1xuICBiYXNlbGluZVBlcmlvZEVuZDogc3RyaW5nO1xuICBjdXJyZW50UGVyaW9kU3RhcnQ6IHN0cmluZztcbiAgY3VycmVudFBlcmlvZEVuZDogc3RyaW5nO1xuICBiYXNlbGluZUV2YWxDb3VudD86IG51bWJlcjtcbiAgY3VycmVudEV2YWxDb3VudD86IG51bWJlcjtcbiAgc3VzcGVjdGVkQ2F1c2VzPzogdW5rbm93bltdO1xuICBpc1NpZ25pZmljYW50PzogYm9vbGVhbjtcbiAgaXNSZXNvbHZlZDogYm9vbGVhbjtcbiAgaXNBY2tub3dsZWRnZWQ6IGJvb2xlYW47XG4gIHJlc29sdmVkQXQ/OiBzdHJpbmc7XG4gIHJlc29sdmVkQnk/OiBzdHJpbmc7XG4gIHJlc29sdXRpb25UeXBlPzogc3RyaW5nO1xuICByZXNvbHV0aW9uTm90ZXM/OiBzdHJpbmc7XG4gIGFja25vd2xlZGdlZEF0Pzogc3RyaW5nO1xuICBhY2tub3dsZWRnZWRCeT86IHN0cmluZztcbiAgZGV0ZWN0ZWRBdDogc3RyaW5nO1xuICBjcmVhdGVkQXQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBIZWFsdGhSZXBvcnQge1xuICBhZ2VudElkOiBzdHJpbmc7XG4gIGdlbmVyYXRlZEF0OiBzdHJpbmc7XG4gIG92ZXJhbGxIZWFsdGg6IEhlYWx0aFN0YXR1cztcbiAgb3ZlcmFsbFNjb3JlOiBudW1iZXI7XG4gIHBhc3NSYXRlOiBudW1iZXI7XG4gIGV2YWxDb3VudDogbnVtYmVyO1xuICBzYXR1cmF0aW9uU3RhdHVzOiB7XG4gICAgdHlwZTogU2F0dXJhdGlvblR5cGU7XG4gICAgZGF5c0F0U2F0dXJhdGlvbjogbnVtYmVyO1xuICAgIHJlY29tbWVuZGF0aW9uOiBzdHJpbmc7XG4gIH07XG4gIHJlZ3Jlc3Npb25Db3VudDogbnVtYmVyO1xuICBhY3RpdmVSZWdyZXNzaW9uczogRXZhbFJlZ3Jlc3Npb25bXTtcbiAgdHJlbmQ6IHtcbiAgICBkaXJlY3Rpb246ICdpbXByb3ZpbmcnIHwgJ3N0YWJsZScgfCAnZGVjbGluaW5nJztcbiAgICBzdHJlbmd0aDogbnVtYmVyO1xuICAgIGRlc2NyaXB0aW9uOiBzdHJpbmc7XG4gIH07XG4gIHJlY29tbWVuZGF0aW9uczogc3RyaW5nW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlU25hcHNob3RPcHRpb25zIHtcbiAgYWdlbnRJZDogc3RyaW5nO1xuICBjcml0ZXJpb25JZD86IHN0cmluZztcbiAgc25hcHNob3REYXRlOiBzdHJpbmc7XG4gIHBhc3NSYXRlPzogc3RyaW5nO1xuICBldmFsQ291bnQ/OiBudW1iZXI7XG4gIG1lYW5TY29yZT86IHN0cmluZztcbiAgc2F0dXJhdGlvblR5cGU/OiBTYXR1cmF0aW9uVHlwZTtcbiAgZGF5c0F0U2F0dXJhdGlvbj86IG51bWJlcjtcbiAgdHJlbmREaXJlY3Rpb24/OiBzdHJpbmc7XG4gIHRyZW5kU3RyZW5ndGg/OiBzdHJpbmc7XG4gIGhlYWx0aFN0YXR1cz86IEhlYWx0aFN0YXR1cztcbiAgaGVhbHRoU2NvcmU/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlUmVncmVzc2lvbk9wdGlvbnMge1xuICBhZ2VudElkOiBzdHJpbmc7XG4gIGNyaXRlcmlvbklkPzogc3RyaW5nO1xuICBzZXZlcml0eTogUmVncmVzc2lvblNldmVyaXR5O1xuICBiYXNlbGluZVBhc3NSYXRlOiBzdHJpbmc7XG4gIGN1cnJlbnRQYXNzUmF0ZTogc3RyaW5nO1xuICBkZWx0YTogc3RyaW5nO1xuICBkZWx0YVBlcmNlbnQ/OiBzdHJpbmc7XG4gIGJhc2VsaW5lUGVyaW9kU3RhcnQ6IHN0cmluZztcbiAgYmFzZWxpbmVQZXJpb2RFbmQ6IHN0cmluZztcbiAgY3VycmVudFBlcmlvZFN0YXJ0OiBzdHJpbmc7XG4gIGN1cnJlbnRQZXJpb2RFbmQ6IHN0cmluZztcbiAgYmFzZWxpbmVFdmFsQ291bnQ/OiBudW1iZXI7XG4gIGN1cnJlbnRFdmFsQ291bnQ/OiBudW1iZXI7XG4gIHN1c3BlY3RlZENhdXNlcz86IHVua25vd25bXTtcbiAgaXNTaWduaWZpY2FudD86IGJvb2xlYW47XG4gIGRldGVjdGVkQXQ/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVzb2x2ZVJlZ3Jlc3Npb25PcHRpb25zIHtcbiAgcmVzb2x1dGlvblR5cGU6IHN0cmluZztcbiAgbm90ZXM/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2V0U25hcHNob3RzT3B0aW9ucyB7XG4gIGFnZW50SWQ6IHN0cmluZztcbiAgY3JpdGVyaW9uSWQ/OiBzdHJpbmc7XG4gIHN0YXJ0RGF0ZT86IHN0cmluZztcbiAgZW5kRGF0ZT86IHN0cmluZztcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gRVZBTCBIRUFMVEggQVBJIENMSUVOVFxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIEV2YWx1YXRpb24gSGVhbHRoIEFQSSBjbGllbnQgZm9yIG1vbml0b3JpbmcgZXZhbCBxdWFsaXR5IGFuZCBkZXRlY3RpbmcgcmVncmVzc2lvbnNcbiAqL1xuZXhwb3J0IGNvbnN0IGV2YWxIZWFsdGggPSB7XG4gIC8qKlxuICAgKiBHZXQgY29tcHJlaGVuc2l2ZSBoZWFsdGggcmVwb3J0IGZvciBhbiBhZ2VudFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHJlcG9ydCA9IGF3YWl0IGV2YWxIZWFsdGguZ2V0UmVwb3J0KCdhZ2VudF8xMjMnKTtcbiAgICogY29uc29sZS5sb2coYE92ZXJhbGwgaGVhbHRoOiAke3JlcG9ydC5vdmVyYWxsSGVhbHRofWApO1xuICAgKiBjb25zb2xlLmxvZyhgQWN0aXZlIHJlZ3Jlc3Npb25zOiAke3JlcG9ydC5yZWdyZXNzaW9uQ291bnR9YCk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgZ2V0UmVwb3J0KGFnZW50SWQ6IHN0cmluZyk6IFByb21pc2U8SGVhbHRoUmVwb3J0PiB7XG4gICAgcmV0dXJuIGFwaVJlcXVlc3RXaXRoRGF0YTxIZWFsdGhSZXBvcnQ+KFxuICAgICAgYC9ldmFsLWhlYWx0aC9yZXBvcnQ/YWdlbnRJZD0ke2FnZW50SWR9YCxcbiAgICAgIHsgYXBpVmVyc2lvbjogJ3YxJyB9XG4gICAgKTtcbiAgfSxcblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gU05BUFNIT1RTXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKlxuICAgKiBHZXQgaGlzdG9yaWNhbCBoZWFsdGggc25hcHNob3RzXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3Qgc25hcHNob3RzID0gYXdhaXQgZXZhbEhlYWx0aC5nZXRTbmFwc2hvdHMoe1xuICAgKiAgIGFnZW50SWQ6ICdhZ2VudF8xMjMnLFxuICAgKiAgIHN0YXJ0RGF0ZTogJzIwMjQtMDEtMDFUMDA6MDA6MDBaJyxcbiAgICogICBlbmREYXRlOiAnMjAyNC0wMS0zMVQyMzo1OTo1OVonLFxuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBnZXRTbmFwc2hvdHMob3B0aW9uczogR2V0U25hcHNob3RzT3B0aW9ucyk6IFByb21pc2U8RXZhbEhlYWx0aFNuYXBzaG90W10+IHtcbiAgICBjb25zdCBwYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKCk7XG4gICAgcGFyYW1zLnNldCgnYWdlbnRJZCcsIG9wdGlvbnMuYWdlbnRJZCk7XG4gICAgaWYgKG9wdGlvbnMuY3JpdGVyaW9uSWQpIHBhcmFtcy5zZXQoJ2NyaXRlcmlvbklkJywgb3B0aW9ucy5jcml0ZXJpb25JZCk7XG4gICAgaWYgKG9wdGlvbnMuc3RhcnREYXRlKSBwYXJhbXMuc2V0KCdzdGFydERhdGUnLCBvcHRpb25zLnN0YXJ0RGF0ZSk7XG4gICAgaWYgKG9wdGlvbnMuZW5kRGF0ZSkgcGFyYW1zLnNldCgnZW5kRGF0ZScsIG9wdGlvbnMuZW5kRGF0ZSk7XG5cbiAgICByZXR1cm4gYXBpUmVxdWVzdFdpdGhEYXRhPEV2YWxIZWFsdGhTbmFwc2hvdFtdPihcbiAgICAgIGAvZXZhbC1oZWFsdGgvc25hcHNob3RzPyR7cGFyYW1zLnRvU3RyaW5nKCl9YCxcbiAgICAgIHsgYXBpVmVyc2lvbjogJ3YxJyB9XG4gICAgKTtcbiAgfSxcblxuICAvKipcbiAgICogR2V0IGxhdGVzdCBoZWFsdGggc25hcHNob3RcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IGV2YWxIZWFsdGguZ2V0TGF0ZXN0U25hcHNob3QoJ2FnZW50XzEyMycpO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGdldExhdGVzdFNuYXBzaG90KGFnZW50SWQ6IHN0cmluZywgY3JpdGVyaW9uSWQ/OiBzdHJpbmcpOiBQcm9taXNlPEV2YWxIZWFsdGhTbmFwc2hvdCB8IG51bGw+IHtcbiAgICBjb25zdCBwYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKCk7XG4gICAgcGFyYW1zLnNldCgnYWdlbnRJZCcsIGFnZW50SWQpO1xuICAgIGlmIChjcml0ZXJpb25JZCkgcGFyYW1zLnNldCgnY3JpdGVyaW9uSWQnLCBjcml0ZXJpb25JZCk7XG5cbiAgICByZXR1cm4gYXBpUmVxdWVzdFdpdGhEYXRhPEV2YWxIZWFsdGhTbmFwc2hvdCB8IG51bGw+KFxuICAgICAgYC9ldmFsLWhlYWx0aC9zbmFwc2hvdHMvbGF0ZXN0PyR7cGFyYW1zLnRvU3RyaW5nKCl9YCxcbiAgICAgIHsgYXBpVmVyc2lvbjogJ3YxJyB9XG4gICAgKTtcbiAgfSxcblxuICAvKipcbiAgICogUmVjb3JkIGEgaGVhbHRoIHNuYXBzaG90XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3Qgc25hcHNob3QgPSBhd2FpdCBldmFsSGVhbHRoLnJlY29yZFNuYXBzaG90KHtcbiAgICogICBhZ2VudElkOiAnYWdlbnRfMTIzJyxcbiAgICogICBzbmFwc2hvdERhdGU6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICogICBwYXNzUmF0ZTogJzAuODUnLFxuICAgKiAgIGV2YWxDb3VudDogMTUwLFxuICAgKiAgIGhlYWx0aFN0YXR1czogJ2hlYWx0aHknLFxuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyByZWNvcmRTbmFwc2hvdChvcHRpb25zOiBDcmVhdGVTbmFwc2hvdE9wdGlvbnMpOiBQcm9taXNlPEV2YWxIZWFsdGhTbmFwc2hvdD4ge1xuICAgIHJldHVybiBhcGlSZXF1ZXN0V2l0aERhdGE8RXZhbEhlYWx0aFNuYXBzaG90PignL2V2YWwtaGVhbHRoL3NuYXBzaG90cycsIHtcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgYm9keTogb3B0aW9ucyxcbiAgICAgIGFwaVZlcnNpb246ICd2MScsXG4gICAgfSk7XG4gIH0sXG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIFJFR1JFU1NJT05TXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKlxuICAgKiBHZXQgdW5yZXNvbHZlZCByZWdyZXNzaW9ucyBmb3IgYW4gYWdlbnRcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCByZWdyZXNzaW9ucyA9IGF3YWl0IGV2YWxIZWFsdGguZ2V0UmVncmVzc2lvbnMoJ2FnZW50XzEyMycpO1xuICAgKiBmb3IgKGNvbnN0IHJlZ3Jlc3Npb24gb2YgcmVncmVzc2lvbnMpIHtcbiAgICogICBjb25zb2xlLmxvZyhgJHtyZWdyZXNzaW9uLnNldmVyaXR5fTogJHtyZWdyZXNzaW9uLmRlbHRhfSUgZHJvcGApO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgZ2V0UmVncmVzc2lvbnMoYWdlbnRJZDogc3RyaW5nKTogUHJvbWlzZTxFdmFsUmVncmVzc2lvbltdPiB7XG4gICAgcmV0dXJuIGFwaVJlcXVlc3RXaXRoRGF0YTxFdmFsUmVncmVzc2lvbltdPihcbiAgICAgIGAvZXZhbC1oZWFsdGgvcmVncmVzc2lvbnM/YWdlbnRJZD0ke2FnZW50SWR9YCxcbiAgICAgIHsgYXBpVmVyc2lvbjogJ3YxJyB9XG4gICAgKTtcbiAgfSxcblxuICAvKipcbiAgICogUmVjb3JkIGEgbmV3IHJlZ3Jlc3Npb25cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCByZWdyZXNzaW9uID0gYXdhaXQgZXZhbEhlYWx0aC5yZWNvcmRSZWdyZXNzaW9uKHtcbiAgICogICBhZ2VudElkOiAnYWdlbnRfMTIzJyxcbiAgICogICBzZXZlcml0eTogJ21vZGVyYXRlJyxcbiAgICogICBiYXNlbGluZVBhc3NSYXRlOiAnMC45MicsXG4gICAqICAgY3VycmVudFBhc3NSYXRlOiAnMC43OCcsXG4gICAqICAgZGVsdGE6ICctMC4xNCcsXG4gICAqICAgYmFzZWxpbmVQZXJpb2RTdGFydDogJzIwMjQtMDEtMDFUMDA6MDA6MDBaJyxcbiAgICogICBiYXNlbGluZVBlcmlvZEVuZDogJzIwMjQtMDEtMTVUMjM6NTk6NTlaJyxcbiAgICogICBjdXJyZW50UGVyaW9kU3RhcnQ6ICcyMDI0LTAxLTE2VDAwOjAwOjAwWicsXG4gICAqICAgY3VycmVudFBlcmlvZEVuZDogJzIwMjQtMDEtMzFUMjM6NTk6NTlaJyxcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgcmVjb3JkUmVncmVzc2lvbihvcHRpb25zOiBDcmVhdGVSZWdyZXNzaW9uT3B0aW9ucyk6IFByb21pc2U8RXZhbFJlZ3Jlc3Npb24+IHtcbiAgICByZXR1cm4gYXBpUmVxdWVzdFdpdGhEYXRhPEV2YWxSZWdyZXNzaW9uPignL2V2YWwtaGVhbHRoL3JlZ3Jlc3Npb25zJywge1xuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBib2R5OiBvcHRpb25zLFxuICAgICAgYXBpVmVyc2lvbjogJ3YxJyxcbiAgICB9KTtcbiAgfSxcblxuICAvKipcbiAgICogUmVzb2x2ZSBhIHJlZ3Jlc3Npb25cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBhd2FpdCBldmFsSGVhbHRoLnJlc29sdmVSZWdyZXNzaW9uKCdyZWdyZXNzaW9uXzEyMycsIHtcbiAgICogICByZXNvbHV0aW9uVHlwZTogJ2ZpeGVkJyxcbiAgICogICBub3RlczogJ1VwZGF0ZWQgcHJvbXB0IHRlbXBsYXRlIHRvIGFkZHJlc3MgcXVhbGl0eSBpc3N1ZXMnLFxuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBhc3luYyByZXNvbHZlUmVncmVzc2lvbihyZWdyZXNzaW9uSWQ6IHN0cmluZywgb3B0aW9uczogUmVzb2x2ZVJlZ3Jlc3Npb25PcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgYXBpUmVxdWVzdChgL2V2YWwtaGVhbHRoL3JlZ3Jlc3Npb25zLyR7cmVncmVzc2lvbklkfS9yZXNvbHZlYCwge1xuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBib2R5OiBvcHRpb25zLFxuICAgICAgYXBpVmVyc2lvbjogJ3YxJyxcbiAgICB9KTtcbiAgfSxcblxuICAvKipcbiAgICogQWNrbm93bGVkZ2UgYSByZWdyZXNzaW9uXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogYXdhaXQgZXZhbEhlYWx0aC5hY2tub3dsZWRnZVJlZ3Jlc3Npb24oJ3JlZ3Jlc3Npb25fMTIzJyk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgYWNrbm93bGVkZ2VSZWdyZXNzaW9uKHJlZ3Jlc3Npb25JZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgYXBpUmVxdWVzdChgL2V2YWwtaGVhbHRoL3JlZ3Jlc3Npb25zLyR7cmVncmVzc2lvbklkfS9hY2tub3dsZWRnZWAsIHtcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgYXBpVmVyc2lvbjogJ3YxJyxcbiAgICB9KTtcbiAgfSxcbn07XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEhFTFBFUiBGVU5DVElPTlNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBDaGVjayBpZiBoZWFsdGggc3RhdHVzIGluZGljYXRlcyBhbiBpc3N1ZVxuICpcbiAqIEBwYXJhbSBzdGF0dXMgLSBIZWFsdGggc3RhdHVzIHRvIGNoZWNrXG4gKiBAcmV0dXJucyBXaGV0aGVyIHRoZSBzdGF0dXMgaW5kaWNhdGVzIGEgcHJvYmxlbVxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzSGVhbHRoSXNzdWUoc3RhdHVzOiBIZWFsdGhTdGF0dXMpOiBib29sZWFuIHtcbiAgcmV0dXJuIHN0YXR1cyA9PT0gJ3dhcm5pbmcnIHx8IHN0YXR1cyA9PT0gJ2NyaXRpY2FsJztcbn1cblxuLyoqXG4gKiBHZXQgc2V2ZXJpdHkgbGV2ZWwgYXMgbnVtZXJpYyB2YWx1ZSBmb3Igc29ydGluZ1xuICpcbiAqIEBwYXJhbSBzZXZlcml0eSAtIFJlZ3Jlc3Npb24gc2V2ZXJpdHlcbiAqIEByZXR1cm5zIE51bWVyaWMgc2V2ZXJpdHkgKDEtMywgaGlnaGVyIGlzIHdvcnNlKVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2V2ZXJpdHlMZXZlbChzZXZlcml0eTogUmVncmVzc2lvblNldmVyaXR5KTogbnVtYmVyIHtcbiAgc3dpdGNoIChzZXZlcml0eSkge1xuICAgIGNhc2UgJ21pbm9yJzogcmV0dXJuIDE7XG4gICAgY2FzZSAnbW9kZXJhdGUnOiByZXR1cm4gMjtcbiAgICBjYXNlICdzZXZlcmUnOiByZXR1cm4gMztcbiAgICBkZWZhdWx0OiByZXR1cm4gMDtcbiAgfVxufVxuXG4vKipcbiAqIENoZWNrIGlmIGV2YWx1YXRpb24gaXMgc2F0dXJhdGVkXG4gKlxuICogQHBhcmFtIHNuYXBzaG90IC0gSGVhbHRoIHNuYXBzaG90IHRvIGNoZWNrXG4gKiBAcmV0dXJucyBXaGV0aGVyIGV2YWx1YXRpb24gaXMgYXQgY2VpbGluZyBvciBmbG9vclxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTYXR1cmF0ZWQoc25hcHNob3Q6IEV2YWxIZWFsdGhTbmFwc2hvdCk6IGJvb2xlYW4ge1xuICByZXR1cm4gc25hcHNob3Quc2F0dXJhdGlvblR5cGUgPT09ICdjZWlsaW5nJyB8fCBzbmFwc2hvdC5zYXR1cmF0aW9uVHlwZSA9PT0gJ2Zsb29yJztcbn1cblxuLyoqXG4gKiBHZXQgcmVjb21tZW5kYXRpb24gZm9yIHNhdHVyYXRpb24gdHlwZVxuICpcbiAqIEBwYXJhbSBzYXR1cmF0aW9uVHlwZSAtIFR5cGUgb2Ygc2F0dXJhdGlvblxuICogQHJldHVybnMgUmVjb21tZW5kYXRpb24gc3RyaW5nXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTYXR1cmF0aW9uUmVjb21tZW5kYXRpb24oc2F0dXJhdGlvblR5cGU6IFNhdHVyYXRpb25UeXBlKTogc3RyaW5nIHtcbiAgc3dpdGNoIChzYXR1cmF0aW9uVHlwZSkge1xuICAgIGNhc2UgJ2NlaWxpbmcnOlxuICAgICAgcmV0dXJuICdFdmFsdWF0aW9uIGNyaXRlcmlhIG1heSBiZSB0b28gbGVuaWVudC4gQ29uc2lkZXIgYWRkaW5nIHN0cmljdGVyIGNoZWNrcyBvciBtb3JlIGNoYWxsZW5naW5nIHRlc3QgY2FzZXMuJztcbiAgICBjYXNlICdmbG9vcic6XG4gICAgICByZXR1cm4gJ0V2YWx1YXRpb24gY3JpdGVyaWEgbWF5IGJlIHRvbyBzdHJpY3QuIENvbnNpZGVyIHJlbGF4aW5nIHRocmVzaG9sZHMgb3IgcmV2aWV3aW5nIGNyaXRlcmlhIGZvciBhY2N1cmFjeS4nO1xuICAgIGNhc2UgJ2hlYWx0aHknOlxuICAgICAgcmV0dXJuICdFdmFsdWF0aW9uIGlzIG9wZXJhdGluZyB3aXRoaW4gaGVhbHRoeSBwYXJhbWV0ZXJzLic7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiAnVW5hYmxlIHRvIGRldGVybWluZSBzYXR1cmF0aW9uIHN0YXR1cy4nO1xuICB9XG59XG4iXX0=