cdk-amazon-chime-resources
Version:

276 lines • 38.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DeleteVoiceConnector = exports.UpdateVoiceConnector = exports.CreateVoiceConnector = void 0;
/* eslint-disable import/no-extraneous-dependencies */
const client_chime_sdk_voice_1 = require("@aws-sdk/client-chime-sdk-voice");
const client_ssm_1 = require("@aws-sdk/client-ssm");
const chimeSDKVoiceClient = new client_chime_sdk_voice_1.ChimeSDKVoiceClient({
region: process.env.AWS_REGION,
});
const ssmClient = new client_ssm_1.SSMClient({ region: process.env.AWS_REGION });
let createVoiceConnectorResponse;
let createVoiceConnectorParams;
let updateVoiceConnectorParams;
let getParameterCommandOutput;
let voiceConnectorId;
let phoneNumbersToDisassociate;
let routes;
let terminationConfiguration;
let streamingConfiguration;
let loggingConfiguration;
let deleteVoiceConnectorResponse;
exports.CreateVoiceConnector = async (uid, props) => {
console.log(`Creating Voice Connector: ${uid}`);
console.log(`Create Voice Connector Props: ${JSON.stringify(props)}`);
createVoiceConnectorParams = {
Name: props.name,
RequireEncryption: props.encryption,
AwsRegion: props.region,
};
console.log(`createVoiceConnectorParams: ${JSON.stringify(createVoiceConnectorParams)}`);
try {
createVoiceConnectorResponse = await chimeSDKVoiceClient.send(new client_chime_sdk_voice_1.CreateVoiceConnectorCommand(createVoiceConnectorParams));
console.log(`createVoiceConnectorResponse: ${JSON.stringify(createVoiceConnectorResponse)}`);
if (createVoiceConnectorResponse.VoiceConnector &&
createVoiceConnectorResponse.VoiceConnector.VoiceConnectorId) {
voiceConnectorId =
createVoiceConnectorResponse.VoiceConnector?.VoiceConnectorId;
}
else {
throw new Error('Voice Connector failed to create');
}
}
catch (error) {
if (error instanceof Error) {
console.error(error);
throw error;
}
}
console.log(`Voice Connector Created: ${voiceConnectorId}`);
if (props.origination) {
await putOrigination(voiceConnectorId, props.origination);
}
if (props.termination) {
await putTermination(voiceConnectorId, props.termination);
}
if (props.streaming) {
await putStreaming(voiceConnectorId, props.streaming);
}
if (props.logging) {
await putLogging(voiceConnectorId, props.logging);
}
try {
await ssmClient.send(new client_ssm_1.PutParameterCommand({
Name: '/chime/voiceConnector' + uid,
Value: voiceConnectorId,
Description: 'Voice Connector ID',
Overwrite: true,
Type: 'String',
}));
}
catch (error) {
if (error instanceof Error) {
console.error(error);
throw error;
}
}
return {
voiceConnectorId: voiceConnectorId,
};
};
exports.UpdateVoiceConnector = async (uid, props) => {
console.log(`Updating Voice Connector: ${uid}`);
console.log(`Updating Voice Connector Props: ${JSON.stringify(props)}`);
updateVoiceConnectorParams = {
Name: props.name,
RequireEncryption: props.encryption,
AwsRegion: props.region,
};
console.log(`updateVoiceConnectorParams: ${JSON.stringify(updateVoiceConnectorParams)}`);
try {
getParameterCommandOutput = await ssmClient.send(new client_ssm_1.GetParameterCommand({ Name: '/chime/voiceConnector' + uid }));
if (getParameterCommandOutput.Parameter &&
getParameterCommandOutput.Parameter.Value) {
voiceConnectorId = getParameterCommandOutput.Parameter.Value;
}
}
catch (error) {
if (error instanceof Error) {
console.error(error);
throw error;
}
}
if (props.origination) {
await putOrigination(voiceConnectorId, props.origination);
}
if (props.termination) {
await putTermination(voiceConnectorId, props.termination);
}
if (props.streaming) {
await putStreaming(voiceConnectorId, props.streaming);
}
if (props.logging) {
await putLogging(voiceConnectorId, props.logging);
}
return {
voiceConnectorId: voiceConnectorId,
};
};
exports.DeleteVoiceConnector = async (uid) => {
try {
getParameterCommandOutput = await ssmClient.send(new client_ssm_1.GetParameterCommand({ Name: '/chime/voiceConnector' + uid }));
if (getParameterCommandOutput.Parameter &&
getParameterCommandOutput.Parameter.Value) {
voiceConnectorId = getParameterCommandOutput.Parameter.Value;
}
}
catch (error) {
if (error instanceof Error) {
console.error(error);
throw error;
}
}
console.log(`voiceConnectorId to delete: ${voiceConnectorId}`);
try {
const phoneNumbersAssociated = await chimeSDKVoiceClient.send(new client_chime_sdk_voice_1.ListPhoneNumbersCommand({
FilterName: 'VoiceConnectorId',
FilterValue: voiceConnectorId,
}));
console.log(`phoneNumbers to disassociate: ${JSON.stringify(phoneNumbersAssociated)}`);
if (phoneNumbersAssociated.PhoneNumbers &&
phoneNumbersAssociated.PhoneNumbers.length > 0) {
phoneNumbersAssociated.PhoneNumbers.forEach(async (phoneNumber) => {
phoneNumbersToDisassociate.push(phoneNumber.PhoneNumberId);
});
console.log(`Disassociate Phone Numbers: ${phoneNumbersToDisassociate}`);
await chimeSDKVoiceClient.send(new client_chime_sdk_voice_1.DisassociatePhoneNumbersFromVoiceConnectorCommand({
VoiceConnectorId: voiceConnectorId,
E164PhoneNumbers: phoneNumbersToDisassociate,
}));
}
}
catch (error) {
if (error instanceof Error) {
console.error(error);
throw error;
}
}
console.log(`Deleting Voice Connector: ${voiceConnectorId}`);
try {
deleteVoiceConnectorResponse = await chimeSDKVoiceClient.send(new client_chime_sdk_voice_1.DeleteVoiceConnectorCommand({
VoiceConnectorId: voiceConnectorId,
}));
console.log(`Delete Voice Connector Response: ${deleteVoiceConnectorResponse}`);
await ssmClient.send(new client_ssm_1.DeleteParameterCommand({ Name: '/chime/voiceConnector' + uid }));
}
catch (error) {
if (error instanceof Error) {
console.error(error);
throw error;
}
}
};
const putOrigination = async (originationVoiceConnectorId, originations) => {
console.log(`originations: ${JSON.stringify(originations)}`);
console.info(`voiceConnectorId: ${originationVoiceConnectorId}`);
routes = [];
originations.forEach(async (origination) => {
routes.push({
Protocol: origination.protocol,
Host: origination.host,
Port: parseInt(origination.port),
Priority: parseInt(origination.priority),
Weight: parseInt(origination.weight),
});
});
console.log(`routes: ${JSON.stringify(routes)}`);
try {
await chimeSDKVoiceClient.send(new client_chime_sdk_voice_1.PutVoiceConnectorOriginationCommand({
VoiceConnectorId: originationVoiceConnectorId,
Origination: {
Routes: routes,
Disabled: false,
},
}));
}
catch (error) {
if (error instanceof Error) {
console.error(error);
throw error;
}
}
};
const putTermination = async (terminationVoiceConnectorId, termination) => {
console.log(`termination: ${JSON.stringify(termination)}`);
console.info(`voiceConnectorId: ${terminationVoiceConnectorId}`);
terminationConfiguration = {
CallingRegions: termination.callingRegions,
CidrAllowedList: termination.terminationCidrs,
CpsLimit: parseInt(termination.cpsLimit),
};
console.log(`terminationConfiguration: ${JSON.stringify(terminationConfiguration)}`);
try {
await chimeSDKVoiceClient.send(new client_chime_sdk_voice_1.PutVoiceConnectorTerminationCommand({
VoiceConnectorId: terminationVoiceConnectorId,
Termination: terminationConfiguration,
}));
}
catch (error) {
if (error instanceof Error) {
console.error(error);
throw error;
}
}
};
const putStreaming = async (streamingVoiceConnectorId, streaming) => {
console.log(`streaming: ${JSON.stringify(streaming)}`);
console.info(`voiceConnectorId: ${streamingVoiceConnectorId}`);
streamingConfiguration = {
StreamingNotificationTargets: streaming.notificationTarget,
Disabled: false,
DataRetentionInHours: parseInt(streaming.dataRetention),
...(streaming.mediaInsightsConfiguration && {
MediaInsightsConfiguration: {
Disabled: streaming.mediaInsightsConfiguration.disabled,
ConfigurationArn: streaming.mediaInsightsConfiguration.configurationArn,
},
}),
};
console.log(`streamingConfiguration: ${JSON.stringify(streamingConfiguration)}`);
try {
await chimeSDKVoiceClient.send(new client_chime_sdk_voice_1.PutVoiceConnectorStreamingConfigurationCommand({
VoiceConnectorId: streamingVoiceConnectorId,
StreamingConfiguration: streamingConfiguration,
}));
}
catch (error) {
if (error instanceof Error) {
console.error(error);
throw error;
}
}
};
const putLogging = async (loggingVoiceConnectorId, logging) => {
console.log(`logging: ${JSON.stringify(logging)}`);
console.info(`voiceConnectorId: ${loggingVoiceConnectorId}`);
loggingConfiguration = {
...(logging.enableSIPLogs && { EnableSIPLogs: logging.enableSIPLogs }),
...(logging.enableMediaMetricLogs && {
EnableMediaMetricLogs: logging.enableMediaMetricLogs,
}),
};
console.log(`loggingConfiguration: ${JSON.stringify(loggingConfiguration)}`);
try {
await chimeSDKVoiceClient.send(new client_chime_sdk_voice_1.PutVoiceConnectorLoggingConfigurationCommand({
VoiceConnectorId: loggingVoiceConnectorId,
LoggingConfiguration: loggingConfiguration,
}));
}
catch (error) {
if (error instanceof Error) {
console.error(error);
throw error;
}
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidm9pY2VDb25uZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcmVzb3VyY2VzL3BzdG4vdm9pY2VDb25uZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsc0RBQXNEO0FBQ3RELDRFQWtCeUM7QUFFekMsb0RBTTZCO0FBSTdCLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSw0Q0FBbUIsQ0FBQztJQUNsRCxNQUFNLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVO0NBQy9CLENBQUMsQ0FBQztBQUVILE1BQU0sU0FBUyxHQUFHLElBQUksc0JBQVMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7QUFFcEUsSUFBSSw0QkFBK0QsQ0FBQztBQUNwRSxJQUFJLDBCQUE0RCxDQUFDO0FBQ2pFLElBQUksMEJBQTRELENBQUM7QUFDakUsSUFBSSx5QkFBb0QsQ0FBQztBQUN6RCxJQUFJLGdCQUF3QixDQUFDO0FBQzdCLElBQUksMEJBQW9DLENBQUM7QUFDekMsSUFBSSxNQUEwQixDQUFDO0FBQy9CLElBQUksd0JBQXFDLENBQUM7QUFDMUMsSUFBSSxzQkFBOEMsQ0FBQztBQUNuRCxJQUFJLG9CQUEwQyxDQUFDO0FBQy9DLElBQUksNEJBQStELENBQUM7QUFzQ3ZELFFBQUEsb0JBQW9CLEdBQUcsS0FBSyxFQUN2QyxHQUFXLEVBQ1gsS0FBZ0MsRUFDaEMsRUFBRTtJQUNGLE9BQU8sQ0FBQyxHQUFHLENBQUMsNkJBQTZCLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDaEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQ0FBaUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDdEUsMEJBQTBCLEdBQUc7UUFDM0IsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO1FBQ2hCLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxVQUFVO1FBQ25D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QztJQUM5RSxJQUFJO1FBQ0YsTUFBTSxtQkFBbUIsQ0FBQyxJQUFJLENBQzVCLElBQUkscUVBQTRDLENBQUM7WUFDL0MsZ0JBQWdCLEVBQUUsdUJBQXVCO1lBQ3pDLG9CQUFvQixFQUFFLG9CQUFvQjtTQUMzQyxDQUFDLENBQ0gsQ0FBQztLQUNIO0lBQUMsT0FBTyxLQUFLLEVBQUU7UUFDZCxJQUFJLEtBQUssWUFBWSxLQUFLLEVBQUU7WUFDMUIsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNyQixNQUFNLEtBQUssQ0FBQztTQUNiO0tBQ0Y7QUFDSCxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXMgKi9cbmltcG9ydCB7XG4gIENoaW1lU0RLVm9pY2VDbGllbnQsXG4gIENyZWF0ZVZvaWNlQ29ubmVjdG9yQ29tbWFuZCxcbiAgUHV0Vm9pY2VDb25uZWN0b3JMb2dnaW5nQ29uZmlndXJhdGlvbkNvbW1hbmQsXG4gIFB1dFZvaWNlQ29ubmVjdG9yU3RyZWFtaW5nQ29uZmlndXJhdGlvbkNvbW1hbmQsXG4gIFB1dFZvaWNlQ29ubmVjdG9yVGVybWluYXRpb25Db21tYW5kLFxuICBQdXRWb2ljZUNvbm5lY3Rvck9yaWdpbmF0aW9uQ29tbWFuZCxcbiAgRGVsZXRlVm9pY2VDb25uZWN0b3JDb21tYW5kLFxuICBEZWxldGVWb2ljZUNvbm5lY3RvckNvbW1hbmRPdXRwdXQsXG4gIERpc2Fzc29jaWF0ZVBob25lTnVtYmVyc0Zyb21Wb2ljZUNvbm5lY3RvckNvbW1hbmQsXG4gIENyZWF0ZVZvaWNlQ29ubmVjdG9yQ29tbWFuZElucHV0LFxuICBDcmVhdGVWb2ljZUNvbm5lY3RvckNvbW1hbmRPdXRwdXQsXG4gIFRlcm1pbmF0aW9uLFxuICBPcmlnaW5hdGlvblJvdXRlLFxuICBTdHJlYW1pbmdDb25maWd1cmF0aW9uLFxuICBMb2dnaW5nQ29uZmlndXJhdGlvbixcbiAgTGlzdFBob25lTnVtYmVyc0NvbW1hbmQsXG4gIFN0cmVhbWluZ05vdGlmaWNhdGlvblRhcmdldCxcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWNoaW1lLXNkay12b2ljZSc7XG5cbmltcG9ydCB7XG4gIFNTTUNsaWVudCxcbiAgRGVsZXRlUGFyYW1ldGVyQ29tbWFuZCxcbiAgR2V0UGFyYW1ldGVyQ29tbWFuZCxcbiAgR2V0UGFyYW1ldGVyQ29tbWFuZE91dHB1dCxcbiAgUHV0UGFyYW1ldGVyQ29tbWFuZCxcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LXNzbSc7XG5cbmltcG9ydCB7IE1lZGlhSW5zaWdodHNDb25maWd1cmF0aW9uIH0gZnJvbSAnLi4vLi4vcHN0bi92b2ljZUNvbm5lY3Rvcic7XG5cbmNvbnN0IGNoaW1lU0RLVm9pY2VDbGllbnQgPSBuZXcgQ2hpbWVTREtWb2ljZUNsaWVudCh7XG4gIHJlZ2lvbjogcHJvY2Vzcy5lbnYuQVdTX1JFR0lPTixcbn0pO1xuXG5jb25zdCBzc21DbGllbnQgPSBuZXcgU1NNQ2xpZW50KHsgcmVnaW9uOiBwcm9jZXNzLmVudi5BV1NfUkVHSU9OIH0pO1xuXG5sZXQgY3JlYXRlVm9pY2VDb25uZWN0b3JSZXNwb25zZTogQ3JlYXRlVm9pY2VDb25uZWN0b3JDb21tYW5kT3V0cHV0O1xubGV0IGNyZWF0ZVZvaWNlQ29ubmVjdG9yUGFyYW1zOiBDcmVhdGVWb2ljZUNvbm5lY3RvckNvbW1hbmRJbnB1dDtcbmxldCB1cGRhdGVWb2ljZUNvbm5lY3RvclBhcmFtczogQ3JlYXRlVm9pY2VDb25uZWN0b3JDb21tYW5kSW5wdXQ7XG5sZXQgZ2V0UGFyYW1ldGVyQ29tbWFuZE91dHB1dDogR2V0UGFyYW1ldGVyQ29tbWFuZE91dHB1dDtcbmxldCB2b2ljZUNvbm5lY3RvcklkOiBzdHJpbmc7XG5sZXQgcGhvbmVOdW1iZXJzVG9EaXNhc3NvY2lhdGU6IHN0cmluZ1tdO1xubGV0IHJvdXRlczogT3JpZ2luYXRpb25Sb3V0ZVtdO1xubGV0IHRlcm1pbmF0aW9uQ29uZmlndXJhdGlvbjogVGVybWluYXRpb247XG5sZXQgc3RyZWFtaW5nQ29uZmlndXJhdGlvbjogU3RyZWFtaW5nQ29uZmlndXJhdGlvbjtcbmxldCBsb2dnaW5nQ29uZmlndXJhdGlvbjogTG9nZ2luZ0NvbmZpZ3VyYXRpb247XG5sZXQgZGVsZXRlVm9pY2VDb25uZWN0b3JSZXNwb25zZTogRGVsZXRlVm9pY2VDb25uZWN0b3JDb21tYW5kT3V0cHV0O1xuXG5pbnRlcmZhY2UgUm91dGVzIHtcbiAgcHJvdG9jb2w6IHN0cmluZztcbiAgaG9zdDogc3RyaW5nO1xuICBwb3J0OiBzdHJpbmc7XG4gIHByaW9yaXR5OiBzdHJpbmc7XG4gIHdlaWdodDogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgVGVybWluYXRpb25Qcm9wcyB7XG4gIGNhbGxpbmdSZWdpb25zOiBzdHJpbmdbXTtcbiAgdGVybWluYXRpb25DaWRyczogc3RyaW5nW107XG4gIGNwc0xpbWl0OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBTdHJlYW1pbmdQcm9wcyB7XG4gIGVuYWJsZWQ6IGJvb2xlYW47XG4gIGRhdGFSZXRlbnRpb246IHN0cmluZztcbiAgbm90aWZpY2F0aW9uVGFyZ2V0OiBTdHJlYW1pbmdOb3RpZmljYXRpb25UYXJnZXRbXTtcbiAgbWVkaWFJbnNpZ2h0c0NvbmZpZ3VyYXRpb246IE1lZGlhSW5zaWdodHNDb25maWd1cmF0aW9uO1xufVxuXG5pbnRlcmZhY2UgTG9nZ2luZ1Byb3BzIHtcbiAgZW5hYmxlU0lQTG9nczogYm9vbGVhbjtcbiAgZW5hYmxlTWVkaWFNZXRyaWNMb2dzOiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENyZWF0ZVZvaWNlQ29ubmVjdG9yUHJvcHMge1xuICBuYW1lPzogc3RyaW5nO1xuICByZWdpb24/OiBzdHJpbmc7XG4gIGVuY3J5cHRpb24/OiBib29sZWFuO1xuICB0ZXJtaW5hdGlvbj86IFRlcm1pbmF0aW9uUHJvcHM7XG4gIG9yaWdpbmF0aW9uPzogUm91dGVzW107XG4gIGxvZ2dpbmc/OiBMb2dnaW5nUHJvcHM7XG4gIHN0cmVhbWluZz86IFN0cmVhbWluZ1Byb3BzO1xufVxuXG5leHBvcnQgY29uc3QgQ3JlYXRlVm9pY2VDb25uZWN0b3IgPSBhc3luYyAoXG4gIHVpZDogc3RyaW5nLFxuICBwcm9wczogQ3JlYXRlVm9pY2VDb25uZWN0b3JQcm9wcyxcbikgPT4ge1xuICBjb25zb2xlLmxvZyhgQ3JlYXRpbmcgVm9pY2UgQ29ubmVjdG9yOiAke3VpZH1gKTtcbiAgY29uc29sZS5sb2coYENyZWF0ZSBWb2ljZSBDb25uZWN0b3IgUHJvcHM6ICR7SlNPTi5zdHJpbmdpZnkocHJvcHMpfWApO1xuICBjcmVhdGVWb2ljZUNvbm5lY3RvclBhcmFtcyA9IHtcbiAgICBOYW1lOiBwcm9wcy5uYW1lLFxuICAgIFJlcXVpcmVFbmNyeXB0aW9uOiBwcm9wcy5lbmNyeXB0aW9uLFxuICAgIEF3c1JlZ2lvbjogcHJvcHMucmVnaW9uLFxuICB9O1xuICBjb25zb2xlLmxvZyhcbiAgICBgY3JlYXRlVm9pY2VDb25uZWN0b3JQYXJhbXM6ICR7SlNPTi5zdHJpbmdpZnkoY3JlYXRlVm9pY2VDb25uZWN0b3JQYXJhbXMpfWAsXG4gICk7XG5cbiAgdHJ5IHtcbiAgICBjcmVhdGVWb2ljZUNvbm5lY3RvclJlc3BvbnNlID0gYXdhaXQgY2hpbWVTREtWb2ljZUNsaWVudC5zZW5kKFxuICAgICAgbmV3IENyZWF0ZVZvaWNlQ29ubmVjdG9yQ29tbWFuZChjcmVhdGVWb2ljZUNvbm5lY3RvclBhcmFtcyksXG4gICAgKTtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIGBjcmVhdGVWb2ljZUNvbm5lY3RvclJlc3BvbnNlOiAke0pTT04uc3RyaW5naWZ5KFxuICAgICAgICBjcmVhdGVWb2ljZUNvbm5lY3RvclJlc3BvbnNlLFxuICAgICAgKX1gLFxuICAgICk7XG4gICAgaWYgKFxuICAgICAgY3JlYXRlVm9pY2VDb25uZWN0b3JSZXNwb25zZS5Wb2ljZUNvbm5lY3RvciAmJlxuICAgICAgY3JlYXRlVm9pY2VDb25uZWN0b3JSZXNwb25zZS5Wb2ljZUNvbm5lY3Rvci5Wb2ljZUNvbm5lY3RvcklkXG4gICAgKSB7XG4gICAgICB2b2ljZUNvbm5lY3RvcklkID1cbiAgICAgICAgY3JlYXRlVm9pY2VDb25uZWN0b3JSZXNwb25zZS5Wb2ljZUNvbm5lY3Rvcj8uVm9pY2VDb25uZWN0b3JJZDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdWb2ljZSBDb25uZWN0b3IgZmFpbGVkIHRvIGNyZWF0ZScpO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cbiAgY29uc29sZS5sb2coYFZvaWNlIENvbm5lY3RvciBDcmVhdGVkOiAke3ZvaWNlQ29ubmVjdG9ySWR9YCk7XG5cbiAgaWYgKHByb3BzLm9yaWdpbmF0aW9uKSB7XG4gICAgYXdhaXQgcHV0T3JpZ2luYXRpb24odm9pY2VDb25uZWN0b3JJZCwgcHJvcHMub3JpZ2luYXRpb24pO1xuICB9XG5cbiAgaWYgKHByb3BzLnRlcm1pbmF0aW9uKSB7XG4gICAgYXdhaXQgcHV0VGVybWluYXRpb24odm9pY2VDb25uZWN0b3JJZCwgcHJvcHMudGVybWluYXRpb24pO1xuICB9XG5cbiAgaWYgKHByb3BzLnN0cmVhbWluZykge1xuICAgIGF3YWl0IHB1dFN0cmVhbWluZyh2b2ljZUNvbm5lY3RvcklkLCBwcm9wcy5zdHJlYW1pbmcpO1xuICB9XG5cbiAgaWYgKHByb3BzLmxvZ2dpbmcpIHtcbiAgICBhd2FpdCBwdXRMb2dnaW5nKHZvaWNlQ29ubmVjdG9ySWQsIHByb3BzLmxvZ2dpbmcpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBzc21DbGllbnQuc2VuZChcbiAgICAgIG5ldyBQdXRQYXJhbWV0ZXJDb21tYW5kKHtcbiAgICAgICAgTmFtZTogJy9jaGltZS92b2ljZUNvbm5lY3RvcicgKyB1aWQsXG4gICAgICAgIFZhbHVlOiB2b2ljZUNvbm5lY3RvcklkLFxuICAgICAgICBEZXNjcmlwdGlvbjogJ1ZvaWNlIENvbm5lY3RvciBJRCcsXG4gICAgICAgIE92ZXJ3cml0ZTogdHJ1ZSxcbiAgICAgICAgVHlwZTogJ1N0cmluZycsXG4gICAgICB9KSxcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgdm9pY2VDb25uZWN0b3JJZDogdm9pY2VDb25uZWN0b3JJZCxcbiAgfTtcbn07XG5cbmV4cG9ydCBpbnRlcmZhY2UgVXBkYXRlVm9pY2VDb25uZWN0b3JQcm9wcyB7XG4gIG5hbWU/OiBzdHJpbmc7XG4gIHJlZ2lvbj86IHN0cmluZztcbiAgZW5jcnlwdGlvbj86IGJvb2xlYW47XG4gIHRlcm1pbmF0aW9uPzogVGVybWluYXRpb25Qcm9wcztcbiAgb3JpZ2luYXRpb24/OiBSb3V0ZXNbXTtcbiAgbG9nZ2luZz86IExvZ2dpbmdQcm9wcztcbiAgc3RyZWFtaW5nPzogU3RyZWFtaW5nUHJvcHM7XG59XG5cbmV4cG9ydCBjb25zdCBVcGRhdGVWb2ljZUNvbm5lY3RvciA9IGFzeW5jIChcbiAgdWlkOiBzdHJpbmcsXG4gIHByb3BzOiBVcGRhdGVWb2ljZUNvbm5lY3RvclByb3BzLFxuKSA9PiB7XG4gIGNvbnNvbGUubG9nKGBVcGRhdGluZyBWb2ljZSBDb25uZWN0b3I6ICR7dWlkfWApO1xuICBjb25zb2xlLmxvZyhgVXBkYXRpbmcgVm9pY2UgQ29ubmVjdG9yIFByb3BzOiAke0pTT04uc3RyaW5naWZ5KHByb3BzKX1gKTtcbiAgdXBkYXRlVm9pY2VDb25uZWN0b3JQYXJhbXMgPSB7XG4gICAgTmFtZTogcHJvcHMubmFtZSxcbiAgICBSZXF1aXJlRW5jcnlwdGlvbjogcHJvcHMuZW5jcnlwdGlvbixcbiAgICBBd3NSZWdpb246IHByb3BzLnJlZ2lvbixcbiAgfTtcbiAgY29uc29sZS5sb2coXG4gICAgYHVwZGF0ZVZvaWNlQ29ubmVjdG9yUGFyYW1zOiAke0pTT04uc3RyaW5naWZ5KHVwZGF0ZVZvaWNlQ29ubmVjdG9yUGFyYW1zKX1gLFxuICApO1xuXG4gIHRyeSB7XG4gICAgZ2V0UGFyYW1ldGVyQ29tbWFuZE91dHB1dCA9IGF3YWl0IHNzbUNsaWVudC5zZW5kKFxuICAgICAgbmV3IEdldFBhcmFtZXRlckNvbW1hbmQoeyBOYW1lOiAnL2NoaW1lL3ZvaWNlQ29ubmVjdG9yJyArIHVpZCB9KSxcbiAgICApO1xuICAgIGlmIChcbiAgICAgIGdldFBhcmFtZXRlckNvbW1hbmRPdXRwdXQuUGFyYW1ldGVyICYmXG4gICAgICBnZXRQYXJhbWV0ZXJDb21tYW5kT3V0cHV0LlBhcmFtZXRlci5WYWx1ZVxuICAgICkge1xuICAgICAgdm9pY2VDb25uZWN0b3JJZCA9IGdldFBhcmFtZXRlckNvbW1hbmRPdXRwdXQuUGFyYW1ldGVyLlZhbHVlO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICBpZiAocHJvcHMub3JpZ2luYXRpb24pIHtcbiAgICBhd2FpdCBwdXRPcmlnaW5hdGlvbih2b2ljZUNvbm5lY3RvcklkLCBwcm9wcy5vcmlnaW5hdGlvbik7XG4gIH1cblxuICBpZiAocHJvcHMudGVybWluYXRpb24pIHtcbiAgICBhd2FpdCBwdXRUZXJtaW5hdGlvbih2b2ljZUNvbm5lY3RvcklkLCBwcm9wcy50ZXJtaW5hdGlvbik7XG4gIH1cblxuICBpZiAocHJvcHMuc3RyZWFtaW5nKSB7XG4gICAgYXdhaXQgcHV0U3RyZWFtaW5nKHZvaWNlQ29ubmVjdG9ySWQsIHByb3BzLnN0cmVhbWluZyk7XG4gIH1cblxuICBpZiAocHJvcHMubG9nZ2luZykge1xuICAgIGF3YWl0IHB1dExvZ2dpbmcodm9pY2VDb25uZWN0b3JJZCwgcHJvcHMubG9nZ2luZyk7XG4gIH1cbiAgcmV0dXJuIHtcbiAgICB2b2ljZUNvbm5lY3RvcklkOiB2b2ljZUNvbm5lY3RvcklkLFxuICB9O1xufTtcblxuZXhwb3J0IGNvbnN0IERlbGV0ZVZvaWNlQ29ubmVjdG9yID0gYXN5bmMgKHVpZDogc3RyaW5nKSA9PiB7XG4gIHRyeSB7XG4gICAgZ2V0UGFyYW1ldGVyQ29tbWFuZE91dHB1dCA9IGF3YWl0IHNzbUNsaWVudC5zZW5kKFxuICAgICAgbmV3IEdldFBhcmFtZXRlckNvbW1hbmQoeyBOYW1lOiAnL2NoaW1lL3ZvaWNlQ29ubmVjdG9yJyArIHVpZCB9KSxcbiAgICApO1xuICAgIGlmIChcbiAgICAgIGdldFBhcmFtZXRlckNvbW1hbmRPdXRwdXQuUGFyYW1ldGVyICYmXG4gICAgICBnZXRQYXJhbWV0ZXJDb21tYW5kT3V0cHV0LlBhcmFtZXRlci5WYWx1ZVxuICAgICkge1xuICAgICAgdm9pY2VDb25uZWN0b3JJZCA9IGdldFBhcmFtZXRlckNvbW1hbmRPdXRwdXQuUGFyYW1ldGVyLlZhbHVlO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cbiAgY29uc29sZS5sb2coYHZvaWNlQ29ubmVjdG9ySWQgdG8gZGVsZXRlOiAke3ZvaWNlQ29ubmVjdG9ySWR9YCk7XG4gIHRyeSB7XG4gICAgY29uc3QgcGhvbmVOdW1iZXJzQXNzb2NpYXRlZCA9IGF3YWl0IGNoaW1lU0RLVm9pY2VDbGllbnQuc2VuZChcbiAgICAgIG5ldyBMaXN0UGhvbmVOdW1iZXJzQ29tbWFuZCh7XG4gICAgICAgIEZpbHRlck5hbWU6ICdWb2ljZUNvbm5lY3RvcklkJyxcbiAgICAgICAgRmlsdGVyVmFsdWU6IHZvaWNlQ29ubmVjdG9ySWQsXG4gICAgICB9KSxcbiAgICApO1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgYHBob25lTnVtYmVycyB0byBkaXNhc3NvY2lhdGU6ICAke0pTT04uc3RyaW5naWZ5KFxuICAgICAgICBwaG9uZU51bWJlcnNBc3NvY2lhdGVkLFxuICAgICAgKX1gLFxuICAgICk7XG4gICAgaWYgKFxuICAgICAgcGhvbmVOdW1iZXJzQXNzb2NpYXRlZC5QaG9uZU51bWJlcnMgJiZcbiAgICAgIHBob25lTnVtYmVyc0Fzc29jaWF0ZWQuUGhvbmVOdW1iZXJzLmxlbmd0aCA+IDBcbiAgICApIHtcbiAgICAgIHBob25lTnVtYmVyc0Fzc29jaWF0ZWQuUGhvbmVOdW1iZXJzLmZvckVhY2goYXN5bmMgKHBob25lTnVtYmVyKSA9PiB7XG4gICAgICAgIHBob25lTnVtYmVyc1RvRGlzYXNzb2NpYXRlLnB1c2gocGhvbmVOdW1iZXIuUGhvbmVOdW1iZXJJZCEpO1xuICAgICAgfSk7XG4gICAgICBjb25zb2xlLmxvZyhgRGlzYXNzb2NpYXRlIFBob25lIE51bWJlcnM6ICR7cGhvbmVOdW1iZXJzVG9EaXNhc3NvY2lhdGV9YCk7XG4gICAgICBhd2FpdCBjaGltZVNES1ZvaWNlQ2xpZW50LnNlbmQoXG4gICAgICAgIG5ldyBEaXNhc3NvY2lhdGVQaG9uZU51bWJlcnNGcm9tVm9pY2VDb25uZWN0b3JDb21tYW5kKHtcbiAgICAgICAgICBWb2ljZUNvbm5lY3RvcklkOiB2b2ljZUNvbm5lY3RvcklkLFxuICAgICAgICAgIEUxNjRQaG9uZU51bWJlcnM6IHBob25lTnVtYmVyc1RvRGlzYXNzb2NpYXRlLFxuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuICBjb25zb2xlLmxvZyhgRGVsZXRpbmcgVm9pY2UgQ29ubmVjdG9yOiAke3ZvaWNlQ29ubmVjdG9ySWR9YCk7XG4gIHRyeSB7XG4gICAgZGVsZXRlVm9pY2VDb25uZWN0b3JSZXNwb25zZSA9IGF3YWl0IGNoaW1lU0RLVm9pY2VDbGllbnQuc2VuZChcbiAgICAgIG5ldyBEZWxldGVWb2ljZUNvbm5lY3RvckNvbW1hbmQoe1xuICAgICAgICBWb2ljZUNvbm5lY3RvcklkOiB2b2ljZUNvbm5lY3RvcklkLFxuICAgICAgfSksXG4gICAgKTtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIGBEZWxldGUgVm9pY2UgQ29ubmVjdG9yIFJlc3BvbnNlOiAke2RlbGV0ZVZvaWNlQ29ubmVjdG9yUmVzcG9uc2V9YCxcbiAgICApO1xuICAgIGF3YWl0IHNzbUNsaWVudC5zZW5kKFxuICAgICAgbmV3IERlbGV0ZVBhcmFtZXRlckNvbW1hbmQoeyBOYW1lOiAnL2NoaW1lL3ZvaWNlQ29ubmVjdG9yJyArIHVpZCB9KSxcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxufTtcblxuY29uc3QgcHV0T3JpZ2luYXRpb24gPSBhc3luYyAoXG4gIG9yaWdpbmF0aW9uVm9pY2VDb25uZWN0b3JJZDogc3RyaW5nLFxuICBvcmlnaW5hdGlvbnM6IHtcbiAgICBwcm90b2NvbDogc3RyaW5nO1xuICAgIGhvc3Q6IHN0cmluZztcbiAgICBwb3J0OiBzdHJpbmc7XG4gICAgcHJpb3JpdHk6IHN0cmluZztcbiAgICB3ZWlnaHQ6IHN0cmluZztcbiAgfVtdLFxuKSA9PiB7XG4gIGNvbnNvbGUubG9nKGBvcmlnaW5hdGlvbnM6ICAke0pTT04uc3RyaW5naWZ5KG9yaWdpbmF0aW9ucyl9YCk7XG4gIGNvbnNvbGUuaW5mbyhgdm9pY2VDb25uZWN0b3JJZDogJHtvcmlnaW5hdGlvblZvaWNlQ29ubmVjdG9ySWR9YCk7XG4gIHJvdXRlcyA9IFtdO1xuICBvcmlnaW5hdGlvbnMuZm9yRWFjaChhc3luYyAob3JpZ2luYXRpb24pID0+IHtcbiAgICByb3V0ZXMucHVzaCh7XG4gICAgICBQcm90b2NvbDogb3JpZ2luYXRpb24ucHJvdG9jb2wsXG4gICAgICBIb3N0OiBvcmlnaW5hdGlvbi5ob3N0LFxuICAgICAgUG9ydDogcGFyc2VJbnQob3JpZ2luYXRpb24ucG9ydCksXG4gICAgICBQcmlvcml0eTogcGFyc2VJbnQob3JpZ2luYXRpb24ucHJpb3JpdHkpLFxuICAgICAgV2VpZ2h0OiBwYXJzZUludChvcmlnaW5hdGlvbi53ZWlnaHQpLFxuICAgIH0pO1xuICB9KTtcbiAgY29uc29sZS5sb2coYHJvdXRlczogICR7SlNPTi5zdHJpbmdpZnkocm91dGVzKX1gKTtcbiAgdHJ5IHtcbiAgICBhd2FpdCBjaGltZVNES1ZvaWNlQ2xpZW50LnNlbmQoXG4gICAgICBuZXcgUHV0Vm9pY2VDb25uZWN0b3JPcmlnaW5hdGlvbkNvbW1hbmQoe1xuICAgICAgICBWb2ljZUNvbm5lY3RvcklkOiBvcmlnaW5hdGlvblZvaWNlQ29ubmVjdG9ySWQsXG4gICAgICAgIE9yaWdpbmF0aW9uOiB7XG4gICAgICAgICAgUm91dGVzOiByb3V0ZXMsXG4gICAgICAgICAgRGlzYWJsZWQ6IGZhbHNlLFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cbn07XG5cbmNvbnN0IHB1dFRlcm1pbmF0aW9uID0gYXN5bmMgKFxuICB0ZXJtaW5hdGlvblZvaWNlQ29ubmVjdG9ySWQ6IHN0cmluZyxcbiAgdGVybWluYXRpb246IHtcbiAgICBjYWxsaW5nUmVnaW9uczogc3RyaW5nW107XG4gICAgdGVybWluYXRpb25DaWRyczogc3RyaW5nW107XG4gICAgY3BzTGltaXQ6IHN0cmluZztcbiAgfSxcbikgPT4ge1xuICBjb25zb2xlLmxvZyhgdGVybWluYXRpb246ICAke0pTT04uc3RyaW5naWZ5KHRlcm1pbmF0aW9uKX1gKTtcbiAgY29uc29sZS5pbmZvKGB2b2ljZUNvbm5lY3RvcklkOiAke3Rlcm1pbmF0aW9uVm9pY2VDb25uZWN0b3JJZH1gKTtcbiAgdGVybWluYXRpb25Db25maWd1cmF0aW9uID0ge1xuICAgIENhbGxpbmdSZWdpb25zOiB0ZXJtaW5hdGlvbi5jYWxsaW5nUmVnaW9ucyxcbiAgICBDaWRyQWxsb3dlZExpc3Q6IHRlcm1pbmF0aW9uLnRlcm1pbmF0aW9uQ2lkcnMsXG4gICAgQ3BzTGltaXQ6IHBhcnNlSW50KHRlcm1pbmF0aW9uLmNwc0xpbWl0KSxcbiAgfTtcbiAgY29uc29sZS5sb2coXG4gICAgYHRlcm1pbmF0aW9uQ29uZmlndXJhdGlvbjogICR7SlNPTi5zdHJpbmdpZnkodGVybWluYXRpb25Db25maWd1cmF0aW9uKX1gLFxuICApO1xuICB0cnkge1xuICAgIGF3YWl0IGNoaW1lU0RLVm9pY2VDbGllbnQuc2VuZChcbiAgICAgIG5ldyBQdXRWb2ljZUNvbm5lY3RvclRlcm1pbmF0aW9uQ29tbWFuZCh7XG4gICAgICAgIFZvaWNlQ29ubmVjdG9ySWQ6IHRlcm1pbmF0aW9uVm9pY2VDb25uZWN0b3JJZCxcbiAgICAgICAgVGVybWluYXRpb246IHRlcm1pbmF0aW9uQ29uZmlndXJhdGlvbixcbiAgICAgIH0pLFxuICAgICk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG59O1xuXG5jb25zdCBwdXRTdHJlYW1pbmcgPSBhc3luYyAoXG4gIHN0cmVhbWluZ1ZvaWNlQ29ubmVjdG9ySWQ6IHN0cmluZyxcbiAgc3RyZWFtaW5nOiBTdHJlYW1pbmdQcm9wcyxcbikgPT4ge1xuICBjb25zb2xlLmxvZyhgc3RyZWFtaW5nOiAgJHtKU09OLnN0cmluZ2lmeShzdHJlYW1pbmcpfWApO1xuICBjb25zb2xlLmluZm8oYHZvaWNlQ29ubmVjdG9ySWQ6ICR7c3RyZWFtaW5nVm9pY2VDb25uZWN0b3JJZH1gKTtcblxuICBzdHJlYW1pbmdDb25maWd1cmF0aW9uID0ge1xuICAgIFN0cmVhbWluZ05vdGlmaWNhdGlvblRhcmdldHM6IHN0cmVhbWluZy5ub3RpZmljYXRpb25UYXJnZXQsXG4gICAgRGlzYWJsZWQ6IGZhbHNlLFxuICAgIERhdGFSZXRlbnRpb25JbkhvdXJzOiBwYXJzZUludChzdHJlYW1pbmcuZGF0YVJldGVudGlvbiksXG4gICAgLi4uKHN0cmVhbWluZy5tZWRpYUluc2lnaHRzQ29uZmlndXJhdGlvbiAmJiB7XG4gICAgICBNZWRpYUluc2lnaHRzQ29uZmlndXJhdGlvbjoge1xuICAgICAgICBEaXNhYmxlZDogc3RyZWFtaW5nLm1lZGlhSW5zaWdodHNDb25maWd1cmF0aW9uLmRpc2FibGVkLFxuICAgICAgICBDb25maWd1cmF0aW9uQXJuOiBzdHJlYW1pbmcubWVkaWFJbnNpZ2h0c0NvbmZpZ3VyYXRpb24uY29uZmlndXJhdGlvbkFybixcbiAgICAgIH0sXG4gICAgfSksXG4gIH07XG4gIGNvbnNvbGUubG9nKFxuICAgIGBzdHJlYW1pbmdDb25maWd1cmF0aW9uOiAgJHtKU09OLnN0cmluZ2lmeShzdHJlYW1pbmdDb25maWd1cmF0aW9uKX1gLFxuICApO1xuICB0cnkge1xuICAgIGF3YWl0IGNoaW1lU0RLVm9pY2VDbGllbnQuc2VuZChcbiAgICAgIG5ldyBQdXRWb2ljZUNvbm5lY3RvclN0cmVhbWluZ0NvbmZpZ3VyYXRpb25Db21tYW5kKHtcbiAgICAgICAgVm9pY2VDb25uZWN0b3JJZDogc3RyZWFtaW5nVm9pY2VDb25uZWN0b3JJZCxcbiAgICAgICAgU3RyZWFtaW5nQ29uZmlndXJhdGlvbjogc3RyZWFtaW5nQ29uZmlndXJhdGlvbixcbiAgICAgIH0pLFxuICAgICk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG59O1xuXG5jb25zdCBwdXRMb2dnaW5nID0gYXN5bmMgKFxuICBsb2dnaW5nVm9pY2VDb25uZWN0b3JJZDogc3RyaW5nLFxuICBsb2dnaW5nOiBMb2dnaW5nUHJvcHMsXG4pID0+IHtcbiAgY29uc29sZS5sb2coYGxvZ2dpbmc6ICAke0pTT04uc3RyaW5naWZ5KGxvZ2dpbmcpfWApO1xuICBjb25zb2xlLmluZm8oYHZvaWNlQ29ubmVjdG9ySWQ6ICR7bG9nZ2luZ1ZvaWNlQ29ubmVjdG9ySWR9YCk7XG4gIGxvZ2dpbmdDb25maWd1cmF0aW9uID0ge1xuICAgIC4uLihsb2dnaW5nLmVuYWJsZVNJUExvZ3MgJiYgeyBFbmFibGVTSVBMb2dzOiBsb2dnaW5nLmVuYWJsZVNJUExvZ3MgfSksXG4gICAgLi4uKGxvZ2dpbmcuZW5hYmxlTWVkaWFNZXRyaWNMb2dzICYmIHtcbiAgICAgIEVuYWJsZU1lZGlhTWV0cmljTG9nczogbG9nZ2luZy5lbmFibGVNZWRpYU1ldHJpY0xvZ3MsXG4gICAgfSksXG4gIH07XG4gIGNvbnNvbGUubG9nKGBsb2dnaW5nQ29uZmlndXJhdGlvbjogICR7SlNPTi5zdHJpbmdpZnkobG9nZ2luZ0NvbmZpZ3VyYXRpb24pfWApO1xuICB0cnkge1xuICAgIGF3YWl0IGNoaW1lU0RLVm9pY2VDbGllbnQuc2VuZChcbiAgICAgIG5ldyBQdXRWb2ljZUNvbm5lY3RvckxvZ2dpbmdDb25maWd1cmF0aW9uQ29tbWFuZCh7XG4gICAgICAgIFZvaWNlQ29ubmVjdG9ySWQ6IGxvZ2dpbmdWb2ljZUNvbm5lY3RvcklkLFxuICAgICAgICBMb2dnaW5nQ29uZmlndXJhdGlvbjogbG9nZ2luZ0NvbmZpZ3VyYXRpb24sXG4gICAgICB9KSxcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxufTtcbiJdfQ==