aws-cdk
Version:
AWS CDK CLI, the command line tool for CDK apps
411 lines • 60.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CachedDataSource = exports.WebsiteNoticeDataSource = exports.FilteredNotice = exports.Notices = exports.NoticesFilter = void 0;
const https = require("node:https");
const path = require("path");
const fs = require("fs-extra");
const semver = require("semver");
const awscli_compatible_1 = require("./api/aws-auth/awscli-compatible");
const tree_1 = require("./api/tree");
const version_1 = require("./cli/version");
const util_1 = require("./util");
const api_1 = require("../../@aws-cdk/tmp-toolkit-helpers/src/api");
const private_1 = require("../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private");
const CACHE_FILE_PATH = path.join((0, util_1.cdkCacheDir)(), 'notices.json');
class NoticesFilter {
constructor(ioMessages) {
this.ioMessages = ioMessages;
}
filter(options) {
const components = [
...this.constructTreeComponents(options.outDir),
...this.otherComponents(options),
];
return this.findForNamedComponents(options.data, components);
}
/**
* From a set of input options, return the notices components we are searching for
*/
otherComponents(options) {
return [
// CLI
{
name: 'cli',
version: options.cliVersion,
},
// Node version
{
name: 'node',
version: process.version.replace(/^v/, ''), // remove the 'v' prefix.
dynamicName: 'node',
},
// Bootstrap environments
...options.bootstrappedEnvironments.flatMap(env => {
const semverBootstrapVersion = semver.coerce(env.bootstrapStackVersion);
if (!semverBootstrapVersion) {
// we don't throw because notices should never crash the cli.
this.ioMessages.warning(`While filtering notices, could not coerce bootstrap version '${env.bootstrapStackVersion}' into semver`);
return [];
}
return [{
name: 'bootstrap',
version: `${semverBootstrapVersion}`,
dynamicName: 'ENVIRONMENTS',
dynamicValue: env.environment.name,
}];
}),
];
}
/**
* Based on a set of component names, find all notices that match one of the given components
*/
findForNamedComponents(data, actualComponents) {
return data.flatMap(notice => {
const ors = this.resolveAliases(normalizeComponents(notice.components));
// Find the first set of the disjunctions of which all components match against the actual components.
// Return the actual components we found so that we can inject their dynamic values. A single filter
// component can match more than one actual component
for (const ands of ors) {
const matched = ands.map(affected => actualComponents.filter(actual => this.componentNameMatches(affected, actual) && semver.satisfies(actual.version, affected.version, { includePrerelease: true })));
// For every clause in the filter we matched one or more components
if (matched.every(xs => xs.length > 0)) {
const ret = new FilteredNotice(notice);
this.addDynamicValues(matched.flatMap(x => x), ret);
return [ret];
}
}
return [];
});
}
/**
* Whether the given "affected component" name applies to the given actual component name.
*
* The name matches if the name is exactly the same, or the name in the notice
* is a prefix of the node name when the query ends in '.'.
*/
componentNameMatches(pattern, actual) {
return pattern.name.endsWith('.') ? actual.name.startsWith(pattern.name) : pattern.name === actual.name;
}
/**
* Adds dynamic values from the given ActualComponents
*
* If there are multiple components with the same dynamic name, they are joined
* by a comma.
*/
addDynamicValues(comps, notice) {
const dynamicValues = {};
for (const comp of comps) {
if (comp.dynamicName) {
dynamicValues[comp.dynamicName] = dynamicValues[comp.dynamicName] ?? [];
dynamicValues[comp.dynamicName].push(comp.dynamicValue ?? comp.version);
}
}
for (const [key, values] of Object.entries(dynamicValues)) {
notice.addDynamicValue(key, values.join(','));
}
}
/**
* Treat 'framework' as an alias for either `aws-cdk-lib.` or `@aws-cdk/core.`.
*
* Because it's EITHER `aws-cdk-lib` or `@aws-cdk/core`, we need to add multiple
* arrays at the top level.
*/
resolveAliases(ors) {
return ors.flatMap(ands => {
const hasFramework = ands.find(c => c.name === 'framework');
if (!hasFramework) {
return [ands];
}
return [
ands.map(c => c.name === 'framework' ? { ...c, name: '@aws-cdk/core.' } : c),
ands.map(c => c.name === 'framework' ? { ...c, name: 'aws-cdk-lib.' } : c),
];
});
}
/**
* Load the construct tree from the given directory and return its components
*/
constructTreeComponents(manifestDir) {
const tree = (0, tree_1.loadTreeFromDir)(manifestDir, (msg) => void this.ioMessages.notify(private_1.IO.DEFAULT_ASSEMBLY_TRACE.msg(msg)));
if (!tree) {
return [];
}
const ret = [];
recurse(tree);
return ret;
function recurse(x) {
if (x.constructInfo?.fqn && x.constructInfo?.version) {
ret.push({
name: x.constructInfo?.fqn,
version: x.constructInfo?.version,
});
}
for (const child of Object.values(x.children ?? {})) {
recurse(child);
}
}
}
}
exports.NoticesFilter = NoticesFilter;
/**
* Provides access to notices the CLI can display.
*/
class Notices {
/**
* Create an instance. Note that this replaces the singleton.
*/
static create(props) {
this._instance = new Notices(props);
return this._instance;
}
/**
* Get the singleton instance. May return `undefined` if `create` has not been called.
*/
static get() {
return this._instance;
}
constructor(props) {
this.data = new Set();
// sets don't deduplicate interfaces, so we use a map.
this.bootstrappedEnvironments = new Map();
this.context = props.context;
this.acknowledgedIssueNumbers = new Set(this.context.get('acknowledged-issue-numbers') ?? []);
this.includeAcknowlegded = props.includeAcknowledged ?? false;
this.output = props.output ?? 'cdk.out';
this.httpOptions = props.httpOptions ?? {};
this.ioMessages = new private_1.IoDefaultMessages((0, private_1.asIoHelper)(props.ioHost, 'notices' /* forcing a CliAction to a ToolkitAction */));
}
/**
* Add a bootstrap information to filter on. Can have multiple values
* in case of multi-environment deployments.
*/
addBootstrappedEnvironment(bootstrapped) {
const key = [
bootstrapped.bootstrapStackVersion,
bootstrapped.environment.account,
bootstrapped.environment.region,
bootstrapped.environment.name,
].join(':');
this.bootstrappedEnvironments.set(key, bootstrapped);
}
/**
* Refresh the list of notices this instance is aware of.
* To make sure this never crashes the CLI process, all failures are caught and
* silently logged.
*
* If context is configured to not display notices, this will no-op.
*/
async refresh(options = {}) {
try {
const underlyingDataSource = options.dataSource ?? new WebsiteNoticeDataSource(this.ioMessages, this.httpOptions);
const dataSource = new CachedDataSource(this.ioMessages, CACHE_FILE_PATH, underlyingDataSource, options.force ?? false);
const notices = await dataSource.fetch();
this.data = new Set(this.includeAcknowlegded ? notices : notices.filter(n => !this.acknowledgedIssueNumbers.has(n.issueNumber)));
}
catch (e) {
this.ioMessages.debug(`Could not refresh notices: ${e}`);
}
}
/**
* Display the relevant notices (unless context dictates we shouldn't).
*/
display(options = {}) {
const filteredNotices = new NoticesFilter(this.ioMessages).filter({
data: Array.from(this.data),
cliVersion: (0, version_1.versionNumber)(),
outDir: this.output,
bootstrappedEnvironments: Array.from(this.bootstrappedEnvironments.values()),
});
if (filteredNotices.length > 0) {
void this.ioMessages.notify(private_1.IO.CDK_TOOLKIT_I0100.msg([
'',
'NOTICES (What\'s this? https://github.com/aws/aws-cdk/wiki/CLI-Notices)',
'',
].join('\n')));
for (const filtered of filteredNotices) {
const formatted = filtered.format() + '\n';
switch (filtered.notice.severity) {
case 'warning':
void this.ioMessages.notify(private_1.IO.CDK_TOOLKIT_W0101.msg(formatted));
break;
case 'error':
void this.ioMessages.notify(private_1.IO.CDK_TOOLKIT_E0101.msg(formatted));
break;
default:
void this.ioMessages.notify(private_1.IO.CDK_TOOLKIT_I0101.msg(formatted));
break;
}
}
void this.ioMessages.notify(private_1.IO.CDK_TOOLKIT_I0100.msg(`If you don’t want to see a notice anymore, use "cdk acknowledge <id>". For example, "cdk acknowledge ${filteredNotices[0].notice.issueNumber}".`));
}
if (options.showTotal ?? false) {
void this.ioMessages.notify(private_1.IO.CDK_TOOLKIT_I0100.msg(`\nThere are ${filteredNotices.length} unacknowledged notice(s).`));
}
}
}
exports.Notices = Notices;
/**
* Normalizes the given components structure into DNF form
*/
function normalizeComponents(xs) {
return xs.map(x => Array.isArray(x) ? x : [x]);
}
function renderConjunction(xs) {
return xs.map(c => `${c.name}: ${c.version}`).join(' AND ');
}
/**
* Notice after passing the filter. A filter can augment a notice with
* dynamic values as it has access to the dynamic matching data.
*/
class FilteredNotice {
constructor(notice) {
this.notice = notice;
this.dynamicValues = {};
}
addDynamicValue(key, value) {
this.dynamicValues[`{resolve:${key}}`] = value;
}
format() {
const componentsValue = normalizeComponents(this.notice.components).map(renderConjunction).join(', ');
return this.resolveDynamicValues([
`${this.notice.issueNumber}\t${this.notice.title}`,
this.formatOverview(),
`\tAffected versions: ${componentsValue}`,
`\tMore information at: https://github.com/aws/aws-cdk/issues/${this.notice.issueNumber}`,
].join('\n\n') + '\n');
}
formatOverview() {
const wrap = (s) => s.replace(/(?![^\n]{1,60}$)([^\n]{1,60})\s/g, '$1\n');
const heading = 'Overview: ';
const separator = `\n\t${' '.repeat(heading.length)}`;
const content = wrap(this.notice.overview)
.split('\n')
.join(separator);
return '\t' + heading + content;
}
resolveDynamicValues(input) {
const pattern = new RegExp(Object.keys(this.dynamicValues).join('|'), 'g');
return input.replace(pattern, (matched) => this.dynamicValues[matched] ?? matched);
}
}
exports.FilteredNotice = FilteredNotice;
class WebsiteNoticeDataSource {
constructor(ioMessages, options = {}) {
this.ioMessages = ioMessages;
this.options = options;
}
fetch() {
const timeout = 3000;
return new Promise((resolve, reject) => {
let req;
let timer = setTimeout(() => {
if (req) {
req.destroy(new api_1.ToolkitError('Request timed out'));
}
}, timeout);
timer.unref();
const options = {
agent: awscli_compatible_1.AwsCliCompatible.proxyAgent(this.options),
};
try {
req = https.get('https://cli.cdk.dev-tools.aws.dev/notices.json', options, res => {
if (res.statusCode === 200) {
res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => {
rawData += chunk;
});
res.on('end', () => {
try {
const data = JSON.parse(rawData).notices;
if (!data) {
throw new api_1.ToolkitError("'notices' key is missing");
}
this.ioMessages.debug('Notices refreshed');
resolve(data ?? []);
}
catch (e) {
reject(new api_1.ToolkitError(`Failed to parse notices: ${(0, util_1.formatErrorMessage)(e)}`));
}
});
res.on('error', e => {
reject(new api_1.ToolkitError(`Failed to fetch notices: ${(0, util_1.formatErrorMessage)(e)}`));
});
}
else {
reject(new api_1.ToolkitError(`Failed to fetch notices. Status code: ${res.statusCode}`));
}
});
req.on('error', reject);
}
catch (e) {
reject(new api_1.ToolkitError(`HTTPS 'get' call threw an error: ${(0, util_1.formatErrorMessage)(e)}`));
}
});
}
}
exports.WebsiteNoticeDataSource = WebsiteNoticeDataSource;
const TIME_TO_LIVE_SUCCESS = 60 * 60 * 1000; // 1 hour
const TIME_TO_LIVE_ERROR = 1 * 60 * 1000; // 1 minute
class CachedDataSource {
constructor(ioMessages, fileName, dataSource, skipCache) {
this.ioMessages = ioMessages;
this.fileName = fileName;
this.dataSource = dataSource;
this.skipCache = skipCache;
}
async fetch() {
const cachedData = await this.load();
const data = cachedData.notices;
const expiration = cachedData.expiration ?? 0;
if (Date.now() > expiration || this.skipCache) {
const freshData = await this.fetchInner();
await this.save(freshData);
return freshData.notices;
}
else {
this.ioMessages.debug(`Reading cached notices from ${this.fileName}`);
return data;
}
}
async fetchInner() {
try {
return {
expiration: Date.now() + TIME_TO_LIVE_SUCCESS,
notices: await this.dataSource.fetch(),
};
}
catch (e) {
this.ioMessages.debug(`Could not refresh notices: ${e}`);
return {
expiration: Date.now() + TIME_TO_LIVE_ERROR,
notices: [],
};
}
}
async load() {
const defaultValue = {
expiration: 0,
notices: [],
};
try {
return fs.existsSync(this.fileName)
? await fs.readJSON(this.fileName)
: defaultValue;
}
catch (e) {
this.ioMessages.debug(`Failed to load notices from cache: ${e}`);
return defaultValue;
}
}
async save(cached) {
try {
await fs.writeJSON(this.fileName, cached);
}
catch (e) {
this.ioMessages.debug(`Failed to store notices in the cache: ${e}`);
}
}
}
exports.CachedDataSource = CachedDataSource;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm5vdGljZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRUEsb0NBQW9DO0FBQ3BDLDZCQUE2QjtBQUU3QiwrQkFBK0I7QUFDL0IsaUNBQWlDO0FBRWpDLHdFQUFvRTtBQUdwRSxxQ0FBNkM7QUFFN0MsMkNBQThDO0FBQzlDLGlDQUF5RDtBQUN6RCxvRUFBMEU7QUFDMUUsbUZBQTBHO0FBRTFHLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBQSxrQkFBVyxHQUFFLEVBQUUsY0FBYyxDQUFDLENBQUM7QUFrRWpFLE1BQWEsYUFBYTtJQUN4QixZQUE2QixVQUE2QjtRQUE3QixlQUFVLEdBQVYsVUFBVSxDQUFtQjtJQUMxRCxDQUFDO0lBRU0sTUFBTSxDQUFDLE9BQW1DO1FBQy9DLE1BQU0sVUFBVSxHQUFHO1lBQ2pCLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7WUFDL0MsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQztTQUNqQyxDQUFDO1FBRUYsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxlQUFlLENBQUMsT0FBbUM7UUFDekQsT0FBTztZQUNMLE1BQU07WUFDTjtnQkFDRSxJQUFJLEVBQUUsS0FBSztnQkFDWCxPQUFPLEVBQUUsT0FBTyxDQUFDLFVBQVU7YUFDNUI7WUFFRCxlQUFlO1lBQ2Y7Z0JBQ0UsSUFBSSxFQUFFLE1BQU07Z0JBQ1osT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsRUFBRSx5QkFBeUI7Z0JBQ3JFLFdBQVcsRUFBRSxNQUFNO2FBQ3BCO1lBRUQseUJBQXlCO1lBQ3pCLEdBQUcsT0FBTyxDQUFDLHdCQUF3QixDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRTtnQkFDaEQsTUFBTSxzQkFBc0IsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO2dCQUN4RSxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztvQkFDNUIsNkRBQTZEO29CQUM3RCxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxnRUFBZ0UsR0FBRyxDQUFDLHFCQUFxQixlQUFlLENBQUMsQ0FBQztvQkFDbEksT0FBTyxFQUFFLENBQUM7Z0JBQ1osQ0FBQztnQkFFRCxPQUFPLENBQUM7d0JBQ04sSUFBSSxFQUFFLFdBQVc7d0JBQ2pCLE9BQU8sRUFBRSxHQUFHLHNCQUFzQixFQUFFO3dCQUNwQyxXQUFXLEVBQUUsY0FBYzt3QkFDM0IsWUFBWSxFQUFFLEdBQUcsQ0FBQyxXQUFXLENBQUMsSUFBSTtxQkFDbkMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQyxDQUFDO1NBQ0gsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNLLHNCQUFzQixDQUFDLElBQWMsRUFBRSxnQkFBbUM7UUFDaEYsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFO1lBQzNCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsbUJBQW1CLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7WUFFeEUsc0dBQXNHO1lBQ3RHLG9HQUFvRztZQUNwRyxxREFBcUQ7WUFDckQsS0FBSyxNQUFNLElBQUksSUFBSSxHQUFHLEVBQUUsQ0FBQztnQkFDdkIsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUNwRSxJQUFJLENBQUMsb0JBQW9CLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsT0FBTyxFQUFFLEVBQUUsaUJBQWlCLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBRW5JLG1FQUFtRTtnQkFDbkUsSUFBSSxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO29CQUN2QyxNQUFNLEdBQUcsR0FBRyxJQUFJLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQztvQkFDdkMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztvQkFDcEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUNmLENBQUM7WUFDSCxDQUFDO1lBRUQsT0FBTyxFQUFFLENBQUM7UUFDWixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLG9CQUFvQixDQUFDLE9BQWtCLEVBQUUsTUFBdUI7UUFDdEUsT0FBTyxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxLQUFLLE1BQU0sQ0FBQyxJQUFJLENBQUM7SUFDMUcsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ssZ0JBQWdCLENBQUMsS0FBd0IsRUFBRSxNQUFzQjtRQUN2RSxNQUFNLGFBQWEsR0FBNkIsRUFBRSxDQUFDO1FBQ25ELEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7WUFDekIsSUFBSSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQ3JCLGFBQWEsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsYUFBYSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ3hFLGFBQWEsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzFFLENBQUM7UUFDSCxDQUFDO1FBQ0QsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztZQUMxRCxNQUFNLENBQUMsZUFBZSxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDaEQsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLGNBQWMsQ0FBQyxHQUFrQjtRQUN2QyxPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDeEIsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssV0FBVyxDQUFDLENBQUM7WUFDNUQsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUNsQixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDaEIsQ0FBQztZQUVELE9BQU87Z0JBQ0wsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUFFLElBQUksRUFBRSxnQkFBZ0IsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQzVFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxJQUFJLEVBQUUsY0FBYyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUMzRSxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSyx1QkFBdUIsQ0FBQyxXQUFtQjtRQUNqRCxNQUFNLElBQUksR0FBRyxJQUFBLHNCQUFlLEVBQUMsV0FBVyxFQUFFLENBQUMsR0FBVyxFQUFFLEVBQUUsQ0FBQyxLQUFLLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLFlBQUUsQ0FBQyxzQkFBc0IsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzVILElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNWLE9BQU8sRUFBRSxDQUFDO1FBQ1osQ0FBQztRQUVELE1BQU0sR0FBRyxHQUFzQixFQUFFLENBQUM7UUFDbEMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2QsT0FBTyxHQUFHLENBQUM7UUFFWCxTQUFTLE9BQU8sQ0FBQyxDQUFvQjtZQUNuQyxJQUFJLENBQUMsQ0FBQyxhQUFhLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxhQUFhLEVBQUUsT0FBTyxFQUFFLENBQUM7Z0JBQ3JELEdBQUcsQ0FBQyxJQUFJLENBQUM7b0JBQ1AsSUFBSSxFQUFFLENBQUMsQ0FBQyxhQUFhLEVBQUUsR0FBRztvQkFDMUIsT0FBTyxFQUFFLENBQUMsQ0FBQyxhQUFhLEVBQUUsT0FBTztpQkFDbEMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUVELEtBQUssTUFBTSxLQUFLLElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUM7Z0JBQ3BELE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNqQixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7Q0FDRjtBQXZKRCxzQ0F1SkM7QUE2Q0Q7O0dBRUc7QUFDSCxNQUFhLE9BQU87SUFDbEI7O09BRUc7SUFDSSxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQW1CO1FBQ3RDLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDcEMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDO0lBQ3hCLENBQUM7SUFFRDs7T0FFRztJQUNJLE1BQU0sQ0FBQyxHQUFHO1FBQ2YsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDO0lBQ3hCLENBQUM7SUFnQkQsWUFBb0IsS0FBbUI7UUFML0IsU0FBSSxHQUFnQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRXRDLHNEQUFzRDtRQUNyQyw2QkFBd0IsR0FBeUMsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUcxRixJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUM7UUFDN0IsSUFBSSxDQUFDLHdCQUF3QixHQUFHLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLDRCQUE0QixDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFDOUYsSUFBSSxDQUFDLG1CQUFtQixHQUFHLEtBQUssQ0FBQyxtQkFBbUIsSUFBSSxLQUFLLENBQUM7UUFDOUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxJQUFJLFNBQVMsQ0FBQztRQUN4QyxJQUFJLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFDO1FBQzNDLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSwyQkFBaUIsQ0FBQyxJQUFBLG9CQUFVLEVBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxTQUFnQixDQUFDLDRDQUE0QyxDQUFDLENBQUMsQ0FBQztJQUNuSSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksMEJBQTBCLENBQUMsWUFBcUM7UUFDckUsTUFBTSxHQUFHLEdBQUc7WUFDVixZQUFZLENBQUMscUJBQXFCO1lBQ2xDLFlBQVksQ0FBQyxXQUFXLENBQUMsT0FBTztZQUNoQyxZQUFZLENBQUMsV0FBVyxDQUFDLE1BQU07WUFDL0IsWUFBWSxDQUFDLFdBQVcsQ0FBQyxJQUFJO1NBQzlCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ1osSUFBSSxDQUFDLHdCQUF3QixDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDdkQsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNJLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBaUMsRUFBRTtRQUN0RCxJQUFJLENBQUM7WUFDSCxNQUFNLG9CQUFvQixHQUFHLE9BQU8sQ0FBQyxVQUFVLElBQUksSUFBSSx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUNsSCxNQUFNLFVBQVUsR0FBRyxJQUFJLGdCQUFnQixDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsZUFBZSxFQUFFLG9CQUFvQixFQUFFLE9BQU8sQ0FBQyxLQUFLLElBQUksS0FBSyxDQUFDLENBQUM7WUFDeEgsTUFBTSxPQUFPLEdBQUcsTUFBTSxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDekMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLHdCQUF3QixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25JLENBQUM7UUFBQyxPQUFPLENBQU0sRUFBRSxDQUFDO1lBQ2hCLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLDhCQUE4QixDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzNELENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxPQUFPLENBQUMsVUFBK0IsRUFBRTtRQUM5QyxNQUFNLGVBQWUsR0FBRyxJQUFJLGFBQWEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsTUFBTSxDQUFDO1lBQ2hFLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7WUFDM0IsVUFBVSxFQUFFLElBQUEsdUJBQWEsR0FBRTtZQUMzQixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDbkIsd0JBQXdCLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsd0JBQXdCLENBQUMsTUFBTSxFQUFFLENBQUM7U0FDN0UsQ0FBQyxDQUFDO1FBRUgsSUFBSSxlQUFlLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQy9CLEtBQUssSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsWUFBRSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQztnQkFDbkQsRUFBRTtnQkFDRixpRkFBaUY7Z0JBQ2pGLEVBQUU7YUFDSCxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDZixLQUFLLE1BQU0sUUFBUSxJQUFJLGVBQWUsRUFBRSxDQUFDO2dCQUN2QyxNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDO2dCQUMzQyxRQUFRLFFBQVEsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7b0JBQ2pDLEtBQUssU0FBUzt3QkFDWixLQUFLLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLFlBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQzt3QkFDakUsTUFBTTtvQkFDUixLQUFLLE9BQU87d0JBQ1YsS0FBSyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxZQUFFLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7d0JBQ2pFLE1BQU07b0JBQ1I7d0JBQ0UsS0FBSyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxZQUFFLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7d0JBQ2pFLE1BQU07Z0JBQ1YsQ0FBQztZQUNILENBQUM7WUFDRCxLQUFLLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLFlBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQ2xELHdHQUF3RyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLFdBQVcsSUFBSSxDQUNsSixDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsSUFBSSxPQUFPLENBQUMsU0FBUyxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQy9CLEtBQUssSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsWUFBRSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FDbEQsZUFBZSxlQUFlLENBQUMsTUFBTSw0QkFBNEIsQ0FDbEUsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUM7Q0FDRjtBQWpIRCwwQkFpSEM7QUErQkQ7O0dBRUc7QUFDSCxTQUFTLG1CQUFtQixDQUFDLEVBQWtDO0lBQzdELE9BQU8sRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2pELENBQUM7QUFFRCxTQUFTLGlCQUFpQixDQUFDLEVBQWU7SUFDeEMsT0FBTyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxLQUFLLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUM5RCxDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsTUFBYSxjQUFjO0lBR3pCLFlBQW1DLE1BQWM7UUFBZCxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBRmhDLGtCQUFhLEdBQThCLEVBQUUsQ0FBQztJQUcvRCxDQUFDO0lBRU0sZUFBZSxDQUFDLEdBQVcsRUFBRSxLQUFhO1FBQy9DLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxHQUFHLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQztJQUNqRCxDQUFDO0lBRU0sTUFBTTtRQUNYLE1BQU0sZUFBZSxHQUFHLG1CQUFtQixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3RHLE9BQU8sSUFBSSxDQUFDLG9CQUFvQixDQUFDO1lBQy9CLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLEtBQUssSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7WUFDbEQsSUFBSSxDQUFDLGNBQWMsRUFBRTtZQUNyQix3QkFBd0IsZUFBZSxFQUFFO1lBQ3pDLGdFQUFnRSxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRTtTQUMxRixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUN6QixDQUFDO0lBRU8sY0FBYztRQUNwQixNQUFNLElBQUksR0FBRyxDQUFDLENBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxrQ0FBa0MsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVsRixNQUFNLE9BQU8sR0FBRyxZQUFZLENBQUM7UUFDN0IsTUFBTSxTQUFTLEdBQUcsT0FBTyxHQUFHLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQ3RELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQzthQUN2QyxLQUFLLENBQUMsSUFBSSxDQUFDO2FBQ1gsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRW5CLE9BQU8sSUFBSSxHQUFHLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDbEMsQ0FBQztJQUVPLG9CQUFvQixDQUFDLEtBQWE7UUFDeEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzNFLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLElBQUksT0FBTyxDQUFDLENBQUM7SUFDckYsQ0FBQztDQUNGO0FBcENELHdDQW9DQztBQU1ELE1BQWEsdUJBQXVCO0lBR2xDLFlBQTZCLFVBQTZCLEVBQUUsVUFBMEIsRUFBRTtRQUEzRCxlQUFVLEdBQVYsVUFBVSxDQUFtQjtRQUN4RCxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztJQUN6QixDQUFDO0lBRUQsS0FBSztRQUNILE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQztRQUNyQixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ3JDLElBQUksR0FBOEIsQ0FBQztZQUVuQyxJQUFJLEtBQUssR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFO2dCQUMxQixJQUFJLEdBQUcsRUFBRSxDQUFDO29CQUNSLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxrQkFBWSxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQztnQkFDckQsQ0FBQztZQUNILENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQztZQUVaLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUVkLE1BQU0sT0FBTyxHQUFtQjtnQkFDOUIsS0FBSyxFQUFFLG9DQUFnQixDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO2FBQ2pELENBQUM7WUFFRixJQUFJLENBQUM7Z0JBQ0gsR0FBRyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsZ0RBQWdELEVBQzlELE9BQU8sRUFDUCxHQUFHLENBQUMsRUFBRTtvQkFDSixJQUFJLEdBQUcsQ0FBQyxVQUFVLEtBQUssR0FBRyxFQUFFLENBQUM7d0JBQzNCLEdBQUcsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7d0JBQ3hCLElBQUksT0FBTyxHQUFHLEVBQUUsQ0FBQzt3QkFDakIsR0FBRyxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTs0QkFDdkIsT0FBTyxJQUFJLEtBQUssQ0FBQzt3QkFDbkIsQ0FBQyxDQUFDLENBQUM7d0JBQ0gsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFOzRCQUNqQixJQUFJLENBQUM7Z0NBQ0gsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFtQixDQUFDO2dDQUNyRCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7b0NBQ1YsTUFBTSxJQUFJLGtCQUFZLENBQUMsMEJBQTBCLENBQUMsQ0FBQztnQ0FDckQsQ0FBQztnQ0FDRCxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO2dDQUMzQyxPQUFPLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDOzRCQUN0QixDQUFDOzRCQUFDLE9BQU8sQ0FBTSxFQUFFLENBQUM7Z0NBQ2hCLE1BQU0sQ0FBQyxJQUFJLGtCQUFZLENBQUMsNEJBQTRCLElBQUEseUJBQWtCLEVBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7NEJBQ2hGLENBQUM7d0JBQ0gsQ0FBQyxDQUFDLENBQUM7d0JBQ0gsR0FBRyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUU7NEJBQ2xCLE1BQU0sQ0FBQyxJQUFJLGtCQUFZLENBQUMsNEJBQTRCLElBQUEseUJBQWtCLEVBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7d0JBQ2hGLENBQUMsQ0FBQyxDQUFDO29CQUNMLENBQUM7eUJBQU0sQ0FBQzt3QkFDTixNQUFNLENBQUMsSUFBSSxrQkFBWSxDQUFDLHlDQUF5QyxHQUFHLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDO29CQUN0RixDQUFDO2dCQUNILENBQUMsQ0FBQyxDQUFDO2dCQUNMLEdBQUcsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzFCLENBQUM7WUFBQyxPQUFPLENBQU0sRUFBRSxDQUFDO2dCQUNoQixNQUFNLENBQUMsSUFBSSxrQkFBWSxDQUFDLG9DQUFvQyxJQUFBLHlCQUFrQixFQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ3hGLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQTNERCwwREEyREM7QUFPRCxNQUFNLG9CQUFvQixHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsU0FBUztBQUN0RCxNQUFNLGtCQUFrQixHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUMsV0FBVztBQUVyRCxNQUFhLGdCQUFnQjtJQUMzQixZQUNtQixVQUE2QixFQUM3QixRQUFnQixFQUNoQixVQUE0QixFQUM1QixTQUFtQjtRQUhuQixlQUFVLEdBQVYsVUFBVSxDQUFtQjtRQUM3QixhQUFRLEdBQVIsUUFBUSxDQUFRO1FBQ2hCLGVBQVUsR0FBVixVQUFVLENBQWtCO1FBQzVCLGNBQVMsR0FBVCxTQUFTLENBQVU7SUFDdEMsQ0FBQztJQUVELEtBQUssQ0FBQyxLQUFLO1FBQ1QsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDckMsTUFBTSxJQUFJLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQztRQUNoQyxNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQztRQUU5QyxJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxVQUFVLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQzlDLE1BQU0sU0FBUyxHQUFHLE1BQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQzFDLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUMzQixPQUFPLFNBQVMsQ0FBQyxPQUFPLENBQUM7UUFDM0IsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQywrQkFBK0IsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7WUFDdEUsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxVQUFVO1FBQ3RCLElBQUksQ0FBQztZQUNILE9BQU87Z0JBQ0wsVUFBVSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxvQkFBb0I7Z0JBQzdDLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFO2FBQ3ZDLENBQUM7UUFDSixDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLDhCQUE4QixDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3pELE9BQU87Z0JBQ0wsVUFBVSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxrQkFBa0I7Z0JBQzNDLE9BQU8sRUFBRSxFQUFFO2FBQ1osQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLElBQUk7UUFDaEIsTUFBTSxZQUFZLEdBQUc7WUFDbkIsVUFBVSxFQUFFLENBQUM7WUFDYixPQUFPLEVBQUUsRUFBRTtTQUNaLENBQUM7UUFFRixJQUFJLENBQUM7WUFDSCxPQUFPLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQztnQkFDakMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFrQjtnQkFDbkQsQ0FBQyxDQUFDLFlBQVksQ0FBQztRQUNuQixDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLHNDQUFzQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ2pFLE9BQU8sWUFBWSxDQUFDO1FBQ3RCLENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFxQjtRQUN0QyxJQUFJLENBQUM7WUFDSCxNQUFNLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUM1QyxDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNYLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLHlDQUF5QyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3RFLENBQUM7SUFDSCxDQUFDO0NBQ0Y7QUE3REQsNENBNkRDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBDbGllbnRSZXF1ZXN0IH0gZnJvbSAnaHR0cCc7XG5pbXBvcnQgdHlwZSB7IFJlcXVlc3RPcHRpb25zIH0gZnJvbSAnaHR0cHMnO1xuaW1wb3J0ICogYXMgaHR0cHMgZnJvbSAnbm9kZTpodHRwcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHR5cGUgeyBFbnZpcm9ubWVudCB9IGZyb20gJ0Bhd3MtY2RrL2N4LWFwaSc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy1leHRyYSc7XG5pbXBvcnQgKiBhcyBzZW12ZXIgZnJvbSAnc2VtdmVyJztcbmltcG9ydCB0eXBlIHsgU2RrSHR0cE9wdGlvbnMgfSBmcm9tICcuL2FwaSc7XG5pbXBvcnQgeyBBd3NDbGlDb21wYXRpYmxlIH0gZnJvbSAnLi9hcGkvYXdzLWF1dGgvYXdzY2xpLWNvbXBhdGlibGUnO1xuaW1wb3J0IHR5cGUgeyBDb250ZXh0IH0gZnJvbSAnLi9hcGkvY29udGV4dCc7XG5pbXBvcnQgdHlwZSB7IENvbnN0cnVjdFRyZWVOb2RlIH0gZnJvbSAnLi9hcGkvdHJlZSc7XG5pbXBvcnQgeyBsb2FkVHJlZUZyb21EaXIgfSBmcm9tICcuL2FwaS90cmVlJztcbmltcG9ydCB0eXBlIHsgSUlvSG9zdCB9IGZyb20gJy4vY2xpL2lvLWhvc3QnO1xuaW1wb3J0IHsgdmVyc2lvbk51bWJlciB9IGZyb20gJy4vY2xpL3ZlcnNpb24nO1xuaW1wb3J0IHsgY2RrQ2FjaGVEaXIsIGZvcm1hdEVycm9yTWVzc2FnZSB9IGZyb20gJy4vdXRpbCc7XG5pbXBvcnQgeyBUb29sa2l0RXJyb3IgfSBmcm9tICcuLi8uLi9AYXdzLWNkay90bXAtdG9vbGtpdC1oZWxwZXJzL3NyYy9hcGknO1xuaW1wb3J0IHsgSU8sIGFzSW9IZWxwZXIsIElvRGVmYXVsdE1lc3NhZ2VzIH0gZnJvbSAnLi4vLi4vQGF3cy1jZGsvdG1wLXRvb2xraXQtaGVscGVycy9zcmMvYXBpL2lvL3ByaXZhdGUnO1xuXG5jb25zdCBDQUNIRV9GSUxFX1BBVEggPSBwYXRoLmpvaW4oY2RrQ2FjaGVEaXIoKSwgJ25vdGljZXMuanNvbicpO1xuXG5leHBvcnQgaW50ZXJmYWNlIE5vdGljZXNQcm9wcyB7XG4gIC8qKlxuICAgKiBDREsgY29udGV4dFxuICAgKi9cbiAgcmVhZG9ubHkgY29udGV4dDogQ29udGV4dDtcblxuICAvKipcbiAgICogSW5jbHVkZSBub3RpY2VzIHRoYXQgaGF2ZSBhbHJlYWR5IGJlZW4gYWNrbm93bGVkZ2VkLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgaW5jbHVkZUFja25vd2xlZGdlZD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEdsb2JhbCBDTEkgb3B0aW9uIGZvciBvdXRwdXQgZGlyZWN0b3J5IGZvciBzeW50aGVzaXplZCBjbG91ZCBhc3NlbWJseVxuICAgKlxuICAgKiBAZGVmYXVsdCAnY2RrLm91dCdcbiAgICovXG4gIHJlYWRvbmx5IG91dHB1dD86IHN0cmluZztcblxuICAvKipcbiAgICogT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdFxuICAgKi9cbiAgcmVhZG9ubHkgaHR0cE9wdGlvbnM/OiBTZGtIdHRwT3B0aW9ucztcblxuICAvKipcbiAgICogV2hlcmUgbWVzc2FnZXMgYXJlIGdvaW5nIHRvIGJlIHNlbnRcbiAgICovXG4gIHJlYWRvbmx5IGlvSG9zdDogSUlvSG9zdDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBOb3RpY2VzUHJpbnRPcHRpb25zIHtcblxuICAvKipcbiAgICogV2hldGhlciB0byBhcHBlbmQgdGhlIHRvdGFsIG51bWJlciBvZiB1bmFja25vd2xlZGdlZCBub3RpY2VzIHRvIHRoZSBkaXNwbGF5LlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgc2hvd1RvdGFsPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBOb3RpY2VzUmVmcmVzaE9wdGlvbnMge1xuICAvKipcbiAgICogV2hldGhlciB0byBmb3JjZSBhIGNhY2hlIHJlZnJlc2ggcmVnYXJkbGVzcyBvZiBleHBpcmF0aW9uIHRpbWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBmb3JjZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIERhdGEgc291cmNlIGZvciBmZXRjaCBub3RpY2VzIGZyb20uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gV2Vic2l0ZU5vdGljZURhdGFTb3VyY2VcbiAgICovXG4gIHJlYWRvbmx5IGRhdGFTb3VyY2U/OiBOb3RpY2VEYXRhU291cmNlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5vdGljZXNGaWx0ZXJGaWx0ZXJPcHRpb25zIHtcbiAgcmVhZG9ubHkgZGF0YTogTm90aWNlW107XG4gIHJlYWRvbmx5IGNsaVZlcnNpb246IHN0cmluZztcbiAgcmVhZG9ubHkgb3V0RGlyOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGJvb3RzdHJhcHBlZEVudmlyb25tZW50czogQm9vdHN0cmFwcGVkRW52aXJvbm1lbnRbXTtcbn1cblxuZXhwb3J0IGNsYXNzIE5vdGljZXNGaWx0ZXIge1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGlvTWVzc2FnZXM6IElvRGVmYXVsdE1lc3NhZ2VzKSB7XG4gIH1cblxuICBwdWJsaWMgZmlsdGVyKG9wdGlvbnM6IE5vdGljZXNGaWx0ZXJGaWx0ZXJPcHRpb25zKTogRmlsdGVyZWROb3RpY2VbXSB7XG4gICAgY29uc3QgY29tcG9uZW50cyA9IFtcbiAgICAgIC4uLnRoaXMuY29uc3RydWN0VHJlZUNvbXBvbmVudHMob3B0aW9ucy5vdXREaXIpLFxuICAgICAgLi4udGhpcy5vdGhlckNvbXBvbmVudHMob3B0aW9ucyksXG4gICAgXTtcblxuICAgIHJldHVybiB0aGlzLmZpbmRGb3JOYW1lZENvbXBvbmVudHMob3B0aW9ucy5kYXRhLCBjb21wb25lbnRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGcm9tIGEgc2V0IG9mIGlucHV0IG9wdGlvbnMsIHJldHVybiB0aGUgbm90aWNlcyBjb21wb25lbnRzIHdlIGFyZSBzZWFyY2hpbmcgZm9yXG4gICAqL1xuICBwcml2YXRlIG90aGVyQ29tcG9uZW50cyhvcHRpb25zOiBOb3RpY2VzRmlsdGVyRmlsdGVyT3B0aW9ucyk6IEFjdHVhbENvbXBvbmVudFtdIHtcbiAgICByZXR1cm4gW1xuICAgICAgLy8gQ0xJXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICdjbGknLFxuICAgICAgICB2ZXJzaW9uOiBvcHRpb25zLmNsaVZlcnNpb24sXG4gICAgICB9LFxuXG4gICAgICAvLyBOb2RlIHZlcnNpb25cbiAgICAgIHtcbiAgICAgICAgbmFtZTogJ25vZGUnLFxuICAgICAgICB2ZXJzaW9uOiBwcm9jZXNzLnZlcnNpb24ucmVwbGFjZSgvXnYvLCAnJyksIC8vIHJlbW92ZSB0aGUgJ3YnIHByZWZpeC5cbiAgICAgICAgZHluYW1pY05hbWU6ICdub2RlJyxcbiAgICAgIH0sXG5cbiAgICAgIC8vIEJvb3RzdHJhcCBlbnZpcm9ubWVudHNcbiAgICAgIC4uLm9wdGlvbnMuYm9vdHN0cmFwcGVkRW52aXJvbm1lbnRzLmZsYXRNYXAoZW52ID0+IHtcbiAgICAgICAgY29uc3Qgc2VtdmVyQm9vdHN0cmFwVmVyc2lvbiA9IHNlbXZlci5jb2VyY2UoZW52LmJvb3RzdHJhcFN0YWNrVmVyc2lvbik7XG4gICAgICAgIGlmICghc2VtdmVyQm9vdHN0cmFwVmVyc2lvbikge1xuICAgICAgICAgIC8vIHdlIGRvbid0IHRocm93IGJlY2F1c2Ugbm90aWNlcyBzaG91bGQgbmV2ZXIgY3Jhc2ggdGhlIGNsaS5cbiAgICAgICAgICB0aGlzLmlvTWVzc2FnZXMud2FybmluZyhgV2hpbGUgZmlsdGVyaW5nIG5vdGljZXMsIGNvdWxkIG5vdCBjb2VyY2UgYm9vdHN0cmFwIHZlcnNpb24gJyR7ZW52LmJvb3RzdHJhcFN0YWNrVmVyc2lvbn0nIGludG8gc2VtdmVyYCk7XG4gICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIFt7XG4gICAgICAgICAgbmFtZTogJ2Jvb3RzdHJhcCcsXG4gICAgICAgICAgdmVyc2lvbjogYCR7c2VtdmVyQm9vdHN0cmFwVmVyc2lvbn1gLFxuICAgICAgICAgIGR5bmFtaWNOYW1lOiAnRU5WSVJPTk1FTlRTJyxcbiAgICAgICAgICBkeW5hbWljVmFsdWU6IGVudi5lbnZpcm9ubWVudC5uYW1lLFxuICAgICAgICB9XTtcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICAvKipcbiAgICogQmFzZWQgb24gYSBzZXQgb2YgY29tcG9uZW50IG5hbWVzLCBmaW5kIGFsbCBub3RpY2VzIHRoYXQgbWF0Y2ggb25lIG9mIHRoZSBnaXZlbiBjb21wb25lbnRzXG4gICAqL1xuICBwcml2YXRlIGZpbmRGb3JOYW1lZENvbXBvbmVudHMoZGF0YTogTm90aWNlW10sIGFjdHVhbENvbXBvbmVudHM6IEFjdHVhbENvbXBvbmVudFtdKTogRmlsdGVyZWROb3RpY2VbXSB7XG4gICAgcmV0dXJuIGRhdGEuZmxhdE1hcChub3RpY2UgPT4ge1xuICAgICAgY29uc3Qgb3JzID0gdGhpcy5yZXNvbHZlQWxpYXNlcyhub3JtYWxpemVDb21wb25lbnRzKG5vdGljZS5jb21wb25lbnRzKSk7XG5cbiAgICAgIC8vIEZpbmQgdGhlIGZpcnN0IHNldCBvZiB0aGUgZGlzanVuY3Rpb25zIG9mIHdoaWNoIGFsbCBjb21wb25lbnRzIG1hdGNoIGFnYWluc3QgdGhlIGFjdHVhbCBjb21wb25lbnRzLlxuICAgICAgLy8gUmV0dXJuIHRoZSBhY3R1YWwgY29tcG9uZW50cyB3ZSBmb3VuZCBzbyB0aGF0IHdlIGNhbiBpbmplY3QgdGhlaXIgZHluYW1pYyB2YWx1ZXMuIEEgc2luZ2xlIGZpbHRlclxuICAgICAgLy8gY29tcG9uZW50IGNhbiBtYXRjaCBtb3JlIHRoYW4gb25lIGFjdHVhbCBjb21wb25lbnRcbiAgICAgIGZvciAoY29uc3QgYW5kcyBvZiBvcnMpIHtcbiAgICAgICAgY29uc3QgbWF0Y2hlZCA9IGFuZHMubWFwKGFmZmVjdGVkID0+IGFjdHVhbENvbXBvbmVudHMuZmlsdGVyKGFjdHVhbCA9PlxuICAgICAgICAgIHRoaXMuY29tcG9uZW50TmFtZU1hdGNoZXMoYWZmZWN0ZWQsIGFjdHVhbCkgJiYgc2VtdmVyLnNhdGlzZmllcyhhY3R1YWwudmVyc2lvbiwgYWZmZWN0ZWQudmVyc2lvbiwgeyBpbmNsdWRlUHJlcmVsZWFzZTogdHJ1ZSB9KSkpO1xuXG4gICAgICAgIC8vIEZvciBldmVyeSBjbGF1c2UgaW4gdGhlIGZpbHRlciB3ZSBtYXRjaGVkIG9uZSBvciBtb3JlIGNvbXBvbmVudHNcbiAgICAgICAgaWYgKG1hdGNoZWQuZXZlcnkoeHMgPT4geHMubGVuZ3RoID4gMCkpIHtcbiAgICAgICAgICBjb25zdCByZXQgPSBuZXcgRmlsdGVyZWROb3RpY2Uobm90aWNlKTtcbiAgICAgICAgICB0aGlzLmFkZER5bmFtaWNWYWx1ZXMobWF0Y2hlZC5mbGF0TWFwKHggPT4geCksIHJldCk7XG4gICAgICAgICAgcmV0dXJuIFtyZXRdO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBbXTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBnaXZlbiBcImFmZmVjdGVkIGNvbXBvbmVudFwiIG5hbWUgYXBwbGllcyB0byB0aGUgZ2l2ZW4gYWN0dWFsIGNvbXBvbmVudCBuYW1lLlxuICAgKlxuICAgKiBUaGUgbmFtZSBtYXRjaGVzIGlmIHRoZSBuYW1lIGlzIGV4YWN0bHkgdGhlIHNhbWUsIG9yIHRoZSBuYW1lIGluIHRoZSBub3RpY2VcbiAgICogaXMgYSBwcmVmaXggb2YgdGhlIG5vZGUgbmFtZSB3aGVuIHRoZSBxdWVyeSBlbmRzIGluICcuJy5cbiAgICovXG4gIHByaXZhdGUgY29tcG9uZW50TmFtZU1hdGNoZXMocGF0dGVybjogQ29tcG9uZW50LCBhY3R1YWw6IEFjdHVhbENvbXBvbmVudCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBwYXR0ZXJuLm5hbWUuZW5kc1dpdGgoJy4nKSA/IGFjdHVhbC5uYW1lLnN0YXJ0c1dpdGgocGF0dGVybi5uYW1lKSA6IHBhdHRlcm4ubmFtZSA9PT0gYWN0dWFsLm5hbWU7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBkeW5hbWljIHZhbHVlcyBmcm9tIHRoZSBnaXZlbiBBY3R1YWxDb21wb25lbnRzXG4gICAqXG4gICAqIElmIHRoZXJlIGFyZSBtdWx0aXBsZSBjb21wb25lbnRzIHdpdGggdGhlIHNhbWUgZHluYW1pYyBuYW1lLCB0aGV5IGFyZSBqb2luZWRcbiAgICogYnkgYSBjb21tYS5cbiAgICovXG4gIHByaXZhdGUgYWRkRHluYW1pY1ZhbHVlcyhjb21wczogQWN0dWFsQ29tcG9uZW50W10sIG5vdGljZTogRmlsdGVyZWROb3RpY2UpIHtcbiAgICBjb25zdCBkeW5hbWljVmFsdWVzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT4gPSB7fTtcbiAgICBmb3IgKGNvbnN0IGNvbXAgb2YgY29tcHMpIHtcbiAgICAgIGlmIChjb21wLmR5bmFtaWNOYW1lKSB7XG4gICAgICAgIGR5bmFtaWNWYWx1ZXNbY29tcC5keW5hbWljTmFtZV0gPSBkeW5hbWljVmFsdWVzW2NvbXAuZHluYW1pY05hbWVdID8/IFtdO1xuICAgICAgICBkeW5hbWljVmFsdWVzW2NvbXAuZHluYW1pY05hbWVdLnB1c2goY29tcC5keW5hbWljVmFsdWUgPz8gY29tcC52ZXJzaW9uKTtcbiAgICAgIH1cbiAgICB9XG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZXNdIG9mIE9iamVjdC5lbnRyaWVzKGR5bmFtaWNWYWx1ZXMpKSB7XG4gICAgICBub3RpY2UuYWRkRHluYW1pY1ZhbHVlKGtleSwgdmFsdWVzLmpvaW4oJywnKSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRyZWF0ICdmcmFtZXdvcmsnIGFzIGFuIGFsaWFzIGZvciBlaXRoZXIgYGF3cy1jZGstbGliLmAgb3IgYEBhd3MtY2RrL2NvcmUuYC5cbiAgICpcbiAgICogQmVjYXVzZSBpdCdzIEVJVEhFUiBgYXdzLWNkay1saWJgIG9yIGBAYXdzLWNkay9jb3JlYCwgd2UgbmVlZCB0byBhZGQgbXVsdGlwbGVcbiAgICogYXJyYXlzIGF0IHRoZSB0b3AgbGV2ZWwuXG4gICAqL1xuICBwcml2YXRlIHJlc29sdmVBbGlhc2VzKG9yczogQ29tcG9uZW50W11bXSk6IENvbXBvbmVudFtdW10ge1xuICAgIHJldHVybiBvcnMuZmxhdE1hcChhbmRzID0+IHtcbiAgICAgIGNvbnN0IGhhc0ZyYW1ld29yayA9IGFuZHMuZmluZChjID0+IGMubmFtZSA9PT0gJ2ZyYW1ld29yaycpO1xuICAgICAgaWYgKCFoYXNGcmFtZXdvcmspIHtcbiAgICAgICAgcmV0dXJuIFthbmRzXTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIFtcbiAgICAgICAgYW5kcy5tYXAoYyA9PiBjLm5hbWUgPT09ICdmcmFtZXdvcmsnID8geyAuLi5jLCBuYW1lOiAnQGF3cy1jZGsvY29yZS4nIH0gOiBjKSxcbiAgICAgICAgYW5kcy5tYXAoYyA9PiBjLm5hbWUgPT09ICdmcmFtZXdvcmsnID8geyAuLi5jLCBuYW1lOiAnYXdzLWNkay1saWIuJyB9IDogYyksXG4gICAgICBdO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWQgdGhlIGNvbnN0cnVjdCB0cmVlIGZyb20gdGhlIGdpdmVuIGRpcmVjdG9yeSBhbmQgcmV0dXJuIGl0cyBjb21wb25lbnRzXG4gICAqL1xuICBwcml2YXRlIGNvbnN0cnVjdFRyZWVDb21wb25lbnRzKG1hbmlmZXN0RGlyOiBzdHJpbmcpOiBBY3R1YWxDb21wb25lbnRbXSB7XG4gICAgY29uc3QgdHJlZSA9IGxvYWRUcmVlRnJvbURpcihtYW5pZmVzdERpciwgKG1zZzogc3RyaW5nKSA9PiB2b2lkIHRoaXMuaW9NZXNzYWdlcy5ub3RpZnkoSU8uREVGQVVMVF9BU1NFTUJMWV9UUkFDRS5tc2cobXNnKSkpO1xuICAgIGlmICghdHJlZSkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIGNvbnN0IHJldDogQWN0dWFsQ29tcG9uZW50W10gPSBbXTtcbiAgICByZWN1cnNlKHRyZWUpO1xuICAgIHJldHVybiByZXQ7XG5cbiAgICBmdW5jdGlvbiByZWN1cnNlKHg6IENvbnN0cnVjdFRyZWVOb2RlKSB7XG4gICAgICBpZiAoeC5jb25zdHJ1Y3RJbmZvPy5mcW4gJiYgeC5jb25zdHJ1Y3RJbmZvPy52ZXJzaW9uKSB7XG4gICAgICAgIHJldC5wdXNoKHtcbiAgICAgICAgICBuYW1lOiB4LmNvbnN0cnVjdEluZm8/LmZxbixcbiAgICAgICAgICB2ZXJzaW9uOiB4LmNvbnN0cnVjdEluZm8/LnZlcnNpb24sXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIE9iamVjdC52YWx1ZXMoeC5jaGlsZHJlbiA/PyB7fSkpIHtcbiAgICAgICAgcmVjdXJzZShjaGlsZCk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbmludGVyZmFjZSBBY3R1YWxDb21wb25lbnQge1xuICAvKipcbiAgICogTmFtZSBvZiB0aGUgY29tcG9uZW50XG4gICAqL1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFZlcnNpb24gb2YgdGhlIGNvbXBvbmVudFxuICAgKi9cbiAgcmVhZG9ubHkgdmVyc2lvbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBJZiBtYXRjaGVkLCB1bmRlciB3aGF0IG5hbWUgc2hvdWxkIGl0IGJlIGFkZGVkIHRvIHRoZSBzZXQgb2YgZHluYW1pYyB2YWx1ZXNcbiAgICpcbiAgICogVGhlc2Ugd2lsbCBiZSB1c2VkIHRvIHN1YnN0aXR1dGUgcGxhY2Vob2xkZXJzIGluIHRoZSBtZXNzYWdlIHN0cmluZywgd2hlcmVcbiAgICogcGxhY2Vob2xkZXJzIGxvb2sgbGlrZSBge3Jlc29sdmU6WFlafWAuXG4gICAqXG4gICAqIElmIHRoZXJlIGlzIG1vcmUgdGhhbiBvbmUgY29tcG9uZW50IHdpdGggdGhlIHNhbWUgZHluYW1pYyBuYW1lLCB0aGV5IGFyZVxuICAgKiBqb2luZWQgYnkgJywnLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIERvbid0IGFkZCB0byB0aGUgc2V0IG9mIGR5bmFtaWMgdmFsdWVzLlxuICAgKi9cbiAgcmVhZG9ubHkgZHluYW1pY05hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIElmIG1hdGNoZWQsIHdoYXQgd2Ugc2hvdWxkIHB1dCBpbiB0aGUgc2V0IG9mIGR5bmFtaWMgdmFsdWVzIGluc3N0ZWFkIG9mIHRoZSB2ZXJzaW9uLlxuICAgKlxuICAgKiBPbmx5IHVzZWQgaWYgYGR5bmFtaWNOYW1lYCBpcyBzZXQ7IGJ5IGRlZmF1bHQgd2Ugd2lsbCBhZGQgdGhlIGFjdHVhbCB2ZXJzaW9uXG4gICAqIG9mIHRoZSBjb21wb25lbnQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVGhlIHZlcnNpb24uXG4gICAqL1xuICByZWFkb25seSBkeW5hbWljVmFsdWU/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogSW5mb3JtYXRpb24gYWJvdXQgYSBib290c3RyYXBwZWQgZW52aXJvbm1lbnQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQm9vdHN0cmFwcGVkRW52aXJvbm1lbnQge1xuICByZWFkb25seSBib290c3RyYXBTdGFja1ZlcnNpb246IG51bWJlcjtcbiAgcmVhZG9ubHkgZW52aXJvbm1lbnQ6IEVudmlyb25tZW50O1xufVxuXG4vKipcbiAqIFByb3ZpZGVzIGFjY2VzcyB0byBub3RpY2VzIHRoZSBDTEkgY2FuIGRpc3BsYXkuXG4gKi9cbmV4cG9ydCBjbGFzcyBOb3RpY2VzIHtcbiAgLyoqXG4gICAqIENyZWF0ZSBhbiBpbnN0YW5jZS4gTm90ZSB0aGF0IHRoaXMgcmVwbGFjZXMgdGhlIHNpbmdsZXRvbi5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY3JlYXRlKHByb3BzOiBOb3RpY2VzUHJvcHMpOiBOb3RpY2VzIHtcbiAgICB0aGlzLl9pbnN0YW5jZSA9IG5ldyBOb3RpY2VzKHByb3BzKTtcbiAgICByZXR1cm4gdGhpcy5faW5zdGFuY2U7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBzaW5nbGV0b24gaW5zdGFuY2UuIE1heSByZXR1cm4gYHVuZGVmaW5lZGAgaWYgYGNyZWF0ZWAgaGFzIG5vdCBiZWVuIGNhbGxlZC5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZ2V0KCk6IE5vdGljZXMgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9pbnN0YW5jZTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIF9pbnN0YW5jZTogTm90aWNlcyB8IHVuZGVmaW5lZDtcblxuICBwcml2YXRlIHJlYWRvbmx5IGNvbnRleHQ6IENvbnRleHQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgb3V0cHV0OiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgYWNrbm93bGVkZ2VkSXNzdWVOdW1iZXJzOiBTZXQ8TnVtYmVyPjtcbiAgcHJpdmF0ZSByZWFkb25seSBpbmNsdWRlQWNrbm93bGVnZGVkOiBib29sZWFuO1xuICBwcml2YXRlIHJlYWRvbmx5IGh0dHBPcHRpb25zOiBTZGtIdHRwT3B0aW9ucztcbiAgcHJpdmF0ZSByZWFkb25seSBpb01lc3NhZ2VzOiBJb0RlZmF1bHRNZXNzYWdlcztcblxuICBwcml2YXRlIGRhdGE6IFNldDxOb3RpY2U+ID0gbmV3IFNldCgpO1xuXG4gIC8vIHNldHMgZG9uJ3QgZGVkdXBsaWNhdGUgaW50ZXJmYWNlcywgc28gd2UgdXNlIGEgbWFwLlxuICBwcml2YXRlIHJlYWRvbmx5IGJvb3RzdHJhcHBlZEVudmlyb25tZW50czogTWFwPHN0cmluZywgQm9vdHN0cmFwcGVkRW52aXJvbm1lbnQ+ID0gbmV3IE1hcCgpO1xuXG4gIHByaXZhdGUgY29uc3RydWN0b3IocHJvcHM6IE5vdGljZXNQcm9wcykge1xuICAgIHRoaXMuY29udGV4dCA9IHByb3BzLmNvbnRleHQ7XG4gICAgdGhpcy5hY2tub3dsZWRnZWRJc3N1ZU51bWJlcnMgPSBuZXcgU2V0KHRoaXMuY29udGV4dC5nZXQoJ2Fja25vd2xlZGdlZC1pc3N1ZS1udW1iZXJzJykgPz8gW10pO1xuICAgIHRoaXMuaW5jbHVkZUFja25vd2xlZ2RlZCA9IHByb3BzLmluY2x1ZGVBY2tub3dsZWRnZWQgPz8gZmFsc2U7XG4gICAgdGhpcy5vdXRwdXQgPSBwcm9wcy5vdXRwdXQgPz8gJ2Nkay5vdXQnO1xuICAgIHRoaXMuaHR0cE9wdGlvbnMgPSBwcm9wcy5odHRwT3B0aW9ucyA/PyB7fTtcbiAgICB0aGlzLmlvTWVzc2FnZXMgPSBuZXcgSW9EZWZhdWx0TWVzc2FnZXMoYXNJb0hlbHBlcihwcm9wcy5pb0hvc3QsICdub3RpY2VzJyBhcyBhbnkgLyogZm9yY2luZyBhIENsaUFjdGlvbiB0byBhIFRvb2xraXRBY3Rpb24gKi8pKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBib290c3RyYXAgaW5mb3JtYXRpb24gdG8gZmlsdGVyIG9uLiBDYW4gaGF2ZSBtdWx0aXBsZSB2YWx1ZXNcbiAgICogaW4gY2FzZSBvZiBtdWx0aS1lbnZpcm9ubWVudCBkZXBsb3ltZW50cy5cbiAgICovXG4gIHB1YmxpYyBhZGRCb290c3RyYXBwZWRFbnZpcm9ubWVudChib290c3RyYXBwZWQ6IEJvb3RzdHJhcHBlZEVudmlyb25tZW50KSB7XG4gICAgY29uc3Qga2V5ID0gW1xuICAgICAgYm9vdHN0cmFwcGVkLmJvb3RzdHJhcFN0YWNrVmVyc2lvbixcbiAgICAgIGJvb3RzdHJhcHBlZC5lbnZpcm9ubWVudC5hY2NvdW50LFxuICAgICAgYm9vdHN0cmFwcGVkLmVudmlyb25tZW50LnJlZ2lvbixcbiAgICAgIGJvb3RzdHJhcHBlZC5lbnZpcm9ubWVudC5uYW1lLFxuICAgIF0uam9pbignOicpO1xuICAgIHRoaXMuYm9vdHN0cmFwcGVkRW52aXJvbm1lbnRzLnNldChrZXksIGJvb3RzdHJhcHBlZCk7XG4gIH1cblxuICAvKipcbiAgICogUmVmcmVzaCB0aGUgbGlzdCBvZiBub3RpY2VzIHRoaXMgaW5zdGFuY2UgaXMgYXdhcmUgb2YuXG4gICAqIFRvIG1ha2Ugc3VyZSB0aGlzIG5ldmVyIGNyYXNoZXMgdGhlIENMSSBwcm9jZXNzLCBhbGwgZmFpbHVyZXMgYXJlIGNhdWdodCBhbmRcbiAgICogc2lsZW50bHkgbG9nZ2VkLlxuICAgKlxuICAgKiBJZiBjb250ZXh0IGlzIGNvbmZpZ3VyZWQgdG8gbm90IGRpc3BsYXkgbm90aWNlcywgdGhpcyB3aWxsIG5vLW9wLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIHJlZnJlc2gob3B0aW9uczogTm90aWNlc1JlZnJlc2hPcHRpb25zID0ge30pIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdW5kZXJseWluZ0RhdGFTb3VyY2UgPSBvcHRpb25zLmRhdGFTb3VyY2UgPz8gbmV3IFdlYnNpdGVOb3RpY2VEYXRhU291cmNlKHRoaXMuaW9NZXNzYWdlcywgdGhpcy5odHRwT3B0aW9ucyk7XG4gICAgICBjb25zdCBkYXRhU291cmNlID0gbmV3IENhY2hlZERhdGFTb3VyY2UodGhpcy5pb01lc3NhZ2VzLCBDQUNIRV9GSUxFX1BBVEgsIHVuZGVybHlpbmdEYXRhU291cmNlLCBvcHRpb25zLmZvcmNlID8/IGZhbHNlKTtcbiAgICAgIGNvbnN0IG5vdGljZXMgPSBhd2FpdCBkYXRhU291cmNlLmZldGNoKCk7XG4gICAgICB0aGlzLmRhdGEgPSBuZXcgU2V0KHRoaXMuaW5jbHVkZUFja25vd2xlZ2RlZCA/IG5vdGljZXMgOiBub3RpY2VzLmZpbHRlcihuID0+ICF0aGlzLmFja25vd2xlZGdlZElzc3VlTnVtYmVycy5oYXMobi5pc3N1ZU51bWJlcikpKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIHRoaXMuaW9NZXNzYWdlcy5kZWJ1ZyhgQ291bGQgbm90IHJlZnJlc2ggbm90aWNlczogJHtlfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNwbGF5IHRoZSByZWxldmFudCBub3RpY2VzICh1bmxlc3MgY29udGV4dCBkaWN0YXRlcyB3ZSBzaG91bGRuJ3QpLlxuICAgKi9cbiAgcHVibGljIGRpc3BsYXkob3B0aW9uczogTm90aWNlc1ByaW50T3B0aW9ucyA9IHt9KSB7XG4gICAgY29uc3QgZmlsdGVyZWROb3RpY2VzID0gbmV3IE5vdGljZXNGaWx0ZXIodGhpcy5pb01lc3NhZ2VzKS5maWx0ZXIoe1xuICAgICAgZGF0YTogQXJyYXkuZnJvbSh0aGlzLmRhdGEpLFxuICAgICAgY2xpVmVyc2lvbjogdmVyc2lvbk51bWJlcigpLFxuICAgICAgb3V0RGlyOiB0aGlzLm91dHB1dCxcbiAgICAgIGJvb3RzdHJhcHBlZEVudmlyb25tZW50czogQXJyYXkuZnJvbSh0aGlzLmJvb3RzdHJhcHBlZEVudmlyb25tZW50cy52YWx1ZXMoKSksXG4gICAgfSk7XG5cbiAgICBpZiAoZmlsdGVyZWROb3RpY2VzLmxlbmd0aCA+IDApIHtcbiAgICAgIHZvaWQgdGhpcy5pb01lc3NhZ2VzLm5vdGlmeShJTy5DREtfVE9PTEtJVF9JMDEwMC5tc2coW1xuICAgICAgICAnJyxcbiAgICAgICAgJ05PVElDRVMgICAgICAgICAoV2hhdFxcJ3MgdGhpcz8gaHR0cHM6Ly9naXRodWIuY29tL2F3cy9hd3MtY2RrL3dpa2kvQ0xJLU5vdGljZXMpJyxcbiAgICAgICAgJycsXG4gICAgICBdLmpvaW4oJ1xcbi