@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,303 @@
1
+ /**
2
+ * ThinkHive SDK v3.1 - Quality Metrics API
3
+ *
4
+ * RAG Evaluation & Hallucination Detection for AI quality assurance
5
+ */
6
+ /**
7
+ * Retrieved context for RAG evaluation
8
+ */
9
+ export interface RetrievedContext {
10
+ content: string;
11
+ chunkIndex?: number;
12
+ metadata?: Record<string, unknown>;
13
+ score?: number;
14
+ }
15
+ /**
16
+ * Ground truth context
17
+ */
18
+ export interface GroundTruthContext {
19
+ content: string;
20
+ chunkIndex?: number;
21
+ }
22
+ /**
23
+ * Grounded span evidence
24
+ */
25
+ export interface GroundedSpan {
26
+ text: string;
27
+ confidence: number;
28
+ sourceChunkIndex?: number;
29
+ }
30
+ /**
31
+ * Ungrounded span evidence
32
+ */
33
+ export interface UngroundedSpan {
34
+ text: string;
35
+ confidence: number;
36
+ }
37
+ /**
38
+ * Citation mapping
39
+ */
40
+ export interface CitationMap {
41
+ claim: string;
42
+ citedIndex: number;
43
+ isValid: boolean;
44
+ }
45
+ /**
46
+ * RAG evaluation result
47
+ */
48
+ export interface RAGEvaluation {
49
+ contextRelevance: number;
50
+ contextPrecision: number;
51
+ contextRecall: number;
52
+ groundedness: number;
53
+ faithfulness: number;
54
+ answerRelevance: number;
55
+ citationAccuracy: number;
56
+ citationCompleteness: number;
57
+ overallScore: number;
58
+ grade: 'A' | 'B' | 'C' | 'D' | 'F';
59
+ groundedSpanCount?: number;
60
+ ungroundedSpanCount?: number;
61
+ issues: string[];
62
+ recommendations: string[];
63
+ }
64
+ /**
65
+ * RAG evaluation evidence
66
+ */
67
+ export interface RAGEvidence {
68
+ groundedSpans: GroundedSpan[];
69
+ ungroundedSpans: UngroundedSpan[];
70
+ citationMap: CitationMap[];
71
+ }
72
+ /**
73
+ * Hallucination instance
74
+ */
75
+ export interface HallucinationInstance {
76
+ type: string;
77
+ severity: 'low' | 'medium' | 'high' | 'critical';
78
+ text: string;
79
+ explanation: string;
80
+ confidence: number;
81
+ suggestedFix?: string;
82
+ }
83
+ /**
84
+ * Hallucination detection report
85
+ */
86
+ export interface HallucinationReport {
87
+ hasHallucinations: boolean;
88
+ hallucinationScore: number;
89
+ riskLevel: 'low' | 'medium' | 'high' | 'critical';
90
+ factualClaims: number;
91
+ verifiedClaims: number;
92
+ unverifiedClaims: number;
93
+ summary: string;
94
+ recommendations: string[];
95
+ instances: HallucinationInstance[];
96
+ }
97
+ /**
98
+ * Groundedness analysis result
99
+ */
100
+ export interface GroundednessResult {
101
+ score: number;
102
+ faithfulness: number;
103
+ contextRelevance: number;
104
+ grade: string;
105
+ }
106
+ /**
107
+ * Batch evaluation result for a single trace
108
+ */
109
+ export interface BatchEvaluationResult {
110
+ traceId: string;
111
+ success: boolean;
112
+ error?: string;
113
+ rag?: {
114
+ score: number;
115
+ grade: string;
116
+ mainIssue?: string;
117
+ };
118
+ hallucination?: {
119
+ hasIssues: boolean;
120
+ score: number;
121
+ topIssue?: string;
122
+ };
123
+ }
124
+ /**
125
+ * Batch evaluation summary
126
+ */
127
+ export interface BatchEvaluationSummary {
128
+ totalTraces: number;
129
+ successfulEvaluations: number;
130
+ avgRagScore: number;
131
+ hallucinationRate: number;
132
+ gradeDistribution: {
133
+ A: number;
134
+ B: number;
135
+ C: number;
136
+ D: number;
137
+ F: number;
138
+ };
139
+ }
140
+ /**
141
+ * Quality Metrics API client for RAG evaluation and hallucination detection
142
+ */
143
+ export declare const qualityMetrics: {
144
+ /**
145
+ * Get RAG quality scores for a specific trace
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * const scores = await qualityMetrics.getRagScores('trace_abc123');
150
+ * console.log(`Groundedness: ${scores.evaluation.groundedness}`);
151
+ * console.log(`Grade: ${scores.evaluation.grade}`);
152
+ * ```
153
+ */
154
+ getRagScores(traceId: string): Promise<{
155
+ traceId: string;
156
+ evaluation: RAGEvaluation;
157
+ evidence: RAGEvidence;
158
+ }>;
159
+ /**
160
+ * Get hallucination detection report for a trace
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * const report = await qualityMetrics.getHallucinationReport('trace_abc123');
165
+ * if (report.report.hasHallucinations) {
166
+ * console.log(`Risk level: ${report.report.riskLevel}`);
167
+ * for (const instance of report.report.instances) {
168
+ * console.log(`- ${instance.type}: ${instance.text}`);
169
+ * }
170
+ * }
171
+ * ```
172
+ */
173
+ getHallucinationReport(traceId: string): Promise<{
174
+ traceId: string;
175
+ report: HallucinationReport;
176
+ }>;
177
+ /**
178
+ * Evaluate RAG quality for provided content (ad-hoc evaluation)
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * const result = await qualityMetrics.evaluateRag({
183
+ * query: 'What is the refund policy?',
184
+ * response: 'You can get a refund within 30 days.',
185
+ * retrievedContexts: [
186
+ * { content: 'Our refund policy allows returns within 30 days of purchase.' },
187
+ * ],
188
+ * });
189
+ * console.log(`Groundedness: ${result.evaluation.groundedness}`);
190
+ * ```
191
+ */
192
+ evaluateRag(input: {
193
+ query: string;
194
+ response: string;
195
+ retrievedContexts: RetrievedContext[];
196
+ groundTruthContexts?: GroundTruthContext[];
197
+ citations?: string[];
198
+ }): Promise<{
199
+ evaluation: RAGEvaluation;
200
+ evidence: RAGEvidence;
201
+ }>;
202
+ /**
203
+ * Detect hallucinations in provided content (ad-hoc detection)
204
+ *
205
+ * @example
206
+ * ```typescript
207
+ * const result = await qualityMetrics.detectHallucinations({
208
+ * response: 'The product costs $99 and comes with a 2-year warranty.',
209
+ * contexts: [
210
+ * { content: 'The product costs $99 with a 1-year warranty.' },
211
+ * ],
212
+ * });
213
+ * if (result.report.hasHallucinations) {
214
+ * console.log('Detected hallucinations:', result.report.instances);
215
+ * }
216
+ * ```
217
+ */
218
+ detectHallucinations(input: {
219
+ response: string;
220
+ contexts: Array<{
221
+ content: string;
222
+ metadata?: Record<string, unknown>;
223
+ }>;
224
+ query?: string;
225
+ previousResponses?: string[];
226
+ }): Promise<{
227
+ report: HallucinationReport;
228
+ }>;
229
+ /**
230
+ * Get groundedness analysis for a trace
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * const result = await qualityMetrics.getGroundedness('trace_abc123');
235
+ * console.log(`Groundedness score: ${result.groundedness.score}`);
236
+ * console.log(`Grounded spans: ${result.summary.groundedSpans}`);
237
+ * ```
238
+ */
239
+ getGroundedness(traceId: string): Promise<{
240
+ traceId: string;
241
+ groundedness: GroundednessResult;
242
+ spans: {
243
+ grounded: Array<{
244
+ text: string;
245
+ confidence: number;
246
+ sourceIndex: number;
247
+ }>;
248
+ ungrounded: Array<{
249
+ text: string;
250
+ confidence: number;
251
+ }>;
252
+ };
253
+ summary: {
254
+ totalSpans: number;
255
+ groundedSpans: number;
256
+ ungroundedSpans: number;
257
+ groundednessRatio: number;
258
+ };
259
+ }>;
260
+ /**
261
+ * Evaluate multiple traces for quality metrics in batch
262
+ *
263
+ * @example
264
+ * ```typescript
265
+ * const result = await qualityMetrics.evaluateBatch({
266
+ * traceIds: ['trace_1', 'trace_2', 'trace_3'],
267
+ * });
268
+ * console.log(`Average RAG score: ${result.summary.avgRagScore}`);
269
+ * console.log(`Hallucination rate: ${result.summary.hallucinationRate}%`);
270
+ * ```
271
+ */
272
+ evaluateBatch(options: {
273
+ traceIds: string[];
274
+ includeDetails?: boolean;
275
+ }): Promise<{
276
+ summary: BatchEvaluationSummary;
277
+ results: BatchEvaluationResult[];
278
+ }>;
279
+ };
280
+ /**
281
+ * Check if a RAG evaluation passes quality thresholds
282
+ */
283
+ export declare function passesQualityThreshold(evaluation: RAGEvaluation, thresholds?: {
284
+ minGroundedness?: number;
285
+ minOverallScore?: number;
286
+ minGrade?: 'A' | 'B' | 'C' | 'D';
287
+ }): boolean;
288
+ /**
289
+ * Check if hallucination risk is acceptable
290
+ */
291
+ export declare function isHallucinationRiskAcceptable(report: HallucinationReport, maxRiskLevel?: 'low' | 'medium' | 'high'): boolean;
292
+ /**
293
+ * Get quality recommendations based on evaluation
294
+ */
295
+ export declare function getQualityRecommendations(ragEval: RAGEvaluation, hallucinationReport?: HallucinationReport): string[];
296
+ /**
297
+ * Format quality score for display
298
+ */
299
+ export declare function formatQualityScore(score: number): string;
300
+ /**
301
+ * Get color indicator for grade
302
+ */
303
+ export declare function getGradeColor(grade: 'A' | 'B' | 'C' | 'D' | 'F'): 'green' | 'blue' | 'yellow' | 'orange' | 'red';
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ /**
3
+ * ThinkHive SDK v3.1 - Quality Metrics API
4
+ *
5
+ * RAG Evaluation & Hallucination Detection for AI quality assurance
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.qualityMetrics = void 0;
9
+ exports.passesQualityThreshold = passesQualityThreshold;
10
+ exports.isHallucinationRiskAcceptable = isHallucinationRiskAcceptable;
11
+ exports.getQualityRecommendations = getQualityRecommendations;
12
+ exports.formatQualityScore = formatQualityScore;
13
+ exports.getGradeColor = getGradeColor;
14
+ const client_1 = require("../core/client");
15
+ // ============================================================================
16
+ // QUALITY METRICS API CLIENT
17
+ // ============================================================================
18
+ /**
19
+ * Quality Metrics API client for RAG evaluation and hallucination detection
20
+ */
21
+ exports.qualityMetrics = {
22
+ /**
23
+ * Get RAG quality scores for a specific trace
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const scores = await qualityMetrics.getRagScores('trace_abc123');
28
+ * console.log(`Groundedness: ${scores.evaluation.groundedness}`);
29
+ * console.log(`Grade: ${scores.evaluation.grade}`);
30
+ * ```
31
+ */
32
+ async getRagScores(traceId) {
33
+ return (0, client_1.apiRequestWithData)(`/quality/rag-scores/${traceId}`, {
34
+ apiVersion: 'v1',
35
+ });
36
+ },
37
+ /**
38
+ * Get hallucination detection report for a trace
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const report = await qualityMetrics.getHallucinationReport('trace_abc123');
43
+ * if (report.report.hasHallucinations) {
44
+ * console.log(`Risk level: ${report.report.riskLevel}`);
45
+ * for (const instance of report.report.instances) {
46
+ * console.log(`- ${instance.type}: ${instance.text}`);
47
+ * }
48
+ * }
49
+ * ```
50
+ */
51
+ async getHallucinationReport(traceId) {
52
+ return (0, client_1.apiRequestWithData)(`/quality/hallucination-report/${traceId}`, {
53
+ apiVersion: 'v1',
54
+ });
55
+ },
56
+ /**
57
+ * Evaluate RAG quality for provided content (ad-hoc evaluation)
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const result = await qualityMetrics.evaluateRag({
62
+ * query: 'What is the refund policy?',
63
+ * response: 'You can get a refund within 30 days.',
64
+ * retrievedContexts: [
65
+ * { content: 'Our refund policy allows returns within 30 days of purchase.' },
66
+ * ],
67
+ * });
68
+ * console.log(`Groundedness: ${result.evaluation.groundedness}`);
69
+ * ```
70
+ */
71
+ async evaluateRag(input) {
72
+ return (0, client_1.apiRequestWithData)('/quality/evaluate-rag', {
73
+ method: 'POST',
74
+ body: input,
75
+ apiVersion: 'v1',
76
+ });
77
+ },
78
+ /**
79
+ * Detect hallucinations in provided content (ad-hoc detection)
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * const result = await qualityMetrics.detectHallucinations({
84
+ * response: 'The product costs $99 and comes with a 2-year warranty.',
85
+ * contexts: [
86
+ * { content: 'The product costs $99 with a 1-year warranty.' },
87
+ * ],
88
+ * });
89
+ * if (result.report.hasHallucinations) {
90
+ * console.log('Detected hallucinations:', result.report.instances);
91
+ * }
92
+ * ```
93
+ */
94
+ async detectHallucinations(input) {
95
+ return (0, client_1.apiRequestWithData)('/quality/detect-hallucinations', {
96
+ method: 'POST',
97
+ body: input,
98
+ apiVersion: 'v1',
99
+ });
100
+ },
101
+ /**
102
+ * Get groundedness analysis for a trace
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * const result = await qualityMetrics.getGroundedness('trace_abc123');
107
+ * console.log(`Groundedness score: ${result.groundedness.score}`);
108
+ * console.log(`Grounded spans: ${result.summary.groundedSpans}`);
109
+ * ```
110
+ */
111
+ async getGroundedness(traceId) {
112
+ return (0, client_1.apiRequestWithData)(`/quality/groundedness/${traceId}`, {
113
+ apiVersion: 'v1',
114
+ });
115
+ },
116
+ /**
117
+ * Evaluate multiple traces for quality metrics in batch
118
+ *
119
+ * @example
120
+ * ```typescript
121
+ * const result = await qualityMetrics.evaluateBatch({
122
+ * traceIds: ['trace_1', 'trace_2', 'trace_3'],
123
+ * });
124
+ * console.log(`Average RAG score: ${result.summary.avgRagScore}`);
125
+ * console.log(`Hallucination rate: ${result.summary.hallucinationRate}%`);
126
+ * ```
127
+ */
128
+ async evaluateBatch(options) {
129
+ return (0, client_1.apiRequestWithData)('/quality/evaluate-batch', {
130
+ method: 'POST',
131
+ body: options,
132
+ apiVersion: 'v1',
133
+ });
134
+ },
135
+ };
136
+ // ============================================================================
137
+ // HELPER FUNCTIONS
138
+ // ============================================================================
139
+ /**
140
+ * Check if a RAG evaluation passes quality thresholds
141
+ */
142
+ function passesQualityThreshold(evaluation, thresholds = {}) {
143
+ const { minGroundedness = 0.7, minOverallScore = 60, minGrade = 'C' } = thresholds;
144
+ const gradeOrder = { A: 4, B: 3, C: 2, D: 1, F: 0 };
145
+ const meetsGroundedness = evaluation.groundedness >= minGroundedness;
146
+ const meetsScore = evaluation.overallScore >= minOverallScore;
147
+ const meetsGrade = gradeOrder[evaluation.grade] >= gradeOrder[minGrade];
148
+ return meetsGroundedness && meetsScore && meetsGrade;
149
+ }
150
+ /**
151
+ * Check if hallucination risk is acceptable
152
+ */
153
+ function isHallucinationRiskAcceptable(report, maxRiskLevel = 'medium') {
154
+ const riskOrder = { low: 0, medium: 1, high: 2, critical: 3 };
155
+ return riskOrder[report.riskLevel] <= riskOrder[maxRiskLevel];
156
+ }
157
+ /**
158
+ * Get quality recommendations based on evaluation
159
+ */
160
+ function getQualityRecommendations(ragEval, hallucinationReport) {
161
+ const recommendations = [];
162
+ if (ragEval.groundedness < 0.7) {
163
+ recommendations.push('Improve grounding by increasing context relevance');
164
+ }
165
+ if (ragEval.contextRelevance < 0.6) {
166
+ recommendations.push('Tune retrieval to return more relevant contexts');
167
+ }
168
+ if (ragEval.citationAccuracy < 0.8) {
169
+ recommendations.push('Improve citation accuracy in responses');
170
+ }
171
+ if (hallucinationReport?.hasHallucinations) {
172
+ recommendations.push('Add fact-checking layer to reduce hallucinations');
173
+ }
174
+ if (recommendations.length === 0) {
175
+ recommendations.push('Quality metrics are within acceptable ranges');
176
+ }
177
+ return recommendations;
178
+ }
179
+ /**
180
+ * Format quality score for display
181
+ */
182
+ function formatQualityScore(score) {
183
+ return `${Math.round(score * 100)}%`;
184
+ }
185
+ /**
186
+ * Get color indicator for grade
187
+ */
188
+ function getGradeColor(grade) {
189
+ const colors = {
190
+ A: 'green',
191
+ B: 'blue',
192
+ C: 'yellow',
193
+ D: 'orange',
194
+ F: 'red',
195
+ };
196
+ return colors[grade];
197
+ }
198
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVhbGl0eS1tZXRyaWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9xdWFsaXR5LW1ldHJpY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7O0dBSUc7OztBQXFWSCx3REFnQkM7QUFLRCxzRUFNQztBQUtELDhEQTJCQztBQUtELGdEQUVDO0FBS0Qsc0NBV0M7QUFyYUQsMkNBQWdFO0FBa0toRSwrRUFBK0U7QUFDL0UsNkJBQTZCO0FBQzdCLCtFQUErRTtBQUUvRTs7R0FFRztBQUNVLFFBQUEsY0FBYyxHQUFHO0lBQzVCOzs7Ozs7Ozs7T0FTRztJQUNILEtBQUssQ0FBQyxZQUFZLENBQUMsT0FBZTtRQUtoQyxPQUFPLElBQUEsMkJBQWtCLEVBQUMsdUJBQXVCLE9BQU8sRUFBRSxFQUFFO1lBQzFELFVBQVUsRUFBRSxJQUFJO1NBQ2pCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7OztPQWFHO0lBQ0gsS0FBSyxDQUFDLHNCQUFzQixDQUFDLE9BQWU7UUFJMUMsT0FBTyxJQUFBLDJCQUFrQixFQUFDLGlDQUFpQyxPQUFPLEVBQUUsRUFBRTtZQUNwRSxVQUFVLEVBQUUsSUFBSTtTQUNqQixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7O09BY0c7SUFDSCxLQUFLLENBQUMsV0FBVyxDQUFDLEtBTWpCO1FBSUMsT0FBTyxJQUFBLDJCQUFrQixFQUFDLHVCQUF1QixFQUFFO1lBQ2pELE1BQU0sRUFBRSxNQUFNO1lBQ2QsSUFBSSxFQUFFLEtBQUs7WUFDWCxVQUFVLEVBQUUsSUFBSTtTQUNqQixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7OztPQWVHO0lBQ0gsS0FBSyxDQUFDLG9CQUFvQixDQUFDLEtBSzFCO1FBR0MsT0FBTyxJQUFBLDJCQUFrQixFQUFDLGdDQUFnQyxFQUFFO1lBQzFELE1BQU0sRUFBRSxNQUFNO1lBQ2QsSUFBSSxFQUFFLEtBQUs7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O0dBRUc7QUFDSCxTQUFnQixrQkFBa0IsQ0FBQyxLQUFhO0lBQzlDLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDO0FBQ3ZDLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLGFBQWEsQ0FDM0IsS0FBa0M7SUFFbEMsTUFBTSxNQUFNLEdBQUc7UUFDYixDQUFDLEVBQUUsT0FBZ0I7UUFDbkIsQ0FBQyxFQUFFLE1BQWU7UUFDbEIsQ0FBQyxFQUFFLFFBQWlCO1FBQ3BCLENBQUMsRUFBRSxRQUFpQjtRQUNwQixDQUFDLEVBQUUsS0FBYztLQUNsQixDQUFDO0lBQ0YsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDdkIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogVGhpbmtIaXZlIFNESyB2My4xIC0gUXVhbGl0eSBNZXRyaWNzIEFQSVxuICpcbiAqIFJBRyBFdmFsdWF0aW9uICYgSGFsbHVjaW5hdGlvbiBEZXRlY3Rpb24gZm9yIEFJIHF1YWxpdHkgYXNzdXJhbmNlXG4gKi9cblxuaW1wb3J0IHsgYXBpUmVxdWVzdCwgYXBpUmVxdWVzdFdpdGhEYXRhIH0gZnJvbSAnLi4vY29yZS9jbGllbnQnO1xuaW1wb3J0IHR5cGUgeyBBcGlSZXNwb25zZSB9IGZyb20gJy4uL2NvcmUvdHlwZXMnO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBUWVBFU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIFJldHJpZXZlZCBjb250ZXh0IGZvciBSQUcgZXZhbHVhdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJldHJpZXZlZENvbnRleHQge1xuICBjb250ZW50OiBzdHJpbmc7XG4gIGNodW5rSW5kZXg/OiBudW1iZXI7XG4gIG1ldGFkYXRhPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIHNjb3JlPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIEdyb3VuZCB0cnV0aCBjb250ZXh0XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR3JvdW5kVHJ1dGhDb250ZXh0IHtcbiAgY29udGVudDogc3RyaW5nO1xuICBjaHVua0luZGV4PzogbnVtYmVyO1xufVxuXG4vKipcbiAqIEdyb3VuZGVkIHNwYW4gZXZpZGVuY2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHcm91bmRlZFNwYW4ge1xuICB0ZXh0OiBzdHJpbmc7XG4gIGNvbmZpZGVuY2U6IG51bWJlcjtcbiAgc291cmNlQ2h1bmtJbmRleD86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBVbmdyb3VuZGVkIHNwYW4gZXZpZGVuY2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBVbmdyb3VuZGVkU3BhbiB7XG4gIHRleHQ6IHN0cmluZztcbiAgY29uZmlkZW5jZTogbnVtYmVyO1xufVxuXG4vKipcbiAqIENpdGF0aW9uIG1hcHBpbmdcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDaXRhdGlvbk1hcCB7XG4gIGNsYWltOiBzdHJpbmc7XG4gIGNpdGVkSW5kZXg6IG51bWJlcjtcbiAgaXNWYWxpZDogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBSQUcgZXZhbHVhdGlvbiByZXN1bHRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSQUdFdmFsdWF0aW9uIHtcbiAgLy8gUmV0cmlldmFsIFF1YWxpdHlcbiAgY29udGV4dFJlbGV2YW5jZTogbnVtYmVyO1xuICBjb250ZXh0UHJlY2lzaW9uOiBudW1iZXI7XG4gIGNvbnRleHRSZWNhbGw6IG51bWJlcjtcblxuICAvLyBHZW5lcmF0aW9uIFF1YWxpdHlcbiAgZ3JvdW5kZWRuZXNzOiBudW1iZXI7XG4gIGZhaXRoZnVsbmVzczogbnVtYmVyO1xuICBhbnN3ZXJSZWxldmFuY2U6IG51bWJlcjtcblxuICAvLyBDaXRhdGlvbiBRdWFsaXR5XG4gIGNpdGF0aW9uQWNjdXJhY3k6IG51bWJlcjtcbiAgY2l0YXRpb25Db21wbGV0ZW5lc3M6IG51bWJlcjtcblxuICAvLyBPdmVyYWxsXG4gIG92ZXJhbGxTY29yZTogbnVtYmVyO1xuICBncmFkZTogJ0EnIHwgJ0InIHwgJ0MnIHwgJ0QnIHwgJ0YnO1xuXG4gIC8vIERldGFpbHNcbiAgZ3JvdW5kZWRTcGFuQ291bnQ/OiBudW1iZXI7XG4gIHVuZ3JvdW5kZWRTcGFuQ291bnQ/OiBudW1iZXI7XG4gIGlzc3Vlczogc3RyaW5nW107XG4gIHJlY29tbWVuZGF0aW9uczogc3RyaW5nW107XG59XG5cbi8qKlxuICogUkFHIGV2YWx1YXRpb24gZXZpZGVuY2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSQUdFdmlkZW5jZSB7XG4gIGdyb3VuZGVkU3BhbnM6IEdyb3VuZGVkU3BhbltdO1xuICB1bmdyb3VuZGVkU3BhbnM6IFVuZ3JvdW5kZWRTcGFuW107XG4gIGNpdGF0aW9uTWFwOiBDaXRhdGlvbk1hcFtdO1xufVxuXG4vKipcbiAqIEhhbGx1Y2luYXRpb24gaW5zdGFuY2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBIYWxsdWNpbmF0aW9uSW5zdGFuY2Uge1xuICB0eXBlOiBzdHJpbmc7XG4gIHNldmVyaXR5OiAnbG93JyB8ICdtZWRpdW0nIHwgJ2hpZ2gnIHwgJ2NyaXRpY2FsJztcbiAgdGV4dDogc3RyaW5nO1xuICBleHBsYW5hdGlvbjogc3RyaW5nO1xuICBjb25maWRlbmNlOiBudW1iZXI7XG4gIHN1Z2dlc3RlZEZpeD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBIYWxsdWNpbmF0aW9uIGRldGVjdGlvbiByZXBvcnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBIYWxsdWNpbmF0aW9uUmVwb3J0IHtcbiAgaGFzSGFsbHVjaW5hdGlvbnM6IGJvb2xlYW47XG4gIGhhbGx1Y2luYXRpb25TY29yZTogbnVtYmVyO1xuICByaXNrTGV2ZWw6ICdsb3cnIHwgJ21lZGl1bScgfCAnaGlnaCcgfCAnY3JpdGljYWwnO1xuICBmYWN0dWFsQ2xhaW1zOiBudW1iZXI7XG4gIHZlcmlmaWVkQ2xhaW1zOiBudW1iZXI7XG4gIHVudmVyaWZpZWRDbGFpbXM6IG51bWJlcjtcbiAgc3VtbWFyeTogc3RyaW5nO1xuICByZWNvbW1lbmRhdGlvbnM6IHN0cmluZ1tdO1xuICBpbnN0YW5jZXM6IEhhbGx1Y2luYXRpb25JbnN0YW5jZVtdO1xufVxuXG4vKipcbiAqIEdyb3VuZGVkbmVzcyBhbmFseXNpcyByZXN1bHRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHcm91bmRlZG5lc3NSZXN1bHQge1xuICBzY29yZTogbnVtYmVyO1xuICBmYWl0aGZ1bG5lc3M6IG51bWJlcjtcbiAgY29udGV4dFJlbGV2YW5jZTogbnVtYmVyO1xuICBncmFkZTogc3RyaW5nO1xufVxuXG4vKipcbiAqIEJhdGNoIGV2YWx1YXRpb24gcmVzdWx0IGZvciBhIHNpbmdsZSB0cmFjZVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEJhdGNoRXZhbHVhdGlvblJlc3VsdCB7XG4gIHRyYWNlSWQ6IHN0cmluZztcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgZXJyb3I/OiBzdHJpbmc7XG4gIHJhZz86IHtcbiAgICBzY29yZTogbnVtYmVyO1xuICAgIGdyYWRlOiBzdHJpbmc7XG4gICAgbWFpbklzc3VlPzogc3RyaW5nO1xuICB9O1xuICBoYWxsdWNpbmF0aW9uPzoge1xuICAgIGhhc0lzc3VlczogYm9vbGVhbjtcbiAgICBzY29yZTogbnVtYmVyO1xuICAgIHRvcElzc3VlPzogc3RyaW5nO1xuICB9O1xufVxuXG4vKipcbiAqIEJhdGNoIGV2YWx1YXRpb24gc3VtbWFyeVxuICovXG5leHBvcnQgaW50ZXJmYWNlIEJhdGNoRXZhbHVhdGlvblN1bW1hcnkge1xuICB0b3RhbFRyYWNlczogbnVtYmVyO1xuICBzdWNjZXNzZnVsRXZhbHVhdGlvbnM6IG51bWJlcjtcbiAgYXZnUmFnU2NvcmU6IG51bWJlcjtcbiAgaGFsbHVjaW5hdGlvblJhdGU6IG51bWJlcjtcbiAgZ3JhZGVEaXN0cmlidXRpb246IHtcbiAgICBBOiBudW1iZXI7XG4gICAgQjogbnVtYmVyO1xuICAgIEM6IG51bWJlcjtcbiAgICBEOiBudW1iZXI7XG4gICAgRjogbnVtYmVyO1xuICB9O1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBRVUFMSVRZIE1FVFJJQ1MgQVBJIENMSUVOVFxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIFF1YWxpdHkgTWV0cmljcyBBUEkgY2xpZW50IGZvciBSQUcgZXZhbHVhdGlvbiBhbmQgaGFsbHVjaW5hdGlvbiBkZXRlY3Rpb25cbiAqL1xuZXhwb3J0IGNvbnN0IHF1YWxpdHlNZXRyaWNzID0ge1xuICAvKipcbiAgICogR2V0IFJBRyBxdWFsaXR5IHNjb3JlcyBmb3IgYSBzcGVjaWZpYyB0cmFjZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHNjb3JlcyA9IGF3YWl0IHF1YWxpdHlNZXRyaWNzLmdldFJhZ1Njb3JlcygndHJhY2VfYWJjMTIzJyk7XG4gICAqIGNvbnNvbGUubG9nKGBHcm91bmRlZG5lc3M6ICR7c2NvcmVzLmV2YWx1YXRpb24uZ3JvdW5kZWRuZXNzfWApO1xuICAgKiBjb25zb2xlLmxvZyhgR3JhZGU6ICR7c2NvcmVzLmV2YWx1YXRpb24uZ3JhZGV9YCk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgZ2V0UmFnU2NvcmVzKHRyYWNlSWQ6IHN0cmluZyk6IFByb21pc2U8e1xuICAgIHRyYWNlSWQ6IHN0cmluZztcbiAgICBldmFsdWF0aW9uOiBSQUdFdmFsdWF0aW9uO1xuICAgIGV2aWRlbmNlOiBSQUdFdmlkZW5jZTtcbiAgfT4ge1xuICAgIHJldHVybiBhcGlSZXF1ZXN0V2l0aERhdGEoYC9xdWFsaXR5L3JhZy1zY29yZXMvJHt0cmFjZUlkfWAsIHtcbiAgICAgIGFwaVZlcnNpb246ICd2MScsXG4gICAgfSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEdldCBoYWxsdWNpbmF0aW9uIGRldGVjdGlvbiByZXBvcnQgZm9yIGEgdHJhY2VcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCByZXBvcnQgPSBhd2FpdCBxdWFsaXR5TWV0cmljcy5nZXRIYWxsdWNpbmF0aW9uUmVwb3J0KCd0cmFjZV9hYmMxMjMnKTtcbiAgICogaWYgKHJlcG9ydC5yZXBvcnQuaGFzSGFsbHVjaW5hdGlvbnMpIHtcbiAgICogICBjb25zb2xlLmxvZyhgUmlzayBsZXZlbDogJHtyZXBvcnQucmVwb3J0LnJpc2tMZXZlbH1gKTtcbiAgICogICBmb3IgKGNvbnN0IGluc3RhbmNlIG9mIHJlcG9ydC5yZXBvcnQuaW5zdGFuY2VzKSB7XG4gICAqICAgICBjb25zb2xlLmxvZyhgLSAke2luc3RhbmNlLnR5cGV9OiAke2luc3RhbmNlLnRleHR9YCk7XG4gICAqICAgfVxuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgZ2V0SGFsbHVjaW5hdGlvblJlcG9ydCh0cmFjZUlkOiBzdHJpbmcpOiBQcm9taXNlPHtcbiAgICB0cmFjZUlkOiBzdHJpbmc7XG4gICAgcmVwb3J0OiBIYWxsdWNpbmF0aW9uUmVwb3J0O1xuICB9PiB7XG4gICAgcmV0dXJuIGFwaVJlcXVlc3RXaXRoRGF0YShgL3F1YWxpdHkvaGFsbHVjaW5hdGlvbi1yZXBvcnQvJHt0cmFjZUlkfWAsIHtcbiAgICAgIGFwaVZlcnNpb246ICd2MScsXG4gICAgfSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEV2YWx1YXRlIFJBRyBxdWFsaXR5IGZvciBwcm92aWRlZCBjb250ZW50IChhZC1ob2MgZXZhbHVhdGlvbilcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCByZXN1bHQgPSBhd2FpdCBxdWFsaXR5TWV0cmljcy5ldmFsdWF0ZVJhZyh7XG4gICAqICAgcXVlcnk6ICdXaGF0IGlzIHRoZSByZWZ1bmQgcG9saWN5PycsXG4gICAqICAgcmVzcG9uc2U6ICdZb3UgY2FuIGdldCBhIHJlZnVuZCB3aXRoaW4gMzAgZGF5cy4nLFxuICAgKiAgIHJldHJpZXZlZENvbnRleHRzOiBbXG4gICAqICAgICB7IGNvbnRlbnQ6ICdPdXIgcmVmdW5kIHBvbGljeSBhbGxvd3MgcmV0dXJucyB3aXRoaW4gMzAgZGF5cyBvZiBwdXJjaGFzZS4nIH0sXG4gICAqICAgXSxcbiAgICogfSk7XG4gICAqIGNvbnNvbGUubG9nKGBHcm91bmRlZG5lc3M6ICR7cmVzdWx0LmV2YWx1YXRpb24uZ3JvdW5kZWRuZXNzfWApO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGV2YWx1YXRlUmFnKGlucHV0OiB7XG4gICAgcXVlcnk6IHN0cmluZztcbiAgICByZXNwb25zZTogc3RyaW5nO1xuICAgIHJldHJpZXZlZENvbnRleHRzOiBSZXRyaWV2ZWRDb250ZXh0W107XG4gICAgZ3JvdW5kVHJ1dGhDb250ZXh0cz86IEdyb3VuZFRydXRoQ29udGV4dFtdO1xuICAgIGNpdGF0aW9ucz86IHN0cmluZ1tdO1xuICB9KTogUHJvbWlzZTx7XG4gICAgZXZhbHVhdGlvbjogUkFHRXZhbHVhdGlvbjtcbiAgICBldmlkZW5jZTogUkFHRXZpZGVuY2U7XG4gIH0+IHtcbiAgICByZXR1cm4gYXBpUmVxdWVzdFdpdGhEYXRhKCcvcXVhbGl0eS9ldmFsdWF0ZS1yYWcnLCB7XG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIGJvZHk6IGlucHV0LFxuICAgICAgYXBpVmVyc2lvbjogJ3YxJyxcbiAgICB9KTtcbiAgfSxcblxuICAvKipcbiAgICogRGV0ZWN0IGhhbGx1Y2luYXRpb25zIGluIHByb3ZpZGVkIGNvbnRlbnQgKGFkLWhvYyBkZXRlY3Rpb24pXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgcmVzdWx0ID0gYXdhaXQgcXVhbGl0eU1ldHJpY3MuZGV0ZWN0SGFsbHVjaW5hdGlvbnMoe1xuICAgKiAgIHJlc3BvbnNlOiAnVGhlIHByb2R1Y3QgY29zdHMgJDk5IGFuZCBjb21lcyB3aXRoIGEgMi15ZWFyIHdhcnJhbnR5LicsXG4gICAqICAgY29udGV4dHM6IFtcbiAgICogICAgIHsgY29udGVudDogJ1RoZSBwcm9kdWN0IGNvc3RzICQ5OSB3aXRoIGEgMS15ZWFyIHdhcnJhbnR5LicgfSxcbiAgICogICBdLFxuICAgKiB9KTtcbiAgICogaWYgKHJlc3VsdC5yZXBvcnQuaGFzSGFsbHVjaW5hdGlvbnMpIHtcbiAgICogICBjb25zb2xlLmxvZygnRGV0ZWN0ZWQgaGFsbHVjaW5hdGlvbnM6JywgcmVzdWx0LnJlcG9ydC5pbnN0YW5jZXMpO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgZGV0ZWN0SGFsbHVjaW5hdGlvbnMoaW5wdXQ6IHtcbiAgICByZXNwb25zZTogc3RyaW5nO1xuICAgIGNvbnRleHRzOiBBcnJheTx7IGNvbnRlbnQ6IHN0cmluZzsgbWV0YWRhdGE/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9PjtcbiAgICBxdWVyeT86IHN0cmluZztcbiAgICBwcmV2aW91c1Jlc3BvbnNlcz86IHN0cmluZ1tdO1xuICB9KTogUHJvbWlzZTx7XG4gICAgcmVwb3J0OiBIYWxsdWNpbmF0aW9uUmVwb3J0O1xuICB9PiB7XG4gICAgcmV0dXJuIGFwaVJlcXVlc3RXaXRoRGF0YSgnL3F1YWxpdHkvZGV0ZWN0LWhhbGx1Y2luYXRpb25zJywge1xuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBib2R5OiBpbnB1dCxcbiAgICAgIGFwaVZlcnNpb246ICd2MScsXG4gICAgfSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEdldCBncm91bmRlZG5lc3MgYW5hbHlzaXMgZm9yIGEgdHJhY2VcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCByZXN1bHQgPSBhd2FpdCBxdWFsaXR5TWV0cmljcy5nZXRHcm91bmRlZG5lc3MoJ3RyYWNlX2FiYzEyMycpO1xuICAgKiBjb25zb2xlLmxvZyhgR3JvdW5kZWRuZXNzIHNjb3JlOiAke3Jlc3VsdC5ncm91bmRlZG5lc3Muc2NvcmV9YCk7XG4gICAqIGNvbnNvbGUubG9nKGBHcm91bmRlZCBzcGFuczogJHtyZXN1bHQuc3VtbWFyeS5ncm91bmRlZFNwYW5zfWApO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGdldEdyb3VuZGVkbmVzcyh0cmFjZUlkOiBzdHJpbmcpOiBQcm9taXNlPHtcbiAgICB0cmFjZUlkOiBzdHJpbmc7XG4gICAgZ3JvdW5kZWRuZXNzOiBHcm91bmRlZG5lc3NSZXN1bHQ7XG4gICAgc3BhbnM6IHtcbiAgICAgIGdyb3VuZGVkOiBBcnJheTx7IHRleHQ6IHN0cmluZzsgY29uZmlkZW5jZTogbnVtYmVyOyBzb3VyY2VJbmRleDogbnVtYmVyIH0+O1xuICAgICAgdW5ncm91bmRlZDogQXJyYXk8eyB0ZXh0OiBzdHJpbmc7IGNvbmZpZGVuY2U6IG51bWJlciB9PjtcbiAgICB9O1xuICAgIHN1bW1hcnk6IHtcbiAgICAgIHRvdGFsU3BhbnM6IG51bWJlcjtcbiAgICAgIGdyb3VuZGVkU3BhbnM6IG51bWJlcjtcbiAgICAgIHVuZ3JvdW5kZWRTcGFuczogbnVtYmVyO1xuICAgICAgZ3JvdW5kZWRuZXNzUmF0aW86IG51bWJlcjtcbiAgICB9O1xuICB9PiB7XG4gICAgcmV0dXJuIGFwaVJlcXVlc3RXaXRoRGF0YShgL3F1YWxpdHkvZ3JvdW5kZWRuZXNzLyR7dHJhY2VJZH1gLCB7XG4gICAgICBhcGlWZXJzaW9uOiAndjEnLFxuICAgIH0pO1xuICB9LFxuXG4gIC8qKlxuICAgKiBFdmFsdWF0ZSBtdWx0aXBsZSB0cmFjZXMgZm9yIHF1YWxpdHkgbWV0cmljcyBpbiBiYXRjaFxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHF1YWxpdHlNZXRyaWNzLmV2YWx1YXRlQmF0Y2goe1xuICAgKiAgIHRyYWNlSWRzOiBbJ3RyYWNlXzEnLCAndHJhY2VfMicsICd0cmFjZV8zJ10sXG4gICAqIH0pO1xuICAgKiBjb25zb2xlLmxvZyhgQXZlcmFnZSBSQUcgc2NvcmU6ICR7cmVzdWx0LnN1bW1hcnkuYXZnUmFnU2NvcmV9YCk7XG4gICAqIGNvbnNvbGUubG9nKGBIYWxsdWNpbmF0aW9uIHJhdGU6ICR7cmVzdWx0LnN1bW1hcnkuaGFsbHVjaW5hdGlvblJhdGV9JWApO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGV2YWx1YXRlQmF0Y2gob3B0aW9uczoge1xuICAgIHRyYWNlSWRzOiBzdHJpbmdbXTtcbiAgICBpbmNsdWRlRGV0YWlscz86IGJvb2xlYW47XG4gIH0pOiBQcm9taXNlPHtcbiAgICBzdW1tYXJ5OiBCYXRjaEV2YWx1YXRpb25TdW1tYXJ5O1xuICAgIHJlc3VsdHM6IEJhdGNoRXZhbHVhdGlvblJlc3VsdFtdO1xuICB9PiB7XG4gICAgcmV0dXJuIGFwaVJlcXVlc3RXaXRoRGF0YSgnL3F1YWxpdHkvZXZhbHVhdGUtYmF0Y2gnLCB7XG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIGJvZHk6IG9wdGlvbnMsXG4gICAgICBhcGlWZXJzaW9uOiAndjEnLFxuICAgIH0pO1xuICB9LFxufTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gSEVMUEVSIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIENoZWNrIGlmIGEgUkFHIGV2YWx1YXRpb24gcGFzc2VzIHF1YWxpdHkgdGhyZXNob2xkc1xuICovXG5leHBvcnQgZnVuY3Rpb24gcGFzc2VzUXVhbGl0eVRocmVzaG9sZChcbiAgZXZhbHVhdGlvbjogUkFHRXZhbHVhdGlvbixcbiAgdGhyZXNob2xkczoge1xuICAgIG1pbkdyb3VuZGVkbmVzcz86IG51bWJlcjtcbiAgICBtaW5PdmVyYWxsU2NvcmU/OiBudW1iZXI7XG4gICAgbWluR3JhZGU/OiAnQScgfCAnQicgfCAnQycgfCAnRCc7XG4gIH0gPSB7fVxuKTogYm9vbGVhbiB7XG4gIGNvbnN0IHsgbWluR3JvdW5kZWRuZXNzID0gMC43LCBtaW5PdmVyYWxsU2NvcmUgPSA2MCwgbWluR3JhZGUgPSAnQycgfSA9IHRocmVzaG9sZHM7XG5cbiAgY29uc3QgZ3JhZGVPcmRlciA9IHsgQTogNCwgQjogMywgQzogMiwgRDogMSwgRjogMCB9O1xuICBjb25zdCBtZWV0c0dyb3VuZGVkbmVzcyA9IGV2YWx1YXRpb24uZ3JvdW5kZWRuZXNzID49IG1pbkdyb3VuZGVkbmVzcztcbiAgY29uc3QgbWVldHNTY29yZSA9IGV2YWx1YXRpb24ub3ZlcmFsbFNjb3JlID49IG1pbk92ZXJhbGxTY29yZTtcbiAgY29uc3QgbWVldHNHcmFkZSA9IGdyYWRlT3JkZXJbZXZhbHVhdGlvbi5ncmFkZV0gPj0gZ3JhZGVPcmRlclttaW5HcmFkZV07XG5cbiAgcmV0dXJuIG1lZXRzR3JvdW5kZWRuZXNzICYmIG1lZXRzU2NvcmUgJiYgbWVldHNHcmFkZTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBoYWxsdWNpbmF0aW9uIHJpc2sgaXMgYWNjZXB0YWJsZVxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNIYWxsdWNpbmF0aW9uUmlza0FjY2VwdGFibGUoXG4gIHJlcG9ydDogSGFsbHVjaW5hdGlvblJlcG9ydCxcbiAgbWF4Umlza0xldmVsOiAnbG93JyB8ICdtZWRpdW0nIHwgJ2hpZ2gnID0gJ21lZGl1bSdcbik6IGJvb2xlYW4ge1xuICBjb25zdCByaXNrT3JkZXIgPSB7IGxvdzogMCwgbWVkaXVtOiAxLCBoaWdoOiAyLCBjcml0aWNhbDogMyB9O1xuICByZXR1cm4gcmlza09yZGVyW3JlcG9ydC5yaXNrTGV2ZWxdIDw9IHJpc2tPcmRlclttYXhSaXNrTGV2ZWxdO1xufVxuXG4vKipcbiAqIEdldCBxdWFsaXR5IHJlY29tbWVuZGF0aW9ucyBiYXNlZCBvbiBldmFsdWF0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRRdWFsaXR5UmVjb21tZW5kYXRpb25zKFxuICByYWdFdmFsOiBSQUdFdmFsdWF0aW9uLFxuICBoYWxsdWNpbmF0aW9uUmVwb3J0PzogSGFsbHVjaW5hdGlvblJlcG9ydFxuKTogc3RyaW5nW10ge1xuICBjb25zdCByZWNvbW1lbmRhdGlvbnM6IHN0cmluZ1tdID0gW107XG5cbiAgaWYgKHJhZ0V2YWwuZ3JvdW5kZWRuZXNzIDwgMC43KSB7XG4gICAgcmVjb21tZW5kYXRpb25zLnB1c2goJ0ltcHJvdmUgZ3JvdW5kaW5nIGJ5IGluY3JlYXNpbmcgY29udGV4dCByZWxldmFuY2UnKTtcbiAgfVxuXG4gIGlmIChyYWdFdmFsLmNvbnRleHRSZWxldmFuY2UgPCAwLjYpIHtcbiAgICByZWNvbW1lbmRhdGlvbnMucHVzaCgnVHVuZSByZXRyaWV2YWwgdG8gcmV0dXJuIG1vcmUgcmVsZXZhbnQgY29udGV4dHMnKTtcbiAgfVxuXG4gIGlmIChyYWdFdmFsLmNpdGF0aW9uQWNjdXJhY3kgPCAwLjgpIHtcbiAgICByZWNvbW1lbmRhdGlvbnMucHVzaCgnSW1wcm92ZSBjaXRhdGlvbiBhY2N1cmFjeSBpbiByZXNwb25zZXMnKTtcbiAgfVxuXG4gIGlmIChoYWxsdWNpbmF0aW9uUmVwb3J0Py5oYXNIYWxsdWNpbmF0aW9ucykge1xuICAgIHJlY29tbWVuZGF0aW9ucy5wdXNoKCdBZGQgZmFjdC1jaGVja2luZyBsYXllciB0byByZWR1Y2UgaGFsbHVjaW5hdGlvbnMnKTtcbiAgfVxuXG4gIGlmIChyZWNvbW1lbmRhdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgcmVjb21tZW5kYXRpb25zLnB1c2goJ1F1YWxpdHkgbWV0cmljcyBhcmUgd2l0aGluIGFjY2VwdGFibGUgcmFuZ2VzJyk7XG4gIH1cblxuICByZXR1cm4gcmVjb21tZW5kYXRpb25zO1xufVxuXG4vKipcbiAqIEZvcm1hdCBxdWFsaXR5IHNjb3JlIGZvciBkaXNwbGF5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRRdWFsaXR5U2NvcmUoc2NvcmU6IG51bWJlcik6IHN0cmluZyB7XG4gIHJldHVybiBgJHtNYXRoLnJvdW5kKHNjb3JlICogMTAwKX0lYDtcbn1cblxuLyoqXG4gKiBHZXQgY29sb3IgaW5kaWNhdG9yIGZvciBncmFkZVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0R3JhZGVDb2xvcihcbiAgZ3JhZGU6ICdBJyB8ICdCJyB8ICdDJyB8ICdEJyB8ICdGJ1xuKTogJ2dyZWVuJyB8ICdibHVlJyB8ICd5ZWxsb3cnIHwgJ29yYW5nZScgfCAncmVkJyB7XG4gIGNvbnN0IGNvbG9ycyA9IHtcbiAgICBBOiAnZ3JlZW4nIGFzIGNvbnN0LFxuICAgIEI6ICdibHVlJyBhcyBjb25zdCxcbiAgICBDOiAneWVsbG93JyBhcyBjb25zdCxcbiAgICBEOiAnb3JhbmdlJyBhcyBjb25zdCxcbiAgICBGOiAncmVkJyBhcyBjb25zdCxcbiAgfTtcbiAgcmV0dXJuIGNvbG9yc1tncmFkZV07XG59XG4iXX0=