UNPKG

@oaklean/profiler-core

Version:

Part of the @oaklean suite. It provides all basic functions to work with the `.oak` file format. It allows parsing the `.oak` file format as well as tools for analyzing the measurement values. It also provides all necessary capabilities required for prec

549 lines 53.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Report = void 0; const BaseModel_1 = require("./BaseModel"); const ModelMap_1 = require("./ModelMap"); const NodeModule_1 = require("./NodeModule"); const SourceFileMetaData_1 = require("./SourceFileMetaData"); const SourceNodeMetaData_1 = require("./SourceNodeMetaData"); const ProfilerConfig_1 = require("./ProfilerConfig"); const SensorValues_1 = require("./SensorValues"); const env_1 = require("../constants/env"); const app_1 = require("../constants/app"); const PermissionHelper_1 = require("../helper/PermissionHelper"); const UnifiedPath_1 = require("../system/UnifiedPath"); const BufferHelper_1 = require("../helper/BufferHelper"); const VersionHelper_1 = require("../helper/VersionHelper"); // Types const types_1 = require("../types"); // global variable to assign an intern id to every report // the intern id is only used to uniquely identify a report within a project report, // since there could be multiple module reports for the same node module (but as a child of another module report) let currentInternID = 0; class Report extends BaseModel_1.BaseModel { constructor(moduleIndex, kind) { super(); this.reportVersion = app_1.VERSION; this.kind = kind; this.moduleIndex = moduleIndex; this.internID = currentInternID++; } /** * Resolve a source node ID to its corresponding source node metadata within this report. * @param report - The report to which the source node belongs (necessary for lang internal and extern). * @param globalIndex - The global index of the project report. * @param sourceNodeID - The unique identifier of the source node to resolve. * @returns An object containing either the resolved report, source file metadata, and source node metadata, * or an error indication if the resolution fails. */ resolveSourceNodeID(globalIndex, sourceNodeID) { const sourceNodeIndex = globalIndex.getSourceNodeIndexByID(sourceNodeID); if (sourceNodeIndex === undefined) { throw new Error('Report.getSourceNodeMetaDataByID: could not resolve source node index from sourceNodeID: ' + sourceNodeID.toString()); } const pathIndex = sourceNodeIndex.pathIndex; if (pathIndex.id === undefined) { return { error: true }; } const moduleIndex = pathIndex.moduleIndex; const reportToCheck = moduleIndex.identifier === '{node}' || this.moduleIndex === moduleIndex ? this : this.extern.get(moduleIndex.id); if (reportToCheck === undefined) { return { error: true }; } if (reportToCheck !== undefined) { const sourceFileMetaData = reportToCheck.getSourceFileMetaDataByPathID(pathIndex.id); if (sourceFileMetaData === undefined) { return { error: true, report: reportToCheck }; } const sourceNode = sourceFileMetaData.functions.get(sourceNodeID); if (sourceNode === undefined) { return { error: true, report: reportToCheck, sourceFileMetaData }; } return { error: false, report: reportToCheck, sourceFileMetaData, sourceNode }; } return { error: true, report: reportToCheck }; } getSourceFileMetaDataByPathID(pathID) { let sourceFileMetaData = this.lang_internal.get(pathID); if (sourceFileMetaData !== undefined) { return sourceFileMetaData; } sourceFileMetaData = this.intern.get(pathID); if (sourceFileMetaData !== undefined) { return sourceFileMetaData; } return undefined; } normalize(newGlobalIndex) { function sortIDsByPath(input) { return Array.from(input.values()) .map((value) => ({ path: value.path, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion id: value.pathIndex.id })) // Pair identifier with id .sort((a, b) => a.path.localeCompare(b.path)) // Sort by path .map((pair) => pair.id); // Extract sorted ids } function sortIDsByModuleIdentifier(input) { return Array.from(input.values()) .map((value) => ({ identifier: value.nodeModule.identifier, id: value.moduleIndex.id })) // Pair identifier with id .sort((a, b) => a.identifier.localeCompare(b.identifier)) // Sort by identifier .map((pair) => pair.id); // Extract sorted ids } const new_lang_internal = new ModelMap_1.ModelMap('number'); for (const pathID of sortIDsByPath(this.lang_internal)) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const sourceFileMetaData = this.lang_internal.get(pathID); sourceFileMetaData.normalize(newGlobalIndex); if (sourceFileMetaData.pathIndex.id === undefined) { throw new Error('Report.normalize(lang_internal): cannot resolve id of new created pathIndex'); } new_lang_internal.set(sourceFileMetaData.pathIndex.id, sourceFileMetaData); } const newModuleIndex = this.moduleIndex.insertToOtherIndex(newGlobalIndex); const new_intern = new ModelMap_1.ModelMap('number'); for (const pathID of sortIDsByPath(this.intern)) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const sourceFileMetaData = this.intern.get(pathID); sourceFileMetaData.normalize(newGlobalIndex); if (sourceFileMetaData.pathIndex.id === undefined) { throw new Error('Report.normalize(intern): cannot resolve id of new created pathIndex'); } new_intern.set(sourceFileMetaData.pathIndex.id, sourceFileMetaData); } const new_extern = new ModelMap_1.ModelMap('number'); for (const moduleID of sortIDsByModuleIdentifier(this.extern)) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const moduleReport = this.extern.get(moduleID); moduleReport.normalize(newGlobalIndex); new_extern.set(moduleReport.moduleIndex.id, moduleReport); } this.moduleIndex = newModuleIndex; this._lang_internal = new_lang_internal; this._intern = new_intern; this._extern = new_extern; } get headlessSensorValues() { if (this._headlessSensorValues === undefined) { this._headlessSensorValues = new SensorValues_1.SensorValues({}); } return this._headlessSensorValues; } set headlessSensorValues(value) { this._headlessSensorValues = value; } get lang_internal() { if (!this._lang_internal) { this._lang_internal = new ModelMap_1.ModelMap('number'); } return this._lang_internal; } get intern() { if (!this._intern) { this._intern = new ModelMap_1.ModelMap('number'); } return this._intern; } get extern() { if (!this._extern) { this._extern = new ModelMap_1.ModelMap('number'); } return this._extern; } getLangInternalPathIndex(indexRequestType, filePath) { var _a; return (_a = this.moduleIndex.globalIndex .getLangInternalIndex(indexRequestType)) === null || _a === void 0 ? void 0 : _a.getFilePathIndex(indexRequestType, filePath); } getModuleIndexByID(id) { return this.moduleIndex.globalIndex.getModuleIndexByID(id); } getModuleIndex(indexRequestType, moduleIdentifier) { return this.moduleIndex.globalIndex.getModuleIndex(indexRequestType, moduleIdentifier); } getPathIndexByID(id) { return this.moduleIndex.globalIndex.getPathIndexByID(id); } getPathIndex(indexRequestType, filePath) { return this.moduleIndex.getFilePathIndex(indexRequestType, filePath); } addToLangInternal(filePath, functionIdentifier) { const pathIndex = this.getLangInternalPathIndex('upsert', filePath); const filePathID = pathIndex.id; // check if filePath is in lang_internal let sourceFileMetaData = this.lang_internal.get(filePathID); if (!sourceFileMetaData) { sourceFileMetaData = new SourceFileMetaData_1.SourceFileMetaData(filePath, pathIndex); this.lang_internal.set(filePathID, sourceFileMetaData); } return sourceFileMetaData.createOrGetSourceNodeMetaData(functionIdentifier, types_1.SourceNodeMetaDataType.LangInternalSourceNode); } addToIntern(filePath, functionIdentifier) { const filePathIndex = this.getPathIndex('upsert', filePath); const filePathID = filePathIndex.id; // check if filePath is in intern let sourceFileMetaData = this.intern.get(filePathID); if (!sourceFileMetaData) { sourceFileMetaData = new SourceFileMetaData_1.SourceFileMetaData(filePath, filePathIndex); this.intern.set(filePathID, sourceFileMetaData); } return sourceFileMetaData.createOrGetSourceNodeMetaData(functionIdentifier, types_1.SourceNodeMetaDataType.SourceNode); } addToExtern(filePath, nodeModule, functionIdentifier) { const moduleIndex = this.moduleIndex.globalIndex.getModuleIndex('upsert', nodeModule.identifier); // check if filePath is in extern let moduleReport = this.extern.get(moduleIndex.id); if (!moduleReport) { moduleReport = new ModuleReport_1.ModuleReport(moduleIndex, nodeModule, this.kind); this.extern.set(moduleIndex.id, moduleReport); } const sourceNodeMetaData = moduleReport.addToIntern(filePath.toString(), functionIdentifier); return { report: moduleReport, sourceNodeMetaData: sourceNodeMetaData }; } /** * Returns the meta data of a file * * since a meta data file is anonymized (no absolute path is stored) * there is a total of three paths necessary to retrieve the correct meta data of a file * * this.relativeRootDir: * describes the location of the execution (relative to the meta data file) * * projectReportFilePath: * is the current location of the ProjectReport file * * relativeFilePath: * is the location of a measured source file, * relative to the execution path (this.relativeRootDir) * * All measurements are stored in this.lang_internal, this,intern and this,extern * the keys are the corresponding relativeFilePaths * * the absolute path of the measured source file is: * path.join(projectReportFilePath, this.relativeRootDir, relativeFilePath) * * therefore the relativeFilePath of the absolute one is: * const relativeFilePath = path.relative(path.join(projectReportFilePath, this.relativeRootDir), absoluteFilePath) * * @param projectReportFilePath is the current location of the ProjectReport file * @param absoluteFilePath is the absolute path of the measured source file * @returns the measurements of the given source file */ getMetaDataFromFile(projectReportFilePath, absoluteFilePath) { if (!this.relativeRootDir) { const absoluteFilePathIndex = this.getPathIndex('get', absoluteFilePath.toString()); if (absoluteFilePathIndex === undefined) { return undefined; } const absoluteFilePathID = absoluteFilePathIndex === null || absoluteFilePathIndex === void 0 ? void 0 : absoluteFilePathIndex.id; return this.intern.get(absoluteFilePathID); } const relativeFilePath = projectReportFilePath .dirName() .join(this.relativeRootDir) .pathTo(absoluteFilePath); const relativeFilePathIndex = this.getPathIndex('get', relativeFilePath.toString()); if (relativeFilePathIndex === undefined) { return undefined; } const relativeFilePathID = relativeFilePathIndex === null || relativeFilePathIndex === void 0 ? void 0 : relativeFilePathIndex.id; return this.intern.get(relativeFilePathID); } /** * @returns the total sensor values (sum) and the maximum (max) of all measurements in the report */ totalAndMaxMetaData() { function aggregate(report) { const result = []; for (const file of report.intern.values()) { for (const func of file.functions.values()) { result.push(func.sensorValues); } } for (const file of report.lang_internal.values()) { for (const func of file.functions.values()) { result.push(func.sensorValues); } } for (const externReport of report.extern.values()) { result.push(...aggregate(externReport)); } return result; } const allSensorValues = aggregate(this); const totalSensorValues = SensorValues_1.SensorValues.sum(...allSensorValues).cloneAsIsolated(); const maxSensorValues = SensorValues_1.SensorValues.max(...allSensorValues); return new SourceFileMetaData_1.AggregatedSourceNodeMetaData(new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, totalSensorValues, undefined), new SourceNodeMetaData_1.SourceNodeMetaData(types_1.SourceNodeMetaDataType.Aggregate, undefined, maxSensorValues, undefined)); } validate() { for (const sourceFileMetaData of this.intern.values()) { sourceFileMetaData.validate(); } for (const moduleReport of this.extern.values()) { moduleReport.validate(); } } toJSON() { var _a; if (env_1.NODE_ENV === 'test') { this.validate(); } return { reportVersion: this.reportVersion, kind: this.kind, relativeRootDir: (_a = this.relativeRootDir) === null || _a === void 0 ? void 0 : _a.toJSON(), headlessSensorValues: this.headlessSensorValues.toJSON(), lang_internal: this.lang_internal.toJSON(), intern: this.intern.toJSON(), extern: this.extern.toJSON() }; } static fromJSONReport(json, moduleIndex) { let data; if (typeof json === 'string') { data = JSON.parse(json); } else { data = json; } const result = new Report(moduleIndex, data.kind); if (data.lang_internal) { for (const key of Object.keys(data.lang_internal)) { const keyNumber = parseInt(key); const pathIndex = result.getPathIndexByID(keyNumber); if (pathIndex === undefined) { throw new Error(`Report.fromJSONReport: (lang_internal) could not resolve path index from id: ${keyNumber}`); } result.lang_internal.set(keyNumber, SourceFileMetaData_1.SourceFileMetaData.fromJSON(data.lang_internal[keyNumber], pathIndex)); } } if (data.headlessSensorValues) { result.headlessSensorValues = SensorValues_1.SensorValues.fromJSON(data.headlessSensorValues); } if (data.intern) { for (const key of Object.keys(data.intern)) { const keyNumber = parseInt(key); const pathIndex = result.getPathIndexByID(keyNumber); if (pathIndex === undefined) { throw new Error(`Report.fromJSONReport: (intern) could not resolve path index from id: ${keyNumber}`); } result.intern.set(keyNumber, SourceFileMetaData_1.SourceFileMetaData.fromJSON(data.intern[keyNumber], pathIndex)); } } if (data.extern) { for (const key of Object.keys(data.extern)) { const keyNumber = parseInt(key); const nodeModule = NodeModule_1.NodeModule.fromJSON(data.extern[keyNumber].nodeModule); const nextModuleIndex = moduleIndex.globalIndex.getModuleIndex('upsert', nodeModule.identifier); result.extern.set(keyNumber, ModuleReport_1.ModuleReport.fromJSON(data.extern[keyNumber], nextModuleIndex)); } } if (data.relativeRootDir) { result.relativeRootDir = new UnifiedPath_1.UnifiedPath(data.relativeRootDir); } result.reportVersion = data.reportVersion; return result; } storeToFileReport(filePath, kind, type, config) { if (!this.relativeRootDir) { const usedConfig = config !== undefined ? config : ProfilerConfig_1.ProfilerConfig.autoResolve(); this.relativeRootDir = filePath.dirName().pathTo(usedConfig.getRootDir()); } switch (kind) { case 'pretty-json': PermissionHelper_1.PermissionHelper.writeFileWithUserPermission(filePath, JSON.stringify(this, null, 2)); break; case 'json': PermissionHelper_1.PermissionHelper.writeFileWithUserPermission(filePath, JSON.stringify(this)); break; case 'bin': PermissionHelper_1.PermissionHelper.writeFileWithUserPermission(filePath, this.toBuffer(type)); break; default: break; } } static merge(moduleIndex, ...args) { if (args.length === 0) { throw new Error('Report.merge: no Reports were given'); } const result = new Report(moduleIndex, types_1.ReportKind.accumulated); const version = args[0].reportVersion; result.reportVersion = version; const headlessSensorValues = []; const valuesToMerge = { lang_internal: {}, intern: {}, extern: {} }; for (const currentProjectReport of args) { if (currentProjectReport.reportVersion !== version) { throw new Error('ProjectReport.merge: Project reports versions are not compatible'); } headlessSensorValues.push(currentProjectReport.headlessSensorValues); for (const [langInternalPathID, sourceFileMetaData] of currentProjectReport.lang_internal.entries()) { const langInternalPathIndex = currentProjectReport.getPathIndexByID(langInternalPathID); if (langInternalPathIndex === undefined) { throw new Error('Report.merge: (lang_internal) could not resolve langInternalPath from id'); } const langInternalPath = langInternalPathIndex.identifier; if (!valuesToMerge.lang_internal[langInternalPath]) { valuesToMerge.lang_internal[langInternalPath] = []; } valuesToMerge.lang_internal[langInternalPath].push(sourceFileMetaData); } for (const [sourceFilePathID, sourceFileMetaData] of currentProjectReport.intern.entries()) { const sourceFilePathIndex = currentProjectReport.getPathIndexByID(sourceFilePathID); if (sourceFilePathIndex === undefined) { throw new Error('Report.merge: (intern) could not resolve sourceFilePath from id'); } const sourceFilePath = sourceFilePathIndex.identifier; if (!valuesToMerge.intern[sourceFilePath]) { valuesToMerge.intern[sourceFilePath] = []; } valuesToMerge.intern[sourceFilePath].push(sourceFileMetaData); } for (const [moduleID, moduleReport] of currentProjectReport.extern.entries()) { const nodeModuleIndex = currentProjectReport.getModuleIndexByID(moduleID); if (nodeModuleIndex === undefined) { throw new Error('Report.merge: (intern) could not resolve nodeModuleIdentifier from id'); } const nodeModuleIdentifier = nodeModuleIndex.identifier; if (!valuesToMerge.extern[nodeModuleIdentifier]) { valuesToMerge.extern[nodeModuleIdentifier] = []; } valuesToMerge.extern[nodeModuleIdentifier].push(moduleReport); } } for (const [langInternalPath, sourceFileMetaDatas] of Object.entries(valuesToMerge.lang_internal)) { const langInternalPathIndex = result.getLangInternalPathIndex('upsert', langInternalPath); const langInternalPathID = langInternalPathIndex.id; result.lang_internal.set(langInternalPathID, SourceFileMetaData_1.SourceFileMetaData.merge(langInternalPathIndex, ...sourceFileMetaDatas)); } for (const [sourceFilePath, sourceFileMetaDatas] of Object.entries(valuesToMerge.intern)) { const sourceFilePathIndex = result.getPathIndex('upsert', sourceFilePath); const sourceFilePathID = sourceFilePathIndex.id; result.intern.set(sourceFilePathID, SourceFileMetaData_1.SourceFileMetaData.merge(sourceFilePathIndex, ...sourceFileMetaDatas)); } for (const [nodeModuleIdentifier, moduleReports] of Object.entries(valuesToMerge.extern)) { const nodeModuleIndex = result.getModuleIndex('upsert', nodeModuleIdentifier); const nodeModuleID = nodeModuleIndex.id; result.extern.set(nodeModuleID, ModuleReport_1.ModuleReport.merge(nodeModuleIndex, ...moduleReports)); } result.headlessSensorValues = SensorValues_1.SensorValues.sum(...headlessSensorValues); return result; } toBuffer(type) { const buffers = [ BufferHelper_1.BufferHelper.String2LToBuffer(this.reportVersion), BufferHelper_1.BufferHelper.UInt8ToBuffer(this.kind), BufferHelper_1.BufferHelper.UInt8ToBuffer(type), BufferHelper_1.BufferHelper.BooleanToBuffer(this.relativeRootDir !== undefined) ]; if (this.relativeRootDir !== undefined) { buffers.push(BufferHelper_1.BufferHelper.String2LToBuffer(this.relativeRootDir.toString())); } // if current Oaklean version is greater or equal to 0.1.4 // add lang_internal_headless_cpu_time to the buffer if (VersionHelper_1.VersionHelper.compare(this.reportVersion, '0.1.4') >= 0) { buffers.push(this.headlessSensorValues.toBuffer()); } buffers.push(this.intern.toBuffer(), this.lang_internal.toBuffer(), this.extern.toBuffer()); return Buffer.concat(buffers); } static consumeFromBufferReport(buffer, moduleIndex) { let remainingBuffer = buffer; const { instance: reportVersion, remainingBuffer: newRemainingBuffer0 } = BufferHelper_1.BufferHelper.String2LFromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer0; const { instance: kind, remainingBuffer: newRemainingBuffer1 } = BufferHelper_1.BufferHelper.UInt8FromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer1; const { instance: type, remainingBuffer: newRemainingBuffer2 } = BufferHelper_1.BufferHelper.UInt8FromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer2; const { instance: relativeRootDirPresent, remainingBuffer: newRemainingBuffer3 } = BufferHelper_1.BufferHelper.BooleanFromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer3; let relativeRootDir = undefined; if (relativeRootDirPresent) { const { instance, remainingBuffer: newRemainingBuffer3 } = BufferHelper_1.BufferHelper.String2LFromBuffer(remainingBuffer); relativeRootDir = instance; remainingBuffer = newRemainingBuffer3; } let headlessSensorValues = undefined; // if the version of the Report is greater or equal to 0.1.4 // consume lang_internal_headless_cpu_time from the buffer if (VersionHelper_1.VersionHelper.compare(reportVersion, '0.1.4') >= 0) { const { instance: headlessSensorValues_instance, remainingBuffer: newRemainingBuffer3_1 } = SensorValues_1.SensorValues.consumeFromBuffer(remainingBuffer); remainingBuffer = newRemainingBuffer3_1; headlessSensorValues = headlessSensorValues_instance; } // if the version of the Report is less or equal to 0.1.4 // consume internMapping from the buffer and ignore it (since it is not used anymore) if (VersionHelper_1.VersionHelper.compare(reportVersion, '0.1.4') <= 0) { const { // eslint-disable-next-line @typescript-eslint/no-unused-vars instance: internMapping, remainingBuffer: newRemainingBuffer4 } = ModelMap_1.ModelMap.consumeFromBuffer(remainingBuffer, 'number', 'number'); remainingBuffer = newRemainingBuffer4; } const consumeFromBuffer_SourceFileMetaData = (buffer) => { return SourceFileMetaData_1.SourceFileMetaData.consumeFromBuffer(buffer, moduleIndex.globalIndex); }; const { instance: intern, remainingBuffer: newRemainingBuffer5 } = ModelMap_1.ModelMap.consumeFromBuffer(remainingBuffer, 'number', consumeFromBuffer_SourceFileMetaData); remainingBuffer = newRemainingBuffer5; const { instance: lang_internal, remainingBuffer: newRemainingBuffer6 } = ModelMap_1.ModelMap.consumeFromBuffer(remainingBuffer, 'number', consumeFromBuffer_SourceFileMetaData); remainingBuffer = newRemainingBuffer6; const consumeFromBuffer_ModuleReport = (buffer) => { return ModuleReport_1.ModuleReport.consumeFromBuffer_ModuleReport(buffer, moduleIndex.globalIndex); }; const { instance: extern, remainingBuffer: newRemainingBuffer7 } = ModelMap_1.ModelMap.consumeFromBuffer(remainingBuffer, 'number', consumeFromBuffer_ModuleReport); remainingBuffer = newRemainingBuffer7; const result = new Report(moduleIndex, kind); result.reportVersion = reportVersion; result.relativeRootDir = relativeRootDir !== undefined ? new UnifiedPath_1.UnifiedPath(relativeRootDir) : undefined; result._intern = intern; result._lang_internal = lang_internal; result._extern = extern; if (headlessSensorValues) { result.headlessSensorValues = headlessSensorValues; } return { instance: result, type, remainingBuffer }; } } exports.Report = Report; // eslint-disable-next-line import/order const ModuleReport_1 = require("./ModuleReport"); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVwb3J0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL21vZGVsL1JlcG9ydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwyQ0FBdUM7QUFDdkMseUNBQXFDO0FBQ3JDLDZDQUF5QztBQUN6Qyw2REFHNkI7QUFDN0IsNkRBQXlEO0FBQ3pELHFEQUFpRDtBQUNqRCxpREFBNkM7QUFLN0MsMENBQTJDO0FBQzNDLDBDQUEwQztBQUMxQyxpRUFBNkQ7QUFDN0QsdURBQW1EO0FBQ25ELHlEQUFxRDtBQUNyRCwyREFBdUQ7QUFDdkQsUUFBUTtBQUNSLG9DQWlCaUI7QUFFakIseURBQXlEO0FBQ3pELG9GQUFvRjtBQUNwRixrSEFBa0g7QUFDbEgsSUFBSSxlQUFlLEdBQUcsQ0FBQyxDQUFBO0FBRXZCLE1BQWEsTUFBTyxTQUFRLHFCQUFTO0lBZXBDLFlBQVksV0FBd0IsRUFBRSxJQUFnQjtRQUNyRCxLQUFLLEVBQUUsQ0FBQTtRQUNQLElBQUksQ0FBQyxhQUFhLEdBQUcsYUFBTyxDQUFBO1FBQzVCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFBO1FBQ2hCLElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFBO1FBQzlCLElBQUksQ0FBQyxRQUFRLEdBQUcsZUFBZSxFQUFFLENBQUE7SUFDbEMsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxtQkFBbUIsQ0FDbEIsV0FBd0IsRUFDeEIsWUFBaUM7UUFvQmpDLE1BQU0sZUFBZSxHQUFHLFdBQVcsQ0FBQyxzQkFBc0IsQ0FBQyxZQUFZLENBQUMsQ0FBQTtRQUN4RSxJQUFJLGVBQWUsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNuQyxNQUFNLElBQUksS0FBSyxDQUNkLDJGQUEyRjtnQkFDMUYsWUFBWSxDQUFDLFFBQVEsRUFBRSxDQUN4QixDQUFBO1FBQ0YsQ0FBQztRQUNELE1BQU0sU0FBUyxHQUFHLGVBQWUsQ0FBQyxTQUFTLENBQUE7UUFDM0MsSUFBSSxTQUFTLENB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