@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
JavaScript
"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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