@flxbl-io/sfp
Version:
sfp is a CLI tool to help you manage your Salesforce projects in an artifact centric model
284 lines • 28.4 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 (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 DeploymentExecutor_1 = require("../../deployers/DeploymentExecutor");
const ReconcileProfileAgainstOrgImpl_1 = __importDefault(require("../components/ReconcileProfileAgainstOrgImpl"));
const DeployDestructiveManifestToOrgImpl_1 = __importDefault(require("../components/DeployDestructiveManifestToOrgImpl"));
const sfp_logger_1 = __importStar(require("@flxbl-io/sfp-logger"));
const fs = __importStar(require("fs-extra"));
const path = require('path');
const tmp = require('tmp');
const InstallPackage_1 = require("./InstallPackage");
const DeploySourceToOrgImpl_1 = __importDefault(require("../../deployers/DeploySourceToOrgImpl"));
const PackageEmptyChecker_1 = __importDefault(require("../validators/PackageEmptyChecker"));
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
const ProjectConfig_1 = __importDefault(require("../../project/ProjectConfig"));
const DeploymentFilterRegistry_1 = require("../deploymentFilters/DeploymentFilterRegistry");
const DeploymentOptionDisplayer_1 = __importDefault(require("../../display/DeploymentOptionDisplayer"));
const PackageComponentPrinter_1 = __importDefault(require("../../display/PackageComponentPrinter"));
const DeployErrorDisplayer_1 = __importDefault(require("../../display/DeployErrorDisplayer"));
const sfp_logger_2 = require("@flxbl-io/sfp-logger");
const glob_1 = require("glob");
class InstallSourcePackageImpl extends InstallPackage_1.InstallPackage {
constructor(sfpPackage, targetOrg, options, logger) {
super(sfpPackage, targetOrg, logger, options);
this.options = options;
this.pathToReplacementForceIgnore = options.pathToReplacementForceIgnore;
this.deploymentType = options.deploymentType;
}
async install() {
let tmpDirObj = tmp.dirSync({ unsafeCleanup: true });
let tempDir = tmpDirObj.name;
try {
//Handle the right force ignore file
this.handleForceIgnores();
// Apply Destructive Manifest
await this.applyDestructiveChanges();
//Apply Reconcile if Profiles are found
//To Reconcile we have to go for multiple deploys, first we have to reconcile profiles and deploy the metadata
let isReconcileActivated = false;
let isReconcileErrored = false;
let profileFolders;
({
profileFolders,
isReconcileActivated,
isReconcileErrored,
} = await this.reconcileProfilesBeforeDeployment(this.sfpPackage.sourceDir, this.sfpOrg.getUsername(), tempDir));
let deploymentOptions;
let result;
//Construct Deploy Command for actual payload
deploymentOptions = await this.generateDeploymentOptions(this.options.waitTime, this.options.optimizeDeployment, this.options.skipTesting, this.sfpOrg.getUsername(), this.options.apiVersion);
//enable source tracking
if (this.deploymentType === DeploymentExecutor_1.DeploymentType.SOURCE_PUSH) {
deploymentOptions.sourceTracking = true;
}
//Make a copy.. dont mutate sourceDirectory
let resolvedSourceDirectory = this.sfpPackage.sourceDir;
let emptyCheck = this.handleEmptyPackage(resolvedSourceDirectory, this.packageDirectory);
if (emptyCheck.isToSkip == true) {
sfp_logger_1.default.log(`${(0, sfp_logger_1.COLOR_SUCCESS)(`Skipping the package as there is nothing to be deployed`)}`, sfp_logger_1.LoggerLevel.INFO, this.logger);
return {
deploy_id: `000000`,
result: true,
message: `Package is empty, nothing to install,skipped`,
};
}
else if (emptyCheck.isToSkip == false) {
//Create componentSet To Be Deployed
let componentSet = source_deploy_retrieve_1.ComponentSet.fromSource(path.resolve(emptyCheck.resolvedSourceDirectory, this.packageDirectory));
//Apply Filters
let deploymentFilters = DeploymentFilterRegistry_1.DeploymentFilterRegistry.getImplementations();
for (const deploymentFilter of deploymentFilters) {
if (deploymentFilter.isToApply(ProjectConfig_1.default.getSFDXProjectConfig(emptyCheck.resolvedSourceDirectory), this.sfpPackage.packageType))
componentSet = await deploymentFilter.apply(this.sfpOrg, componentSet, this.logger);
}
//Check if there are components to be deployed after filtering
//Assume its successfully deployed
if (componentSet.size == 0) {
return {
deploy_id: `000000`,
result: true,
message: `Package contents were filtered out, nothing to install`,
};
}
//Print components inside Component Set
let components = componentSet.getSourceComponents();
PackageComponentPrinter_1.default.printComponentTable(components, this.logger);
if (!this.options.isInstallingForValidation) {
DeploymentOptionDisplayer_1.default.printDeploymentOptions(deploymentOptions, this.logger);
}
let deploySourceToOrgImpl = new DeploySourceToOrgImpl_1.default(this.sfpOrg, this.sfpPackage.sourceDir, componentSet, deploymentOptions, this.logger);
result = await deploySourceToOrgImpl.exec();
if (result.result) {
//Apply PostDeployment Activities
try {
if (isReconcileActivated) {
//Bring back the original profiles, reconcile and redeploy again
await this.reconcileAndRedeployProfiles(profileFolders, this.sfpPackage.sourceDir, this.sfpOrg.getUsername(), this.packageDirectory, tempDir, deploymentOptions);
}
}
catch (error) {
sfp_logger_1.default.log('Failed to apply reconcile the second time, Partial Metadata applied', sfp_logger_1.LoggerLevel.INFO, this.logger);
}
}
else if (result.result === false) {
DeployErrorDisplayer_1.default.displayErrors(result.response, this.logger);
throw new Error(result.message);
}
}
//}
}
catch (error) {
tmpDirObj.removeCallback();
throw error;
}
}
handleEmptyPackage(sourceDirectory, packageDirectory) {
//Check empty conditions
let status = PackageEmptyChecker_1.default.isToBreakBuildForEmptyDirectory(sourceDirectory, packageDirectory, false);
if (status.result == 'break') {
throw new Error('No components in the package, Please check your build again');
}
else if (status.result == 'skip') {
return {
isToSkip: true,
resolvedSourceDirectory: sourceDirectory,
};
}
else {
return {
isToSkip: false,
resolvedSourceDirectory: sourceDirectory,
};
}
}
handleForceIgnores() {
if (this.pathToReplacementForceIgnore) {
this.replaceForceIgnoreInSourceDirectory(this.sfpPackage.sourceDir, this.pathToReplacementForceIgnore);
//Handle Diff condition
// if (this.isDiffFolderAvailable)
// this.replaceForceIgnoreInSourceDirectory(
// path.join(this.sfpPackage.sourceDir, 'diff'),
// this.pathToReplacementForceIgnore
// );
}
}
async applyDestructiveChanges() {
if (this.sfpPackage.destructiveChanges) {
try {
sfp_logger_1.default.log('Attempt to delete components mentioned in destructive manifest', sfp_logger_1.LoggerLevel.INFO, this.logger);
let deployDestructiveManifestToOrg = new DeployDestructiveManifestToOrgImpl_1.default(this.sfpOrg, path.join(this.sfpPackage.sourceDir, 'destructive', 'destructiveChanges.xml'));
await deployDestructiveManifestToOrg.exec();
}
catch (error) {
sfp_logger_1.default.log(`We attempted a deletion of components, However we are not successful. \
Either the components are already deleted or there are components which \
have dependency to components in the manifest. \
Please check whether this manifest works! \
Actual Error Observed: \
-------------------------------------- \
${(0, sfp_logger_2.COLOR_ERROR)(error.message)}`, sfp_logger_1.LoggerLevel.INFO, this.logger);
}
}
}
async reconcileProfilesBeforeDeployment(sourceDirectoryPath, target_org, tempDir) {
let profileFolders;
let isReconcileActivated = false;
let isReconcileErrored = false;
try {
//Hard exit.. no reconcile set in orchestrator
if (this.sfpPackage.reconcileProfiles == false)
return { isReconcileActivated: false };
//Handle diff for fastfeedback
if (this.sfpPackage.isProfilesFound) {
}
else {
return { isReconcileActivated: false };
}
sfp_logger_1.default.log('Attempting reconcile to profiles as payload contain profiles', sfp_logger_1.LoggerLevel.INFO, this.logger);
//copy the original profiles to temporary location
profileFolders = (0, glob_1.globSync)('**/profiles', {
cwd: path.join(sourceDirectoryPath),
});
if (profileFolders.length > 0) {
profileFolders.forEach((folder) => {
fs.copySync(path.join(sourceDirectoryPath, folder), path.join(tempDir, folder));
});
}
//Now Reconcile
let reconcileProfileAgainstOrg = new ReconcileProfileAgainstOrgImpl_1.default(this.sfpOrg, path.join(sourceDirectoryPath), this.logger);
await reconcileProfileAgainstOrg.exec();
isReconcileActivated = true;
}
catch (err) {
sfp_logger_1.default.log('Failed to reconcile profiles:' + err, sfp_logger_1.LoggerLevel.INFO, this.logger);
isReconcileErrored = true;
if (profileFolders.length > 0) {
sfp_logger_1.default.log('Restoring original profiles as preprocessing failed', sfp_logger_1.LoggerLevel.INFO, this.logger);
profileFolders.forEach((folder) => {
fs.copySync(path.join(tempDir, folder), path.join(this.sfpPackage.sourceDir, folder));
});
}
}
return { profileFolders, isReconcileActivated, isReconcileErrored };
}
async reconcileAndRedeployProfiles(profileFolders, sourceDirectoryPath, target_org, sourceDirectory, tmpdir, deploymentOptions) {
//if no profile supported metadata, no point in
//doing a reconcile
if (this.sfpPackage.isProfilesFound == false)
return;
if (this.sfpPackage.isPayLoadContainTypesSupportedByProfiles == false)
return;
if (profileFolders.length > 0) {
sfp_logger_1.default.log(`Restoring original profiles for reconcile and deploy`, sfp_logger_1.LoggerLevel.INFO, this.logger);
profileFolders.forEach((folder) => {
fs.copySync(path.join(tmpdir, folder), path.join(sourceDirectoryPath, folder));
});
//Now Reconcile
let reconcileProfileAgainstOrg = new ReconcileProfileAgainstOrgImpl_1.default(this.sfpOrg, sourceDirectoryPath, this.logger);
await reconcileProfileAgainstOrg.exec();
//Now deploy the profiles alone
const profilesDirs = (0, glob_1.globSync)('**/profiles/', {
cwd: path.join(sourceDirectoryPath, sourceDirectory),
absolute: true,
});
const profileDeploymentStagingDirectory = path.join(sourceDirectoryPath, 'ProfileDeploymentStagingDirectory');
fs.mkdirpSync(path.join(profileDeploymentStagingDirectory, sourceDirectory, 'profiles'));
for (const dir of profilesDirs) {
// Duplicate profiles are overwritten
fs.copySync(dir, path.join(profileDeploymentStagingDirectory, sourceDirectory, 'profiles'));
}
fs.copySync(path.join(sourceDirectoryPath, 'sfdx-project.json'), path.join(profileDeploymentStagingDirectory, 'sfdx-project.json'));
fs.copySync(path.join(sourceDirectoryPath, '.forceignore'), path.join(profileDeploymentStagingDirectory, '.forceignore'));
//Create componentSet To Be Deployed
let componentSet = source_deploy_retrieve_1.ComponentSet.fromSource(path.resolve(profileDeploymentStagingDirectory, sourceDirectory));
DeploymentOptionDisplayer_1.default.printDeploymentOptions(deploymentOptions, this.logger);
let deploySourceToOrgImpl = new DeploySourceToOrgImpl_1.default(this.sfpOrg, this.sfpPackage.sourceDir, componentSet, deploymentOptions, this.logger);
let profileReconcile = await deploySourceToOrgImpl.exec();
if (!profileReconcile.result) {
DeployErrorDisplayer_1.default.displayErrors(profileReconcile.response, this.logger);
sfp_logger_1.default.log('Unable to deploy reconciled profiles', sfp_logger_1.LoggerLevel.INFO, this.logger);
}
}
}
/**
* Replaces forceignore in source directory with provided forceignore
* @param sourceDirectory
* @param pathToReplacementForceIgnore
*/
replaceForceIgnoreInSourceDirectory(sourceDirectory, pathToReplacementForceIgnore) {
if (fs.existsSync(pathToReplacementForceIgnore))
fs.copySync(pathToReplacementForceIgnore, path.join(sourceDirectory, '.forceignore'));
else {
sfp_logger_1.default.log(`${pathToReplacementForceIgnore} does not exist`, sfp_logger_1.LoggerLevel.INFO, this.logger);
sfp_logger_1.default.log('Package installation will continue using the unchanged forceignore in the source directory', null, this.logger);
}
}
}
exports.default = InstallSourcePackageImpl;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW5zdGFsbFNvdXJjZVBhY2thZ2VJbXBsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NvcmUvcGFja2FnZS9wYWNrYWdlSW5zdGFsbGVycy9JbnN0YWxsU291cmNlUGFja2FnZUltcGwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDJFQUE0RztBQUM1RyxrSEFBMEY7QUFDMUYsMEhBQWtHO0FBQ2xHLG1FQUFvRztBQUNwRyw2Q0FBK0I7QUFDL0IsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQzdCLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUMzQixxREFBaUY7QUFDakYsa0dBQWlHO0FBQ2pHLDRGQUFvRTtBQUlwRSwrRUFBa0U7QUFDbEUsZ0ZBQXdEO0FBQ3hELDRGQUF5RjtBQUN6Rix3R0FBZ0Y7QUFDaEYsb0dBQTRFO0FBQzVFLDhGQUFzRTtBQUN0RSxxREFBbUQ7QUFDbkQsK0JBQWdDO0FBRWhDLE1BQXFCLHdCQUF5QixTQUFRLCtCQUFjO0lBTWhFLFlBQ0ksVUFBc0IsRUFDdEIsU0FBaUIsRUFDakIsT0FBc0MsRUFDdEMsTUFBYztRQUVkLEtBQUssQ0FBQyxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM5QyxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsNEJBQTRCLEdBQUcsT0FBTyxDQUFDLDRCQUE0QixDQUFDO1FBQ3pFLElBQUksQ0FBQyxjQUFjLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQztJQUNqRCxDQUFDO0lBRU0sS0FBSyxDQUFDLE9BQU87UUFDaEIsSUFBSSxTQUFTLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ3JELElBQUksT0FBTyxHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUM7UUFFN0IsSUFBSSxDQUFDO1lBQ0Qsb0NBQW9DO1lBQ3BDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBRTFCLDZCQUE2QjtZQUM3QixNQUFNLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1lBR3JDLHVDQUF1QztZQUN2Qyw4R0FBOEc7WUFDOUcsSUFBSSxvQkFBb0IsR0FBRyxLQUFLLENBQUM7WUFDakMsSUFBSSxrQkFBa0IsR0FBRyxLQUFLLENBQUM7WUFDL0IsSUFBSSxjQUFjLENBQUM7WUFDbkIsQ0FBQztnQkFDRyxjQUFjO2dCQUNkLG9CQUFvQjtnQkFDcEIsa0JBQWtCO2FBQ3JCLEdBQUcsTUFBTSxJQUFJLENBQUMsaUNBQWlDLENBQzVDLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUN6QixJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxFQUN6QixPQUFPLENBQ1YsQ0FBQyxDQUFDO1lBRUgsSUFBSSxpQkFBb0MsQ0FBQztZQUN6QyxJQUFJLE1BQTBCLENBQUM7WUFDL0IsNkNBQTZDO1lBQzdDLGlCQUFpQixHQUFHLE1BQU0sSUFBSSxDQUFDLHlCQUF5QixDQUNwRCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFDckIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxrQkFBa0IsRUFDL0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQ3hCLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLEVBQ3pCLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUMxQixDQUFDO1lBRUYsd0JBQXdCO1lBQ3hCLElBQUksSUFBSSxDQUFDLGNBQWMsS0FBSyxtQ0FBYyxDQUFDLFdBQVcsRUFBRSxDQUFDO2dCQUNyRCxpQkFBaUIsQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO1lBQzVDLENBQUM7WUFFRCwyQ0FBMkM7WUFDM0MsSUFBSSx1QkFBdUIsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQztZQUV4RCxJQUFJLFVBQVUsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsdUJBQXVCLEVBQUUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7WUFFekYsSUFBSSxVQUFVLENBQUMsUUFBUSxJQUFJLElBQUksRUFBRSxDQUFDO2dCQUM5QixvQkFBUyxDQUFDLEdBQUcsQ0FDVCxHQUFHLElBQUEsMEJBQWEsRUFBQyx5REFBeUQsQ0FBQyxFQUFFLEVBQzdFLHdCQUFXLENBQUMsSUFBSSxFQUNoQixJQUFJLENBQUMsTUFBTSxDQUNkLENBQUM7Z0JBQ0YsT0FBTztvQkFDSCxTQUFTLEVBQUUsUUFBUTtvQkFDbkIsTUFBTSxFQUFFLElBQUk7b0JBQ1osT0FBTyxFQUFFLDhDQUE4QztpQkFDMUQsQ0FBQztZQUNOLENBQUM7aUJBQU0sSUFBSSxVQUFVLENBQUMsUUFBUSxJQUFJLEtBQUssRUFBRSxDQUFDO2dCQUV0QyxvQ0FBb0M7Z0JBQ3BDLElBQUksWUFBWSxHQUFHLHFDQUFZLENBQUMsVUFBVSxDQUN0QyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyx1QkFBdUIsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsQ0FDMUUsQ0FBQztnQkFFRixlQUFlO2dCQUNmLElBQUksaUJBQWlCLEdBQUcsbURBQXdCLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztnQkFFdEUsS0FBSyxNQUFNLGdCQUFnQixJQUFJLGlCQUFpQixFQUFFLENBQUM7b0JBQy9DLElBQ0ksZ0JBQWdCLENBQUMsU0FBUyxDQUN0Qix1QkFBYSxDQUFDLG9CQUFvQixDQUFDLFVBQVUsQ0FBQyx1QkFBdUIsQ0FBQyxFQUN0RSxJQUFJLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FDOUI7d0JBRUQsWUFBWSxHQUFHLE1BQU0sZ0JBQWdCLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsWUFBWSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDNUYsQ0FBQztnQkFFRCw4REFBOEQ7Z0JBQzlELGtDQUFrQztnQkFDbEMsSUFBSSxZQUFZLENBQUMsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDO29CQUN6QixPQUFPO3dCQUNILFNBQVMsRUFBRSxRQUFRO3dCQUNuQixNQUFNLEVBQUUsSUFBSTt3QkFDWixPQUFPLEVBQUUsd0RBQXdEO3FCQUNwRSxDQUFDO2dCQUNOLENBQUM7Z0JBRUQsdUNBQXVDO2dCQUN2QyxJQUFJLFVBQVUsR0FBRyxZQUFZLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztnQkFDcEQsaUNBQXVCLENBQUMsbUJBQW1CLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFHckUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMseUJBQXlCLEVBQUUsQ0FBQztvQkFDMUMsbUNBQXlCLENBQUMsc0JBQXNCLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUNyRixDQUFDO2dCQUVELElBQUkscUJBQXFCLEdBQXVCLElBQUksK0JBQXFCLENBQ3JFLElBQUksQ0FBQyxNQUFNLEVBQ1gsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLEVBQ3pCLFlBQVksRUFDWixpQkFBaUIsRUFDakIsSUFBSSxDQUFDLE1BQU0sQ0FDZCxDQUFDO2dCQUVGLE1BQU0sR0FBRyxNQUFNLHFCQUFxQixDQUFDLElBQUksRUFBRSxDQUFDO2dCQUU1QyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQztvQkFDaEIsaUNBQWlDO29CQUNqQyxJQUFJLENBQUM7d0JBQ0QsSUFBSSxvQkFBb0IsRUFBRSxDQUFDOzRCQUN2QixnRUFBZ0U7NEJBQ2hFLE1BQU0sSUFBSSxDQUFDLDRCQUE0QixDQUNuQyxjQUFjLEVBQ2QsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLEVBQ3pCLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLEVBQ3pCLElBQUksQ0FBQyxnQkFBZ0IsRUFDckIsT0FBTyxFQUNQLGlCQUFpQixDQUNwQixDQUFDO3dCQUNOLENBQUM7b0JBQ0wsQ0FBQztvQkFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO3dCQUViLG9CQUFTLENBQUMsR0FBRyxDQUNULHFFQUFxRSxFQUNyRSx3QkFBVyxDQUFDLElBQUksRUFDaEIsSUFBSSxDQUFDLE1BQU0sQ0FDZCxDQUFDO29CQUNOLENBQUM7Z0JBQ0wsQ0FBQztxQkFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssS0FBSyxFQUFFLENBQUM7b0JBQ2pDLDhCQUFvQixDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFDakUsTUFBTSxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3BDLENBQUM7WUFDTCxDQUFDO1lBQ0QsR0FBRztRQUNQLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2IsU0FBUyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQzNCLE1BQU0sS0FBSyxDQUFDO1FBQ2hCLENBQUM7SUFDTCxDQUFDO0lBRU8sa0JBQWtCLENBQ3RCLGVBQXVCLEVBQ3ZCLGdCQUF3QjtRQUV4Qix3QkFBd0I7UUFDeEIsSUFBSSxNQUFNLEdBQUcsNkJBQW1CLENBQUMsK0JBQStCLENBQUMsZUFBZSxFQUFFLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRzNHLElBQUksTUFBTSxDQUFDLE1BQU0sSUFBSSxPQUFPLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLDZEQUE2RCxDQUFDLENBQUM7UUFDbkYsQ0FBQzthQUFNLElBQUksTUFBTSxDQUFDLE1BQU0sSUFBSSxNQUFNLEVBQUUsQ0FBQztZQUNqQyxPQUFPO2dCQUNILFFBQVEsRUFBRSxJQUFJO2dCQUNkLHVCQUF1QixFQUFFLGVBQWU7YUFDM0MsQ0FBQztRQUNOLENBQUM7YUFBTSxDQUFDO1lBQ0osT0FBTztnQkFDSCxRQUFRLEVBQUUsS0FBSztnQkFDZix1QkFBdUIsRUFBRSxlQUFlO2FBQzNDLENBQUM7UUFDTixDQUFDO0lBQ0wsQ0FBQztJQUVPLGtCQUFrQjtRQUN0QixJQUFJLElBQUksQ0FBQyw0QkFBNEIsRUFBRSxDQUFDO1lBQ3BDLElBQUksQ0FBQyxtQ0FBbUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsNEJBQTRCLENBQUMsQ0FBQztZQUd2Ryx1QkFBdUI7WUFDdkIsa0NBQWtDO1lBQ2xDLGdEQUFnRDtZQUNoRCx3REFBd0Q7WUFDeEQsNENBQTRDO1lBQzVDLFNBQVM7UUFDYixDQUFDO0lBQ0wsQ0FBQztJQUVPLEtBQUssQ0FBQyx1QkFBdUI7UUFFakMsSUFBRyxJQUFJLENBQUMsVUFBVSxDQUFDLGtCQUFrQixFQUNyQyxDQUFDO1lBQ0QsSUFBSSxDQUFDO2dCQUNELG9CQUFTLENBQUMsR0FBRyxDQUNULGdFQUFnRSxFQUNoRSx3QkFBVyxDQUFDLElBQUksRUFDaEIsSUFBSSxDQUFDLE1BQU0sQ0FDZCxDQUFDO2dCQUNGLElBQUksOEJBQThCLEdBQUcsSUFBSSw0Q0FBa0MsQ0FDdkUsSUFBSSxDQUFDLE1BQU0sRUFDWCxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLGFBQWEsRUFBRSx3QkFBd0IsQ0FBQyxDQUNoRixDQUFDO2dCQUVGLE1BQU0sOEJBQThCLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDaEQsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2Isb0JBQVMsQ0FBQyxHQUFHLENBQ2Q7Ozs7OztjQU1HLElBQUEsd0JBQVcsRUFBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFDMUIsd0JBQVcsQ0FBQyxJQUFJLEVBQ2hCLElBQUksQ0FBQyxNQUFNLENBQ2QsQ0FBQztZQUNOLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxtQkFBMkIsRUFBRSxVQUFrQixFQUFFLE9BQWU7UUFDNUcsSUFBSSxjQUFtQixDQUFDO1FBQ3hCLElBQUksb0JBQW9CLEdBQVksS0FBSyxDQUFDO1FBQzFDLElBQUksa0JBQWtCLEdBQVksS0FBSyxDQUFDO1FBQ3hDLElBQUksQ0FBQztZQUNELDhDQUE4QztZQUM5QyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsaUJBQWlCLElBQUksS0FBSztnQkFBRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsS0FBSyxFQUFFLENBQUM7WUFFdkYsOEJBQThCO1lBQzlCLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN0QyxDQUFDO2lCQUFNLENBQUM7Z0JBQ0osT0FBTyxFQUFFLG9CQUFvQixFQUFFLEtBQUssRUFBRSxDQUFDO1lBQzNDLENBQUM7WUFFRCxvQkFBUyxDQUFDLEdBQUcsQ0FDVCw4REFBOEQsRUFDOUQsd0JBQVcsQ0FBQyxJQUFJLEVBQ2hCLElBQUksQ0FBQyxNQUFNLENBQ2QsQ0FBQztZQUNGLGtEQUFrRDtZQUNsRCxjQUFjLEdBQUcsSUFBQSxlQUFRLEVBQUMsYUFBYSxFQUFFO2dCQUNyQyxHQUFHLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQzthQUN0QyxDQUFDLENBQUM7WUFDSCxJQUFJLGNBQWMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzVCLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRTtvQkFDOUIsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFtQixFQUFFLE1BQU0sQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7Z0JBQ3BGLENBQUMsQ0FBQyxDQUFDO1lBQ1AsQ0FBQztZQUNELGVBQWU7WUFDZixJQUFJLDBCQUEwQixHQUFtQyxJQUFJLHdDQUE4QixDQUMvRixJQUFJLENBQUMsTUFBTSxFQUNYLElBQUksQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsRUFDOUIsSUFBSSxDQUFDLE1BQU0sQ0FDZCxDQUFDO1lBQ0YsTUFBTSwwQkFBMEIsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN4QyxvQkFBb0IsR0FBRyxJQUFJLENBQUM7UUFDaEMsQ0FBQztRQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7WUFDWCxvQkFBUyxDQUFDLEdBQUcsQ0FBQywrQkFBK0IsR0FBRyxHQUFHLEVBQUUsd0JBQVcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3BGLGtCQUFrQixHQUFHLElBQUksQ0FBQztZQUMxQixJQUFJLGNBQWMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzVCLG9CQUFTLENBQUMsR0FBRyxDQUFDLHFEQUFxRCxFQUFFLHdCQUFXLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDcEcsY0FBYyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFO29CQUM5QixFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztnQkFDMUYsQ0FBQyxDQUFDLENBQUM7WUFDUCxDQUFDO1FBQ0wsQ0FBQztRQUNELE9BQU8sRUFBRSxjQUFjLEVBQUUsb0JBQW9CLEVBQUUsa0JBQWtCLEVBQUUsQ0FBQztJQUN4RSxDQUFDO0lBRU8sS0FBSyxDQUFDLDRCQUE0QixDQUN0QyxjQUF3QixFQUN4QixtQkFBMkIsRUFDM0IsVUFBa0IsRUFDbEIsZUFBdUIsRUFDdkIsTUFBYyxFQUNkLGlCQUFzQjtRQUV0QiwrQ0FBK0M7UUFDL0MsbUJBQW1CO1FBQ25CLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxlQUFlLElBQUksS0FBSztZQUFFLE9BQU87UUFDckQsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLHdDQUF3QyxJQUFJLEtBQUs7WUFBRSxPQUFPO1FBRzlFLElBQUksY0FBYyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUM1QixvQkFBUyxDQUFDLEdBQUcsQ0FBQyxzREFBc0QsRUFBRSx3QkFBVyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDckcsY0FBYyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFO2dCQUM5QixFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztZQUNuRixDQUFDLENBQUMsQ0FBQztZQUVILGVBQWU7WUFDZixJQUFJLDBCQUEwQixHQUFtQyxJQUFJLHdDQUE4QixDQUMvRixJQUFJLENBQUMsTUFBTSxFQUNYLG1CQUFtQixFQUNuQixJQUFJLENBQUMsTUFBTSxDQUNkLENBQUM7WUFDRixNQUFNLDBCQUEwQixDQUFDLElBQUksRUFBRSxDQUFDO1lBRXhDLCtCQUErQjtZQUUvQixNQUFNLFlBQVksR0FBRyxJQUFBLGVBQVEsRUFBQyxjQUFjLEVBQUU7Z0JBQzFDLEdBQUcsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFtQixFQUFFLGVBQWUsQ0FBQztnQkFDcEQsUUFBUSxFQUFFLElBQUk7YUFDakIsQ0FBQyxDQUFDO1lBRUgsTUFBTSxpQ0FBaUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUMvQyxtQkFBbUIsRUFDbkIsbUNBQW1DLENBQ3RDLENBQUM7WUFDRixFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsaUNBQWlDLEVBQUUsZUFBZSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUM7WUFFekYsS0FBSyxNQUFNLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztnQkFDN0IscUNBQXFDO2dCQUNyQyxFQUFFLENBQUMsUUFBUSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxFQUFFLGVBQWUsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDO1lBQ2hHLENBQUM7WUFFRCxFQUFFLENBQUMsUUFBUSxDQUNQLElBQUksQ0FBQyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsbUJBQW1CLENBQUMsRUFDbkQsSUFBSSxDQUFDLElBQUksQ0FBQyxpQ0FBaUMsRUFBRSxtQkFBbUIsQ0FBQyxDQUNwRSxDQUFDO1lBQ0YsRUFBRSxDQUFDLFFBQVEsQ0FDUCxJQUFJLENBQUMsSUFBSSxDQUFDLG1CQUFtQixFQUFFLGNBQWMsQ0FBQyxFQUM5QyxJQUFJLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxFQUFFLGNBQWMsQ0FBQyxDQUMvRCxDQUFDO1lBRUYsb0NBQW9DO1lBQ3BDLElBQUksWUFBWSxHQUFHLHFDQUFZLENBQUMsVUFBVSxDQUN0QyxJQUFJLENBQUMsT0FBTyxDQUFDLGlDQUFpQyxFQUFFLGVBQWUsQ0FBQyxDQUNuRSxDQUFDO1lBRUYsbUNBQXlCLENBQUMsc0JBQXNCLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ2pGLElBQUkscUJBQXFCLEdBQTBCLElBQUksK0JBQXFCLENBQ3hFLElBQUksQ0FBQyxNQUFNLEVBQ1gsSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLEVBQ3pCLFlBQVksRUFDWixpQkFBaUIsRUFDakIsSUFBSSxDQUFDLE1BQU0sQ0FDZCxDQUFDO1lBQ0YsSUFBSSxnQkFBZ0IsR0FBdUIsTUFBTSxxQkFBcUIsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUU5RSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQzNCLDhCQUFvQixDQUFDLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUMzRSxvQkFBUyxDQUFDLEdBQUcsQ0FBQyx1Q0FBdUMsRUFBRSx3QkFBVyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDMUYsQ0FBQztRQUNMLENBQUM7SUFDTCxDQUFDO0lBSUQ7Ozs7T0FJRztJQUNLLG1DQUFtQyxDQUFDLGVBQXVCLEVBQUUsNEJBQW9DO1FBQ3JHLElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyw0QkFBNEIsQ0FBQztZQUMzQyxFQUFFLENBQUMsUUFBUSxDQUFDLDRCQUE0QixFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUM7YUFDckYsQ0FBQztZQUNGLG9CQUFTLENBQUMsR0FBRyxDQUFDLEdBQUcsNEJBQTRCLGlCQUFpQixFQUFFLHdCQUFXLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUMvRixvQkFBUyxDQUFDLEdBQUcsQ0FDVCw0RkFBNEYsRUFDNUYsSUFBSSxFQUNKLElBQUksQ0FBQyxNQUFNLENBQ2QsQ0FBQztRQUNOLENBQUM7SUFDTCxDQUFDO0NBQ0o7QUF0WEQsMkNBc1hDIn0=