@openhealth/oht-custom-parser-lib 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/service/ohtAgnosticMeasurementsExtractor.service.d.ts +59 -0
- package/dist/service/ohtAgnosticMeasurementsExtractor.service.js +603 -0
- package/dist/service/ohtAgnosticMeasurementsExtractor.service.js.map +1 -0
- package/dist/service/reportCreator.service.d.ts +1 -1
- package/dist/service/reportCreator.service.js +7 -2
- package/dist/service/reportCreator.service.js.map +1 -1
- package/package.json +36 -36
- package/readme.md +115 -115
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { LabToOhtContract, LabToOhtMapper, RangeExtractionResponse, SynonymUnit, UnknownUnits, TransformationRulesChains } from "../types/custom-parser.types";
|
|
2
|
+
import { Biomarker, BiomarkerValueType, Measurement, MeasurementValueComparator, PatientInfo, UnknownMeasurement, Exam } from "../types/oht.types";
|
|
3
|
+
/**
|
|
4
|
+
* Extracts unit from rawData (OhtExam object)
|
|
5
|
+
* @param rawData - OhtExam object (not a JSON string)
|
|
6
|
+
* @param ohtBiomarker - Biomarker information
|
|
7
|
+
* @param synonymUnits - Synonym units for unit resolution
|
|
8
|
+
* @param partnerId - Partner ID for synonym resolution
|
|
9
|
+
*/
|
|
10
|
+
declare function agnosticExtractUnit(rawData: any, ohtBiomarker: Biomarker, synonymUnits?: SynonymUnit[] | null, partnerId?: string | null | undefined): {
|
|
11
|
+
unit: string;
|
|
12
|
+
isUnitParsedCorrectly: boolean;
|
|
13
|
+
originalUnit: string;
|
|
14
|
+
isArbitraryUnit: boolean;
|
|
15
|
+
unknownUnit: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Extracts reference annotation from rawExam (OhtExam object)
|
|
19
|
+
* @param labToOhtMapper - Lab to OHT mapper configuration
|
|
20
|
+
* @param rawExam - OhtExam object (not a JSON string)
|
|
21
|
+
* @param patientInfo - Patient information
|
|
22
|
+
* @param documentDate - Document date
|
|
23
|
+
* @param exams - Array of exams for appended mappings
|
|
24
|
+
*/
|
|
25
|
+
declare function agnosticExtractReferenceAnnotation(labToOhtMapper: LabToOhtMapper, rawExam: any, patientInfo: PatientInfo, documentDate?: Date, exams?: Exam[]): string;
|
|
26
|
+
/**
|
|
27
|
+
* Extracts reference ranges from rawData (OhtExam object)
|
|
28
|
+
* Always uses parseRange function from extractionUtils for range extraction
|
|
29
|
+
*/
|
|
30
|
+
declare function agnosticExtractReferenceRanges(labToOhtMapper: LabToOhtMapper, rawData: any, patientInfo: PatientInfo, documentDate?: Date): RangeExtractionResponse;
|
|
31
|
+
declare function agnosticExtractValueFromGreaterLowerThan(value: string): {
|
|
32
|
+
extractedValue: number | null;
|
|
33
|
+
extractedValueComparator: MeasurementValueComparator | null;
|
|
34
|
+
valueParsedCorrectly: boolean;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Parses exam value from rawExamObj (OhtExam object)
|
|
38
|
+
* Now uses value directly from ohtExam
|
|
39
|
+
*/
|
|
40
|
+
declare function agnosticParseExamValue(rawExamObj: any, ohtBiomarker: Biomarker): {
|
|
41
|
+
valueType: BiomarkerValueType;
|
|
42
|
+
alphanumericalValue: string | null;
|
|
43
|
+
numberValue: number | null;
|
|
44
|
+
valueComparator: MeasurementValueComparator;
|
|
45
|
+
isValueParsedCorrectly: boolean;
|
|
46
|
+
};
|
|
47
|
+
declare function agnosticCheckValueForPlausibleValues(labToOhtMapper: LabToOhtMapper, ohtBiomarker: Biomarker, unit: string, value: number, isUnitParsedCorrectly: boolean): boolean;
|
|
48
|
+
type ApplyTransformationRulesResult = {
|
|
49
|
+
transformedExams: Exam[];
|
|
50
|
+
applicationErrorMessages: string[];
|
|
51
|
+
};
|
|
52
|
+
declare function ohtAgnosticMeasurementsExtractor(labToOhtContract: LabToOhtContract, exams: Exam[], transformationRules: TransformationRulesChains, ohtCoreApiKey: string, partnerId?: string | null | undefined): Promise<{
|
|
53
|
+
measurements: Measurement[];
|
|
54
|
+
unknownMeasurements: UnknownMeasurement[];
|
|
55
|
+
unknownUnits: UnknownUnits[];
|
|
56
|
+
isReportCorrectlyParsed: boolean;
|
|
57
|
+
transformationRulesErrors: string[];
|
|
58
|
+
}>;
|
|
59
|
+
export { ApplyTransformationRulesResult, ohtAgnosticMeasurementsExtractor, agnosticCheckValueForPlausibleValues, agnosticExtractReferenceRanges, agnosticExtractReferenceAnnotation, agnosticParseExamValue, agnosticExtractUnit, agnosticExtractValueFromGreaterLowerThan };
|
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ohtAgnosticMeasurementsExtractor = ohtAgnosticMeasurementsExtractor;
|
|
7
|
+
exports.agnosticCheckValueForPlausibleValues = agnosticCheckValueForPlausibleValues;
|
|
8
|
+
exports.agnosticExtractReferenceRanges = agnosticExtractReferenceRanges;
|
|
9
|
+
exports.agnosticExtractReferenceAnnotation = agnosticExtractReferenceAnnotation;
|
|
10
|
+
exports.agnosticParseExamValue = agnosticParseExamValue;
|
|
11
|
+
exports.agnosticExtractUnit = agnosticExtractUnit;
|
|
12
|
+
exports.agnosticExtractValueFromGreaterLowerThan = agnosticExtractValueFromGreaterLowerThan;
|
|
13
|
+
const dataUtils_1 = require("../util-ts/dataUtils");
|
|
14
|
+
const regexUtils_1 = require("../util-ts/regexUtils");
|
|
15
|
+
const extractionUtils_1 = require("../util-ts/extractionUtils");
|
|
16
|
+
const pinoLogger_1 = __importDefault(require("../util-ts/pinoLogger"));
|
|
17
|
+
const apiUtils_1 = require("../util-ts/apiUtils");
|
|
18
|
+
const oht_types_1 = require("../types/oht.types");
|
|
19
|
+
const transformationRules_service_1 = require("./transformationRules.service");
|
|
20
|
+
const auxiliaryFunctions_service_1 = require("./auxiliaryFunctions.service");
|
|
21
|
+
const logger = (0, pinoLogger_1.default)();
|
|
22
|
+
const OHT_CORE_URL = process.env.OHT_CORE_URL;
|
|
23
|
+
let filename = '';
|
|
24
|
+
/**
|
|
25
|
+
* Extracts unit from rawData (OhtExam object)
|
|
26
|
+
* @param rawData - OhtExam object (not a JSON string)
|
|
27
|
+
* @param ohtBiomarker - Biomarker information
|
|
28
|
+
* @param synonymUnits - Synonym units for unit resolution
|
|
29
|
+
* @param partnerId - Partner ID for synonym resolution
|
|
30
|
+
*/
|
|
31
|
+
function agnosticExtractUnit(rawData, ohtBiomarker, synonymUnits = null, partnerId = null) {
|
|
32
|
+
if (!(0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker)) {
|
|
33
|
+
return { unit: "None", isUnitParsedCorrectly: true, originalUnit: "", isArbitraryUnit: false, unknownUnit: '' };
|
|
34
|
+
}
|
|
35
|
+
const isArbitraryUnit = ohtBiomarker.acf.standardUnitArbUnitLogic === 'default';
|
|
36
|
+
let originalUnit = '';
|
|
37
|
+
// Use unit directly from ohtExam
|
|
38
|
+
const unit = rawData?.unit ?? '';
|
|
39
|
+
let unitLowerCase = unit?.toLowerCase();
|
|
40
|
+
unitLowerCase = unitLowerCase?.replaceAll(/ /g, '') ?? '';
|
|
41
|
+
const standardUnit = ohtBiomarker.acf.standardUnit;
|
|
42
|
+
const allBmOhtUnits = [
|
|
43
|
+
standardUnit?.toLowerCase(),
|
|
44
|
+
...ohtBiomarker.acf?.alternativeUnits
|
|
45
|
+
?.map((bmAlternative) => bmAlternative.name.toLowerCase()) ?? []
|
|
46
|
+
];
|
|
47
|
+
// If the biomarker uses an arbitrary unit, return standard unit and set the original unit as the unit extracted from the data
|
|
48
|
+
if (isArbitraryUnit) {
|
|
49
|
+
originalUnit = unit;
|
|
50
|
+
return { unit: standardUnit, isUnitParsedCorrectly: true, originalUnit: originalUnit, isArbitraryUnit: isArbitraryUnit, unknownUnit: '' };
|
|
51
|
+
}
|
|
52
|
+
// First test if the biomarker has the unit explicit in the 'unity' field
|
|
53
|
+
const allUnitContainsJsonUnit = allBmOhtUnits.includes(unitLowerCase);
|
|
54
|
+
if (unitLowerCase?.length > 0 && allUnitContainsJsonUnit) {
|
|
55
|
+
// Find the original case version from standardUnit or alternativeUnits
|
|
56
|
+
let matchedUnit = standardUnit?.toLowerCase().replaceAll(/ /g, '') === unitLowerCase
|
|
57
|
+
? standardUnit?.replaceAll(/ /g, '')
|
|
58
|
+
: ohtBiomarker.acf?.alternativeUnits?.find((bmAlternative) => bmAlternative.name.toLowerCase().replaceAll(/ /g, '') === unitLowerCase)?.name?.replaceAll(/ /g, '');
|
|
59
|
+
// Fallback to original unit if no match found (shouldn't happen, but safety check)
|
|
60
|
+
matchedUnit = matchedUnit || unit?.replaceAll(/ /g, '');
|
|
61
|
+
return {
|
|
62
|
+
unit: matchedUnit,
|
|
63
|
+
isUnitParsedCorrectly: true,
|
|
64
|
+
originalUnit: originalUnit,
|
|
65
|
+
isArbitraryUnit: isArbitraryUnit,
|
|
66
|
+
unknownUnit: ''
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// Check if there are any Synonym configured
|
|
70
|
+
if (unitLowerCase?.length > 0) {
|
|
71
|
+
let resolvedUnit = null;
|
|
72
|
+
if (synonymUnits && synonymUnits.length > 0) {
|
|
73
|
+
const resolved = (0, dataUtils_1.resolveUnitFromSynonyms)(unitLowerCase, ohtBiomarker.id, partnerId, synonymUnits);
|
|
74
|
+
if (resolved.found && resolved.targetUnit) {
|
|
75
|
+
resolvedUnit = resolved.targetUnit;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (resolvedUnit) {
|
|
79
|
+
const allUnitContainsJsonUnitSynonyms = allBmOhtUnits.includes(resolvedUnit.toLowerCase());
|
|
80
|
+
if (allUnitContainsJsonUnitSynonyms) {
|
|
81
|
+
return { unit: resolvedUnit, isUnitParsedCorrectly: true, originalUnit: originalUnit, isArbitraryUnit: isArbitraryUnit, unknownUnit: '' };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// if the unit didnt match any of the cases, add the unit to an unknownUnit list
|
|
86
|
+
return { unit: '', isUnitParsedCorrectly: false, originalUnit: '', isArbitraryUnit: false, unknownUnit: unit };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Extracts reference annotation from rawExam (OhtExam object)
|
|
90
|
+
* @param labToOhtMapper - Lab to OHT mapper configuration
|
|
91
|
+
* @param rawExam - OhtExam object (not a JSON string)
|
|
92
|
+
* @param patientInfo - Patient information
|
|
93
|
+
* @param documentDate - Document date
|
|
94
|
+
* @param exams - Array of exams for appended mappings
|
|
95
|
+
*/
|
|
96
|
+
function agnosticExtractReferenceAnnotation(labToOhtMapper, rawExam, patientInfo, documentDate, exams) {
|
|
97
|
+
let annotation = '';
|
|
98
|
+
// if it is an appended mapping, add the extracted values to annotation
|
|
99
|
+
if (labToOhtMapper?.annotationConfig?.enabled) {
|
|
100
|
+
const appendedResult = (0, dataUtils_1.processAppendedMappings)(exams, labToOhtMapper.annotationConfig.labKeys, filename, {
|
|
101
|
+
maxLength: labToOhtMapper.annotationConfig.maxLength,
|
|
102
|
+
fallbackValue: labToOhtMapper.annotationConfig.fallbackValue,
|
|
103
|
+
separator: labToOhtMapper.annotationConfig.separator
|
|
104
|
+
});
|
|
105
|
+
if (appendedResult.text?.length) {
|
|
106
|
+
annotation += appendedResult.text;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Use annotation directly from ohtExam
|
|
110
|
+
const extractedReference = rawExam?.annotation ?? '';
|
|
111
|
+
if (extractedReference?.length) {
|
|
112
|
+
annotation += annotation ? `\n${extractedReference}` : extractedReference;
|
|
113
|
+
}
|
|
114
|
+
return annotation || undefined;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Extracts reference ranges from rawData (OhtExam object)
|
|
118
|
+
* Always uses parseRange function from extractionUtils for range extraction
|
|
119
|
+
*/
|
|
120
|
+
function agnosticExtractReferenceRanges(labToOhtMapper, rawData, patientInfo, documentDate) {
|
|
121
|
+
const nullRangeNotParsedCorrectly = { from: null, to: null, isRangeParsedCorrectly: false };
|
|
122
|
+
const nullRangeParsedCorrectly = { from: null, to: null, isRangeParsedCorrectly: true };
|
|
123
|
+
// if internalRange return null, but is parsed correctly
|
|
124
|
+
if (labToOhtMapper?.rangeExtraction?.useInternalRange) {
|
|
125
|
+
return nullRangeParsedCorrectly;
|
|
126
|
+
}
|
|
127
|
+
// Always use parseRange function from extractionUtils
|
|
128
|
+
const rangeExtractionResult = (0, extractionUtils_1.parseRange)(rawData, labToOhtMapper, patientInfo);
|
|
129
|
+
if (rangeExtractionResult.isRangeParsedCorrectly) {
|
|
130
|
+
return rangeExtractionResult;
|
|
131
|
+
}
|
|
132
|
+
return nullRangeNotParsedCorrectly;
|
|
133
|
+
}
|
|
134
|
+
function agnosticExtractValueFromGreaterLowerThan(value) {
|
|
135
|
+
// Checks first if any greater than pattern is present
|
|
136
|
+
const greaterThanPatterns = (0, regexUtils_1.getGreaterThanPatterns)();
|
|
137
|
+
const lowerThanPatterns = (0, regexUtils_1.getLowerThanPatterns)();
|
|
138
|
+
value = value.toLowerCase();
|
|
139
|
+
for (const pattern of greaterThanPatterns) {
|
|
140
|
+
const match = pattern.exec(value);
|
|
141
|
+
if (match) {
|
|
142
|
+
const value = parseFloat(match?.[1].replaceAll(',', '.'));
|
|
143
|
+
const valueComparator = oht_types_1.MeasurementValueComparator.GREATER_THAN;
|
|
144
|
+
return {
|
|
145
|
+
extractedValue: value,
|
|
146
|
+
extractedValueComparator: valueComparator,
|
|
147
|
+
valueParsedCorrectly: !Number.isNaN(value)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Checks if any lower than pattern is present
|
|
152
|
+
for (const pattern of lowerThanPatterns) {
|
|
153
|
+
const match = pattern.exec(value);
|
|
154
|
+
if (match) {
|
|
155
|
+
const value = parseFloat(match?.[1].replaceAll(',', '.'));
|
|
156
|
+
const valueComparator = oht_types_1.MeasurementValueComparator.LESS_THAN;
|
|
157
|
+
return {
|
|
158
|
+
extractedValue: value,
|
|
159
|
+
extractedValueComparator: valueComparator,
|
|
160
|
+
valueParsedCorrectly: !Number.isNaN(value)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// If no pattern is found, return the value as is and the comparator as EQUAL and isValueParsedCorrectly as false
|
|
165
|
+
return { extractedValue: null, extractedValueComparator: null, valueParsedCorrectly: false };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Parses exam value from rawExamObj (OhtExam object)
|
|
169
|
+
* Now uses value directly from ohtExam
|
|
170
|
+
*/
|
|
171
|
+
function agnosticParseExamValue(rawExamObj, ohtBiomarker) {
|
|
172
|
+
// Use value directly from ohtExam
|
|
173
|
+
let value = rawExamObj?.value ?? '';
|
|
174
|
+
// Normalize to string for parseFloat
|
|
175
|
+
if (value != null) {
|
|
176
|
+
value = String(value);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
value = '';
|
|
180
|
+
}
|
|
181
|
+
// If is parse float nan, the value is alphanumerical
|
|
182
|
+
const valueType = (0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker)
|
|
183
|
+
? oht_types_1.BiomarkerValueType.NUMERICAL
|
|
184
|
+
: oht_types_1.BiomarkerValueType.ALPHANUMERICAL;
|
|
185
|
+
let alphanumericalValue = Number.isNaN(parseFloat(value))
|
|
186
|
+
? value
|
|
187
|
+
: null;
|
|
188
|
+
if (valueType === oht_types_1.BiomarkerValueType.ALPHANUMERICAL
|
|
189
|
+
&& !Number.isNaN(parseFloat(value))) {
|
|
190
|
+
// convert numberValue to string
|
|
191
|
+
alphanumericalValue = value.toString();
|
|
192
|
+
}
|
|
193
|
+
if (valueType === oht_types_1.BiomarkerValueType.NUMERICAL
|
|
194
|
+
&& Number.isNaN(parseFloat(value))) {
|
|
195
|
+
// convert numberValue to string
|
|
196
|
+
const { extractedValue, extractedValueComparator, valueParsedCorrectly } = agnosticExtractValueFromGreaterLowerThan(value);
|
|
197
|
+
return {
|
|
198
|
+
valueType,
|
|
199
|
+
alphanumericalValue,
|
|
200
|
+
numberValue: extractedValue,
|
|
201
|
+
valueComparator: extractedValueComparator ?? oht_types_1.MeasurementValueComparator.EQUAL,
|
|
202
|
+
isValueParsedCorrectly: valueParsedCorrectly
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
if (valueType === 'NUMERICAL') {
|
|
206
|
+
return {
|
|
207
|
+
valueType,
|
|
208
|
+
alphanumericalValue,
|
|
209
|
+
numberValue: parseFloat(value),
|
|
210
|
+
valueComparator: oht_types_1.MeasurementValueComparator.EQUAL,
|
|
211
|
+
isValueParsedCorrectly: !Number.isNaN(parseFloat(value))
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (valueType === 'ALPHANUMERICAL') {
|
|
215
|
+
return {
|
|
216
|
+
valueType,
|
|
217
|
+
alphanumericalValue,
|
|
218
|
+
numberValue: parseFloat(value),
|
|
219
|
+
valueComparator: oht_types_1.MeasurementValueComparator.EQUAL,
|
|
220
|
+
isValueParsedCorrectly: Boolean(alphanumericalValue)
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
valueType,
|
|
225
|
+
alphanumericalValue,
|
|
226
|
+
numberValue: null,
|
|
227
|
+
valueComparator: oht_types_1.MeasurementValueComparator.EQUAL,
|
|
228
|
+
isValueParsedCorrectly: false
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function agnosticCheckValueForPlausibleValues(labToOhtMapper, ohtBiomarker, unit, value, isUnitParsedCorrectly) {
|
|
232
|
+
if (!(0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker) && isUnitParsedCorrectly) {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
const standardUnit = ohtBiomarker.acf.standardUnit;
|
|
236
|
+
const plausibleLowerValue = ohtBiomarker.acf.plausibilityRangeCheck;
|
|
237
|
+
const plausibleUpperValue = ohtBiomarker.acf.plausibilityRangeCheckHigh;
|
|
238
|
+
const biomarkerStdValueDecimals = ohtBiomarker.acf?.displayDecimals ?? 2;
|
|
239
|
+
if (unit !== standardUnit) {
|
|
240
|
+
const alternativeUnit = (Array.isArray(ohtBiomarker.acf?.alternativeUnits)
|
|
241
|
+
? ohtBiomarker.acf?.alternativeUnits
|
|
242
|
+
: [])?.find((altUnit) => altUnit.name === unit);
|
|
243
|
+
if (alternativeUnit) {
|
|
244
|
+
const conversionFactor = alternativeUnit.conversionFactor;
|
|
245
|
+
value = +(value * conversionFactor).toFixed(biomarkerStdValueDecimals);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const isPlausibleValue = value >= plausibleLowerValue && value <= plausibleUpperValue;
|
|
249
|
+
// Log if the value is not plausible
|
|
250
|
+
if (!isPlausibleValue) {
|
|
251
|
+
logger.warn({ labToOhtMapper, value, standardUnit, plausibleLowerValue, plausibleUpperValue, filename }, `Value "${value} ${standardUnit}" not plausible "${plausibleLowerValue} to ${plausibleUpperValue}" for "${labToOhtMapper.ohtBmId}" | "${labToOhtMapper.ohtExam.labKey}", filename: ${filename}`);
|
|
252
|
+
}
|
|
253
|
+
return isPlausibleValue;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Apply transformation rules to exams
|
|
257
|
+
* This function applies transformation rules chain to each exam, passing all exams as context
|
|
258
|
+
*
|
|
259
|
+
* @param exams - Array of original exam objects
|
|
260
|
+
* @param transformationRules - Mapping of labKey to transformation rule chains
|
|
261
|
+
* @param labToOhtContract - The contract containing patient info and other context
|
|
262
|
+
* @returns Promise<Exam[]> - Array of transformed exams
|
|
263
|
+
*/
|
|
264
|
+
async function applyTransformationRulesToExams(exams, transformationRules, patientInfo, documentDate) {
|
|
265
|
+
if (transformationRules.size === 0) {
|
|
266
|
+
return {
|
|
267
|
+
transformedExams: exams,
|
|
268
|
+
applicationErrorMessages: []
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
const transformedExams = [];
|
|
272
|
+
// Prepare context for transformation rules
|
|
273
|
+
const reportContext = {
|
|
274
|
+
patient: {
|
|
275
|
+
sex: patientInfo.sex,
|
|
276
|
+
birthdate: patientInfo.birthdate,
|
|
277
|
+
age: (0, auxiliaryFunctions_service_1.getPatientAge)(documentDate, patientInfo.birthdate),
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
// Prepare the OHT exam data
|
|
281
|
+
const ohtReport = {
|
|
282
|
+
exams: exams.map(e => e.ohtExam),
|
|
283
|
+
};
|
|
284
|
+
logger.info({ examsCount: exams.length, chainsCount: transformationRules.size, filename }, 'Applying transformation rules to exams...');
|
|
285
|
+
let labKeysWithRulesCount = 0;
|
|
286
|
+
let transformedLabKeysCount = 0;
|
|
287
|
+
const applicationErrorMessages = [];
|
|
288
|
+
for (const exam of exams) {
|
|
289
|
+
const labKey = exam.ohtExam.labKey;
|
|
290
|
+
const rulesChain = transformationRules.get(labKey);
|
|
291
|
+
if (!rulesChain || rulesChain.length === 0) {
|
|
292
|
+
transformedExams.push(exam);
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
labKeysWithRulesCount++;
|
|
296
|
+
try {
|
|
297
|
+
const result = await (0, transformationRules_service_1.applyRules)(rulesChain, exam.ohtExam, {
|
|
298
|
+
ohtReportJson: ohtReport,
|
|
299
|
+
contextJson: reportContext,
|
|
300
|
+
});
|
|
301
|
+
if (result.errors.length > 0) {
|
|
302
|
+
logger.warn({ labKey, errors: result.errors, filename }, 'Errors applying transformation rule(s) for labKey.');
|
|
303
|
+
applicationErrorMessages.push(`${labKey}: ${result.errors.map(e => `(rule ID ${e.ruleId}) ${e.error}`).join('; ')}`);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
if (result.appliedRules.length > 0) {
|
|
307
|
+
transformedLabKeysCount++;
|
|
308
|
+
}
|
|
309
|
+
logger.info({ labKey, appliedRules: result.appliedRules.length, filename }, 'Done applying transformation rule(s) for labKey.');
|
|
310
|
+
// Add the transformed exam to the result array only if there are no errors in the chain
|
|
311
|
+
transformedExams.push({
|
|
312
|
+
ohtExam: result.data,
|
|
313
|
+
originalExam: exam.originalExam
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
logger.error({ labKey, error, filename }, 'Failed to apply transformation rules for labKey.');
|
|
319
|
+
applicationErrorMessages.push(`${labKey}: Unhandled error occurred.`);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
logger.info({
|
|
323
|
+
filename,
|
|
324
|
+
examsCount: exams.length,
|
|
325
|
+
chainsCount: transformationRules.size,
|
|
326
|
+
transformedLabKeysCount,
|
|
327
|
+
labKeysWithRulesCount,
|
|
328
|
+
}, 'Done applying the transformation rules to exams.');
|
|
329
|
+
return {
|
|
330
|
+
transformedExams,
|
|
331
|
+
applicationErrorMessages
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
async function ohtAgnosticMeasurementsExtractor(labToOhtContract, exams, transformationRules, ohtCoreApiKey, partnerId) {
|
|
335
|
+
filename = labToOhtContract.sourceFilename;
|
|
336
|
+
const measurements = [];
|
|
337
|
+
const unknownMeasurements = [];
|
|
338
|
+
const unknownUnits = [];
|
|
339
|
+
let isReportCorrectlyParsed = true;
|
|
340
|
+
let transformationRulesErrors = [];
|
|
341
|
+
// Apply transformation rules to all exams
|
|
342
|
+
let transformedExamsResult = { transformedExams: [], applicationErrorMessages: [] };
|
|
343
|
+
try {
|
|
344
|
+
transformedExamsResult = await applyTransformationRulesToExams(exams, transformationRules, labToOhtContract.patientInfo, labToOhtContract.documentDate);
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
logger.error({ error, filename }, 'Unhandled error while applying transformation rules to exams.');
|
|
348
|
+
labToOhtContract.errorMessages.push({
|
|
349
|
+
destination: { slack: true, notes: true, bi: false },
|
|
350
|
+
message: `Failed applying the transformation rules for filename ${filename}. ${error instanceof Error ? error.message : error}`,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
if (transformedExamsResult.applicationErrorMessages.length > 0) {
|
|
354
|
+
transformationRulesErrors = transformedExamsResult.applicationErrorMessages;
|
|
355
|
+
labToOhtContract.errorMessages.push({
|
|
356
|
+
destination: { slack: false, notes: true, bi: false },
|
|
357
|
+
message: `Failed applying some transformation rules:\n${transformedExamsResult.applicationErrorMessages.map((e) => ` - ${e}`).join("\n\n")}`,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
const transformedExams = transformedExamsResult.transformedExams;
|
|
361
|
+
const transformedExamsMap = transformedExams.reduce((map, exam) => map.set(exam.ohtExam.labKey, exam), new Map());
|
|
362
|
+
const allPossibleOHTBmIds = [];
|
|
363
|
+
[
|
|
364
|
+
...Object.values(labToOhtContract.labToOhtList)
|
|
365
|
+
].forEach(labToOhtMapper => {
|
|
366
|
+
if (labToOhtMapper.ohtBmId) {
|
|
367
|
+
allPossibleOHTBmIds.push(labToOhtMapper.ohtBmId);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
// data to request api
|
|
371
|
+
const requestData = {
|
|
372
|
+
"biomarkerIds": allPossibleOHTBmIds,
|
|
373
|
+
"page": 1,
|
|
374
|
+
"pageSize": allPossibleOHTBmIds.length
|
|
375
|
+
};
|
|
376
|
+
// api call to ohtCore to find biomarkers.
|
|
377
|
+
const biomarkers = await (0, apiUtils_1.makeApiCallWithRetry)('post', `${OHT_CORE_URL}/v1/biomarker/biomarkers`, requestData, ohtCoreApiKey);
|
|
378
|
+
// Fetch synonym units from API if enabled
|
|
379
|
+
let synonymUnits = null;
|
|
380
|
+
if (partnerId) {
|
|
381
|
+
synonymUnits = await (0, dataUtils_1.fetchSynonymUnits)(partnerId, ohtCoreApiKey);
|
|
382
|
+
// If API fetch failed or returned empty, set to null to use hardcoded fallback
|
|
383
|
+
if (synonymUnits.length === 0) {
|
|
384
|
+
synonymUnits = null;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
labToOhtContract.labToOhtList.forEach((labToOhtMapper) => {
|
|
388
|
+
let isMeasurementCorrectlyParsed = true;
|
|
389
|
+
if (!labToOhtMapper.ohtExam) {
|
|
390
|
+
labToOhtContract.errorMessages.push({
|
|
391
|
+
destination: { slack: true, notes: false, bi: false },
|
|
392
|
+
message: `Missing ohtExam for labKey: ${labToOhtMapper.ohtExam?.labKey || 'unknown'} filename: ${filename}`,
|
|
393
|
+
});
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
// Get the transformed exam for this labKey, or use the original ohtExam
|
|
397
|
+
const transformedExam = transformedExamsMap.get(labToOhtMapper.ohtExam.labKey);
|
|
398
|
+
const examObj = transformedExam ? transformedExam.ohtExam : labToOhtMapper.ohtExam;
|
|
399
|
+
if (labToOhtMapper?.ohtBmId && labToOhtMapper?.ohtBmId !== -1) {
|
|
400
|
+
// if BM is already in measurements, continue to the next one
|
|
401
|
+
if (measurements.some(measurement => measurement.biomarkerId === labToOhtMapper.ohtBmId)) {
|
|
402
|
+
logger.warn({ labToOhtMapper }, `Biomarker already in measurements array, should investigate, filename: ${filename}`);
|
|
403
|
+
labToOhtContract.errorMessages.push({
|
|
404
|
+
destination: { slack: false, notes: false, bi: true },
|
|
405
|
+
message: `Biomarkers Duplicated keys:[PLACEHOLDER]`,
|
|
406
|
+
item: `bmId:${labToOhtMapper.ohtBmId}, labKey:${examObj.labKey}`
|
|
407
|
+
});
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const ohtBiomarker = biomarkers?.data?.items.find((bm) => bm.id === labToOhtMapper.ohtBmId);
|
|
411
|
+
// Used for error messages
|
|
412
|
+
const bmInfo = ohtBiomarker?.acf?.shortName ?
|
|
413
|
+
`name:${ohtBiomarker.acf.shortName}, bmId:${labToOhtMapper.ohtBmId}, labKey:${examObj.labKey}` :
|
|
414
|
+
`bmId:${labToOhtMapper.ohtBmId}, labKey:${examObj.labKey}`;
|
|
415
|
+
const { unit, isUnitParsedCorrectly, originalUnit, isArbitraryUnit, unknownUnit } = agnosticExtractUnit(examObj, ohtBiomarker, synonymUnits, partnerId);
|
|
416
|
+
if (unknownUnit.length > 0) {
|
|
417
|
+
unknownUnits.push({
|
|
418
|
+
biomarkerId: ohtBiomarker.id,
|
|
419
|
+
unit: unknownUnit,
|
|
420
|
+
partnerId: partnerId,
|
|
421
|
+
labKey: examObj.labKey,
|
|
422
|
+
ohtExam: labToOhtMapper.ohtExam,
|
|
423
|
+
originalExam: labToOhtMapper.originalExam,
|
|
424
|
+
biomarkerName: examObj.mnemonic || '',
|
|
425
|
+
dataImportFileUploadId: null, // is null it will be set later in the structParser.service.ts
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
if (!isUnitParsedCorrectly) {
|
|
429
|
+
logger.warn({ labToOhtMapper }, `Unit not extracted correctly for "${labToOhtMapper.ohtBmId}|${examObj.labKey}", filename: ${filename}`);
|
|
430
|
+
labToOhtContract.errorMessages.push({
|
|
431
|
+
destination: { slack: true, notes: true, bi: true },
|
|
432
|
+
message: `Unit not extracted correctly for:[PLACEHOLDER]`,
|
|
433
|
+
item: `${bmInfo}`
|
|
434
|
+
});
|
|
435
|
+
isMeasurementCorrectlyParsed = false;
|
|
436
|
+
}
|
|
437
|
+
let { valueType, alphanumericalValue, numberValue, valueComparator, isValueParsedCorrectly } = agnosticParseExamValue(examObj, ohtBiomarker);
|
|
438
|
+
if (!isValueParsedCorrectly) {
|
|
439
|
+
logger.warn({ labToOhtMapper }, `Value not extracted correctly for "${labToOhtMapper.ohtBmId}|${examObj.labKey}", filename: ${filename}`);
|
|
440
|
+
labToOhtContract.errorMessages.push({
|
|
441
|
+
destination: { slack: true, notes: true, bi: true },
|
|
442
|
+
message: `Value not extracted correctly for:[PLACEHOLDER]`,
|
|
443
|
+
item: `${bmInfo}`
|
|
444
|
+
});
|
|
445
|
+
isMeasurementCorrectlyParsed = false;
|
|
446
|
+
}
|
|
447
|
+
if ((0, dataUtils_1.isNumericalWithoutValidResult)(valueType, numberValue, alphanumericalValue)) {
|
|
448
|
+
const alphanumericalValueTrimmed = alphanumericalValue?.trim() ?? '';
|
|
449
|
+
const unknownMeasurement = {
|
|
450
|
+
labKey: examObj.labKey,
|
|
451
|
+
biomarkerName: examObj.description ?? '',
|
|
452
|
+
value: alphanumericalValueTrimmed,
|
|
453
|
+
unit: unit ?? '',
|
|
454
|
+
annotation: examObj.annotation ?? '',
|
|
455
|
+
dataOrigin: [{
|
|
456
|
+
itemExtracted: 'measurement',
|
|
457
|
+
method: 'custom-parser',
|
|
458
|
+
methodVersion: 'oht-custom-parser-lib',
|
|
459
|
+
path: 'exams',
|
|
460
|
+
}],
|
|
461
|
+
originalName: examObj.examName ?? '',
|
|
462
|
+
originalExam: {
|
|
463
|
+
contentType: 'application/json',
|
|
464
|
+
exam: JSON.stringify(examObj)
|
|
465
|
+
},
|
|
466
|
+
ohtExam: examObj
|
|
467
|
+
};
|
|
468
|
+
unknownMeasurements.push(unknownMeasurement);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
// Check if the value is plausible
|
|
472
|
+
if (isValueParsedCorrectly && valueType === 'NUMERICAL') {
|
|
473
|
+
const isPlausibleValue = numberValue !== null && agnosticCheckValueForPlausibleValues(labToOhtMapper, ohtBiomarker, unit, numberValue, isUnitParsedCorrectly);
|
|
474
|
+
if (!isPlausibleValue) {
|
|
475
|
+
logger.warn({ labToOhtMapper }, `Value [${numberValue} ${unit}] is not plausible for "${labToOhtMapper.ohtBmId}|${examObj.labKey}", filename: ${filename}`);
|
|
476
|
+
labToOhtContract.errorMessages.push({
|
|
477
|
+
destination: { slack: true, notes: true, bi: true },
|
|
478
|
+
message: `Value is not plausible for:[PLACEHOLDER]`,
|
|
479
|
+
item: `${bmInfo}, value:${numberValue}${unit}`
|
|
480
|
+
});
|
|
481
|
+
isMeasurementCorrectlyParsed = false;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
let from = null, to = null;
|
|
485
|
+
let isRangeParsedCorrectly = true;
|
|
486
|
+
// If the biomarker is numerical, extract the reference range
|
|
487
|
+
if ((0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker)) {
|
|
488
|
+
const extractedRange = agnosticExtractReferenceRanges(labToOhtMapper, examObj, labToOhtContract.patientInfo, labToOhtContract.documentDate);
|
|
489
|
+
from = extractedRange.from ?? null;
|
|
490
|
+
to = extractedRange.to ?? null;
|
|
491
|
+
isRangeParsedCorrectly = extractedRange.isRangeParsedCorrectly;
|
|
492
|
+
if (!isRangeParsedCorrectly) {
|
|
493
|
+
logger.warn({ labToOhtMapper }, `Range not extracted correctly for "${labToOhtMapper.ohtBmId}|${examObj.labKey}", filename: ${filename}`);
|
|
494
|
+
labToOhtContract.errorMessages.push({
|
|
495
|
+
destination: { slack: true, notes: true, bi: true },
|
|
496
|
+
message: `Range not extracted correctly for:[PLACEHOLDER]`,
|
|
497
|
+
item: `${bmInfo}`
|
|
498
|
+
});
|
|
499
|
+
isMeasurementCorrectlyParsed = false;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
let extractedAnnotation;
|
|
503
|
+
if (labToOhtMapper?.referenceAsAnnotation?.use || labToOhtMapper?.annotationConfig?.enabled) {
|
|
504
|
+
extractedAnnotation = agnosticExtractReferenceAnnotation(labToOhtMapper, examObj, labToOhtContract.patientInfo, labToOhtContract.documentDate, transformedExams);
|
|
505
|
+
}
|
|
506
|
+
// Use material and method directly from ohtExam
|
|
507
|
+
const material = examObj?.material ?? '';
|
|
508
|
+
const method = examObj?.method ?? '';
|
|
509
|
+
let alphaValue = !(0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker) && alphanumericalValue
|
|
510
|
+
? alphanumericalValue.trim()
|
|
511
|
+
: '';
|
|
512
|
+
// adding unit for alphanumerical values as number.
|
|
513
|
+
if (!Number.isNaN(parseFloat(alphaValue))) {
|
|
514
|
+
// Use unit directly from ohtExam
|
|
515
|
+
let originalUnit = examObj?.unit ?? '';
|
|
516
|
+
originalUnit = originalUnit?.replaceAll(/ /g, '') ?? '';
|
|
517
|
+
alphaValue = alphaValue && unit?.length > 0 ? `${alphaValue} ${originalUnit}`.trim() : alphaValue;
|
|
518
|
+
}
|
|
519
|
+
// adding dates for measurements in ISO 8601 format
|
|
520
|
+
const collectionDate = examObj.collectionDate ? new Date(examObj.collectionDate).toISOString() : null;
|
|
521
|
+
const effectiveDate = examObj.effectiveDate ? new Date(examObj.effectiveDate).toISOString() : null;
|
|
522
|
+
const examCollectionDate = examObj.examCollectionDate ? new Date(examObj.examCollectionDate).toISOString() : null;
|
|
523
|
+
const examEffectiveDate = examObj.examEffectiveDate ? new Date(examObj.examEffectiveDate).toISOString() : null;
|
|
524
|
+
// add original name for document search
|
|
525
|
+
const originalName = examObj.examName ?? '';
|
|
526
|
+
let measurement = {
|
|
527
|
+
biomarkerId: ohtBiomarker.id,
|
|
528
|
+
valueType,
|
|
529
|
+
value: (0, dataUtils_1.isBiomarkerValueNumerical)(ohtBiomarker) ? numberValue : null,
|
|
530
|
+
alphanumericValue: alphaValue,
|
|
531
|
+
rangeAnnotation: extractedAnnotation ? extractedAnnotation : null,
|
|
532
|
+
showVisualisationIfAnnotated: false, // TODO: WHAT SHOULD BE THE DEFAULT VALUE?
|
|
533
|
+
comparator: valueComparator ?? oht_types_1.MeasurementValueComparator.EQUAL,
|
|
534
|
+
minNormalValue: from,
|
|
535
|
+
maxNormalValue: to,
|
|
536
|
+
unit,
|
|
537
|
+
originalUnit,
|
|
538
|
+
isArbitraryUnit,
|
|
539
|
+
material,
|
|
540
|
+
method,
|
|
541
|
+
isDigitalizationApproved: isMeasurementCorrectlyParsed,
|
|
542
|
+
isManualChecked: isMeasurementCorrectlyParsed,
|
|
543
|
+
collectionDate: collectionDate,
|
|
544
|
+
effectiveDate: effectiveDate,
|
|
545
|
+
examCollectionDate: examCollectionDate,
|
|
546
|
+
examEffectiveDate: examEffectiveDate,
|
|
547
|
+
originalName: originalName,
|
|
548
|
+
};
|
|
549
|
+
measurements.push(measurement);
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
const labKey = examObj.labKey;
|
|
553
|
+
logger.warn(`Created an ungroupedBiomarker for id: ${labKey}, filename: ${filename}`);
|
|
554
|
+
labToOhtContract.errorMessages.push({
|
|
555
|
+
destination: { slack: false, notes: false, bi: true },
|
|
556
|
+
message: `Created ungroupedBiomarkers for:[PLACEHOLDER]`,
|
|
557
|
+
item: `labKey:${labKey}`
|
|
558
|
+
});
|
|
559
|
+
const biomarkerName = labToOhtMapper?.unknownMeasurement?.biomarkerName ?? '';
|
|
560
|
+
const value = labToOhtMapper?.unknownMeasurement?.value ?? '';
|
|
561
|
+
const unit = labToOhtMapper?.unknownMeasurement?.unit ?? '';
|
|
562
|
+
const annotation = labToOhtMapper?.unknownMeasurement?.annotation ?? '';
|
|
563
|
+
const originalName = labToOhtMapper?.unknownMeasurement?.originalName ?? '';
|
|
564
|
+
const originalExam = labToOhtMapper?.unknownMeasurement?.originalExam
|
|
565
|
+
? {
|
|
566
|
+
contentType: typeof labToOhtMapper.unknownMeasurement.originalExam.contentType === 'string'
|
|
567
|
+
? labToOhtMapper.unknownMeasurement.originalExam.contentType
|
|
568
|
+
: '',
|
|
569
|
+
exam: typeof labToOhtMapper.unknownMeasurement.originalExam.exam === 'string'
|
|
570
|
+
? labToOhtMapper.unknownMeasurement.originalExam.exam
|
|
571
|
+
: String(labToOhtMapper.unknownMeasurement.originalExam.exam || '')
|
|
572
|
+
}
|
|
573
|
+
: { contentType: '', exam: '' };
|
|
574
|
+
const ohtExam = labToOhtMapper?.unknownMeasurement?.ohtExam
|
|
575
|
+
? labToOhtMapper.unknownMeasurement.ohtExam
|
|
576
|
+
: { labKey: '', value: '', unit: '', collectionDate: '', documentDate: '', description: '', mnemonic: '', examName: '', range: [], annotation: '' };
|
|
577
|
+
const dataOrigin = labToOhtMapper?.unknownMeasurement?.dataOrigin
|
|
578
|
+
? [labToOhtMapper?.unknownMeasurement?.dataOrigin]
|
|
579
|
+
: [{ path: '' }];
|
|
580
|
+
const unknownMeasurement = {
|
|
581
|
+
labKey: labKey,
|
|
582
|
+
biomarkerName: biomarkerName,
|
|
583
|
+
value: value,
|
|
584
|
+
unit: unit,
|
|
585
|
+
annotation: annotation,
|
|
586
|
+
dataOrigin: dataOrigin,
|
|
587
|
+
originalName: originalName,
|
|
588
|
+
originalExam: originalExam,
|
|
589
|
+
ohtExam: ohtExam
|
|
590
|
+
};
|
|
591
|
+
unknownMeasurements.push(unknownMeasurement);
|
|
592
|
+
}
|
|
593
|
+
isReportCorrectlyParsed = isReportCorrectlyParsed && isMeasurementCorrectlyParsed;
|
|
594
|
+
});
|
|
595
|
+
return {
|
|
596
|
+
measurements,
|
|
597
|
+
unknownMeasurements,
|
|
598
|
+
unknownUnits,
|
|
599
|
+
isReportCorrectlyParsed,
|
|
600
|
+
transformationRulesErrors,
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
//# sourceMappingURL=ohtAgnosticMeasurementsExtractor.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ohtAgnosticMeasurementsExtractor.service.js","sourceRoot":"","sources":["../../service/ohtAgnosticMeasurementsExtractor.service.ts"],"names":[],"mappings":";;;;;AA4yBE,4EAAgC;AAChC,oFAAoC;AACpC,wEAA8B;AAC9B,gFAAkC;AAClC,wDAAsB;AACtB,kDAAmB;AACnB,4FAAwC;AA1yB1C,oDAAmK;AACnK,sDAAmF;AACnF,gEAAsD;AACtD,uEAA+C;AAC/C,kDAAyD;AACzD,kDAQ4B;AAC5B,+EAAyD;AACzD,6EAA6D;AAE7D,MAAM,MAAM,GAAG,IAAA,oBAAU,GAAE,CAAC;AAC5B,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AAC9C,IAAI,QAAQ,GAAG,EAAE,CAAC;AAElB;;;;;;GAMG;AACH,SAAS,mBAAmB,CAC1B,OAAY,EACZ,YAAuB,EACvB,eAAqC,IAAI,EACzC,YAAuC,IAAI;IAE3C,IAAI,CAAC,IAAA,qCAAyB,EAAC,YAAY,CAAC,EAAE,CAAC;QAC7C,OAAO,EAAC,IAAI,EAAE,MAAM,EAAE,qBAAqB,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAC,CAAC;IAChH,CAAC;IAED,MAAM,eAAe,GAAG,YAAY,CAAC,GAAG,CAAC,wBAAwB,KAAK,SAAS,CAAC;IAChF,IAAI,YAAY,GAAG,EAAE,CAAC;IAEtB,iCAAiC;IACjC,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC;IACjC,IAAI,aAAa,GAAG,IAAI,EAAE,WAAW,EAAE,CAAC;IACxC,aAAa,GAAG,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;IAE1D,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,CAAC,YAAY,CAAA;IAClD,MAAM,aAAa,GAAG;QACpB,YAAY,EAAE,WAAW,EAAE;QAC3B,GAAG,YAAY,CAAC,GAAG,EAAE,gBAAgB;YACnC,EAAE,GAAG,CAAC,CAAC,aAAa,EAAE,EAAE,CACtB,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,CACjC,IAAI,EAAE;KACV,CAAC;IAEF,8HAA8H;IAC9H,IAAI,eAAe,EAAE,CAAC;QACpB,YAAY,GAAG,IAAI,CAAC;QACpB,OAAO,EAAC,IAAI,EAAE,YAAY,EAAE,qBAAqB,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,EAAE,EAAC,CAAC;IAC1I,CAAC;IAED,yEAAyE;IACzE,MAAM,uBAAuB,GAAG,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACtE,IAAI,aAAa,EAAE,MAAM,GAAG,CAAC,IAAI,uBAAuB,EAAE,CAAC;QACzD,uEAAuE;QACvE,IAAI,WAAW,GAAG,YAAY,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,aAAa;YAClF,CAAC,CAAC,YAAY,EAAE,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,CAAC,CAAC,YAAY,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,CACtC,CAAC,aAAa,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,aAAa,CAC3F,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAElC,mFAAmF;QACnF,WAAW,GAAG,WAAW,IAAI,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAExD,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,qBAAqB,EAAE,IAAI;YAC3B,YAAY,EAAE,YAAY;YAC1B,eAAe,EAAE,eAAe;YAChC,WAAW,EAAE,EAAE;SAChB,CAAC;IACJ,CAAC;IAGD,4CAA4C;IAC5C,IAAI,aAAa,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,IAAI,YAAY,GAAkB,IAAI,CAAC;QAEvC,IAAI,YAAY,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,MAAM,QAAQ,GAAG,IAAA,mCAAuB,EACtC,aAAa,EACb,YAAY,CAAC,EAAE,EACf,SAAS,EACT,YAAY,CACb,CAAC;YACF,IAAI,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;gBAC1C,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC;YACrC,CAAC;QACH,CAAC;QAED,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,+BAA+B,GAAG,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;YAC3F,IAAI,+BAA+B,EAAE,CAAC;gBACpC,OAAO,EAAC,IAAI,EAAE,YAAY,EAAE,qBAAqB,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,EAAE,EAAC,CAAC;YAC1I,CAAC;QACH,CAAC;IACH,CAAC;IAID,gFAAgF;IAChF,OAAO,EAAC,IAAI,EAAE,EAAE,EAAE,qBAAqB,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAC,CAAC;AAC/G,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,kCAAkC,CAAC,cAA8B,EAAE,OAAY,EAAE,WAAwB,EAAE,YAAmB,EAAE,KAAc;IACrJ,IAAI,UAAU,GAAW,EAAE,CAAC;IAE5B,uEAAuE;IACvE,IAAI,cAAc,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;QAC9C,MAAM,cAAc,GAAG,IAAA,mCAAuB,EAAC,KAAK,EAAE,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE;YACvG,SAAS,EAAE,cAAc,CAAC,gBAAgB,CAAC,SAAS;YACpD,aAAa,EAAE,cAAc,CAAC,gBAAgB,CAAC,aAAa;YAC5D,SAAS,EAAE,cAAc,CAAC,gBAAgB,CAAC,SAAS;SACrD,CAAC,CAAC;QACH,IAAI,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;YAChC,UAAU,IAAI,cAAc,CAAC,IAAI,CAAC;QACpC,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,MAAM,kBAAkB,GAAG,OAAO,EAAE,UAAU,IAAI,EAAE,CAAC;IACrD,IAAI,kBAAkB,EAAE,MAAM,EAAE,CAAC;QAC/B,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,kBAAkB,EAAE,CAAC,CAAC,CAAC,kBAAkB,CAAC;IAC5E,CAAC;IAED,OAAO,UAAU,IAAI,SAAS,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,SAAS,8BAA8B,CAAC,cAA8B,EAAE,OAAY,EAAE,WAAwB,EAAE,YAAmB;IACjI,MAAM,2BAA2B,GAA4B,EAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,KAAK,EAAC,CAAC;IACnH,MAAM,wBAAwB,GAA4B,EAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAC,CAAC;IAE/G,wDAAwD;IACxD,IAAI,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,CAAC;QACtD,OAAO,wBAAwB,CAAC;IAClC,CAAC;IAED,sDAAsD;IACtD,MAAM,qBAAqB,GAAG,IAAA,4BAAU,EAAC,OAAO,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;IAC/E,IAAI,qBAAqB,CAAC,sBAAsB,EAAE,CAAC;QACjD,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAED,OAAO,2BAA2B,CAAC;AACrC,CAAC;AAED,SAAS,wCAAwC,CAAC,KAAa;IAK7D,sDAAsD;IACtD,MAAM,mBAAmB,GAAG,IAAA,mCAAsB,GAAE,CAAC;IACrD,MAAM,iBAAiB,GAAG,IAAA,iCAAoB,GAAE,CAAC;IAEjD,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAE5B,KAAK,MAAM,OAAO,IAAI,mBAAmB,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;YAC1D,MAAM,eAAe,GAAG,sCAA0B,CAAC,YAAY,CAAC;YAChE,OAAO;gBACL,cAAc,EAAE,KAAK;gBACrB,wBAAwB,EAAE,eAAe;gBACzC,oBAAoB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;aAC3C,CAAC;QACJ,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;YAC1D,MAAM,eAAe,GAAG,sCAA0B,CAAC,SAAS,CAAC;YAC7D,OAAO;gBACL,cAAc,EAAE,KAAK;gBACrB,wBAAwB,EAAE,eAAe;gBACzC,oBAAoB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;aAC3C,CAAC;QACJ,CAAC;IACH,CAAC;IAED,iHAAiH;IACjH,OAAO,EAAC,cAAc,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAC,CAAC;AAC7F,CAAC;AAED;;;GAGG;AACH,SAAS,sBAAsB,CAAC,UAAe,EAAE,YAAuB;IAOtE,kCAAkC;IAClC,IAAI,KAAK,GAAG,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC;IAEpC,qCAAqC;IACrC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,EAAE,CAAC;IACb,CAAC;IAED,qDAAqD;IACrD,MAAM,SAAS,GAAG,IAAA,qCAAyB,EAAC,YAAY,CAAC;QACvD,CAAC,CAAC,8BAAkB,CAAC,SAAS;QAC9B,CAAC,CAAC,8BAAkB,CAAC,cAAc,CAAC;IAEtC,IAAI,mBAAmB,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACvD,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAI,CAAC;IAET,IACE,SAAS,KAAK,8BAAkB,CAAC,cAAc;WAC5C,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EACnC,CAAC;QACD,gCAAgC;QAChC,mBAAmB,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;IACzC,CAAC;IAED,IACE,SAAS,KAAK,8BAAkB,CAAC,SAAS;WACvC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAClC,CAAC;QACD,gCAAgC;QAChC,MAAM,EAAC,cAAc,EAAE,wBAAwB,EAAE,oBAAoB,EAAC,GAAG,wCAAwC,CAAC,KAAK,CAAC,CAAC;QACzH,OAAO;YACL,SAAS;YACT,mBAAmB;YACnB,WAAW,EAAE,cAAc;YAC3B,eAAe,EAAE,wBAAwB,IAAI,sCAA0B,CAAC,KAAK;YAC7E,sBAAsB,EAAE,oBAAoB;SAC7C,CAAC;IACJ,CAAC;IAED,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;QAC9B,OAAO;YACL,SAAS;YACT,mBAAmB;YACnB,WAAW,EAAE,UAAU,CAAC,KAAK,CAAC;YAC9B,eAAe,EAAE,sCAA0B,CAAC,KAAK;YACjD,sBAAsB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;SACzD,CAAC;IACJ,CAAC;IAED,IAAI,SAAS,KAAK,gBAAgB,EAAE,CAAC;QACnC,OAAO;YACL,SAAS;YACT,mBAAmB;YACnB,WAAW,EAAE,UAAU,CAAC,KAAK,CAAC;YAC9B,eAAe,EAAE,sCAA0B,CAAC,KAAK;YACjD,sBAAsB,EAAE,OAAO,CAAC,mBAAmB,CAAC;SACrD,CAAC;IACJ,CAAC;IAED,OAAO;QACL,SAAS;QACT,mBAAmB;QACnB,WAAW,EAAE,IAAI;QACjB,eAAe,EAAE,sCAA0B,CAAC,KAAK;QACjD,sBAAsB,EAAE,KAAK;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,oCAAoC,CAAC,cAA8B,EAAE,YAAuB,EAAE,IAAY,EAAE,KAAa,EAAE,qBAA8B;IAChK,IAAI,CAAC,IAAA,qCAAyB,EAAC,YAAY,CAAC,IAAI,qBAAqB,EAAE,CAAC;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC;IACnD,MAAM,mBAAmB,GAAG,YAAY,CAAC,GAAG,CAAC,sBAAsB,CAAC;IACpE,MAAM,mBAAmB,GAAG,YAAY,CAAC,GAAG,CAAC,0BAA0B,CAAC;IACxE,MAAM,yBAAyB,GAAG,YAAY,CAAC,GAAG,EAAE,eAAe,IAAI,CAAC,CAAC;IAEzE,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,MAAM,eAAe,GAAG,CACtB,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,EAAE,gBAAgB,CAAC;YAC/C,CAAC,CAAC,YAAY,CAAC,GAAG,EAAE,gBAAgB;YACpC,CAAC,CAAC,EAAE,CACP,EAAE,IAAI,CACL,CAAC,OAA0B,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CACtD,CAAC;QAEF,IAAI,eAAe,EAAE,CAAC;YACpB,MAAM,gBAAgB,GAAG,eAAe,CAAC,gBAAgB,CAAC;YAE1D,KAAK,GAAG,CAAC,CACP,KAAK,GAAG,gBAAgB,CACzB,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,MAAM,gBAAgB,GAAG,KAAK,IAAI,mBAAmB,IAAI,KAAK,IAAI,mBAAmB,CAAC;IAEtF,oCAAoC;IACpC,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,CACT,EAAC,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAC,EACzF,UAAU,KAAK,IAAI,YAAY,oBAAoB,mBAAmB,OAAO,mBAAmB,UAAU,cAAc,CAAC,OAAO,QAAQ,cAAc,CAAC,OAAO,CAAC,MAAM,gBAAgB,QAAQ,EAAE,CAChM,CAAC;IACJ,CAAC;IAED,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAOD;;;;;;;;GAQG;AACH,KAAK,UAAU,+BAA+B,CAC5C,KAAa,EACb,mBAA8C,EAC9C,WAAwB,EACxB,YAAmB;IAEnB,IAAI,mBAAmB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO;YACL,gBAAgB,EAAE,KAAK;YACvB,wBAAwB,EAAE,EAAE;SAC7B,CAAC;IACJ,CAAC;IAED,MAAM,gBAAgB,GAAW,EAAE,CAAC;IAEpC,2CAA2C;IAC3C,MAAM,aAAa,GAAG;QACpB,OAAO,EAAE;YACP,GAAG,EAAE,WAAW,CAAC,GAAG;YACpB,SAAS,EAAE,WAAW,CAAC,SAAS;YAChC,GAAG,EAAE,IAAA,0CAAa,EAAC,YAAY,EAAE,WAAW,CAAC,SAAS,CAAC;SACxD;KACF,CAAC;IAEF,4BAA4B;IAC5B,MAAM,SAAS,GAAG;QAChB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;KACjC,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,EAAE,UAAU,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,EAAE,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAC7E,2CAA2C,CAC5C,CAAC;IAEF,IAAI,qBAAqB,GAAG,CAAC,CAAC;IAC9B,IAAI,uBAAuB,GAAG,CAAC,CAAC;IAEhC,MAAM,wBAAwB,GAAa,EAAE,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;QACnC,MAAM,UAAU,GAAG,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEnD,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3C,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5B,SAAS;QACX,CAAC;QAED,qBAAqB,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAA,wCAAU,EAC7B,UAAU,EACV,IAAI,CAAC,OAA6C,EAClD;gBACE,aAAa,EAAE,SAAS;gBACxB,WAAW,EAAE,aAAa;aAC3B,CACF,CAAC;YAEF,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CACT,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,EAC3C,oDAAoD,CACrD,CAAC;gBAEF,wBAAwB,CAAC,IAAI,CAC3B,GAAG,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACtF,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACnC,uBAAuB,EAAE,CAAC;gBAC5B,CAAC;gBAED,MAAM,CAAC,IAAI,CACT,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,EAC9D,kDAAkD,CACnD,CAAC;gBAEF,wFAAwF;gBACxF,gBAAgB,CAAC,IAAI,CAAC;oBACpB,OAAO,EAAE,MAAM,CAAC,IAAsC;oBACtD,YAAY,EAAE,IAAI,CAAC,YAAY;iBAChC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CACV,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,EAC3B,kDAAkD,CACnD,CAAC;YAEF,wBAAwB,CAAC,IAAI,CAAC,GAAG,MAAM,6BAA6B,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC;QACV,QAAQ;QACR,UAAU,EAAE,KAAK,CAAC,MAAM;QACxB,WAAW,EAAE,mBAAmB,CAAC,IAAI;QACrC,uBAAuB;QACvB,qBAAqB;KACtB,EAAE,kDAAkD,CAAC,CAAC;IAEvD,OAAO;QACL,gBAAgB;QAChB,wBAAwB;KACzB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,gCAAgC,CAC7C,gBAAkC,EAClC,KAAa,EACb,mBAA8C,EAC9C,aAAqB,EACrB,SAAqC;IAErC,QAAQ,GAAG,gBAAgB,CAAC,cAAc,CAAC;IAC3C,MAAM,YAAY,GAAkB,EAAE,CAAC;IACvC,MAAM,mBAAmB,GAAyB,EAAE,CAAC;IACrD,MAAM,YAAY,GAAmB,EAAE,CAAC;IACxC,IAAI,uBAAuB,GAAG,IAAI,CAAC;IACnC,IAAI,yBAAyB,GAAa,EAAE,CAAC;IAE7C,0CAA0C;IAC1C,IAAI,sBAAsB,GAAmC,EAAE,gBAAgB,EAAE,EAAE,EAAE,wBAAwB,EAAE,EAAE,EAAE,CAAC;IACpH,IAAI,CAAC;QACH,sBAAsB,GAAG,MAAM,+BAA+B,CAC5D,KAAK,EACL,mBAAmB,EACnB,gBAAgB,CAAC,WAAW,EAC5B,gBAAgB,CAAC,YAAY,CAC9B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,+DAA+D,CAAC,CAAC;QAEnG,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;YAClC,WAAW,EAAE,EAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE;YACnD,OAAO,EAAE,yDAAyD,QAAQ,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE;SAChI,CAAC,CAAC;IACL,CAAC;IACD,IAAI,sBAAsB,CAAC,wBAAwB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/D,yBAAyB,GAAG,sBAAsB,CAAC,wBAAwB,CAAC;QAE5E,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;YAClC,WAAW,EAAE,EAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE;YACpD,OAAO,EAAE,+CAA+C,sBAAsB,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;SAC9I,CAAC,CAAC;IACL,CAAC;IAED,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,gBAAgB,CAAC;IACjE,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,MAAM,CACjD,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAgB,CAC3E,CAAC;IAEF,MAAM,mBAAmB,GAAa,EAAE,CAAC;IACzC;QACE,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,YAAY,CAAC;KAChD,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE;QACzB,IAAI,cAAc,CAAC,OAAO,EAAE,CAAC;YAC3B,mBAAmB,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,sBAAsB;IACtB,MAAM,WAAW,GAAG;QAClB,cAAc,EAAE,mBAAmB;QACnC,MAAM,EAAE,CAAC;QACT,UAAU,EAAE,mBAAmB,CAAC,MAAM;KACvC,CAAA;IAED,0CAA0C;IAC1C,MAAM,UAAU,GAAG,MAAM,IAAA,+BAAoB,EAC3C,MAAM,EACN,GAAG,YAAY,0BAA0B,EACzC,WAAW,EACX,aAAa,CACd,CAAC;IAEF,0CAA0C;IAC1C,IAAI,YAAY,GAAyB,IAAI,CAAC;IAC9C,IAAI,SAAS,EAAE,CAAC;QACd,YAAY,GAAG,MAAM,IAAA,6BAAiB,EAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QACjE,+EAA+E;QAC/E,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,YAAY,GAAG,IAAI,CAAC;QACtB,CAAC;IACH,CAAC;IAED,gBAAgB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,cAAc,EAAE,EAAE;QACvD,IAAI,4BAA4B,GAAG,IAAI,CAAC;QACxC,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;YAC5B,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;gBAClC,WAAW,EAAE,EAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAC,KAAK,EAAE;gBACnD,OAAO,EAAE,+BAA+B,cAAc,CAAC,OAAO,EAAE,MAAM,IAAI,SAAS,cAAc,QAAQ,EAAE;aAC5G,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,wEAAwE;QACxE,MAAM,eAAe,GAAG,mBAAmB,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/E,MAAM,OAAO,GAAG,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC;QAEnF,IAAI,cAAc,EAAE,OAAO,IAAI,cAAc,EAAE,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;YAC9D,6DAA6D;YAC7D,IAAI,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,WAAW,CAAC,WAAW,KAAK,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzF,MAAM,CAAC,IAAI,CACT,EAAC,cAAc,EAAC,EAChB,0EAA0E,QAAQ,EAAE,CACrF,CAAC;gBACF,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;oBAClC,WAAW,EAAE,EAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAC,IAAI,EAAE;oBACnD,OAAO,EAAE,0CAA0C;oBACnD,IAAI,EAAE,QAAQ,cAAc,CAAC,OAAO,YAAY,OAAO,CAAC,MAAM,EAAE;iBACjE,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,MAAM,YAAY,GAAG,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,EAElD,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,cAAc,CAAC,OAAO,CAAC,CAAA;YAEvC,0BAA0B;YAC1B,MAAM,MAAM,GAAI,YAAY,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;gBAC5C,QAAQ,YAAY,CAAC,GAAG,CAAC,SAAS,UAAU,cAAc,CAAC,OAAO,YAAY,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;gBAChG,QAAQ,cAAc,CAAC,OAAO,YAAY,OAAO,CAAC,MAAM,EAAE,CAAC;YAE7D,MAAM,EAAC,IAAI,EAAE,qBAAqB,EAAE,YAAY,EAAE,eAAe,EAAE,WAAW,EAAC,GAAG,mBAAmB,CACnG,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,SAAS,CACV,CAAC;YAEF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3B,YAAY,CAAC,IAAI,CAAC;oBAChB,WAAW,EAAE,YAAY,CAAC,EAAE;oBAC5B,IAAI,EAAE,WAAW;oBACjB,SAAS,EAAE,SAAS;oBACpB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,OAAO,EAAE,cAAc,CAAC,OAAO;oBAC/B,YAAY,EAAE,cAAc,CAAC,YAAY;oBACzC,aAAa,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;oBACrC,sBAAsB,EAAE,IAAI,EAAE,8DAA8D;iBAC7F,CAAC,CAAC;YACL,CAAC;YAED,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC3B,MAAM,CAAC,IAAI,CACT,EAAC,cAAc,EAAC,EAChB,qCAAqC,cAAc,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,gBAAgB,QAAQ,EAAE,CACxG,CAAC;gBACF,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;oBAClC,WAAW,EAAE,EAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAC,IAAI,EAAE;oBACjD,OAAO,EAAE,gDAAgD;oBACzD,IAAI,EAAE,GAAG,MAAM,EAAE;iBAClB,CAAC,CAAC;gBACH,4BAA4B,GAAG,KAAK,CAAC;YACvC,CAAC;YAED,IAAI,EACF,SAAS,EACT,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,sBAAsB,EACvB,GAAG,sBAAsB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YAClD,IAAI,CAAC,sBAAsB,EAAE,CAAC;gBAC5B,MAAM,CAAC,IAAI,CACT,EAAC,cAAc,EAAC,EAChB,sCAAsC,cAAc,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,gBAAgB,QAAQ,EAAE,CACzG,CAAC;gBACF,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;oBAClC,WAAW,EAAE,EAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE;oBAClD,OAAO,EAAE,iDAAiD;oBAC1D,IAAI,EAAE,GAAG,MAAM,EAAE;iBAClB,CAAC,CAAC;gBACH,4BAA4B,GAAG,KAAK,CAAC;YACvC,CAAC;YAED,IAAI,IAAA,yCAA6B,EAAC,SAAS,EAAE,WAAW,EAAE,mBAAmB,CAAC,EAAE,CAAC;gBAC/E,MAAM,0BAA0B,GAAG,mBAAmB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;gBACnE,MAAM,kBAAkB,GAAG;oBACzB,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,aAAa,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE;oBACxC,KAAK,EAAE,0BAA0B;oBACjC,IAAI,EAAE,IAAI,IAAI,EAAE;oBAChB,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;oBACpC,UAAU,EAAE,CAAC;4BACX,aAAa,EAAE,aAAa;4BAC5B,MAAM,EAAE,eAAe;4BACvB,aAAa,EAAE,uBAAuB;4BACtC,IAAI,EAAE,OAAO;yBACd,CAAC;oBACF,YAAY,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;oBACpC,YAAY,EAAE;wBACZ,WAAW,EAAE,kBAAkB;wBAC/B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;qBAC9B;oBACD,OAAO,EAAE,OAAO;iBACjB,CAAC;gBAEF,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;gBAC7C,OAAO;YACX,CAAC;YAED,kCAAkC;YAClC,IAAI,sBAAsB,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;gBACxD,MAAM,gBAAgB,GAAG,WAAW,KAAK,IAAI,IAAI,oCAAoC,CACnF,cAAc,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,qBAAqB,CACvE,CAAC;gBACF,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACtB,MAAM,CAAC,IAAI,CACT,EAAC,cAAc,EAAC,EAChB,UAAU,WAAW,IAAI,IAAI,2BAA2B,cAAc,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,gBAAgB,QAAQ,EAAE,CAC3H,CAAC;oBACF,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;wBAClC,WAAW,EAAE,EAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAC;wBACjD,OAAO,EAAE,0CAA0C;wBACnD,IAAI,EAAE,GAAG,MAAM,WAAW,WAAW,GAAG,IAAI,EAAE;qBAC/C,CAAC,CAAC;oBACH,4BAA4B,GAAG,KAAK,CAAC;gBACvC,CAAC;YACH,CAAC;YAED,IAAI,IAAI,GAAkB,IAAI,EAAE,EAAE,GAAkB,IAAI,CAAC;YACzD,IAAI,sBAAsB,GAAG,IAAI,CAAC;YAElC,6DAA6D;YAC7D,IAAI,IAAA,qCAAyB,EAAC,YAAY,CAAC,EAAE,CAAC;gBAC5C,MAAM,cAAc,GAAG,8BAA8B,CAAC,cAAc,EAAE,OAAO,EAAE,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAA;gBAC3I,IAAI,GAAG,cAAc,CAAC,IAAI,IAAI,IAAI,CAAC;gBACnC,EAAE,GAAG,cAAc,CAAC,EAAE,IAAI,IAAI,CAAC;gBAC/B,sBAAsB,GAAG,cAAc,CAAC,sBAAsB,CAAC;gBAC/D,IAAI,CAAC,sBAAsB,EAAE,CAAC;oBAC5B,MAAM,CAAC,IAAI,CACT,EAAC,cAAc,EAAC,EAChB,sCAAsC,cAAc,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,gBAAgB,QAAQ,EAAE,CACzG,CAAC;oBACF,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;wBAClC,WAAW,EAAE,EAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE;wBAClD,OAAO,EAAE,iDAAiD;wBAC1D,IAAI,EAAE,GAAG,MAAM,EAAE;qBAClB,CAAC,CAAC;oBACH,4BAA4B,GAAG,KAAK,CAAA;gBACtC,CAAC;YACH,CAAC;YAED,IAAI,mBAAmB,CAAC;YACxB,IAAI,cAAc,EAAE,qBAAqB,EAAE,GAAG,IAAI,cAAc,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;gBAC5F,mBAAmB,GAAG,kCAAkC,CAAC,cAAc,EAAE,OAAO,EAAE,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;YACnK,CAAC;YAED,gDAAgD;YAChD,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;YACrC,IAAI,UAAU,GAAW,CAAC,IAAA,qCAAyB,EAAC,YAAY,CAAC,IAAI,mBAAmB;gBACtF,CAAC,CAAC,mBAAmB,CAAC,IAAI,EAAE;gBAC5B,CAAC,CAAC,EAAE,CAAC;YAEP,mDAAmD;YACnD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;gBAC1C,iCAAiC;gBACjC,IAAI,YAAY,GAAG,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC;gBACvC,YAAY,GAAG,YAAY,EAAE,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;gBACxD,UAAU,GAAG,UAAU,IAAI,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,YAAY,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;YACpG,CAAC;YAED,mDAAmD;YACnD,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACtG,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACnG,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAClH,MAAM,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAE/G,wCAAwC;YACxC,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;YAE5C,IAAI,WAAW,GAAgB;gBAC7B,WAAW,EAAE,YAAY,CAAC,EAAE;gBAC5B,SAAS;gBACT,KAAK,EAAE,IAAA,qCAAyB,EAAC,YAAY,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;gBACnE,iBAAiB,EAAE,UAAU;gBAC7B,eAAe,EAAE,mBAAmB,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI;gBACjE,4BAA4B,EAAE,KAAK,EAAE,0CAA0C;gBAC/E,UAAU,EAAE,eAAe,IAAI,sCAA0B,CAAC,KAAK;gBAC/D,cAAc,EAAE,IAAI;gBACpB,cAAc,EAAE,EAAE;gBAClB,IAAI;gBACJ,YAAY;gBACZ,eAAe;gBACf,QAAQ;gBACR,MAAM;gBACN,wBAAwB,EAAE,4BAA4B;gBACtD,eAAe,EAAE,4BAA4B;gBAC7C,cAAc,EAAE,cAAc;gBAC9B,aAAa,EAAE,aAAa;gBAC5B,kBAAkB,EAAE,kBAAkB;gBACtC,iBAAiB,EAAE,iBAAiB;gBACpC,YAAY,EAAE,YAAY;aAC3B,CAAC;YAEF,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,yCAAyC,MAAM,eAAe,QAAQ,EAAE,CAAC,CAAC;YACtF,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC;gBAClC,WAAW,EAAE,EAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE;gBACpD,OAAO,EAAE,+CAA+C;gBACxD,IAAI,EAAE,UAAU,MAAM,EAAE;aACzB,CAAC,CAAC;YAEH,MAAM,aAAa,GAAG,cAAc,EAAE,kBAAkB,EAAE,aAAa,IAAI,EAAE,CAAC;YAC9E,MAAM,KAAK,GAAG,cAAc,EAAE,kBAAkB,EAAE,KAAK,IAAI,EAAE,CAAC;YAC9D,MAAM,IAAI,GAAG,cAAc,EAAE,kBAAkB,EAAE,IAAI,IAAI,EAAE,CAAC;YAC5D,MAAM,UAAU,GAAG,cAAc,EAAE,kBAAkB,EAAE,UAAU,IAAI,EAAE,CAAC;YACxE,MAAM,YAAY,GAAG,cAAc,EAAE,kBAAkB,EAAE,YAAY,IAAI,EAAE,CAAC;YAC5E,MAAM,YAAY,GAAG,cAAc,EAAE,kBAAkB,EAAE,YAAY;gBACnE,CAAC,CAAC;oBACE,WAAW,EAAE,OAAO,cAAc,CAAC,kBAAkB,CAAC,YAAY,CAAC,WAAW,KAAK,QAAQ;wBACzF,CAAC,CAAC,cAAc,CAAC,kBAAkB,CAAC,YAAY,CAAC,WAAW;wBAC5D,CAAC,CAAC,EAAE;oBACN,IAAI,EAAE,OAAO,cAAc,CAAC,kBAAkB,CAAC,YAAY,CAAC,IAAI,KAAK,QAAQ;wBAC3E,CAAC,CAAC,cAAc,CAAC,kBAAkB,CAAC,YAAY,CAAC,IAAI;wBACrD,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAAC,YAAY,CAAC,IAAI,IAAI,EAAE,CAAC;iBACtE;gBACH,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,cAAc,EAAE,kBAAkB,EAAE,OAAO;gBACzD,CAAC,CAAC,cAAc,CAAC,kBAAkB,CAAC,OAAO;gBAC3C,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YACtJ,MAAM,UAAU,GAAG,cAAc,EAAE,kBAAkB,EAAE,UAAU;gBACjE,CAAC,CAAC,CAAC,cAAc,EAAE,kBAAkB,EAAE,UAAU,CAAC;gBAClD,CAAC,CAAC,CAAC,EAAC,IAAI,EAAE,EAAE,EAAC,CAAC,CAAC;YAEf,MAAM,kBAAkB,GAAG;gBACzB,MAAM,EAAE,MAAM;gBACd,aAAa,EAAE,aAAa;gBAC5B,KAAK,EAAE,KAAK;gBACZ,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,UAAU;gBACtB,UAAU,EAAE,UAAU;gBACtB,YAAY,EAAE,YAAY;gBAC1B,YAAY,EAAE,YAAY;gBAC1B,OAAO,EAAE,OAAO;aACjB,CAAC;YAEF,mBAAmB,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/C,CAAC;QACD,uBAAuB,GAAG,uBAAuB,IAAI,4BAA4B,CAAC;IACpF,CAAC,CAAC,CAAA;IACF,OAAO;QACL,YAAY;QACZ,mBAAmB;QACnB,YAAY;QACZ,uBAAuB;QACvB,yBAAyB;KAC1B,CAAA;AACH,CAAC"}
|
|
@@ -4,6 +4,6 @@ import { UnknownUnits } from '../types/custom-parser.types';
|
|
|
4
4
|
* Posts report preview data (measurements and unknownMeasurements) to OHT Core API.
|
|
5
5
|
* Uses the shared makeApiCallWithRetry helper (Basic auth) from oht-custom-parser-lib.
|
|
6
6
|
*/
|
|
7
|
-
declare function postReportPreviewToCore(reportPreviewId: string, measurements: Measurement[], unknownMeasurements: UnknownMeasurement[], filename: string, unknownUnits: UnknownUnits[], partnerId: string, ohtCoreApiKey: string): Promise<void>;
|
|
7
|
+
declare function postReportPreviewToCore(reportPreviewId: string, measurements: Measurement[], unknownMeasurements: UnknownMeasurement[], filename: string, unknownUnits: UnknownUnits[], partnerId: string, isReportParsedCorrectly: boolean, notes: string, ohtCoreApiKey: string): Promise<void>;
|
|
8
8
|
declare function postDataImportFileUploadToCore(dataImportFileUpload: DataImportFileUpload, unknownMeasurements: UnknownMeasurementsBulk, unknownUnits: UnknownUnits[], rejectedStatus: string | undefined, rejectReason: string | undefined, isReportParsedCorrectly: boolean, filename: string, ohtCoreApiKey: string): Promise<DataImportFileUpload | null>;
|
|
9
9
|
export { postDataImportFileUploadToCore, postReportPreviewToCore };
|
|
@@ -16,10 +16,13 @@ const OHT_CORE_URL = process.env.OHT_CORE_URL;
|
|
|
16
16
|
* Posts report preview data (measurements and unknownMeasurements) to OHT Core API.
|
|
17
17
|
* Uses the shared makeApiCallWithRetry helper (Basic auth) from oht-custom-parser-lib.
|
|
18
18
|
*/
|
|
19
|
-
async function postReportPreviewToCore(reportPreviewId, measurements, unknownMeasurements, filename, unknownUnits, partnerId, ohtCoreApiKey) {
|
|
19
|
+
async function postReportPreviewToCore(reportPreviewId, measurements, unknownMeasurements, filename, unknownUnits, partnerId, isReportParsedCorrectly, notes, ohtCoreApiKey) {
|
|
20
20
|
if (!OHT_CORE_URL) {
|
|
21
21
|
throw new Error(`ERROR: OHT_CORE_URL is required for report preview, filename: ${filename}`);
|
|
22
22
|
}
|
|
23
|
+
let status = isReportParsedCorrectly
|
|
24
|
+
? oht_types_1.DataImportFileUploadStatus.READY
|
|
25
|
+
: oht_types_1.DataImportFileUploadStatus.FOR_REVIEW;
|
|
23
26
|
const apiUrl = `${OHT_CORE_URL}/v1/report-preview/${reportPreviewId}`;
|
|
24
27
|
// send unknown units to the server
|
|
25
28
|
if (unknownUnits.length > 0) {
|
|
@@ -36,9 +39,10 @@ async function postReportPreviewToCore(reportPreviewId, measurements, unknownMea
|
|
|
36
39
|
}
|
|
37
40
|
// Always send both arrays, with empty arrays if no data
|
|
38
41
|
const requestBody = {
|
|
39
|
-
status:
|
|
42
|
+
status: status,
|
|
40
43
|
measurements: measurements || [],
|
|
41
44
|
unknownMeasurements: unknownMeasurements || [],
|
|
45
|
+
notes: notes,
|
|
42
46
|
};
|
|
43
47
|
processingLogger_service_1.processingLogger.logInfo(`postReportPreviewToCore: Sending report preview to OHT Core API (${(measurements || []).length} measurements, ${(unknownMeasurements || []).length} unknownMeasurements), filename: ${filename}`, {
|
|
44
48
|
filename,
|
|
@@ -58,6 +62,7 @@ async function postReportPreviewToCore(reportPreviewId, measurements, unknownMea
|
|
|
58
62
|
http_status: response?.status,
|
|
59
63
|
response_message: typeof responseData?.message === 'string' ? responseData.message : undefined,
|
|
60
64
|
response_status: responseData?.status,
|
|
65
|
+
hasNotes: Boolean(notes?.trim()),
|
|
61
66
|
});
|
|
62
67
|
}
|
|
63
68
|
catch (apiError) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reportCreator.service.js","sourceRoot":"","sources":["../../service/reportCreator.service.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"reportCreator.service.js","sourceRoot":"","sources":["../../service/reportCreator.service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@openhealth/oht-custom-parser-lib",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "Shared nodejs lib with with reusable functions",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"/dist"
|
|
9
|
-
],
|
|
10
|
-
"scripts": {
|
|
11
|
-
"test": "jest"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [],
|
|
14
|
-
"author": "",
|
|
15
|
-
"license": "ISC",
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"@google-cloud/pubsub": "^4.10.0",
|
|
18
|
-
"@google-cloud/storage": "^7.7.0",
|
|
19
|
-
"axios": "^1.13.2",
|
|
20
|
-
"bottleneck": "^2.19.5",
|
|
21
|
-
"dayjs": "^1.11.13",
|
|
22
|
-
"dotenv": "^16.4.5",
|
|
23
|
-
"jsonata": "^2.1.0",
|
|
24
|
-
"moment": "^2.30.1",
|
|
25
|
-
"mongodb": "^6.3.0",
|
|
26
|
-
"pino": "^8.19.0",
|
|
27
|
-
"pino-pretty": "^11.3.0"
|
|
28
|
-
},
|
|
29
|
-
"devDependencies": {
|
|
30
|
-
"@types/jest": "^29.5.14",
|
|
31
|
-
"axios-mock-adapter": "^2.1.0",
|
|
32
|
-
"jest": "^29.7.0",
|
|
33
|
-
"ts-jest": "^29.2.5",
|
|
34
|
-
"typescript": "^5.0.0"
|
|
35
|
-
}
|
|
36
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@openhealth/oht-custom-parser-lib",
|
|
3
|
+
"version": "0.5.4",
|
|
4
|
+
"description": "Shared nodejs lib with with reusable functions",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"/dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "jest"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [],
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@google-cloud/pubsub": "^4.10.0",
|
|
18
|
+
"@google-cloud/storage": "^7.7.0",
|
|
19
|
+
"axios": "^1.13.2",
|
|
20
|
+
"bottleneck": "^2.19.5",
|
|
21
|
+
"dayjs": "^1.11.13",
|
|
22
|
+
"dotenv": "^16.4.5",
|
|
23
|
+
"jsonata": "^2.1.0",
|
|
24
|
+
"moment": "^2.30.1",
|
|
25
|
+
"mongodb": "^6.3.0",
|
|
26
|
+
"pino": "^8.19.0",
|
|
27
|
+
"pino-pretty": "^11.3.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/jest": "^29.5.14",
|
|
31
|
+
"axios-mock-adapter": "^2.1.0",
|
|
32
|
+
"jest": "^29.7.0",
|
|
33
|
+
"ts-jest": "^29.2.5",
|
|
34
|
+
"typescript": "^5.0.0"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/readme.md
CHANGED
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
# oht-custom-parser-lib
|
|
2
|
-
|
|
3
|
-
`oht-custom-parser-lib` is a shared library designed for use across multiple Node.js cloud functions. It contains common MongoDB connectors and data utilities that can be reused to avoid code duplication and ensure consistency.
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Installation](#installation)
|
|
8
|
-
- [Usage](#usage)
|
|
9
|
-
- [Development](#development)
|
|
10
|
-
- [Patch Versions](#patch-versions)
|
|
11
|
-
- [Publish to npm Registry](#publish-to-npm-registry)
|
|
12
|
-
- [Using the Library in Cloud Functions](#using-the-library-in-cloud-functions)
|
|
13
|
-
|
|
14
|
-
## Installation
|
|
15
|
-
|
|
16
|
-
To install `oht-custom-parser-lib`, you can add it as a dependency in your project using npm:
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npm install oht-custom-parser-lib
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Or, if you want to install a specific version:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
npm install oht-custom-parser-lib@<version>
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Usage
|
|
29
|
-
|
|
30
|
-
After installing, you can import and use the library in your cloud functions:
|
|
31
|
-
|
|
32
|
-
```javascript
|
|
33
|
-
const { connectToMongoDB } = require('oht-custom-parser-lib');
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Logging
|
|
37
|
-
|
|
38
|
-
- **Production / GCP**: Logs are emitted as JSON (one line per log) for Cloud Logging.
|
|
39
|
-
- **Local / development**: When `NODE_ENV !== 'production'`, logs are pretty-printed in the terminal (colors, timestamps, readable structure). You can override: `LOG_PRETTY=true` to force pretty output, or `LOG_PRETTY=false` to force JSON when not in production.
|
|
40
|
-
|
|
41
|
-
### Processing logger: request-scoped state
|
|
42
|
-
|
|
43
|
-
The processing logger (`processingLogger`, `runWithContextAsync`, `getRequestIdFromContext`) uses a **registry + facade** so each request has isolated state and logs never leak context between concurrent invocations (e.g. in Cloud Functions).
|
|
44
|
-
|
|
45
|
-
- **Registry**: One `ProcessingState` per request, keyed by request id (`fileUploadId ?? messageId ?? cloudEventId ?? generatedId`). The same id is used for the whole request.
|
|
46
|
-
- **AsyncLocalStorage**: Holds only the current request id; state is resolved via `registry.get(id)`.
|
|
47
|
-
- **Entry point**: Wrap your handler in `runWithContextAsync(context, async () => { ... })`. The lib creates a registry entry, runs your callback with the id in AsyncLocalStorage, and removes the entry in a `finally` block.
|
|
48
|
-
- **Clear-state rule**: If there is no request id or the id is not in the registry (e.g. logging outside `runWithContextAsync` or after teardown), the logger uses a **transient empty state** for that call only (never stored). That way one request never overwrites another’s context.
|
|
49
|
-
|
|
50
|
-
Use `processingLogger.logInfo`, `logWarn`, `logError`, `logProgress`, etc. inside the callback so logs include the same context and are searchable by `fileUploadId` / filename.
|
|
51
|
-
|
|
52
|
-
## Development
|
|
53
|
-
|
|
54
|
-
### Patch Versions
|
|
55
|
-
|
|
56
|
-
When making changes to the `oht-custom-parser-lib`, you need to update the version number before publishing. Follow these steps:
|
|
57
|
-
|
|
58
|
-
1. **Update the version number**: Use npm's version command to bump the version:
|
|
59
|
-
- **Patch** for bug fixes:
|
|
60
|
-
```bash
|
|
61
|
-
npm version patch
|
|
62
|
-
```
|
|
63
|
-
- **Minor** for new features:
|
|
64
|
-
```bash
|
|
65
|
-
npm version minor
|
|
66
|
-
```
|
|
67
|
-
- **Major** for breaking changes:
|
|
68
|
-
```bash
|
|
69
|
-
npm version major
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
This command will automatically update the version in the `package.json` and create a git tag.
|
|
73
|
-
|
|
74
|
-
2. **Commit Changes**: Ensure your changes and the version bump are committed to the repository.
|
|
75
|
-
|
|
76
|
-
### Publish to npm Registry
|
|
77
|
-
|
|
78
|
-
After updating the version, you can publish the library to the npm registry:
|
|
79
|
-
|
|
80
|
-
1. **Login to npm** (if you haven't already):
|
|
81
|
-
```bash
|
|
82
|
-
npm login
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
2. **Publish the package**:
|
|
86
|
-
```bash
|
|
87
|
-
npm publish
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
If this is a private package, use:
|
|
91
|
-
```bash
|
|
92
|
-
npm publish --access restricted
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
3. **Verify the publish**: You can check the package on [npmjs.com](https://www.npmjs.com/) to verify that the new version is available.
|
|
96
|
-
|
|
97
|
-
## Using the Library in Cloud Functions
|
|
98
|
-
|
|
99
|
-
To use `oht-custom-parser-lib` in your cloud functions:
|
|
100
|
-
|
|
101
|
-
1. **Install the Library**: Add `oht-custom-parser-lib` as a dependency in the cloud function's `package.json`:
|
|
102
|
-
|
|
103
|
-
```json
|
|
104
|
-
{
|
|
105
|
-
"dependencies": {
|
|
106
|
-
"oht-custom-parser-lib": "^1.0.0"
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Replace `^1.0.0` with the appropriate version as needed.
|
|
112
|
-
|
|
113
|
-
2. **Install Dependencies**: Run `npm install` to install the library along with other dependencies.
|
|
114
|
-
|
|
115
|
-
3. **Deploy Your Function**: Deploy your cloud function as usual, ensuring that the updated dependencies are included.
|
|
1
|
+
# oht-custom-parser-lib
|
|
2
|
+
|
|
3
|
+
`oht-custom-parser-lib` is a shared library designed for use across multiple Node.js cloud functions. It contains common MongoDB connectors and data utilities that can be reused to avoid code duplication and ensure consistency.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Usage](#usage)
|
|
9
|
+
- [Development](#development)
|
|
10
|
+
- [Patch Versions](#patch-versions)
|
|
11
|
+
- [Publish to npm Registry](#publish-to-npm-registry)
|
|
12
|
+
- [Using the Library in Cloud Functions](#using-the-library-in-cloud-functions)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
To install `oht-custom-parser-lib`, you can add it as a dependency in your project using npm:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install oht-custom-parser-lib
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or, if you want to install a specific version:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install oht-custom-parser-lib@<version>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
After installing, you can import and use the library in your cloud functions:
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
const { connectToMongoDB } = require('oht-custom-parser-lib');
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Logging
|
|
37
|
+
|
|
38
|
+
- **Production / GCP**: Logs are emitted as JSON (one line per log) for Cloud Logging.
|
|
39
|
+
- **Local / development**: When `NODE_ENV !== 'production'`, logs are pretty-printed in the terminal (colors, timestamps, readable structure). You can override: `LOG_PRETTY=true` to force pretty output, or `LOG_PRETTY=false` to force JSON when not in production.
|
|
40
|
+
|
|
41
|
+
### Processing logger: request-scoped state
|
|
42
|
+
|
|
43
|
+
The processing logger (`processingLogger`, `runWithContextAsync`, `getRequestIdFromContext`) uses a **registry + facade** so each request has isolated state and logs never leak context between concurrent invocations (e.g. in Cloud Functions).
|
|
44
|
+
|
|
45
|
+
- **Registry**: One `ProcessingState` per request, keyed by request id (`fileUploadId ?? messageId ?? cloudEventId ?? generatedId`). The same id is used for the whole request.
|
|
46
|
+
- **AsyncLocalStorage**: Holds only the current request id; state is resolved via `registry.get(id)`.
|
|
47
|
+
- **Entry point**: Wrap your handler in `runWithContextAsync(context, async () => { ... })`. The lib creates a registry entry, runs your callback with the id in AsyncLocalStorage, and removes the entry in a `finally` block.
|
|
48
|
+
- **Clear-state rule**: If there is no request id or the id is not in the registry (e.g. logging outside `runWithContextAsync` or after teardown), the logger uses a **transient empty state** for that call only (never stored). That way one request never overwrites another’s context.
|
|
49
|
+
|
|
50
|
+
Use `processingLogger.logInfo`, `logWarn`, `logError`, `logProgress`, etc. inside the callback so logs include the same context and are searchable by `fileUploadId` / filename.
|
|
51
|
+
|
|
52
|
+
## Development
|
|
53
|
+
|
|
54
|
+
### Patch Versions
|
|
55
|
+
|
|
56
|
+
When making changes to the `oht-custom-parser-lib`, you need to update the version number before publishing. Follow these steps:
|
|
57
|
+
|
|
58
|
+
1. **Update the version number**: Use npm's version command to bump the version:
|
|
59
|
+
- **Patch** for bug fixes:
|
|
60
|
+
```bash
|
|
61
|
+
npm version patch
|
|
62
|
+
```
|
|
63
|
+
- **Minor** for new features:
|
|
64
|
+
```bash
|
|
65
|
+
npm version minor
|
|
66
|
+
```
|
|
67
|
+
- **Major** for breaking changes:
|
|
68
|
+
```bash
|
|
69
|
+
npm version major
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This command will automatically update the version in the `package.json` and create a git tag.
|
|
73
|
+
|
|
74
|
+
2. **Commit Changes**: Ensure your changes and the version bump are committed to the repository.
|
|
75
|
+
|
|
76
|
+
### Publish to npm Registry
|
|
77
|
+
|
|
78
|
+
After updating the version, you can publish the library to the npm registry:
|
|
79
|
+
|
|
80
|
+
1. **Login to npm** (if you haven't already):
|
|
81
|
+
```bash
|
|
82
|
+
npm login
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
2. **Publish the package**:
|
|
86
|
+
```bash
|
|
87
|
+
npm publish
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If this is a private package, use:
|
|
91
|
+
```bash
|
|
92
|
+
npm publish --access restricted
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
3. **Verify the publish**: You can check the package on [npmjs.com](https://www.npmjs.com/) to verify that the new version is available.
|
|
96
|
+
|
|
97
|
+
## Using the Library in Cloud Functions
|
|
98
|
+
|
|
99
|
+
To use `oht-custom-parser-lib` in your cloud functions:
|
|
100
|
+
|
|
101
|
+
1. **Install the Library**: Add `oht-custom-parser-lib` as a dependency in the cloud function's `package.json`:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"dependencies": {
|
|
106
|
+
"oht-custom-parser-lib": "^1.0.0"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Replace `^1.0.0` with the appropriate version as needed.
|
|
112
|
+
|
|
113
|
+
2. **Install Dependencies**: Run `npm install` to install the library along with other dependencies.
|
|
114
|
+
|
|
115
|
+
3. **Deploy Your Function**: Deploy your cloud function as usual, ensuring that the updated dependencies are included.
|