aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
443 lines • 81.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const os = require("os");
const path = require("path");
const util_1 = require("util");
const client_cloudformation_1 = require("@aws-sdk/client-cloudformation");
const fs = require("fs-extra");
const migrate_1 = require("../../lib/commands/migrate");
const mock_sdk_1 = require("../util/mock-sdk");
const exec = (0, util_1.promisify)(child_process_1.exec);
describe('Migrate Function Tests', () => {
let sdkProvider;
const testResourcePath = [__dirname, 'test-resources'];
const templatePath = [...testResourcePath, 'templates'];
const stackPath = [...testResourcePath, 'stacks'];
const validTemplatePath = path.join(...templatePath, 's3-template.json');
const emptyTemplatePath = path.join(...templatePath, 'empty-template.yml');
const invalidTemplatePath = path.join(...templatePath, 'rds-template.json');
const validTemplate = (0, migrate_1.readFromPath)(validTemplatePath);
const invalidTemplate = (0, migrate_1.readFromPath)(invalidTemplatePath);
beforeEach(async () => {
sdkProvider = new mock_sdk_1.MockSdkProvider();
});
test('parseSourceOptions throws if both --from-path and --from-stack is provided', () => {
expect(() => (0, migrate_1.parseSourceOptions)('any-value', true, 'my-awesome-stack')).toThrow('Only one of `--from-path` or `--from-stack` may be provided.');
});
test('parseSourceOptions returns from-scan when neither --from-path or --from-stack are provided', () => {
expect((0, migrate_1.parseSourceOptions)(undefined, undefined, 'my-stack-name')).toStrictEqual({
source: migrate_1.TemplateSourceOptions.SCAN,
});
});
test('parseSourceOptions does not throw when only --from-path is supplied', () => {
expect((0, migrate_1.parseSourceOptions)('my-file-path', undefined, 'my-stack-name')).toStrictEqual({
source: migrate_1.TemplateSourceOptions.PATH,
templatePath: 'my-file-path',
});
});
test('parseSourceOptions does now throw when only --from-stack is provided', () => {
expect((0, migrate_1.parseSourceOptions)(undefined, true, 'my-stack-name')).toStrictEqual({
source: migrate_1.TemplateSourceOptions.STACK,
stackName: 'my-stack-name',
});
});
test('readFromPath produces a string representation of the template at a given path', () => {
expect((0, migrate_1.readFromPath)(validTemplatePath)).toEqual(fs.readFileSync(validTemplatePath, 'utf8'));
});
test('readFromPath throws error when template file is empty', () => {
expect(() => (0, migrate_1.readFromPath)(emptyTemplatePath)).toThrow(`\'${emptyTemplatePath}\' is an empty file.`);
});
test('readFromPath throws error when template file does not exist at a given path', () => {
const badTemplatePath = './not-here.json';
expect(() => (0, migrate_1.readFromPath)(badTemplatePath)).toThrow(`\'${badTemplatePath}\' is not a valid path.`);
});
test('readFromStack produces a string representation of the template retrieved from CloudFormation', async () => {
const template = fs.readFileSync(validTemplatePath, { encoding: 'utf-8' });
mock_sdk_1.mockCloudFormationClient
.on(client_cloudformation_1.GetTemplateCommand)
.resolves({
TemplateBody: template,
})
.on(client_cloudformation_1.DescribeStacksCommand)
.resolves({
Stacks: [
{
StackName: 'this-one',
StackStatus: client_cloudformation_1.StackStatus.CREATE_COMPLETE,
CreationTime: new Date(),
},
],
});
expect(await (0, migrate_1.readFromStack)('this-one', sdkProvider, {
account: '123456789012',
region: 'here',
name: 'hello-my-name-is-what...',
})).toEqual(JSON.stringify(JSON.parse(template)));
});
test('readFromStack throws error when no stack exists with the stack name in the account and region', async () => {
const error = new Error('No stack. This did not go well.');
mock_sdk_1.mockCloudFormationClient.on(client_cloudformation_1.DescribeStacksCommand).rejects(error);
await expect(() => (0, migrate_1.readFromStack)('that-one', sdkProvider, {
account: '123456789012',
region: 'here',
name: 'hello-my-name-is-who...',
})).rejects.toThrow('No stack. This did not go well.');
});
test('readFromStack throws error when stack exists but the status is not healthy', async () => {
mock_sdk_1.mockCloudFormationClient.on(client_cloudformation_1.DescribeStacksCommand).resolves({
Stacks: [
{
StackName: 'this-one',
StackStatus: client_cloudformation_1.StackStatus.CREATE_FAILED,
StackStatusReason: 'Something went wrong',
CreationTime: new Date(),
},
],
});
await expect(() => (0, migrate_1.readFromStack)('that-one', sdkProvider, {
account: '123456789012',
region: 'here',
name: 'hello-my-name-is-chicka-chicka...',
})).rejects.toThrow("Stack 'that-one' in account 123456789012 and region here has a status of 'CREATE_FAILED' due to 'Something went wrong'. The stack cannot be migrated until it is in a healthy state.");
});
test('setEnvironment sets account and region when provided', () => {
expect((0, migrate_1.setEnvironment)('my-account', 'somewhere')).toEqual({
account: 'my-account',
region: 'somewhere',
name: 'cdk-migrate-env',
});
});
test('serEnvironment uses default account and region when not provided', () => {
expect((0, migrate_1.setEnvironment)()).toEqual({ account: 'unknown-account', region: 'unknown-region', name: 'cdk-migrate-env' });
});
test('generateStack generates the expected stack string when called for typescript', () => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodTypeScript', 'typescript');
expect(stack).toEqual(fs.readFileSync(path.join(...stackPath, 's3-stack.ts'), 'utf8'));
});
test('generateStack generates the expected stack string when called for python', () => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodPython', 'python');
expect(stack).toEqual(fs.readFileSync(path.join(...stackPath, 's3_stack.py'), 'utf8'));
});
test('generateStack generates the expected stack string when called for java', () => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodJava', 'java');
expect(stack).toEqual(fs.readFileSync(path.join(...stackPath, 'S3Stack.java'), 'utf8'));
});
test('generateStack generates the expected stack string when called for csharp', () => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodCSharp', 'csharp');
expect(stack).toEqual(fs.readFileSync(path.join(...stackPath, 'S3Stack.cs'), 'utf8'));
});
// TODO: fix with actual go template
test('generateStack generates the expected stack string when called for go', () => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodGo', 'go');
expect(stack).toEqual(fs.readFileSync(path.join(...stackPath, 's3.go'), 'utf8'));
});
test('generateStack throws error when called for other language', () => {
expect(() => (0, migrate_1.generateStack)(validTemplate, 'BadBadBad', 'php')).toThrow('BadBadBadStack could not be generated because php is not a supported language');
});
test('generateStack throws error for invalid resource property', () => {
expect(() => (0, migrate_1.generateStack)(invalidTemplate, 'VeryBad', 'typescript')).toThrow('VeryBadStack could not be generated because ReadEndpoint is not a valid property for resource RDSCluster of type AWS::RDS::DBCluster');
});
cliTest('generateCdkApp generates the expected cdk app when called for typescript', async (workDir) => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodTypeScript', 'typescript');
await (0, migrate_1.generateCdkApp)('GoodTypeScript', stack, 'typescript', workDir);
// Packages exist in the correct spot
expect(fs.pathExistsSync(path.join(workDir, 'GoodTypeScript', 'package.json'))).toBeTruthy();
expect(fs.pathExistsSync(path.join(workDir, 'GoodTypeScript', 'bin', 'good_type_script.ts'))).toBeTruthy();
expect(fs.pathExistsSync(path.join(workDir, 'GoodTypeScript', 'lib', 'good_type_script-stack.ts'))).toBeTruthy();
// Replaced stack file is referenced correctly in app file
const app = fs.readFileSync(path.join(workDir, 'GoodTypeScript', 'bin', 'good_type_script.ts'), 'utf8').split('\n');
expect(app
.map((line) => line.match("import { GoodTypeScriptStack } from '../lib/good_type_script-stack';"))
.filter((line) => line).length).toEqual(1);
expect(app.map((line) => line.match(/new GoodTypeScriptStack\(app, \'GoodTypeScript\', \{/)).filter((line) => line)
.length).toEqual(1);
// Replaced stack file is correctly generated
const replacedStack = fs.readFileSync(path.join(workDir, 'GoodTypeScript', 'lib', 'good_type_script-stack.ts'), 'utf8');
expect(replacedStack).toEqual(fs.readFileSync(path.join(...stackPath, 's3-stack.ts'), 'utf8'));
});
cliTest('generateCdkApp adds cdk-migrate key in context', async (workDir) => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodTypeScript', 'typescript');
await (0, migrate_1.generateCdkApp)('GoodTypeScript', stack, 'typescript', workDir);
// cdk.json exist in the correct spot
expect(fs.pathExistsSync(path.join(workDir, 'GoodTypeScript', 'cdk.json'))).toBeTruthy();
// cdk.json has "cdk-migrate" : true in context
const cdkJson = fs.readJsonSync(path.join(workDir, 'GoodTypeScript', 'cdk.json'), 'utf8');
expect(cdkJson.context['cdk-migrate']).toBeTruthy();
});
cliTest('generateCdkApp generates the expected cdk app when called for python', async (workDir) => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodPython', 'python');
await (0, migrate_1.generateCdkApp)('GoodPython', stack, 'python', workDir);
// Packages exist in the correct spot
expect(fs.pathExistsSync(path.join(workDir, 'GoodPython', 'requirements.txt'))).toBeTruthy();
expect(fs.pathExistsSync(path.join(workDir, 'GoodPython', 'app.py'))).toBeTruthy();
expect(fs.pathExistsSync(path.join(workDir, 'GoodPython', 'good_python', 'good_python_stack.py'))).toBeTruthy();
// Replaced stack file is referenced correctly in app file
const app = fs.readFileSync(path.join(workDir, 'GoodPython', 'app.py'), 'utf8').split('\n');
expect(app.map((line) => line.match('from good_python.good_python_stack import GoodPythonStack')).filter((line) => line)
.length).toEqual(1);
expect(app.map((line) => line.match(/GoodPythonStack\(app, "GoodPython",/)).filter((line) => line).length).toEqual(1);
// Replaced stack file is correctly generated
const replacedStack = fs.readFileSync(path.join(workDir, 'GoodPython', 'good_python', 'good_python_stack.py'), 'utf8');
expect(replacedStack).toEqual(fs.readFileSync(path.join(...stackPath, 's3_stack.py'), 'utf8'));
});
cliTest('generateCdkApp generates the expected cdk app when called for java', async (workDir) => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodJava', 'java');
await (0, migrate_1.generateCdkApp)('GoodJava', stack, 'java', workDir);
// Packages exist in the correct spot
expect(fs.pathExistsSync(path.join(workDir, 'GoodJava', 'pom.xml'))).toBeTruthy();
expect(fs.pathExistsSync(path.join(workDir, 'GoodJava', 'src', 'main', 'java', 'com', 'myorg', 'GoodJavaApp.java'))).toBeTruthy();
expect(fs.pathExistsSync(path.join(workDir, 'GoodJava', 'src', 'main', 'java', 'com', 'myorg', 'GoodJavaStack.java'))).toBeTruthy();
// Replaced stack file is referenced correctly in app file
const app = fs
.readFileSync(path.join(workDir, 'GoodJava', 'src', 'main', 'java', 'com', 'myorg', 'GoodJavaApp.java'), 'utf8')
.split('\n');
expect(app.map((line) => line.match('public class GoodJavaApp {')).filter((line) => line).length).toEqual(1);
expect(app
.map((line) => line.match(/ new GoodJavaStack\(app, "GoodJava", StackProps.builder()/))
.filter((line) => line).length).toEqual(1);
// Replaced stack file is correctly generated
const replacedStack = fs.readFileSync(path.join(workDir, 'GoodJava', 'src', 'main', 'java', 'com', 'myorg', 'GoodJavaStack.java'), 'utf8');
expect(replacedStack).toEqual(fs.readFileSync(path.join(...stackPath, 'S3Stack.java'), 'utf8'));
});
cliTest('generateCdkApp generates the expected cdk app when called for csharp', async (workDir) => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodCSharp', 'csharp');
await (0, migrate_1.generateCdkApp)('GoodCSharp', stack, 'csharp', workDir);
// Packages exist in the correct spot
expect(fs.pathExistsSync(path.join(workDir, 'GoodCSharp', 'src', 'GoodCSharp.sln'))).toBeTruthy();
expect(fs.pathExistsSync(path.join(workDir, 'GoodCSharp', 'src', 'GoodCSharp', 'Program.cs'))).toBeTruthy();
expect(fs.pathExistsSync(path.join(workDir, 'GoodCSharp', 'src', 'GoodCSharp', 'GoodCSharpStack.cs'))).toBeTruthy();
// Replaced stack file is referenced correctly in app file
const app = fs
.readFileSync(path.join(workDir, 'GoodCSharp', 'src', 'GoodCSharp', 'Program.cs'), 'utf8')
.split('\n');
expect(app.map((line) => line.match('namespace GoodCSharp')).filter((line) => line).length).toEqual(1);
expect(app
.map((line) => line.match(/ new GoodCSharpStack\(app, "GoodCSharp", new GoodCSharpStackProps/))
.filter((line) => line).length).toEqual(1);
// Replaced stack file is correctly generated
const replacedStack = fs.readFileSync(path.join(workDir, 'GoodCSharp', 'src', 'GoodCSharp', 'GoodCSharpStack.cs'), 'utf8');
expect(replacedStack).toEqual(fs.readFileSync(path.join(...stackPath, 'S3Stack.cs'), 'utf8'));
});
cliTest('generatedCdkApp generates the expected cdk app when called for go', async (workDir) => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodGo', 'go');
await (0, migrate_1.generateCdkApp)('GoodGo', stack, 'go', workDir);
expect(fs.pathExists(path.join(workDir, 's3.go'))).toBeTruthy();
const app = fs.readFileSync(path.join(workDir, 'GoodGo', 'good_go.go'), 'utf8').split('\n');
expect(app
.map((line) => line.match(/func NewGoodGoStack\(scope constructs.Construct, id string, props \*GoodGoStackProps\) \*GoodGoStack \{/))
.filter((line) => line).length).toEqual(1);
expect(app.map((line) => line.match(/ NewGoodGoStack\(app, "GoodGo", &GoodGoStackProps\{/)));
});
cliTest('generatedCdkApp generates a zip file when --compress is used', async (workDir) => {
const stack = (0, migrate_1.generateStack)(validTemplate, 'GoodTypeScript', 'typescript');
await (0, migrate_1.generateCdkApp)('GoodTypeScript', stack, 'typescript', workDir, true);
// Packages not in outDir
expect(fs.pathExistsSync(path.join(workDir, 'GoodTypeScript', 'package.json'))).toBeFalsy();
expect(fs.pathExistsSync(path.join(workDir, 'GoodTypeScript', 'bin', 'good_type_script.ts'))).toBeFalsy();
expect(fs.pathExistsSync(path.join(workDir, 'GoodTypeScript', 'lib', 'good_type_script-stack.ts'))).toBeFalsy();
// Zip file exists
expect(fs.pathExistsSync(path.join(workDir, 'GoodTypeScript.zip'))).toBeTruthy();
// Unzip it
await exec(`unzip ${path.join(workDir, 'GoodTypeScript.zip')}`, { cwd: workDir });
// Now the files should be there
expect(fs.pathExistsSync(path.join(workDir, 'package.json'))).toBeTruthy();
expect(fs.pathExistsSync(path.join(workDir, 'bin', 'good_type_script.ts'))).toBeTruthy();
expect(fs.pathExistsSync(path.join(workDir, 'lib', 'good_type_script-stack.ts'))).toBeTruthy();
});
});
function cliTest(name, handler) {
test(name, () => withTempDir(handler));
}
async function withTempDir(cb) {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'aws-cdk-test'));
try {
await cb(tmpDir);
}
finally {
await fs.remove(tmpDir);
}
}
describe('generateTemplate', () => {
let sdkProvider;
const sampleResource = {
ResourceType: 'AWS::S3::Bucket',
ManagedByStack: true,
ResourceIdentifier: { 'my-key': 'my-bucket' },
LogicalResourceId: 'my-bucket',
};
const sampleResource2 = {
ResourceType: 'AWS::EC2::Instance',
ResourceIdentifier: {
instanceId: 'i-1234567890abcdef0',
},
LogicalResourceId: 'my-ec2-instance',
ManagedByStack: true,
};
const stackName = 'my-stack';
const environment = (0, migrate_1.setEnvironment)('123456789012', 'us-east-1');
const scanId = 'fake-scan-id';
const defaultExpectedResult = {
migrateJson: {
resources: [
{
LogicalResourceId: 'my-bucket',
ResourceIdentifier: { 'my-key': 'my-bucket' },
ResourceType: 'AWS::S3::Bucket',
},
{
LogicalResourceId: 'my-ec2-instance',
ResourceIdentifier: { instanceId: 'i-1234567890abcdef0' },
ResourceType: 'AWS::EC2::Instance',
},
],
source: 'template-arn',
templateBody: 'template-body',
},
resources: [
{
LogicalResourceId: 'my-bucket',
ManagedByStack: true,
ResourceIdentifier: {
'my-key': 'my-bucket',
},
ResourceType: 'AWS::S3::Bucket',
},
{
LogicalResourceId: 'my-ec2-instance',
ManagedByStack: true,
ResourceIdentifier: {
instanceId: 'i-1234567890abcdef0',
},
ResourceType: 'AWS::EC2::Instance',
},
],
};
beforeEach(() => {
(0, mock_sdk_1.restoreSdkMocksToDefault)();
sdkProvider = new mock_sdk_1.MockSdkProvider();
mock_sdk_1.mockCloudFormationClient
.on(client_cloudformation_1.StartResourceScanCommand)
.resolves({
ResourceScanId: scanId,
})
.on(client_cloudformation_1.ListResourceScansCommand)
.resolves({
ResourceScanSummaries: [
{ ResourceScanId: scanId, Status: client_cloudformation_1.ResourceScanStatus.COMPLETE, PercentageCompleted: 100 },
],
})
.on(client_cloudformation_1.DescribeResourceScanCommand)
.resolves({
Status: 'COMPLETE',
})
.on(client_cloudformation_1.ListResourceScanResourcesCommand)
.resolves({
Resources: [sampleResource2],
})
.on(client_cloudformation_1.CreateGeneratedTemplateCommand)
.resolves({
GeneratedTemplateId: 'template-arn',
})
.on(client_cloudformation_1.DescribeGeneratedTemplateCommand)
.resolves({
Status: 'COMPLETE',
Resources: [sampleResource, sampleResource2],
})
.on(client_cloudformation_1.GetGeneratedTemplateCommand)
.resolves({
TemplateBody: 'template-body',
})
.on(client_cloudformation_1.ListResourceScanRelatedResourcesCommand)
.resolves({
RelatedResources: [sampleResource],
});
});
afterEach(() => {
(0, mock_sdk_1.restoreSdkMocksToDefault)();
});
test('generateTemplate successfully generates template with a new scan', async () => {
const opts = {
stackName: stackName,
filters: [],
fromScan: migrate_1.FromScan.NEW,
sdkProvider: sdkProvider,
environment: environment,
};
const template = await (0, migrate_1.generateTemplate)(opts);
expect(template).toEqual(defaultExpectedResult);
});
test('generateTemplate successfully defaults to latest scan instead of starting a new one', async () => {
mock_sdk_1.mockCloudFormationClient
.on(client_cloudformation_1.StartResourceScanCommand)
.rejects('No >:(')
.on(client_cloudformation_1.ListResourceScansCommand)
.resolvesOnce({
ResourceScanSummaries: [{ ResourceScanId: scanId, Status: 'IN_PROGRESS', PercentageCompleted: 50 }],
})
.resolves({
ResourceScanSummaries: [{ ResourceScanId: scanId, Status: 'COMPLETE', PercentageCompleted: 100 }],
});
const opts = {
stackName: stackName,
filters: [],
newScan: true,
sdkProvider: sdkProvider,
environment: environment,
};
const template = await (0, migrate_1.generateTemplate)(opts);
expect(template).toEqual(defaultExpectedResult);
});
test('generateTemplate throws an error when from-scan most-recent is passed but no scans are found.', async () => {
mock_sdk_1.mockCloudFormationClient.on(client_cloudformation_1.ListResourceScansCommand)
.resolves({
ResourceScanSummaries: [],
});
const opts = {
stackName: stackName,
filters: [],
fromScan: migrate_1.FromScan.MOST_RECENT,
sdkProvider: sdkProvider,
environment: environment,
};
await expect((0, migrate_1.generateTemplate)(opts)).rejects.toThrow('No scans found. Please either start a new scan with the `--from-scan` new or do not specify a `--from-scan` option.');
});
test('generateTemplate throws an error when an invalid key is passed in the filters', async () => {
const opts = {
stackName: stackName,
filters: ['invalid-key=invalid-value'],
fromScan: migrate_1.FromScan.MOST_RECENT,
sdkProvider: sdkProvider,
environment: environment,
};
await expect((0, migrate_1.generateTemplate)(opts)).rejects.toThrow('Invalid filter: invalid-key');
});
test('generateTemplate defaults to starting a new scan when no options are provided and no scans are found', async () => {
mock_sdk_1.mockCloudFormationClient.on(client_cloudformation_1.ListResourceScansCommand)
// First call: list current scans, there aren't any.
.resolvesOnce({ ResourceScanSummaries: [] })
// The generator will then call StartScan and ListResourceScans again which it now will expect to return something
.resolves({
ResourceScanSummaries: [{ ResourceScanId: scanId, Status: 'COMPLETE', PercentageCompleted: 100 }],
});
const opts = {
stackName: stackName,
sdkProvider: sdkProvider,
environment: environment,
};
const template = await (0, migrate_1.generateTemplate)(opts);
expect(template).toEqual(defaultExpectedResult);
expect(mock_sdk_1.mockCloudFormationClient).toHaveReceivedCommand(client_cloudformation_1.StartResourceScanCommand);
});
test('generateTemplate successfully generates templates with valid filter options', async () => {
const opts = {
stackName: stackName,
filters: ['type=AWS::S3::Bucket,identifier={"my-key":"my-bucket"}', 'type=AWS::EC2::Instance'],
sdkProvider: sdkProvider,
environment: environment,
};
const template = await (0, migrate_1.generateTemplate)(opts);
expect(template).toEqual(defaultExpectedResult);
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlncmF0ZS50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibWlncmF0ZS50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsaURBQThDO0FBQzlDLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsK0JBQWlDO0FBQ2pDLDBFQWF3QztBQUN4QywrQkFBK0I7QUFDL0Isd0RBV29DO0FBQ3BDLCtDQUF1RztBQUV2RyxNQUFNLElBQUksR0FBRyxJQUFBLGdCQUFTLEVBQUMsb0JBQUssQ0FBQyxDQUFDO0FBRTlCLFFBQVEsQ0FBQyx3QkFBd0IsRUFBRSxHQUFHLEVBQUU7SUFDdEMsSUFBSSxXQUE0QixDQUFDO0lBRWpDLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxTQUFTLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztJQUN2RCxNQUFNLFlBQVksR0FBRyxDQUFDLEdBQUcsZ0JBQWdCLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDeEQsTUFBTSxTQUFTLEdBQUcsQ0FBQyxHQUFHLGdCQUFnQixFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBRWxELE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLFlBQVksRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO0lBQ3pFLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLFlBQVksRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO0lBQzNFLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLFlBQVksRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0lBQzVFLE1BQU0sYUFBYSxHQUFHLElBQUEsc0JBQVksRUFBQyxpQkFBaUIsQ0FBRSxDQUFDO0lBQ3ZELE1BQU0sZUFBZSxHQUFHLElBQUEsc0JBQVksRUFBQyxtQkFBbUIsQ0FBRSxDQUFDO0lBRTNELFVBQVUsQ0FBQyxLQUFLLElBQUksRUFBRTtRQUNwQixXQUFXLEdBQUcsSUFBSSwwQkFBZSxFQUFFLENBQUM7SUFD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