@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
448 lines • 35.8 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExternalResourceHelper = void 0;
const fs = __importStar(require("fs"));
const LoggerHelper_1 = require("./LoggerHelper");
const PermissionHelper_1 = require("./PermissionHelper");
const TypescriptParser_1 = require("./TypescriptParser");
const GitHelper_1 = require("./GitHelper");
const InspectorSessionHelper_1 = require("./InspectorSessionHelper");
const SourceMap_1 = require("../model/SourceMap");
const UnifiedPath_1 = require("../system/UnifiedPath");
const NodeModule_1 = require("../model/NodeModule");
class ExternalResourceHelper {
constructor(rootDir) {
this._boundInspectorNotification = this.inspectorNotification.bind(this);
this._rootDir = rootDir;
this._frozen = false;
this.fileInfoPerScriptID = new Map();
this.fileInfoPerPath = new Map();
this.nodeModules = new Map();
}
get rootDir() {
return this._rootDir;
}
get isFrozen() {
return this._frozen;
}
get scriptIDs() {
return Array.from(this.fileInfoPerScriptID.keys());
}
get loadedFilePaths() {
return Array.from(this.fileInfoPerPath.keys());
}
get uncommittedFiles() {
return this._uncommittedFiles;
}
trackUncommittedFiles(rootDir, globalIndex) {
var _a;
let uncommittedFiles = this._uncommittedFiles;
if (uncommittedFiles === undefined) {
uncommittedFiles = GitHelper_1.GitHelper.uncommittedFiles();
}
if (uncommittedFiles === null) {
// git is unavailable
this._uncommittedFiles = null;
return null;
}
const trackedUncommittedFiles = [];
for (const file of uncommittedFiles) {
const uncommittedFile = rootDir.pathTo(file).toString();
// track only uncommitted files that are part of the global index
const pathIndex = (_a = globalIndex
.getModuleIndex('get')) === null || _a === void 0 ? void 0 : _a.getFilePathIndex('get', uncommittedFile);
if (pathIndex === undefined) {
continue;
}
// mark the file as uncommitted in the global index
pathIndex.containsUncommittedChanges = true;
// add the file to the uncommitted files list
trackedUncommittedFiles.push(uncommittedFile);
// also mark the file as uncommitted in the file info
const fileInfo = this.fileInfoFromPath(uncommittedFile, rootDir.join(uncommittedFile));
if (fileInfo !== null) {
fileInfo.cucc = true;
}
}
this._uncommittedFiles = trackedUncommittedFiles;
return trackedUncommittedFiles.length > 0;
}
connect() {
return __awaiter(this, void 0, void 0, function* () {
// wait for debugger to be enabled
yield new Promise((resolve) => {
InspectorSessionHelper_1.InspectorSessionHelper.session.post('Debugger.enable', resolve);
});
});
}
storeToFile(filePath, kind) {
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;
default:
break;
}
}
static loadFromFile(rootDir, filePath) {
if (!fs.existsSync(filePath.toPlatformString())) {
return undefined;
}
return ExternalResourceHelper.fromJSON(rootDir, fs.readFileSync(filePath.toPlatformString()).toString());
}
toJSON() {
const fileInfoPerScriptID = {};
for (const [key, value] of this.fileInfoPerScriptID.entries()) {
if (value === null) {
fileInfoPerScriptID[key] = null;
continue;
}
const fileInfo = {
sourceCode: value.sourceCode
};
if (value.cucc !== undefined) {
fileInfo.cucc = value.cucc;
}
fileInfoPerScriptID[key] = fileInfo;
}
const fileInfoPerPath = {};
for (const [key, value] of this.fileInfoPerPath.entries()) {
if (value === null) {
fileInfoPerPath[key] = null;
continue;
}
const fileInfo = {
sourceCode: value.sourceCode
};
if (value.cucc !== undefined) {
fileInfo.cucc = value.cucc;
}
fileInfoPerPath[key] = fileInfo;
}
const nodeModules = {};
for (const [key, value] of this.nodeModules.entries()) {
if (value === null) {
nodeModules[key] = null;
continue;
}
nodeModules[key] = value.toJSON();
}
return {
fileInfoPerScriptID,
fileInfoPerPath,
nodeModules
};
}
static fromJSON(rootDir, json) {
let data;
if (typeof json === 'string') {
data = JSON.parse(json);
}
else {
data = json;
}
const result = new ExternalResourceHelper(rootDir);
result._uncommittedFiles = [];
for (const [key, value] of Object.entries(data.fileInfoPerScriptID)) {
let fileInfo = null;
if (value !== null) {
fileInfo = {
sourceCode: value.sourceCode
};
if (value.cucc !== undefined) {
fileInfo.cucc = value.cucc;
}
}
result.fileInfoPerScriptID.set(key, fileInfo);
}
for (const [key, value] of Object.entries(data.fileInfoPerPath)) {
let fileInfo = null;
if (value !== null) {
fileInfo = {
sourceCode: value.sourceCode
};
if (value.cucc !== undefined) {
fileInfo.cucc = value.cucc;
if (value.cucc === true) {
result._uncommittedFiles.push(key);
}
}
}
result.fileInfoPerPath.set(key, fileInfo);
}
for (const [key, value] of Object.entries(data.nodeModules)) {
result.nodeModules.set(key, value !== null ? NodeModule_1.NodeModule.fromJSON(value) : null);
}
// freeze the object to prevent further modifications
result._frozen = true;
return result;
}
inspectorNotification(message) {
return __awaiter(this, void 0, void 0, function* () {
if (message.method === 'Debugger.scriptParsed') {
const params = message.params;
// store source code for later use
yield this.fileInfoFromScriptID(params.scriptId);
}
});
}
listen() {
return __awaiter(this, void 0, void 0, function* () {
yield InspectorSessionHelper_1.InspectorSessionHelper.session.on('inspectorNotification', this._boundInspectorNotification);
});
}
disconnect() {
return __awaiter(this, void 0, void 0, function* () {
yield new Promise((resolve) => {
InspectorSessionHelper_1.InspectorSessionHelper.session.post('Debugger.disable', resolve);
});
InspectorSessionHelper_1.InspectorSessionHelper.session.removeListener('inspectorNotification', this._boundInspectorNotification);
});
}
fillSourceMapsFromCPUProfile(profile) {
return __awaiter(this, void 0, void 0, function* () {
const scriptMap = new Map();
for (const location of profile.nodes) {
const scriptId = location.callFrame.scriptId.toString();
if (scriptMap.has(scriptId)) {
continue;
}
scriptMap.set(scriptId, location.callFrame.url);
}
const promises = [];
for (const [scriptId, filePath] of scriptMap) {
promises.push(this.sourceMapFromScriptID(scriptId, new UnifiedPath_1.UnifiedPath(filePath)));
}
yield Promise.all(promises);
});
}
fileInfoFromPath(relativePath, filePath) {
const relativePathString = typeof relativePath === 'string' ? relativePath : relativePath.toString();
const filePathPlatformString = typeof filePath === 'string' ? filePath : filePath.toPlatformString();
let fileInfo = this.fileInfoPerPath.get(relativePathString);
if (fileInfo !== undefined) {
return fileInfo;
}
if (this.isFrozen) {
throw new Error('ExternalResourceHelper.fileInfoFromPath: Cannot load file while frozen' +
'Tried to access: ' +
relativePathString);
}
if (fs.existsSync(filePathPlatformString) &&
fs.statSync(filePathPlatformString).isFile()) {
fileInfo = {
sourceCode: fs.readFileSync(filePathPlatformString).toString()
};
}
else {
fileInfo = null;
}
this.fileInfoPerPath.set(relativePathString, fileInfo);
return fileInfo;
}
sourceCodeFromPath(relativePath, filePath) {
const fileInfo = this.fileInfoFromPath(relativePath, filePath);
if (fileInfo === null) {
return null;
}
return fileInfo.sourceCode;
}
sourceMapFromPath(relativePath, filePath) {
return __awaiter(this, void 0, void 0, function* () {
const fileInfo = this.fileInfoFromPath(relativePath, filePath);
if (fileInfo === null) {
return null;
}
if (fileInfo.sourceMap !== undefined) {
return fileInfo.sourceMap;
}
let sourceMap = SourceMap_1.SourceMap.fromCompiledJSString(filePath, fileInfo.sourceCode);
if (sourceMap !== null) {
if (sourceMap.type === 'redirect') {
sourceMap = yield this.sourceMapFromPath(this.rootDir.pathTo(sourceMap.sourceMapLocation), sourceMap.sourceMapLocation);
}
}
fileInfo.sourceMap = sourceMap;
return fileInfo.sourceMap;
});
}
parseFile(relativePath, filePath) {
const fileInfo = this.fileInfoFromPath(relativePath, filePath);
if (fileInfo === null) {
return null;
}
return TypescriptParser_1.TypescriptParser.parseSource(filePath, fileInfo.sourceCode);
}
fileInfoFromScriptID(scriptID, filePath) {
return __awaiter(this, void 0, void 0, function* () {
if (scriptID === '0') {
return null;
}
let fileInfo = this.fileInfoPerScriptID.get(scriptID);
if (fileInfo !== undefined) {
return fileInfo;
}
if (this.isFrozen) {
throw new Error('ExternalResourceHelper.fileInfoFromScriptID: Cannot script from inspector while frozen\n' +
'Tried to access: ' +
scriptID);
}
const result = yield new Promise((resolve) => {
InspectorSessionHelper_1.InspectorSessionHelper.session.post('Debugger.getScriptSource', { scriptId: scriptID }, (err, args) => {
if (err) {
resolve({ source: '', err });
}
else {
resolve({ source: args.scriptSource });
}
});
});
if (result.err) {
LoggerHelper_1.LoggerHelper.error('Error getting script source', result.err, {
scriptId: scriptID,
filePath
});
throw result.err;
}
fileInfo = {
sourceCode: result.source
};
this.fileInfoPerScriptID.set(scriptID, fileInfo);
return fileInfo;
});
}
sourceCodeFromScriptID(scriptID) {
return __awaiter(this, void 0, void 0, function* () {
const fileInfo = yield this.fileInfoFromScriptID(scriptID);
if (fileInfo === null) {
return null;
}
return fileInfo.sourceCode;
});
}
sourceMapFromScriptID(scriptID, filePath) {
return __awaiter(this, void 0, void 0, function* () {
const fileInfo = yield this.fileInfoFromScriptID(scriptID, filePath);
if (fileInfo === null || fileInfo.sourceMap === null) {
return null;
}
if (fileInfo.sourceMap !== undefined) {
return fileInfo.sourceMap;
}
let sourceMap = SourceMap_1.SourceMap.fromCompiledJSString(filePath, fileInfo.sourceCode);
if (sourceMap !== null) {
if (sourceMap.type === 'redirect') {
const sourceMapCode = yield this.sourceCodeFromPath(this.rootDir.pathTo(sourceMap.sourceMapLocation), sourceMap.sourceMapLocation);
sourceMap =
sourceMapCode === null ? null : SourceMap_1.SourceMap.fromJSON(sourceMapCode);
}
}
fileInfo.sourceMap = sourceMap;
return fileInfo.sourceMap;
});
}
nodeModuleFromPath(relativeNodeModulePath) {
let nodeModule = this.nodeModules.get(relativeNodeModulePath.toString());
if (nodeModule !== undefined) {
return nodeModule;
}
if (this.isFrozen) {
throw new Error('ExternalResourceHelper.nodeModuleFromPath: Cannot load node modules while frozen\n' +
'Tried to access: ' +
relativeNodeModulePath.toString());
}
nodeModule =
NodeModule_1.NodeModule.fromNodeModulePath(this.rootDir.join(relativeNodeModulePath)) || null;
this.nodeModules.set(relativeNodeModulePath.toString(), nodeModule);
return nodeModule;
}
replaceSourceMapByScriptID(scriptID, newSourceMap) {
return __awaiter(this, void 0, void 0, function* () {
const fileInfo = yield this.fileInfoFromScriptID(scriptID);
if (fileInfo === null) {
throw new Error(`No source code found for scriptID ${scriptID}`);
}
const result = SourceMap_1.SourceMap.base64StringCompiledJSString(fileInfo.sourceCode);
if (result === null ||
result.base64 === undefined ||
result.base64 === null) {
throw new Error(`No source map found for scriptID ${scriptID}`);
}
const oldBase64String = result.base64;
const newBase64String = newSourceMap.toBase64String();
if (oldBase64String === newBase64String) {
return;
}
fileInfo.sourceCode = fileInfo.sourceCode.replace(oldBase64String, newBase64String);
fileInfo.sourceMap = newSourceMap;
});
}
replaceSourceMapByLoadedFile(relativePath, newSourceMap) {
return __awaiter(this, void 0, void 0, function* () {
const fileInfo = this.fileInfoFromPath(relativePath, relativePath);
if (fileInfo === null) {
throw new Error(`No source code found for relativePath ${relativePath.toString()}`);
}
const result = SourceMap_1.SourceMap.base64StringCompiledJSString(fileInfo.sourceCode);
if (result === null ||
result.base64 === undefined ||
result.base64 === null) {
throw new Error(`No source map found for relativePath ${relativePath.toString()}`);
}
const oldBase64String = result.base64;
const newBase64String = newSourceMap.toBase64String();
if (oldBase64String === newBase64String) {
return;
}
fileInfo.sourceCode = fileInfo.sourceCode.replace(oldBase64String, newBase64String);
fileInfo.sourceMap = newSourceMap;
});
}
}
exports.ExternalResourceHelper = ExternalResourceHelper;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXh0ZXJuYWxSZXNvdXJjZUhlbHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9oZWxwZXIvRXh0ZXJuYWxSZXNvdXJjZUhlbHBlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSx1Q0FBd0I7QUFHeEIsaURBQTZDO0FBQzdDLHlEQUFxRDtBQUNyRCx5REFBcUQ7QUFDckQsMkNBQXVDO0FBQ3ZDLHFFQUFpRTtBQUdqRSxrREFBaUU7QUFDakUsdURBQW1EO0FBQ25ELG9EQUFnRDtBQW1CaEQsTUFBYSxzQkFBc0I7SUEwQmxDLFlBQVksT0FBb0I7UUEyT3hCLGdDQUEyQixHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7UUExTzFFLElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFBO1FBQ3ZCLElBQUksQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFBO1FBQ3BCLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFBO1FBQ3BDLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQTtRQUNoQyxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksR0FBRyxFQUFFLENBQUE7SUFDN0IsQ0FBQztJQUVELElBQUksT0FBTztRQUNWLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQTtJQUNyQixDQUFDO0lBRUQsSUFBSSxRQUFRO1FBQ1gsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFBO0lBQ3BCLENBQUM7SUFFRCxJQUFJLFNBQVM7UUFDWixPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLElBQUksRUFBRSxDQUFDLENBQUE7SUFDbkQsQ0FBQztJQUVELElBQUksZUFBZTtRQUNsQixPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQy9DLENBQUM7SUFFRCxJQUFJLGdCQUFnQjtRQUNuQixPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FBQTtJQUM5QixDQUFDO0lBRUQscUJBQXFCLENBQ3BCLE9BQW9CLEVBQ3BCLFdBQXdCOztRQUV4QixJQUFJLGdCQUFnQixHQUlMLElBQUksQ0FBQyxpQkFBaUIsQ0FBQTtRQUVyQyxJQUFJLGdCQUFnQixLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3BDLGdCQUFnQixHQUFHLHFCQUFTLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQTtRQUNoRCxDQUFDO1FBQ0QsSUFBSSxnQkFBZ0IsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUMvQixxQkFBcUI7WUFDckIsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQTtZQUM3QixPQUFPLElBQUksQ0FBQTtRQUNaLENBQUM7UUFFRCxNQUFNLHVCQUF1QixHQUFHLEVBQUUsQ0FBQTtRQUNsQyxLQUFLLE1BQU0sSUFBSSxJQUFJLGdCQUFnQixFQUFFLENBQUM7WUFDckMsTUFBTSxlQUFlLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQTtZQUN2RCxpRUFBaUU7WUFDakUsTUFBTSxTQUFTLEdBQUcsTUFBQSxXQUFXO2lCQUMzQixjQUFjLENBQUMsS0FBSyxDQUFDLDBDQUNwQixnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsZUFBZSxDQUFDLENBQUE7WUFDM0MsSUFBSSxTQUFTLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQzdCLFNBQVE7WUFDVCxDQUFDO1lBQ0QsbURBQW1EO1lBQ25ELFNBQVMsQ0FBQywwQkFBMEIsR0FBRyxJQUFJLENBQUE7WUFDM0MsNkNBQTZDO1lBQzdDLHVCQUF1QixDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQTtZQUM3QyxxREFBcUQ7WUFDckQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUNyQyxlQUFlLEVBQ2YsT0FBTyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FDN0IsQ0FBQTtZQUVELElBQUksUUFBUSxLQUFLLElBQUksRUFBRSxDQUFDO2dCQUN2QixRQUFRLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQTtZQUNyQixDQUFDO1FBQ0YsQ0FBQztRQUNELElBQUksQ0FBQyxpQkFBaUIsR0FBRyx1QkFBdUIsQ0FBQTtRQUNoRCxPQUFPLHVCQUF1QixDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUE7SUFDMUMsQ0FBQztJQUVLLE9BQU87O1lBQ1osa0NBQWtDO1lBQ2xDLE1BQU0sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtnQkFDN0IsK0NBQXNCLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxPQUFPLENBQUMsQ0FBQTtZQUNoRSxDQUFDLENBQUMsQ0FBQTtRQUNILENBQUM7S0FBQTtJQUVELFdBQVcsQ0FBQyxRQUFxQixFQUFFLElBQTRCO1FBQzlELFFBQVEsSUFBSSxFQUFFLENBQUM7WUFDZCxLQUFLLGFBQWE7Z0JBQ2pCLG1DQUFnQixDQUFDLDJCQUEyQixDQUMzQyxRQUFRLEVBQ1IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUM3QixDQUFBO2dCQUNELE1BQUs7WUFDTixLQUFLLE1BQU07Z0JBQ1YsbUNBQWdCLENBQUMsMkJBQTJCLENBQzNDLFFBQVEsRUFDUixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUNwQixDQUFBO2dCQUNELE1BQUs7WUFDTjtnQkFDQyxNQUFLO1FBQ1AsQ0FBQztJQUNGLENBQUM7SUFFRCxNQUFNLENBQUMsWUFBWSxDQUNsQixPQUFvQixFQUNwQixRQUFxQjtRQUVyQixJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDakQsT0FBTyxTQUFTLENBQUE7UUFDakIsQ0FBQztRQUNELE9BQU8sc0JBQXNCLENBQUMsUUFBUSxDQUNyQyxPQUFPLEVBQ1AsRUFBRSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUN2RCxDQUFBO0lBQ0YsQ0FBQztJQUVELE1BQU07UUFDTCxNQUFNLG1CQUFtQixHQUdyQixFQUFFLENBQUE7UUFDTixLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLG1CQUFtQixDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDL0QsSUFBSSxLQUFLLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3BCLG1CQUFtQixDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQTtnQkFDL0IsU0FBUTtZQUNULENBQUM7WUFDRCxNQUFNLFFBQVEsR0FBOEI7Z0JBQzNDLFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTthQUM1QixDQUFBO1lBQ0QsSUFBSSxLQUFLLENBQUMsSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUM5QixRQUFRLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUE7WUFDM0IsQ0FBQztZQUNELG1CQUFtQixDQUFDLEdBQUcsQ0FBQyxHQUFHLFFBQVEsQ0FBQTtRQUNwQyxDQUFDO1FBRUQsTUFBTSxlQUFlLEdBR2pCLEVBQUUsQ0FBQTtRQUNOLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDM0QsSUFBSSxLQUFLLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3BCLGVBQWUsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUE7Z0JBQzNCLFNBQVE7WUFDVCxDQUFDO1lBQ0QsTUFBTSxRQUFRLEdBQThCO2dCQUMzQyxVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7YUFDNUIsQ0FBQTtZQUNELElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDOUIsUUFBUSxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFBO1lBQzNCLENBQUM7WUFDRCxlQUFlLENBQUMsR0FBRyxDQUFDLEdBQUcsUUFBUSxDQUFBO1FBQ2hDLENBQUM7UUFFRCxNQUFNLFdBQVcsR0FBbUQsRUFBRSxDQUFBO1FBQ3RFLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDdkQsSUFBSSxLQUFLLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3BCLFdBQVcsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUE7Z0JBQ3ZCLFNBQVE7WUFDVCxDQUFDO1lBQ0QsV0FBVyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQTtRQUNsQyxDQUFDO1FBRUQsT0FBTztZQUNOLG1CQUFtQjtZQUNuQixlQUFlO1lBQ2YsV0FBVztTQUNYLENBQUE7SUFDRixDQUFDO0lBRUQsTUFBTSxDQUFDLFFBQVEsQ0FDZCxPQUFvQixFQUNwQixJQUFzQztRQUV0QyxJQUFJLElBQTZCLENBQUE7UUFDakMsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUM5QixJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUN4QixDQUFDO2FBQU0sQ0FBQztZQUNQLElBQUksR0FBRyxJQUFJLENBQUE7UUFDWixDQUFDO1FBQ0QsTUFBTSxNQUFNLEdBQUcsSUFBSSxzQkFBc0IsQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUNsRCxNQUFNLENBQUMsaUJBQWlCLEdBQUcsRUFBRSxDQUFBO1FBRTdCLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLENBQUM7WUFDckUsSUFBSSxRQUFRLEdBQW9DLElBQUksQ0FBQTtZQUNwRCxJQUFJLEtBQUssS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDcEIsUUFBUSxHQUFHO29CQUNWLFVBQVUsRUFBRSxLQUFLLENBQUMsVUFBVTtpQkFDNUIsQ0FBQTtnQkFDRCxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssU0FBUyxFQUFFLENBQUM7b0JBQzlCLFFBQVEsQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQTtnQkFDM0IsQ0FBQztZQUNGLENBQUM7WUFFRCxNQUFNLENBQUMsbUJBQW1CLENBQUMsR0FBRyxDQUFDLEdBQXNCLEVBQUUsUUFBUSxDQUFDLENBQUE7UUFDakUsQ0FBQztRQUVELEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDO1lBQ2pFLElBQUksUUFBUSxHQUFvQyxJQUFJLENBQUE7WUFDcEQsSUFBSSxLQUFLLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3BCLFFBQVEsR0FBRztvQkFDVixVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7aUJBQzVCLENBQUE7Z0JBQ0QsSUFBSSxLQUFLLENBQUMsSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUM5QixRQUFRLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUE7b0JBQzFCLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxJQUFJLEVBQUUsQ0FBQzt3QkFDekIsTUFBTSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxHQUF5QixDQUFDLENBQUE7b0JBQ3pELENBQUM7Z0JBQ0YsQ0FBQztZQUNGLENBQUM7WUFFRCxNQUFNLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxHQUF5QixFQUFFLFFBQVEsQ0FBQyxDQUFBO1FBQ2hFLENBQUM7UUFFRCxLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztZQUM3RCxNQUFNLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FDckIsR0FBeUIsRUFDekIsS0FBSyxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsdUJBQVUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FDbEQsQ0FBQTtRQUNGLENBQUM7UUFFRCxxREFBcUQ7UUFDckQsTUFBTSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUE7UUFFckIsT0FBTyxNQUFNLENBQUE7SUFDZCxDQUFDO0lBRUsscUJBQXFCLENBQUMsT0FBc0M7O1lBQ2pFLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyx1QkFBdUIsRUFBRSxDQUFDO2dCQUNoRCxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFHdEIsQ0FBQTtnQkFDRCxrQ0FBa0M7Z0JBQ2xDLE1BQU0sSUFBSSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQTtZQUNqRCxDQUFDO1FBQ0YsQ0FBQztLQUFBO0lBR0ssTUFBTTs7WUFDWCxNQUFNLCtDQUFzQixDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQ3RDLHVCQUF1QixFQUN2QixJQUFJLENBQUMsMkJBQTJCLENBQ2hDLENBQUE7UUFDRixDQUFDO0tBQUE7SUFFSyxVQUFVOztZQUNmLE1BQU0sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtnQkFDN0IsK0NBQXNCLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxPQUFPLENBQUMsQ0FBQTtZQUNqRSxDQUFDLENBQUMsQ0FBQTtZQUNGLCtDQUFzQixDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQzVDLHVCQUF1QixFQUN2QixJQUFJLENBQUMsMkJBQTJCLENBQ2hDLENBQUE7UUFDRixDQUFDO0tBQUE7SUFFSyw0QkFBNEIsQ0FBQyxPQUF1Qjs7WUFDekQsTUFBTSxTQUFTLEdBQUcsSUFBSSxHQUFHLEVBQTJCLENBQUE7WUFFcEQsS0FBSyxNQUFNLFFBQVEsSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ3RDLE1BQU0sUUFBUSxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBcUIsQ0FBQTtnQkFDMUUsSUFBSSxTQUFTLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7b0JBQzdCLFNBQVE7Z0JBQ1QsQ0FBQztnQkFDRCxTQUFTLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ2hELENBQUM7WUFFRCxNQUFNLFFBQVEsR0FBRyxFQUFFLENBQUE7WUFDbkIsS0FBSyxNQUFNLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxJQUFJLFNBQVMsRUFBRSxDQUFDO2dCQUM5QyxRQUFRLENBQUMsSUFBSSxDQUNaLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLEVBQUUsSUFBSSx5QkFBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQy9ELENBQUE7WUFDRixDQUFDO1lBRUQsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFBO1FBQzVCLENBQUM7S0FBQTtJQUVELGdCQUFnQixDQUNmLFlBQThDLEVBQzlDLFFBQTBDO1FBRTFDLE1BQU0sa0JBQWtCLEdBQ3ZCLE9BQU8sWUFBWSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLENBQUE7UUFDMUUsTUFBTSxzQkFBc0IsR0FDM0IsT0FBTyxRQUFRLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFBO1FBRXRFLElBQUksUUFBUSxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLGtCQUFrQixDQUFDLENBQUE7UUFDM0QsSUFBSSxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDNUIsT0FBTyxRQUFRLENBQUE7UUFDaEIsQ0FBQztRQUNELElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ25CLE1BQU0sSUFBSSxLQUFLLENBQ2Qsd0VBQXdFO2dCQUN2RSxtQkFBbUI7Z0JBQ25CLGtCQUFrQixDQUNuQixDQUFBO1FBQ0YsQ0FBQztRQUNELElBQ0MsRUFBRSxDQUFDLFVBQVUsQ0FBQyxzQkFBc0IsQ0FBQztZQUNyQyxFQUFFLENBQUMsUUFBUSxDQUFDLHNCQUFzQixDQUFDLENBQUMsTUFBTSxFQUFFLEVBQzNDLENBQUM7WUFDRixRQUFRLEdBQUc7Z0JBQ1YsVUFBVSxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxRQUFRLEVBQUU7YUFDOUQsQ0FBQTtRQUNGLENBQUM7YUFBTSxDQUFDO1lBQ1AsUUFBUSxHQUFHLElBQUksQ0FBQTtRQUNoQixDQUFDO1FBRUQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsa0JBQWtCLEVBQUUsUUFBUSxDQUFDLENBQUE7UUFDdEQsT0FBTyxRQUFRLENBQUE7SUFDaEIsQ0FBQztJQUVELGtCQUFrQixDQUNqQixZQUE4QyxFQUM5QyxRQUEwQztRQUUxQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxFQUFFLFFBQVEsQ0FBQyxDQUFBO1FBQzlELElBQUksUUFBUSxLQUFLLElBQUksRUFBRSxDQUFDO1lBQ3ZCLE9BQU8sSUFBSSxDQUFBO1FBQ1osQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDLFVBQVUsQ0FBQTtJQUMzQixDQUFDO0lBRUssaUJBQWlCLENBQ3RCLFlBQThDLEVBQzlDLFFBQXFCOztZQUVyQixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxFQUFFLFFBQVEsQ0FBQyxDQUFBO1lBQzlELElBQUksUUFBUSxLQUFLLElBQUksRUFBRSxDQUFDO2dCQUN2QixPQUFPLElBQUksQ0FBQTtZQUNaLENBQUM7WUFDRCxJQUFJLFFBQVEsQ0FBQyxTQUFTLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ3RDLE9BQU8sUUFBUSxDQUFDLFNBQVMsQ0FBQTtZQUMxQixDQUFDO1lBQ0QsSUFBSSxTQUFTLEdBQUcscUJBQVMsQ0FBQyxvQkFBb0IsQ0FDN0MsUUFBUSxFQUNSLFFBQVEsQ0FBQyxVQUFVLENBQ25CLENBQUE7WUFDRCxJQUFJLFNBQVMsS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDeEIsSUFBSyxTQUErQixDQUFDLElBQUksS0FBSyxVQUFVLEVBQUUsQ0FBQztvQkFDMUQsU0FBUyxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUN2QyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsaUJBQWlCLENBQUMsRUFDaEQsU0FBUyxDQUFDLGlCQUFpQixDQUMzQixDQUFBO2dCQUNGLENBQUM7WUFDRixDQUFDO1lBQ0QsUUFBUSxDQUFDLFNBQVMsR0FBRyxTQUE2QixDQUFBO1lBQ2xELE9BQU8sUUFBUSxDQUFDLFNBQVMsQ0FBQTtRQUMxQixDQUFDO0tBQUE7SUFFRCxTQUFTLENBQ1IsWUFBOEMsRUFDOUMsUUFBMEM7UUFFMUMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFlBQVksRUFBRSxRQUFRLENBQUMsQ0FBQTtRQUM5RCxJQUFJLFFBQVEsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUN2QixPQUFPLElBQUksQ0FBQTtRQUNaLENBQUM7UUFDRCxPQUFPLG1DQUFnQixDQUFDLFdBQVcsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQ25FLENBQUM7SUFFSyxvQkFBb0IsQ0FDekIsUUFBeUIsRUFDekIsUUFBc0I7O1lBRXRCLElBQUksUUFBUSxLQUFLLEdBQUcsRUFBRSxDQUFDO2dCQUN0QixPQUFPLElBQUksQ0FBQTtZQUNaLENBQUM7WUFDRCxJQUFJLFFBQVEsR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFBO1lBQ3JELElBQUksUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUM1QixPQUFPLFFBQVEsQ0FBQTtZQUNoQixDQUFDO1lBRUQsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ25CLE1BQU0sSUFBSSxLQUFLLENBQ2QsMEZBQTBGO29CQUN6RixtQkFBbUI7b0JBQ25CLFFBQVEsQ0FDVCxDQUFBO1lBQ0YsQ0FBQztZQUVELE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxPQUFPLENBRzdCLENBQUMsT0FBTyxFQUFFLEVBQUU7Z0JBQ2QsK0NBQXNCLENBQUMsT0FBTyxDQUFDLElBQUksQ0FDbEMsMEJBQTBCLEVBQzFCLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxFQUN0QixDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRTtvQkFDYixJQUFJLEdBQUcsRUFBRSxDQUFDO3dCQUNULE9BQU8sQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQTtvQkFDN0IsQ0FBQzt5QkFBTSxDQUFDO3dCQUNQLE9BQU8sQ0FBQyxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsQ0FBQTtvQkFDdkMsQ0FBQztnQkFDRixDQUFDLENBQ0QsQ0FBQTtZQUNGLENBQUMsQ0FBQyxDQUFBO1lBQ0YsSUFBSSxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ2hCLDJCQUFZLENBQUMsS0FBSyxDQUFDLDZCQUE2QixFQUFFLE1BQU0sQ0FBQyxHQUFHLEVBQUU7b0JBQzdELFFBQVEsRUFBRSxRQUFRO29CQUNsQixRQUFRO2lCQUNSLENBQUMsQ0FBQTtnQkFDRixNQUFNLE1BQU0sQ0FBQyxHQUFHLENBQUE7WUFDakIsQ0FBQztZQUNELFFBQVEsR0FBRztnQkFDVixVQUFVLEVBQUUsTUFBTSxDQUFDLE1BQU07YUFDekIsQ0FBQTtZQUNELElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFBO1lBQ2hELE9BQU8sUUFBUSxDQUFBO1FBQ2hCLENBQUM7S0FBQTtJQUVLLHNCQUFzQixDQUMzQixRQUF5Qjs7WUFFekIsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUMsUUFBUSxDQUFDLENBQUE7WUFDMUQsSUFBSSxRQUFRLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3ZCLE9BQU8sSUFBSSxDQUFBO1lBQ1osQ0FBQztZQUNELE9BQU8sUUFBUSxDQUFDLFVBQVUsQ0FBQTtRQUMzQixDQUFDO0tBQUE7SUFFSyxxQkFBcUIsQ0FDMUIsUUFBeUIsRUFDekIsUUFBcUI7O1lBRXJCLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLG9CQUFvQixDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQTtZQUNwRSxJQUFJLFFBQVEsS0FBSyxJQUFJLElBQUksUUFBUSxDQUFDLFNBQVMsS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDdEQsT0FBTyxJQUFJLENBQUE7WUFDWixDQUFDO1lBQ0QsSUFBSSxRQUFRLENBQUMsU0FBUyxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUN0QyxPQUFPLFFBQVEsQ0FBQyxTQUFTLENBQUE7WUFDMUIsQ0FBQztZQUNELElBQUksU0FBUyxHQUFHLHFCQUFTLENBQUMsb0JBQW9CLENBQzdDLFFBQVEsRUFDUixRQUFRLENBQUMsVUFBVSxDQUNuQixDQUFBO1lBQ0QsSUFBSSxTQUFTLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3hCLElBQUssU0FBK0IsQ0FBQyxJQUFJLEtBQUssVUFBVSxFQUFFLENBQUM7b0JBQzFELE1BQU0sYUFBYSxHQUFHLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUNsRCxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsaUJBQWlCLENBQUMsRUFDaEQsU0FBUyxDQUFDLGlCQUFpQixDQUMzQixDQUFBO29CQUNELFNBQVM7d0JBQ1IsYUFBYSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxxQkFBUyxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsQ0FBQTtnQkFDbkUsQ0FBQztZQUNGLENBQUM7WUFDRCxRQUFRLENBQUMsU0FBUyxHQUFHLFNBQTZCLENBQUE7WUFDbEQsT0FBTyxRQUFRLENBQUMsU0FBUyxDQUFBO1FBQzFCLENBQUM7S0FBQTtJQUVELGtCQUFrQixDQUFDLHNCQUFtQztRQUNyRCxJQUFJLFVBQVUsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxzQkFBc0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFBO1FBQ3hFLElBQUksVUFBVSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzlCLE9BQU8sVUFBVSxDQUFBO1FBQ2xCLENBQUM7UUFDRCxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNuQixNQUFNLElBQUksS0FBSyxDQUNkLG9GQUFvRjtnQkFDbkYsbUJBQW1CO2dCQUNuQixzQkFBc0IsQ0FBQyxRQUFRLEVBQUUsQ0FDbEMsQ0FBQTtRQUNGLENBQUM7UUFDRCxVQUFVO1lBQ1QsdUJBQVUsQ0FBQyxrQkFBa0IsQ0FDNUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsQ0FDekMsSUFBSSxJQUFJLENBQUE7UUFDVixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxzQkFBc0IsQ0FBQyxRQUFRLEVBQUUsRUFBRSxVQUFVLENBQUMsQ0FBQTtRQUNuRSxPQUFPLFVBQVUsQ0FBQTtJQUNsQixDQUFDO0lBRUssMEJBQTBCLENBQy9CLFFBQXlCLEVBQ3pCLFlBQXVCOztZQUV2QixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLENBQUMsQ0FBQTtZQUMxRCxJQUFJLFFBQVEsS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsUUFBUSxFQUFFLENBQUMsQ0FBQTtZQUNqRSxDQUFDO1lBQ0QsTUFBTSxNQUFNLEdBQUcscUJBQVMsQ0FBQyw0QkFBNEIsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUE7WUFDMUUsSUFDQyxNQUFNLEtBQUssSUFBSTtnQkFDZixNQUFNLENBQUMsTUFBTSxLQUFLLFNBQVM7Z0JBQzNCLE1BQU0sQ0FBQyxNQUFNLEtBQUssSUFBSSxFQUNyQixDQUFDO2dCQUNGLE1BQU0sSUFBSSxLQUFLLENBQUMsb0NBQW9DLFFBQVEsRUFBRSxDQUFDLENBQUE7WUFDaEUsQ0FBQztZQUVELE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUE7WUFDckMsTUFBTSxlQUFlLEdBQUcsWUFBWSxDQUFDLGNBQWMsRUFBRSxDQUFBO1lBRXJELElBQUksZUFBZSxLQUFLLGVBQWUsRUFBRSxDQUFDO2dCQUN6QyxPQUFNO1lBQ1AsQ0FBQztZQUNELFFBQVEsQ0FBQyxVQUFVLEdBQUcsUUFBUSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQ2hELGVBQWUsRUFDZixlQUFlLENBQ2YsQ0FBQTtZQUNELFFBQVEsQ0FBQyxTQUFTLEdBQUcsWUFBWSxDQUFBO1FBQ2xDLENBQUM7S0FBQTtJQUVLLDRCQUE0QixDQUNqQyxZQUF5QixFQUN6QixZQUF1Qjs7WUFFdkIsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFlBQVksRUFBRSxZQUFZLENBQUMsQ0FBQTtZQUNsRSxJQUFJLFFBQVEsS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDdkIsTUFBTSxJQUFJLEtBQUssQ0FDZCx5Q0FBeUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQ2xFLENBQUE7WUFDRixDQUFDO1lBQ0QsTUFBTSxNQUFNLEdBQUcscUJBQVMsQ0FBQyw0QkFBNEIsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUE7WUFDMUUsSUFDQyxNQUFNLEtBQUssSUFBSTtnQkFDZixNQUFNLENBQUMsTUFBTSxLQUFLLFNBQVM7Z0JBQzNCLE1BQU0sQ0FBQyxNQUFNLEtBQUssSUFBSSxFQUNyQixDQUFDO2dCQUNGLE1BQU0sSUFBSSxLQUFLLENBQ2Qsd0NBQXdDLFlBQVksQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUNqRSxDQUFBO1lBQ0YsQ0FBQztZQUVELE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUE7WUFDckMsTUFBTSxlQUFlLEdBQUcsWUFBWSxDQUFDLGNBQWMsRUFBRSxDQUFBO1lBRXJELElBQUksZUFBZSxLQUFLLGVBQWUsRUFBRSxDQUFDO2dCQUN6QyxPQUFNO1lBQ1AsQ0FBQztZQUNELFFBQVEsQ0FBQyxVQUFVLEdBQUcsUUFBUSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQ2hELGVBQWUsRUFDZixlQUFlLENBQ2YsQ0FBQTtZQUNELFFBQVEsQ0FBQyxTQUFTLEdBQUcsWUFBWSxDQUFBO1FBQ2xDLENBQUM7S0FBQTtDQUNEO0FBNWlCRCx3REE0aUJDIn0=