@flxbl-io/sfp
Version:
sfp is a CLI tool to help you manage your Salesforce projects in an artifact centric model
315 lines • 32.5 kB
JavaScript
;
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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const DeployImpl_1 = __importStar(require("../deploy/DeployImpl"));
const sfp_logger_1 = __importStar(require("@flxbl-io/sfp-logger"));
const Stage_1 = require("../Stage");
const ReleaseError_1 = __importDefault(require("../../errors/ReleaseError"));
const ChangelogImpl_1 = __importDefault(require("../changelog/ChangelogImpl"));
const SFPStatsSender_1 = __importDefault(require("../../core/stats/SFPStatsSender"));
const SFPOrg_1 = __importDefault(require("../../core/org/SFPOrg"));
const path = require("path");
const os_1 = require("os");
const InstallUnlockedPackageCollection_1 = __importDefault(require("../../core/package/packageInstallers/InstallUnlockedPackageCollection"));
const FetchImpl_1 = __importDefault(require("../artifacts/FetchImpl"));
const GroupConsoleLogs_1 = __importDefault(require("../../ui/GroupConsoleLogs"));
const ArtifactFetcher_1 = __importDefault(require("../../core/artifacts/ArtifactFetcher"));
const SfpPackageBuilder_1 = __importDefault(require("../../core/package/SfpPackageBuilder"));
const SfpPackageInquirer_1 = __importDefault(require("../../core/package/SfpPackageInquirer"));
const ReleaseDefinitionSorter_1 = __importDefault(require("./ReleaseDefinitionSorter"));
const FileOutputHandler_1 = __importDefault(require("../../outputs/FileOutputHandler"));
class ReleaseImpl {
constructor(props, logger) {
this.props = props;
this.logger = logger;
}
async exec() {
let groupSection = new GroupConsoleLogs_1.default('Fetching artifacts').begin();
let fetchImpl = new FetchImpl_1.default('artifacts', this.props.fetchArtifactScript, this.props.scope, this.props.npmrcPath, this.logger);
await fetchImpl.fetchArtifacts(this.props.releaseDefinitions);
sfp_logger_1.default.log((0, sfp_logger_1.COLOR_INFO)(`Sorting order of release definitions...`), sfp_logger_1.LoggerLevel.INFO, this.logger);
const sortedReleaseDefns = await this.getSortedReleaseDefns('artifacts', this.props.releaseDefinitions, this.logger);
const sortedReleaseOrder = sortedReleaseDefns.map((def) => def.release);
sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Order of Release Definitions: ${JSON.stringify(sortedReleaseOrder)}`), sfp_logger_1.LoggerLevel.INFO, this.logger);
groupSection.end();
let installDependenciesResult;
installDependenciesResult = await this.installPackageDependencies(this.props.releaseDefinitions, this.props.targetOrg, this.props.keys, this.props.waitTime);
//Clear up the deployment output
sfp_logger_1.default.log(`Clearing installation output`, sfp_logger_1.LoggerLevel.TRACE, this.logger);
FileOutputHandler_1.default.getInstance().deleteOutputFile(`deployment-breakdown.md`);
FileOutputHandler_1.default.getInstance().deleteOutputFile(`release-changelog.md`);
let deploymentResults = await this.deployArtifacts(sortedReleaseDefns);
//Get all suceeded deploys
let succeededDeploymentResults = [];
let failedDeploymentResults = [];
for (const deploymentResult of deploymentResults) {
if (deploymentResult.result.failed.length === 0)
succeededDeploymentResults.push(deploymentResult);
else
failedDeploymentResults.push(deploymentResult);
}
//Compute Changelog
//There is atleast one succeeded result, so changelog is required
if (succeededDeploymentResults.length > 0) {
//ReleaseName combines all the release together .. even if failed
//Combine all release defns to create release attributes
let releaseName = '';
let workitemFilters = [];
let limit = 30;
let workItemUrl;
let showAllArtifacts = false;
//Lets go through all the succeeded deployments and get the changelog
for (const succededDeployment of succeededDeploymentResults) {
releaseName = succededDeployment.releaseDefinition.release;
let releaseDefinition = succededDeployment.releaseDefinition;
if (releaseDefinition.changelog) {
if (releaseDefinition.changelog?.workItemFilters) {
workitemFilters.push(...releaseDefinition.changelog?.workItemFilters);
}
if (releaseDefinition.changelog.limit > limit)
limit = releaseDefinition.changelog.limit;
workItemUrl = releaseDefinition.changelog.workItemUrl;
showAllArtifacts = releaseDefinition.changelog.showAllArtifacts;
}
if (this.props.isGenerateChangelog) {
let groupSection = new GroupConsoleLogs_1.default('Release changelog').begin();
try {
let changelogImpl = new ChangelogImpl_1.default(this.logger, this.getArtifactDirectory(releaseDefinition), releaseName, workitemFilters, limit, workItemUrl, showAllArtifacts, releaseDefinition.releaseConfigName
? path.join(this.props.directory ? this.props.directory : "", releaseDefinition.releaseConfigName)
: this.props.directory ? this.props.directory : "", false, this.props.branch, false, this.props.isDryRun, releaseDefinition.releaseConfigName, this.props.targetOrg);
let releaseChangelog = await changelogImpl.exec();
const aggregatedNumberOfWorkItemsInRelease = this.getAggregatedNumberOfWorkItemsInRelease(releaseName, releaseChangelog.releases);
SFPStatsSender_1.default.logGauge('release.workitems', aggregatedNumberOfWorkItemsInRelease, {
releaseName: releaseName,
domain: releaseDefinition.releaseConfigName,
});
const aggregatedNumberOfCommitsInRelease = this.getAggregatedNumberOfCommitsInRelease(releaseName, releaseChangelog.releases);
SFPStatsSender_1.default.logGauge('release.commits', aggregatedNumberOfCommitsInRelease, {
releaseName: releaseName,
domain: releaseDefinition.releaseConfigName,
});
}
catch (error) {
sfp_logger_1.default.log(`Unable to push changelog`, sfp_logger_1.LoggerLevel.WARN, this.logger);
sfp_logger_1.default.log(error, sfp_logger_1.LoggerLevel.TRACE, this.logger);
}
groupSection.end();
}
}
}
if (failedDeploymentResults.length > 0) {
throw new ReleaseError_1.default('Release failed', {
succeededDeployments: succeededDeploymentResults,
failedDeployments: failedDeploymentResults,
installDependenciesResult: installDependenciesResult,
});
}
return {
succeededDeployments: succeededDeploymentResults,
failedDeployments: failedDeploymentResults,
installDependenciesResult: installDependenciesResult,
};
}
/**
*
* @param releases
* @returns aggregated number of work items in a release
*/
getAggregatedNumberOfWorkItemsInRelease(releaseName, releases) {
let aggregatedNumberOfWorkItemsInRelease = 0;
releases.forEach((release) => {
if (release.names?.includes(releaseName)) {
aggregatedNumberOfWorkItemsInRelease += this.getNumberOfWorkItems(release);
}
});
return aggregatedNumberOfWorkItemsInRelease;
}
/**
*
* @param releases
* @returns aggregated number of commits in a release
*/
getAggregatedNumberOfCommitsInRelease(releaseName, releases) {
let aggregatedNumberOfCommitsInRelease = 0;
releases.forEach((release) => {
if (release.names?.includes(releaseName)) {
aggregatedNumberOfCommitsInRelease += this.getNumberOfCommits(release);
}
});
return aggregatedNumberOfCommitsInRelease;
}
getNumberOfWorkItems(release) {
return Object.keys(release.workItems).length;
}
getNumberOfCommits(release) {
let numberOfCommits = 0;
release.artifacts.forEach((artifact) => {
numberOfCommits += artifact.commits.length;
});
return numberOfCommits;
}
async deployArtifacts(releaseDefinitions) {
let deploymentResults = [];
for (const releaseDefinition of releaseDefinitions) {
let groupSection = new GroupConsoleLogs_1.default(`Release ${releaseDefinition.release} for Release Configuration: ${releaseDefinition.releaseConfigName}`).begin();
sfp_logger_1.default.log(os_1.EOL);
this.displayReleaseInfo(releaseDefinition, this.props);
let deployProps = {
targetUsername: this.props.targetOrg,
artifactDir: this.getArtifactDirectory(releaseDefinition),
waitTime: this.props.waitTime,
tags: this.props.tags,
isTestsToBeTriggered: false,
deploymentMode: DeployImpl_1.DeploymentMode.NORMAL,
skipIfPackageInstalled: releaseDefinition.skipIfAlreadyInstalled,
logsGroupSymbol: this.props.logsGroupSymbol,
currentStage: Stage_1.Stage.DEPLOY,
baselineOrg: releaseDefinition.baselineOrg,
isDryRun: this.props.isDryRun,
disableArtifactCommit: releaseDefinition.skipArtifactUpdate
? releaseDefinition.skipArtifactUpdate
: false,
promotePackagesBeforeDeploymentToOrg: releaseDefinition.promotePackagesBeforeDeploymentToOrg,
devhubUserName: this.props.devhubUserName,
};
FileOutputHandler_1.default.getInstance().appendOutput(`deployment-breakdown.md`, `## ReleaseConfig: ${releaseDefinition.releaseConfigName ? releaseDefinition.releaseConfigName : ""}\n`);
let deployImpl = new DeployImpl_1.default(deployProps);
let deploymentResult = await deployImpl.exec();
deploymentResults.push({ releaseDefinition: releaseDefinition, result: deploymentResult });
groupSection.end();
//Don't continue deployments if a release breaks in between
if (deploymentResult.failed.length > 0)
break;
}
return deploymentResults;
}
async getSortedReleaseDefns(artifactDirectory, releaseDefns, logger) {
let artifacts = ArtifactFetcher_1.default.fetchArtifacts(artifactDirectory, null, logger);
if (artifacts.length === 0)
throw new Error(`No artifacts to deploy found in ${artifactDirectory}`);
//Convert artifacts to SfpPackages
let sfpPackages = await this.generateSfpPackageFromArtifacts(artifacts, logger);
let sfpPackageInquirer = new SfpPackageInquirer_1.default(sfpPackages, logger);
let sfdxProjectConfig = sfpPackageInquirer.getLatestProjectConfig();
let releaseDefinitionSorter = new ReleaseDefinitionSorter_1.default();
return releaseDefinitionSorter.sortReleaseDefinitions(releaseDefns, sfdxProjectConfig, logger);
}
async generateSfpPackageFromArtifacts(artifacts, logger) {
let sfpPackages = [];
for (const artifact of artifacts) {
let sfpPackage = await SfpPackageBuilder_1.default.buildPackageFromArtifact(artifact, logger);
sfpPackages.push(sfpPackage);
}
return sfpPackages;
}
async installPackageDependencies(releaseDefinitions, targetOrg, keys, waitTime) {
let result = {
success: [],
skipped: [],
failed: [],
};
let packageDependencies = {};
releaseDefinitions.forEach((releaseDefinition) => {
if (releaseDefinition.packageDependencies) {
packageDependencies = Object.assign(packageDependencies, releaseDefinition.packageDependencies);
}
});
let groupSection = new GroupConsoleLogs_1.default('Installing package dependencies').begin();
try {
let packagesToKeys;
if (keys) {
packagesToKeys = this.parseKeys(keys);
}
let externalPackage2s = [];
// print packages dependencies to install
for (let pkg in packageDependencies) {
let dependendentPackage = { name: pkg };
if (packageDependencies[pkg].startsWith('04t'))
dependendentPackage.subscriberPackageVersionId = packageDependencies[pkg];
if (packagesToKeys?.[pkg]) {
dependendentPackage.key = packagesToKeys[pkg];
}
externalPackage2s.push(dependendentPackage);
}
let sfpOrg = await SFPOrg_1.default.create({ aliasOrUsername: targetOrg });
let packageCollectionInstaller = new InstallUnlockedPackageCollection_1.default(sfpOrg, new sfp_logger_1.ConsoleLogger(), this.props.isDryRun);
await packageCollectionInstaller.install(externalPackage2s, true, true);
groupSection.end();
return result;
}
catch (err) {
console.log(err.message);
throw new ReleaseError_1.default('Failed to install package dependencies', { installDependenciesResult: result, succeededDeployments: [], failedDeployments: [] }, err);
}
}
/**
* Parse keys in string format "packageA:key packageB:key packageC:key"
* Returns map of packages to keys
* @param keys
*/
parseKeys(keys) {
let output = {};
keys = keys.trim();
let listOfKeys = keys.split(' ');
for (let key of listOfKeys) {
let packageKeyPair = key.split(':');
if (packageKeyPair.length === 2) {
output[packageKeyPair[0]] = packageKeyPair[1];
}
else {
// Format is incorrect, throw an error
throw new Error(`Error parsing keys, format should be: "packageA:key packageB:key packageC:key"`);
}
}
return output;
}
displayReleaseInfo(releaseDefinition, props) {
sfp_logger_1.default.printHeaderLine('', sfp_logger_1.COLOR_HEADER, sfp_logger_1.LoggerLevel.INFO);
sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Release: ${releaseDefinition.release}`));
if (releaseDefinition.releaseConfigName) {
sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Release Config Name: ${releaseDefinition.releaseConfigName}`));
}
sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Skip Packages If Already Installed: ${releaseDefinition.skipIfAlreadyInstalled ? true : false}`));
sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Dry-run: ${props.isDryRun}`));
if (releaseDefinition.baselineOrg)
sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Baselined Against Org: ${releaseDefinition.baselineOrg}`));
if (releaseDefinition.promotePackagesBeforeDeploymentToOrg &&
releaseDefinition.promotePackagesBeforeDeploymentToOrg == props.targetOrg)
sfp_logger_1.default.log((0, sfp_logger_1.COLOR_KEY_MESSAGE)(`Promte Packages Before Deployment Activated?: true`));
sfp_logger_1.default.printHeaderLine('', sfp_logger_1.COLOR_HEADER, sfp_logger_1.LoggerLevel.INFO);
}
getArtifactDirectory(releaseDefinition) {
let revisedArtifactDirectory = path.join('artifacts', releaseDefinition.release.replace(/[/\\?%*:|"<>]/g, '-'));
if (releaseDefinition.releaseConfigName) {
revisedArtifactDirectory = path.join('artifacts', releaseDefinition.releaseConfigName.replace(/[/\\?%*:|"<>]/g, '-'), releaseDefinition.release.replace(/[/\\?%*:|"<>]/g, '-'));
}
return revisedArtifactDirectory;
}
}
exports.default = ReleaseImpl;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVsZWFzZUltcGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW1wbC9yZWxlYXNlL1JlbGVhc2VJbXBsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFDQSxtRUFBaUc7QUFDakcsbUVBQWtJO0FBQ2xJLG9DQUFpQztBQUNqQyw2RUFBcUQ7QUFDckQsK0VBQXVEO0FBQ3ZELHFGQUE2RDtBQUU3RCxtRUFBMkM7QUFDM0MsNkJBQThCO0FBQzlCLDJCQUF5QjtBQUV6Qiw2SUFBcUg7QUFDckgsdUVBQStDO0FBQy9DLGlGQUF5RDtBQUN6RCwyRkFBaUY7QUFFakYsNkZBQXFFO0FBQ3JFLCtGQUF1RTtBQUN2RSx3RkFBZ0U7QUFDaEUsd0ZBQWdFO0FBMEJoRSxNQUFxQixXQUFXO0lBSTVCLFlBQW9CLEtBQW1CLEVBQVUsTUFBZTtRQUE1QyxVQUFLLEdBQUwsS0FBSyxDQUFjO1FBQVUsV0FBTSxHQUFOLE1BQU0sQ0FBUztJQUFHLENBQUM7SUFFN0QsS0FBSyxDQUFDLElBQUk7UUFDYixJQUFJLFlBQVksR0FBRyxJQUFJLDBCQUFnQixDQUFDLG9CQUFvQixDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdEUsSUFBSSxTQUFTLEdBQWMsSUFBSSxtQkFBUyxDQUNwQyxXQUFXLEVBQ1gsSUFBSSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsRUFDOUIsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQ2hCLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUNwQixJQUFJLENBQUMsTUFBTSxDQUNkLENBQUM7UUFDRixNQUFNLFNBQVMsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBRTlELG9CQUFTLENBQUMsR0FBRyxDQUFDLElBQUEsdUJBQVUsRUFBQyx5Q0FBeUMsQ0FBQyxFQUFFLHdCQUFXLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNwRyxNQUFNLGtCQUFrQixHQUFHLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLFdBQVcsRUFBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGtCQUFrQixFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNwSCxNQUFNLGtCQUFrQixHQUFHLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3hFLG9CQUFTLENBQUMsR0FBRyxDQUFDLElBQUEsOEJBQWlCLEVBQUMsa0NBQWtDLElBQUksQ0FBQyxTQUFTLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUFDLEVBQUUsd0JBQVcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBR3hJLFlBQVksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUVuQixJQUFJLHlCQUFvRCxDQUFDO1FBQ3pELHlCQUF5QixHQUFHLE1BQU0sSUFBSSxDQUFDLDBCQUEwQixDQUM3RCxJQUFJLENBQUMsS0FBSyxDQUFDLGtCQUFrQixFQUM3QixJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFDcEIsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQ2YsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQ3RCLENBQUM7UUFFRixnQ0FBZ0M7UUFDaEMsb0JBQVMsQ0FBQyxHQUFHLENBQUMsOEJBQThCLEVBQUUsd0JBQVcsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzlFLDJCQUFpQixDQUFDLFdBQVcsRUFBRSxDQUFDLGdCQUFnQixDQUFDLHlCQUF5QixDQUFDLENBQUM7UUFDNUUsMkJBQWlCLENBQUMsV0FBVyxFQUFFLENBQUMsZ0JBQWdCLENBQUMsc0JBQXNCLENBQUMsQ0FBQztRQUV6RSxJQUFJLGlCQUFpQixHQUFHLE1BQU0sSUFBSSxDQUFDLGVBQWUsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBRXZFLDBCQUEwQjtRQUMxQixJQUFJLDBCQUEwQixHQUF1QixFQUFFLENBQUM7UUFDeEQsSUFBSSx1QkFBdUIsR0FBdUIsRUFBRSxDQUFDO1FBQ3JELEtBQUssTUFBTSxnQkFBZ0IsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO1lBQy9DLElBQUksZ0JBQWdCLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQztnQkFBRSwwQkFBMEIsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FBQzs7Z0JBQzlGLHVCQUF1QixDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3hELENBQUM7UUFFRCxtQkFBbUI7UUFFbkIsaUVBQWlFO1FBQ2pFLElBQUksMEJBQTBCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3hDLGlFQUFpRTtZQUNqRSx3REFBd0Q7WUFDeEQsSUFBSSxXQUFXLEdBQVcsRUFBRSxDQUFDO1lBQzdCLElBQUksZUFBZSxHQUFHLEVBQUUsQ0FBQztZQUN6QixJQUFJLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDZixJQUFJLFdBQW1CLENBQUM7WUFDeEIsSUFBSSxnQkFBZ0IsR0FBWSxLQUFLLENBQUM7WUFFdEMscUVBQXFFO1lBQ3JFLEtBQUssTUFBTSxrQkFBa0IsSUFBSSwwQkFBMEIsRUFBRSxDQUFDO2dCQUMxRCxXQUFXLEdBQUcsa0JBQWtCLENBQUMsaUJBQWlCLENBQUMsT0FBTyxDQUFDO2dCQUMzRCxJQUFJLGlCQUFpQixHQUFHLGtCQUFrQixDQUFDLGlCQUFpQixDQUFDO2dCQUM3RCxJQUFJLGlCQUFpQixDQUFDLFNBQVMsRUFBRSxDQUFDO29CQUM5QixJQUFJLGlCQUFpQixDQUFDLFNBQVMsRUFBRSxlQUFlLEVBQUUsQ0FBQzt3QkFDL0MsZUFBZSxDQUFDLElBQUksQ0FBQyxHQUFHLGlCQUFpQixDQUFDLFNBQVMsRUFBRSxlQUFlLENBQUMsQ0FBQztvQkFDMUUsQ0FBQztvQkFDRCxJQUFJLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxLQUFLLEdBQUcsS0FBSzt3QkFBRSxLQUFLLEdBQUcsaUJBQWlCLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQztvQkFDekYsV0FBVyxHQUFHLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUM7b0JBQ3RELGdCQUFnQixHQUFHLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDcEUsQ0FBQztnQkFFRCxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztvQkFDakMsSUFBSSxZQUFZLEdBQUcsSUFBSSwwQkFBZ0IsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUNyRSxJQUFJLENBQUM7d0JBQ0QsSUFBSSxhQUFhLEdBQWtCLElBQUksdUJBQWEsQ0FDaEQsSUFBSSxDQUFDLE1BQU0sRUFDWCxJQUFJLENBQUMsb0JBQW9CLENBQUMsaUJBQWlCLENBQUMsRUFDNUMsV0FBVyxFQUNYLGVBQWUsRUFDZixLQUFLLEVBQ0wsV0FBVyxFQUNYLGdCQUFnQixFQUNoQixpQkFBaUIsQ0FBQyxpQkFBaUI7NEJBQy9CLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFBLENBQUMsQ0FBQSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQSxDQUFDLENBQUEsRUFBRSxFQUFFLGlCQUFpQixDQUFDLGlCQUFpQixDQUFDOzRCQUM5RixDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUEsQ0FBQyxDQUFBLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFBLENBQUMsQ0FBQSxFQUFFLEVBQ2xELEtBQUssRUFDTCxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFDakIsS0FBSyxFQUNMLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUNuQixpQkFBaUIsQ0FBQyxpQkFBaUIsRUFDbkMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQ3ZCLENBQUM7d0JBRUYsSUFBSSxnQkFBZ0IsR0FBRyxNQUFNLGFBQWEsQ0FBQyxJQUFJLEVBQUUsQ0FBQzt3QkFFbEQsTUFBTSxvQ0FBb0MsR0FBRyxJQUFJLENBQUMsdUNBQXVDLENBQ3JGLFdBQVcsRUFDWCxnQkFBZ0IsQ0FBQyxRQUFRLENBQzVCLENBQUM7d0JBRUYsd0JBQWMsQ0FBQyxRQUFRLENBQUMsbUJBQW1CLEVBQUUsb0NBQW9DLEVBQUU7NEJBQy9FLFdBQVcsRUFBRSxXQUFXOzRCQUN4QixNQUFNLEVBQUUsaUJBQWlCLENBQUMsaUJBQWlCO3lCQUM5QyxDQUFDLENBQUM7d0JBRUgsTUFBTSxrQ0FBa0MsR0FBRyxJQUFJLENBQUMscUNBQXFDLENBQ2pGLFdBQVcsRUFDWCxnQkFBZ0IsQ0FBQyxRQUFRLENBQzVCLENBQUM7d0JBRUYsd0JBQWMsQ0FBQyxRQUFRLENBQUMsaUJBQWlCLEVBQUUsa0NBQWtDLEVBQUU7NEJBQzNFLFdBQVcsRUFBRSxXQUFXOzRCQUN4QixNQUFNLEVBQUUsaUJBQWlCLENBQUMsaUJBQWlCO3lCQUM5QyxDQUFDLENBQUM7b0JBQ1AsQ0FBQztvQkFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO3dCQUNiLG9CQUFTLENBQUMsR0FBRyxDQUFDLDBCQUEwQixFQUFFLHdCQUFXLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQzt3QkFDekUsb0JBQVMsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLHdCQUFXLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFDekQsQ0FBQztvQkFFRCxZQUFZLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ3ZCLENBQUM7WUFDTCxDQUFDO1FBQ0wsQ0FBQztRQUVELElBQUksdUJBQXVCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3JDLE1BQU0sSUFBSSxzQkFBWSxDQUFDLGlCQUFpQixFQUFFO2dCQUN0QyxvQkFBb0IsRUFBRSwwQkFBMEI7Z0JBQ2hELGlCQUFpQixFQUFFLHVCQUF1QjtnQkFDMUMseUJBQXlCLEVBQUUseUJBQXlCO2FBQ3ZELENBQUMsQ0FBQztRQUNQLENBQUM7UUFFRCxPQUFPO1lBQ0gsb0JBQW9CLEVBQUUsMEJBQTBCO1lBQ2hELGlCQUFpQixFQUFFLHVCQUF1QjtZQUMxQyx5QkFBeUIsRUFBRSx5QkFBeUI7U0FDdkQsQ0FBQztJQUNOLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ssdUNBQXVDLENBQUMsV0FBbUIsRUFBRSxRQUFtQjtRQUNwRixJQUFJLG9DQUFvQyxHQUFXLENBQUMsQ0FBQztRQUNyRCxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDekIsSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO2dCQUN2QyxvQ0FBb0MsSUFBSSxJQUFJLENBQUMsb0JBQW9CLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDL0UsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxvQ0FBb0MsQ0FBQztJQUNoRCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLHFDQUFxQyxDQUFDLFdBQW1CLEVBQUUsUUFBbUI7UUFDbEYsSUFBSSxrQ0FBa0MsR0FBVyxDQUFDLENBQUM7UUFDbkQsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQ3pCLElBQUksT0FBTyxDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztnQkFDdkMsa0NBQWtDLElBQUksSUFBSSxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzNFLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztRQUNILE9BQU8sa0NBQWtDLENBQUM7SUFDOUMsQ0FBQztJQUVPLG9CQUFvQixDQUFDLE9BQWdCO1FBQ3pDLE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ2pELENBQUM7SUFFTyxrQkFBa0IsQ0FBQyxPQUFnQjtRQUN2QyxJQUFJLGVBQWUsR0FBVyxDQUFDLENBQUM7UUFFaEMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRTtZQUNuQyxlQUFlLElBQUksUUFBUSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7UUFDL0MsQ0FBQyxDQUFDLENBQUM7UUFFSCxPQUFPLGVBQWUsQ0FBQztJQUMzQixDQUFDO0lBSU8sS0FBSyxDQUFDLGVBQWUsQ0FBQyxrQkFBdUM7UUFDakUsSUFBSSxpQkFBaUIsR0FBeUUsRUFBRSxDQUFDO1FBQ2pHLEtBQUssTUFBTSxpQkFBaUIsSUFBSSxrQkFBa0IsRUFBRSxDQUFDO1lBQ2pELElBQUksWUFBWSxHQUFHLElBQUksMEJBQWdCLENBQUMsV0FBVyxpQkFBaUIsQ0FBQyxPQUFPLCtCQUErQixpQkFBaUIsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDMUosb0JBQVMsQ0FBQyxHQUFHLENBQUMsUUFBRyxDQUFDLENBQUM7WUFFbkIsSUFBSSxDQUFDLGtCQUFrQixDQUFDLGlCQUFpQixFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUd2RCxJQUFJLFdBQVcsR0FBZ0I7Z0JBQzNCLGNBQWMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVM7Z0JBQ3BDLFdBQVcsRUFBRSxJQUFJLENBQUMsb0JBQW9CLENBQUMsaUJBQWlCLENBQUM7Z0JBQ3pELFFBQVEsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVE7Z0JBQzdCLElBQUksRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUk7Z0JBQ3JCLG9CQUFvQixFQUFFLEtBQUs7Z0JBQzNCLGNBQWMsRUFBRSwyQkFBYyxDQUFDLE1BQU07Z0JBQ3JDLHNCQUFzQixFQUFFLGlCQUFpQixDQUFDLHNCQUFzQjtnQkFDaEUsZUFBZSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZTtnQkFDM0MsWUFBWSxFQUFFLGFBQUssQ0FBQyxNQUFNO2dCQUMxQixXQUFXLEVBQUUsaUJBQWlCLENBQUMsV0FBVztnQkFDMUMsUUFBUSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUTtnQkFDN0IscUJBQXFCLEVBQUUsaUJBQWlCLENBQUMsa0JBQWtCO29CQUN2RCxDQUFDLENBQUMsaUJBQWlCLENBQUMsa0JBQWtCO29CQUN0QyxDQUFDLENBQUMsS0FBSztnQkFDWCxvQ0FBb0MsRUFBRSxpQkFBaUIsQ0FBQyxvQ0FBb0M7Z0JBQzVGLGNBQWMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLGNBQWM7YUFDNUMsQ0FBQztZQUVGLDJCQUFpQixDQUFDLFdBQVcsRUFBRSxDQUFDLFlBQVksQ0FBQyx5QkFBeUIsRUFBQyxxQkFBcUIsaUJBQWlCLENBQUMsaUJBQWlCLENBQUEsQ0FBQyxDQUFBLGlCQUFpQixDQUFDLGlCQUFpQixDQUFBLENBQUMsQ0FBQSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQzVLLElBQUksVUFBVSxHQUFlLElBQUksb0JBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUV6RCxJQUFJLGdCQUFnQixHQUFHLE1BQU0sVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQy9DLGlCQUFpQixDQUFDLElBQUksQ0FBQyxFQUFFLGlCQUFpQixFQUFFLGlCQUFpQixFQUFFLE1BQU0sRUFBRSxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7WUFDM0YsWUFBWSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ25CLDJEQUEyRDtZQUMzRCxJQUFJLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQztnQkFBRSxNQUFNO1FBQ2xELENBQUM7UUFFRCxPQUFPLGlCQUFpQixDQUFDO0lBQzdCLENBQUM7SUFFTyxLQUFLLENBQUMscUJBQXFCLENBQUMsaUJBQXlCLEVBQUMsWUFBZ0MsRUFBRSxNQUFjO1FBQzFHLElBQUksU0FBUyxHQUFHLHlCQUFlLENBQUMsY0FBYyxDQUFDLGlCQUFpQixFQUFFLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNoRixJQUFJLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsbUNBQW1DLGlCQUFpQixFQUFFLENBQUMsQ0FBQztRQUVwRyxrQ0FBa0M7UUFDbEMsSUFBSSxXQUFXLEdBQUcsTUFBTSxJQUFJLENBQUMsK0JBQStCLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBRWhGLElBQUksa0JBQWtCLEdBQXVCLElBQUksNEJBQWtCLENBQUMsV0FBVyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ3pGLElBQUksaUJBQWlCLEdBQUcsa0JBQWtCLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztRQUVwRSxJQUFJLHVCQUF1QixHQUFHLElBQUksaUNBQXVCLEVBQUUsQ0FBQztRQUM1RCxPQUFPLHVCQUF1QixDQUFDLHNCQUFzQixDQUFDLFlBQVksRUFBRSxpQkFBaUIsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNuRyxDQUFDO0lBRU8sS0FBSyxDQUFDLCtCQUErQixDQUFDLFNBQXFCLEVBQUUsTUFBYztRQUMvRSxJQUFJLFdBQVcsR0FBaUIsRUFBRSxDQUFDO1FBQ25DLEtBQUssTUFBTSxRQUFRLElBQUksU0FBUyxFQUFFLENBQUM7WUFDL0IsSUFBSSxVQUFVLEdBQUcsTUFBTSwyQkFBaUIsQ0FBQyx3QkFBd0IsQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDcEYsV0FBVyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNqQyxDQUFDO1FBQ0QsT0FBTyxXQUFXLENBQUM7SUFDdkIsQ0FBQztJQUVPLEtBQUssQ0FBQywwQkFBMEIsQ0FDcEMsa0JBQXVDLEVBQ3ZDLFNBQWlCLEVBQ2pCLElBQVksRUFDWixRQUFnQjtRQUVoQixJQUFJLE1BQU0sR0FBOEI7WUFDcEMsT0FBTyxFQUFFLEVBQUU7WUFDWCxPQUFPLEVBQUUsRUFBRTtZQUNYLE1BQU0sRUFBRSxFQUFFO1NBQ2IsQ0FBQztRQUVGLElBQUksbUJBQW1CLEdBQTRCLEVBQUUsQ0FBQztRQUV0RCxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxpQkFBaUIsRUFBRSxFQUFFO1lBQzdDLElBQUksaUJBQWlCLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztnQkFDeEMsbUJBQW1CLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsRUFBRSxpQkFBaUIsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQ3BHLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztRQUVILElBQUksWUFBWSxHQUFHLElBQUksMEJBQWdCLENBQUMsaUNBQWlDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUVuRixJQUFJLENBQUM7WUFDRCxJQUFJLGNBQXVDLENBQUM7WUFDNUMsSUFBSSxJQUFJLEVBQUUsQ0FBQztnQkFDUCxjQUFjLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUMxQyxDQUFDO1lBQ0QsSUFBSSxpQkFBaUIsR0FBcUIsRUFBRSxDQUFDO1lBQzdDLHlDQUF5QztZQUN6QyxLQUFLLElBQUksR0FBRyxJQUFJLG1CQUFtQixFQUFFLENBQUM7Z0JBQ2xDLElBQUksbUJBQW1CLEdBQW1CLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDO2dCQUN4RCxJQUFJLG1CQUFtQixDQUFDLEdBQUcsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUM7b0JBQzFDLG1CQUFtQixDQUFDLDBCQUEwQixHQUFHLG1CQUFtQixDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUU5RSxJQUFJLGNBQWMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ3hCLG1CQUFtQixDQUFDLEdBQUcsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQ2xELENBQUM7Z0JBQ0QsaUJBQWlCLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFDaEQsQ0FBQztZQUNELElBQUksTUFBTSxHQUFHLE1BQU0sZ0JBQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxlQUFlLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztZQUNqRSxJQUFJLDBCQUEwQixHQUFHLElBQUksMENBQWdDLENBQ2pFLE1BQU0sRUFDTixJQUFJLDBCQUFhLEVBQUUsRUFDbkIsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQ3RCLENBQUM7WUFDRixNQUFNLDBCQUEwQixDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFFeEUsWUFBWSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ25CLE9BQU8sTUFBTSxDQUFDO1FBQ2xCLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ1gsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7WUFFekIsTUFBTSxJQUFJLHNCQUFZLENBQ2xCLHdDQUF3QyxFQUN4QyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sRUFBRSxvQkFBb0IsRUFBRSxFQUFFLEVBQUUsaUJBQWlCLEVBQUUsRUFBRSxFQUFFLEVBQ3RGLEdBQUcsQ0FDTixDQUFDO1FBQ04sQ0FBQztJQUNMLENBQUM7SUFFRDs7OztPQUlHO0lBQ0ssU0FBUyxDQUFDLElBQVk7UUFDMUIsSUFBSSxNQUFNLEdBQTRCLEVBQUUsQ0FBQztRQUV6QyxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ25CLElBQUksVUFBVSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFakMsS0FBSyxJQUFJLEdBQUcsSUFBSSxVQUFVLEVBQUUsQ0FBQztZQUN6QixJQUFJLGNBQWMsR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3BDLElBQUksY0FBYyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDOUIsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNsRCxDQUFDO2lCQUFNLENBQUM7Z0JBQ0osc0NBQXNDO2dCQUN0QyxNQUFNLElBQUksS0FBSyxDQUFDLGdGQUFnRixDQUFDLENBQUM7WUFDdEcsQ0FBQztRQUNMLENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQztJQUNsQixDQUFDO0lBRU8sa0JBQWtCLENBQUMsaUJBQW9DLEVBQUUsS0FBbUI7UUFDaEYsb0JBQVMsQ0FBQyxlQUFlLENBQUMsRUFBRSxFQUFFLHlCQUFZLEVBQUUsd0JBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUU5RCxvQkFBUyxDQUFDLEdBQUcsQ0FBQyxJQUFBLDhCQUFpQixFQUFDLFlBQVksaUJBQWlCLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzFFLElBQUksaUJBQWlCLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUN0QyxvQkFBUyxDQUFDLEdBQUcsQ0FBQyxJQUFBLDhCQUFpQixFQUFDLHdCQUF3QixpQkFBaUIsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNwRyxDQUFDO1FBRUQsb0JBQVMsQ0FBQyxHQUFHLENBQ1QsSUFBQSw4QkFBaUIsRUFDYix1Q0FBdUMsaUJBQWlCLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQ25HLENBQ0osQ0FBQztRQUVGLG9CQUFTLENBQUMsR0FBRyxDQUFDLElBQUEsOEJBQWlCLEVBQUMsWUFBWSxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRS9ELElBQUksaUJBQWlCLENBQUMsV0FBVztZQUM3QixvQkFBUyxDQUFDLEdBQUcsQ0FBQyxJQUFBLDhCQUFpQixFQUFDLDBCQUEwQixpQkFBaUIsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFFaEcsSUFDSSxpQkFBaUIsQ0FBQyxvQ0FBb0M7WUFDdEQsaUJBQWlCLENBQUMsb0NBQW9DLElBQUksS0FBSyxDQUFDLFNBQVM7WUFFekUsb0JBQVMsQ0FBQyxHQUFHLENBQUMsSUFBQSw4QkFBaUIsRUFBQyxvREFBb0QsQ0FBQyxDQUFDLENBQUM7UUFFM0Ysb0JBQVMsQ0FBQyxlQUFlLENBQUMsRUFBRSxFQUFFLHlCQUFZLEVBQUUsd0JBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBRU8sb0JBQW9CLENBQUMsaUJBQW9DO1FBQzdELElBQUksd0JBQXdCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FDcEMsV0FBVyxFQUNYLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsR0FBRyxDQUFDLENBQzNELENBQUM7UUFDRixJQUFJLGlCQUFpQixDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDdEMsd0JBQXdCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FDaEMsV0FBVyxFQUNYLGlCQUFpQixDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLENBQUMsRUFDbEUsaUJBQWlCLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLENBQUMsQ0FDM0QsQ0FBQztRQUNOLENBQUM7UUFDRCxPQUFPLHdCQUF3QixDQUFDO0lBQ3BDLENBQUM7Q0FDSjtBQXpYRCw4QkF5WEMifQ==