@tripsnek/tmf
Version:
TypeScript Modeling Framework - A TypeScript port of the Eclipse Modeling Framework (EMF)
625 lines • 94.2 kB
JavaScript
import { TGeneratorPackage } from './tgenerator-package.js';
import { TGeneratorFactory } from './tgenerator-factory.js';
import { TGeneratorUtils } from './tgenerator-utils.js';
import { TGeneratorGen } from './tgenerator-gen.js';
import { TGeneratorApi } from './tgenerator-api.js';
import { TGeneratorImpl } from './tgenerator-impl.js';
import { TGeneratorEnum } from './tgenerator-enum.js';
import { TGenUtils as DU } from './tgen-utils.js';
import { EcorePackage } from '../metamodel/ecorepackage.js';
import { TGeneratorBarrelIndexTs } from './tgenerator-barrel-index.js';
import { EClassImpl } from '../metamodel/impl/eclass-impl.js';
import { EReferenceImpl } from '../metamodel/impl/ereference-impl.js';
import { EEnumImpl } from '../metamodel/impl/eenum-impl.js';
import { Environment, ConditionalImports } from '../utils/environment.js';
import { TGeneratorPackageInitializer } from './tgenerator-package-initializer.js';
import { BasicEList } from '../metamodel/basicelist.js';
// Debug flag - set to true to enable detailed logging
const DEBUG = false;
// Debug logging utility
const debug = {
log: (message, ...args) => {
if (DEBUG) {
console.log(`[DEBUG] ${message}`, ...args);
}
},
time: (label) => {
if (DEBUG) {
console.time(`[DEBUG] ${label}`);
}
},
timeEnd: (label) => {
if (DEBUG) {
console.timeEnd(`[DEBUG] ${label}`);
}
},
group: (label) => {
if (DEBUG) {
console.group(`[DEBUG] ${label}`);
}
},
groupEnd: () => {
if (DEBUG) {
console.groupEnd();
}
},
warn: (message, ...args) => {
if (DEBUG) {
console.warn(`[DEBUG WARN] ${message}`, ...args);
}
},
error: (message, ...args) => {
if (DEBUG) {
console.error(`[DEBUG ERROR] ${message}`, ...args);
}
},
};
/**
* Exposes source code generation. Only available in Node.js environment.
* @param pkg
* @param outDir
* @param overwriteImpl
*/
export async function generate(pkg, outDir, overwriteImpl) {
debug.time('Total Generation Time');
debug.log('Starting code generation for package:', pkg.getName() || 'unnamed package');
debug.log('Output directory:', outDir);
debug.log('Overwrite implementation files:', overwriteImpl);
Environment.requireNodeEnvironment('Code generation');
const generator = new TGeneratorMain(pkg, outDir, overwriteImpl);
await generator.generate();
debug.timeEnd('Total Generation Time');
debug.log('Code generation completed successfully');
}
/**
* Generates TypeScript source code for an EPackage and all subpackages, including
* the following artifacts:
* (1) *-package.ts for each EPackage (see TMFPackageSourceGenerator.ts)
* (2) *-factory.ts for each EPackage (see TMFFactorySourceGenerator.ts)
* (3) API interfaces (see TMFApiSourceGenerator.ts)
* (4) Abstract *Gen.ts classes (see TMFGenSourceGenerator.ts)
* (5) Overwritable *Impl.ts classes (see TMFImplSourceGenerator.ts)
* (6) Enums (see TMFEnumSourceGenerator.ts)
*/
export class TGeneratorMain {
pkg;
outDir;
overwriteImpl;
barrelFileDir;
// NOTE: These 5 are all constants computed during initialization
barrelFileOutDir;
pkgOutDir;
pkgRootOutDir;
pkgApiOutDir;
pkgGenOutDir;
pkgImplOutDir;
// NOTE: These 3 are recomputed for each EClass!
eClassApiImports;
eClassGenImports;
eClassPkgImports;
// Cached Node.js modules (loaded once per instance)
fs = null;
path = null;
childProcess = null;
constructor(pkg, outDir, overwriteImpl = false, barrelFileDir) {
this.pkg = pkg;
this.outDir = outDir;
this.overwriteImpl = overwriteImpl;
this.barrelFileDir = barrelFileDir;
debug.log('Initializing TGeneratorMain for package:', pkg.getName() || 'unnamed');
debug.log('Constructor parameters:', {
packageName: pkg.getName(),
outDir,
overwriteImpl,
barrelFileDir,
});
// Initialize directories without file system operations
this.pkgOutDir = this.outDir + (pkg.getName() ? '/' + pkg.getName() : '');
this.pkgRootOutDir = this.pkgOutDir;
this.pkgApiOutDir = this.pkgOutDir + DU.API_PATH;
this.pkgGenOutDir = this.pkgOutDir + DU.GEN_PATH;
this.pkgImplOutDir = this.pkgOutDir + DU.IMPL_PATH;
debug.log('Computed directory paths:', {
pkgOutDir: this.pkgOutDir,
pkgRootOutDir: this.pkgRootOutDir,
pkgApiOutDir: this.pkgApiOutDir,
pkgGenOutDir: this.pkgGenOutDir,
pkgImplOutDir: this.pkgImplOutDir,
});
// Note: barrelFileOutDir will be set during generate() when path is available
}
/**
* Generates typescript sourcecode for all packages, recursing all subpackages.
* Only available in Node.js environment.
*/
async generate(attemptFormatWithPrettier) {
debug.time(`Generation for package: ${this.pkg.getName() || 'unnamed'}`);
debug.group(`Generating package: ${this.pkg.getName() || 'unnamed'}`);
Environment.requireNodeEnvironment('Code generation');
// Load Node.js modules
debug.log('Loading Node.js modules...');
await this.ensureNodeModulesLoaded();
// Now we can resolve directories and create them
debug.log('Initializing directories...');
await this.initializeDirectories();
// Count classifiers for debug info
const classifiers = this.pkg.getEClassifiers();
const eClasses = classifiers.filter((c) => c instanceof EClassImpl);
const eEnums = classifiers.filter((c) => c instanceof EEnumImpl);
const subpackages = this.pkg.getESubPackages();
debug.log('Package contents:', {
totalClassifiers: classifiers.size(),
eClasses: eClasses.size(),
eEnums: eEnums.size(),
subpackages: subpackages.size(),
});
// Generate all the files
debug.log('Generating core files...');
if (this.barrelFileDir) {
debug.log('Writing barrel file...');
await this.writeBarrelFile();
}
debug.log('Writing package file...');
await this.writePackageFile();
debug.log('Writing factory file...');
await this.writeFactoryFile();
debug.log('Writing utils file...');
await this.writeUtilsFile();
// Add this new section:
debug.log('Writing package initializer file...');
await this.writePackageInitializerFile();
debug.log('Writing package registry file...');
await this.writePackageRegistryFile();
// Generate EClass artifacts
debug.log(`Processing ${eClasses.size()} EClass(es)...`);
for (const eClassifier of classifiers) {
if (eClassifier instanceof EClassImpl) {
debug.log(`Generating artifacts for EClass: ${eClassifier.getName()}`);
await this.generateAllEClassArtifacts(eClassifier);
}
else if (eClassifier instanceof EEnumImpl) {
debug.log(`Generating enum file for: ${eClassifier.getName()}`);
await this.writeEnumFile(eClassifier);
}
}
// Deal with recursive subpackages
debug.log(`Processing ${subpackages.size()} subpackage(s)...`);
for (const subpackage of subpackages) {
debug.log(`Recursively generating subpackage: ${subpackage.getName()}`);
const subGenerator = new TGeneratorMain(subpackage, this.pkgRootOutDir, this.overwriteImpl);
await subGenerator.generate();
}
// Finally... format the source code with prettier
if (attemptFormatWithPrettier) {
debug.log('Attempting to format code with Prettier...');
await this.tryFormatWithPrettier();
}
debug.groupEnd();
debug.timeEnd(`Generation for package: ${this.pkg.getName() || 'unnamed'}`);
debug.log(`Completed generation for package: ${this.pkg.getName() || 'unnamed'}`);
}
async generateAllEClassArtifacts(eClassifier) {
debug.group(`Generating EClass artifacts: ${eClassifier.getName()}`);
debug.time(`EClass generation: ${eClassifier.getName()}`);
debug.log('Setting up imports...');
this.setupEClassImports(eClassifier);
debug.log('Import analysis results:', {
apiImports: Array.from(this.eClassApiImports).map((c) => c.getName()),
genImports: Array.from(this.eClassGenImports).map((c) => c.getName()),
packageImports: Array.from(this.eClassPkgImports).map((p) => p.getName()),
});
debug.log('Writing API file...');
await this.writeEClassApiFile(eClassifier);
debug.log('Writing Gen file...');
await this.writeEClassGenFile(eClassifier);
debug.log('Writing Impl file...');
await this.writeEClassImplFile(eClassifier);
debug.timeEnd(`EClass generation: ${eClassifier.getName()}`);
debug.groupEnd();
}
/**
* Check if code generation is supported in current environment
*/
static isGenerationSupported() {
const supported = Environment.isNode;
debug.log('Generation support check:', supported);
return supported;
}
/**
* Get list of supported operations in current environment
*/
static getSupportedOperations() {
const operations = ['In-memory generation'];
if (Environment.isNode) {
operations.push('File-based generation', 'Directory creation', 'Prettier formatting', 'Recursive package processing');
}
debug.log('Supported operations:', operations);
return operations;
}
// ======================================================================
// Private methods
async ensureNodeModulesLoaded() {
debug.log('Loading Node.js modules...');
if (!this.fs) {
debug.log('Loading fs module...');
this.fs = await ConditionalImports.getNodeModule('fs');
}
if (!this.path) {
debug.log('Loading path module...');
this.path = await ConditionalImports.getNodeModule('path');
}
// childProcess is loaded on-demand in tryFormatWithPrettier
debug.log('Node.js modules loaded successfully');
}
async initializeDirectories() {
debug.log('Initializing and creating directories...');
// Now we can use path operations
this.pkgRootOutDir = await this.resolveAndMaybeCreateDir(this.pkgOutDir, false);
this.pkgApiOutDir = await this.resolveAndMaybeCreateDir(this.pkgOutDir + DU.API_PATH, true);
this.pkgGenOutDir = await this.resolveAndMaybeCreateDir(this.pkgOutDir + DU.GEN_PATH, true);
this.pkgImplOutDir = await this.resolveAndMaybeCreateDir(this.pkgOutDir + DU.IMPL_PATH, false);
if (this.barrelFileDir) {
this.barrelFileOutDir = this.path.resolve(process.cwd(), this.barrelFileDir);
debug.log('Barrel file output directory set to:', this.barrelFileOutDir);
}
debug.log('Directory initialization completed');
}
async writeBarrelFile() {
debug.log('Generating barrel file content...');
const generator = new TGeneratorBarrelIndexTs();
const content = await generator.generate(this.pkg, this.barrelFileOutDir);
debug.log('Writing barrel file to:', this.barrelFileOutDir);
await this.writeSourceFile(this.barrelFileOutDir, 'index.ts', content, true);
}
async writePackageFile() {
const fileName = DU.genPackageFileName(this.pkg);
debug.log('Generating package file:', fileName + '.ts');
const generator = new TGeneratorPackage();
const content = generator.generatePackageContents(this.pkg);
await this.writeSourceFile(this.pkgRootOutDir, fileName + '.ts', content, true);
}
async writeFactoryFile() {
const fileName = DU.genFactoryFileName(this.pkg);
debug.log('Generating factory file:', fileName + '.ts');
const generator = new TGeneratorFactory();
const content = generator.generateFactoryContents(this.pkg);
await this.writeSourceFile(this.pkgRootOutDir, fileName + '.ts', content, true);
}
async writeUtilsFile() {
const fileName = DU.genUtilsFileName(this.pkg);
debug.log('Generating utils file:', fileName + '.ts');
const generator = new TGeneratorUtils();
const content = generator.generateUtilsContents(this.pkg);
await this.writeSourceFile(this.pkgRootOutDir, fileName + '.ts', content, false);
}
setupEClassImports(eClass) {
debug.log(`Setting up imports for EClass: ${eClass.getName()}`);
// Determines the set of types that needs to be imported to support the EClass
this.eClassApiImports = new Set();
this.eClassGenImports = new Set();
this.eClassPkgImports = new Set();
debug.log('Collecting imports...');
this.collectEClassImports(this.pkg, eClass);
debug.log('Import collection completed');
}
async writeEClassApiFile(eClass) {
const filename = DU.genClassApiName(eClass);
debug.log(`Writing API file for ${eClass.getName()}: ${filename}.ts`);
const apiGenerator = new TGeneratorApi();
const tsInterfaceContent = apiGenerator.generate(eClass, this.eClassApiImports);
await this.writeSourceFile(this.pkgApiOutDir, filename + '.ts', tsInterfaceContent, true);
}
async writeEClassGenFile(eClass) {
const filename = DU.genClassGenName(eClass);
debug.log(`Writing Gen file for ${eClass.getName()}: ${filename}.ts`);
const genGenerator = new TGeneratorGen();
const tsGenClassContent = genGenerator.generate(eClass, this.eClassApiImports, this.eClassGenImports, this.eClassPkgImports);
await this.writeSourceFile(this.pkgGenOutDir, filename + '.ts', tsGenClassContent, true);
}
async writeEClassImplFile(eClass) {
const filename = DU.genClassImplName(eClass);
debug.log(`Writing Impl file for ${eClass.getName()}: ${filename}.ts`);
debug.log(`Overwrite mode: ${this.overwriteImpl}`);
const implGenerator = new TGeneratorImpl();
const tsImplClassContent = implGenerator.generate(eClass, this.eClassApiImports);
await this.writeSourceFile(this.pkgImplOutDir, filename + '.ts', tsImplClassContent, this.overwriteImpl);
}
async writeEnumFile(eclassifier) {
const filename = DU.genClassApiName(eclassifier) + '.ts';
debug.log(`Writing enum file for ${eclassifier.getName()}: ${filename}`);
const enumGenerator = new TGeneratorEnum();
const enumContent = enumGenerator.generate(eclassifier);
await this.writeSourceFile(this.pkgApiOutDir, filename, enumContent, true);
}
async resolveAndMaybeCreateDir(outDir, deleteAllInDir) {
await this.ensureNodeModulesLoaded();
const resolvedOutDir = this.path.resolve(process.cwd(), outDir);
debug.log(`Processing directory: ${outDir} -> ${resolvedOutDir}`);
debug.log(`Delete all files in directory: ${deleteAllInDir}`);
if (this.fs.existsSync(resolvedOutDir)) {
debug.log('Directory exists');
if (deleteAllInDir) {
debug.log('Deleting all files in directory...');
await this.deleteFilesInFolder(resolvedOutDir);
}
}
else {
debug.log('Directory does not exist, creating...');
this.fs.mkdirSync(resolvedOutDir, { recursive: true });
debug.log('Directory created successfully');
}
return outDir;
}
/**
* Traverses entire EClass structure and collects the set of types that need
* to be imported, including API, Gen and EPackage instances.
*/
collectEClassImports(pkg, eClass) {
debug.group(`Collecting imports for EClass: ${eClass.getName()}`);
// Start with importing supertypes
const superTypes = eClass.getESuperTypes();
debug.log(`Processing ${superTypes.size()} super type(s)...`);
for (const superType of superTypes) {
debug.log(`Adding super type: ${superType.getName()}`);
this.eClassApiImports.add(superType);
if (!superType.isInterface()) {
this.eClassGenImports.add(superType);
debug.log(`Added to Gen imports (not interface): ${superType.getName()}`);
}
}
// Add imports to support EStructuralFeatures
const features = eClass.getEAllStructuralFeatures();
debug.log(`Processing ${features.size()} structural feature(s)...`);
for (const field of features) {
if (field.getEType()) {
this.maybeAddMemberImports(pkg, eClass, field.getEType());
if (field instanceof EReferenceImpl) {
const opposite = field.getEOpposite();
if (opposite) {
debug.log(`Processing opposite reference: ${opposite.getName()}`);
this.maybeAddMemberImports(pkg, eClass, opposite.getEContainingClass());
}
}
}
}
// Add imports to support EOperations
const operationsToImplement = this.eopsToImplement(eClass);
debug.log(`Processing ${operationsToImplement.size()} operation(s) for ${eClass.getName()}...`);
for (const eop of operationsToImplement) {
if (eop.getEType())
this.maybeAddMemberImports(pkg, eClass, eop.getEType());
const params = eop.getEParameters();
for (const param of params) {
if (param.getEType()) {
// make sure to import any parameter type, if necessary
this.maybeAddMemberImports(pkg, eClass, param.getEType());
}
}
}
debug.groupEnd();
}
eopsToImplement(eClass) {
let operationsToImplement = new BasicEList(eClass.getEOperations().elements());
for (const st of eClass.getESuperTypes()) {
if (st.isInterface()) {
operationsToImplement.addAll(st.getEOperations().elements());
}
}
return operationsToImplement;
}
/**
* Possibly adds the type and package of 'etype' to the list of things
* to import.
*/
maybeAddMemberImports(thisPackage, thisEClass, candidate) {
debug.log(`Evaluating import candidate: ${candidate?.getName()}`);
if (candidate instanceof EClassImpl || candidate instanceof EEnumImpl) {
const candidatePackage = candidate.getEPackage();
debug.log(`Candidate package: ${candidatePackage.getName()}, this package: ${thisPackage.getName()}`);
if (candidatePackage !== thisPackage) {
debug.log(`Adding package import: ${candidatePackage.getName()}`);
this.eClassPkgImports.add(candidatePackage);
}
if (candidate !== thisEClass) {
// Ecore types are imported for everything
if (candidatePackage !== EcorePackage.eINSTANCE && !this.eClassApiImports.has(candidate)) {
debug.log(`Adding API import: ${candidate.getName()}`);
this.eClassApiImports.add(candidate);
}
if (candidatePackage !== EcorePackage.eINSTANCE && !this.eClassGenImports.has(candidate)) {
debug.log(`Adding Gen import for ${thisEClass.getName()}: ${candidate.getName()}`);
this.eClassGenImports.add(candidate);
}
else {
debug.log(`Skipping Ecore type: ${candidate.getName()}`);
}
}
else {
debug.log(`Skipping import (already exists or is self): ${candidate.getName()}`);
}
}
}
// Add this method to the TGeneratorMain class
async writePackageInitializerFile() {
// Only generate for root packages (packages without a super package)
if (this.pkg.getESuperPackage()) {
debug.log('Skipping package initializer for ' + this.pkg.getName() + ' - not a root package');
return;
}
const generator = new TGeneratorPackageInitializer();
const fileName = TGeneratorPackageInitializer.generateFileName(this.pkg);
debug.log('Generating package initializer file:', fileName + '.ts');
const content = generator.generate(this.pkg);
await this.writeSourceFile(this.pkgRootOutDir, fileName + '.ts', content, true);
}
async writePackageRegistryFile() {
// Only generate for root packages (packages without a super package)
if (this.pkg.getESuperPackage()) {
debug.log('Skipping package registry for ' + this.pkg.getName() + ' - not a root package');
return;
}
debug.log('Generating package registry file: package-registry.ts');
const content = this.generatePackageRegistryContent();
await this.writeSourceFile(this.pkgRootOutDir, 'package-registry.ts', content, true);
}
generatePackageRegistryContent() {
return `import { TJson, EClassImpl, EFactory } from '@tripsnek/tmf';
import type { EPackageImpl } from '@tripsnek/tmf';
/**
* Registry to track which packages have been initialized and registered with TJson.
* This enables incremental initialization while preventing duplicate work.
*/
export class PackageRegistry {
private static initializedPackages = new Set<string>();
private static registeredWithTJson = new Set<string>();
private static factoryClasses = new Map<string, () => any>();
/**
* Mark a package as initialized (contents created and relationships set up)
*/
static markInitialized(packageName: string): void {
this.initializedPackages.add(packageName);
}
/**
* Check if a package has been initialized
*/
static isInitialized(packageName: string): boolean {
return this.initializedPackages.has(packageName);
}
/**
* Register a factory class constructor for a package
*/
static registerFactoryClass(
packageName: string,
factoryGetter: () => any
): void {
this.factoryClasses.set(packageName, factoryGetter);
}
/**
* Get the factory for a package and ensure it's initialized
*/
static getFactory(packageName: string): EFactory | null {
const factoryGetter = this.factoryClasses.get(packageName);
if (factoryGetter) {
try {
const FactoryClass = factoryGetter();
return FactoryClass?.eINSTANCE || null;
} catch (e) {
return null;
}
}
return null;
}
/**
* Register a package with TJson if not already registered
*/
static registerWithTJson(packageName: string, pkg: EPackageImpl): void {
if (this.registeredWithTJson.has(packageName)) {
return;
}
this.registeredWithTJson.add(packageName);
// Ensure factory is registered with package
const factory = this.getFactory(packageName);
if (factory && !pkg.getEFactoryInstance()) {
pkg.setEFactoryInstance(factory);
}
// Recompute all lists for EClass instances
for (const e of pkg.getEClassifiers()) {
if (e instanceof EClassImpl) {
e.recomputeAllLists();
}
}
// Register with TJson
TJson.addPackages([pkg]);
}
/**
* Check if a package has been registered with TJson
*/
static isRegisteredWithTJson(packageName: string): boolean {
return this.registeredWithTJson.has(packageName);
}
}
`;
}
/**
* Writes the sourcecode file to the file system.
* @param outDir
* @param filename
* @param content
* @param overwrite
*/
async writeSourceFile(outDir, filename, content, overwrite) {
await this.ensureNodeModulesLoaded();
const filePath = this.path.resolve(process.cwd(), outDir + '/' + filename);
debug.log(`Writing file: ${filePath}`);
debug.log(`Overwrite: ${overwrite}, Content length: ${content.length} characters`);
if (overwrite || !this.fs.existsSync(filePath)) {
this.fs.writeFileSync(filePath, content, 'utf8');
debug.log(`File written successfully: ${filename}`);
}
else {
debug.log(`File skipped (already exists, overwrite=false): ${filename}`);
}
}
async deleteFilesInFolder(directoryPath) {
await this.ensureNodeModulesLoaded();
debug.log(`Deleting files in folder: ${directoryPath}`);
try {
const files = this.fs.readdirSync(directoryPath);
debug.log(`Found ${files.length} file(s) to delete`);
for (const file of files) {
try {
const filePath = this.path.join(directoryPath, file);
this.fs.unlinkSync(filePath);
debug.log(`Deleted file: ${file}`);
}
catch (err) {
// Swallow individual file deletion errors as per original logic
debug.warn(`Failed to delete file ${file}:`, err);
}
}
debug.log('File deletion completed');
}
catch (err) {
debug.error(`Failed to read directory ${directoryPath}:`, err);
}
}
async tryFormatWithPrettier() {
debug.log('Attempting to format code with Prettier...');
// Fallback to command line prettier
try {
if (!this.childProcess) {
debug.log('Loading child_process module...');
this.childProcess = await ConditionalImports.getNodeModule('child_process');
}
// Format main output directory
const mainPath = this.path.resolve(process.cwd(), this.outDir);
debug.log(`Formatting main directory with CLI: ${mainPath}`);
this.childProcess.execSync(`prettier --write "${mainPath}"`);
debug.log('Main directory formatted successfully');
// Format barrel file directory if it exists
if (this.barrelFileDir) {
const barrelPath = this.path.resolve(process.cwd(), this.barrelFileOutDir);
debug.log(`Formatting barrel directory with CLI: ${barrelPath}`);
this.childProcess.execSync(`prettier --write "${barrelPath}"`);
debug.log('Barrel directory formatted successfully');
}
debug.log('CLI Prettier formatting completed successfully');
}
catch (error) {
debug.warn('Prettier formatting failed:', error.message);
debug.warn('Make sure prettier is installed: npm install -g prettier');
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGdlbmVyYXRvci1tYWluLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9zb3VyY2UtZ2VuZXJhdG9ycy90Z2VuZXJhdG9yLW1haW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDNUQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDNUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3hELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsU0FBUyxJQUFJLEVBQUUsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUN2RSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDOUQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM1RCxPQUFPLEVBQUUsV0FBVyxFQUFFLGtCQUFrQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDMUUsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFFbkYsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBR3hELHNEQUFzRDtBQUN0RCxNQUFNLEtBQUssR0FBRyxL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USxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDL0QsS0FBSyxDQUFDLEdBQUcsQ0FBQyx1Q0FBdUMsUUFBUSxFQUFFLENBQUMsQ0FBQztZQUM3RCxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsUUFBUSxHQUFHLENBQUMsQ0FBQztZQUM3RCxLQUFLLENBQUMsR0FBRyxDQUFDLHVDQUF1QyxDQUFDLENBQUM7WUFFbkQsNENBQTRDO1lBQzVDLElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUN2QixNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7Z0JBQzNFLEtBQUssQ0FBQyxHQUFHLENBQUMseUNBQXlDLFVBQVUsRUFBRSxDQUFDLENBQUM7Z0JBQ2pFLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLHFCQUFxQixVQUFVLEdBQUcsQ0FBQyxDQUFDO2dCQUMvRCxLQUFLLENBQUMsR0FBRyxDQUFDLHlDQUF5QyxDQUFDLENBQUM7WUFDdkQsQ0FBQztZQUVELEtBQUssQ0FBQyxHQUFHLENBQUMsZ0RBQWdELENBQUMsQ0FBQztRQUM5RCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLEtBQUssQ0FBQyxJQUFJLENBQUMsNkJBQTZCLEVBQUcsS0FBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3BFLEtBQUssQ0FBQyxJQUFJLENBQUMsMERBQTBELENBQUMsQ0FBQztRQUN6RSxDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRVBhY2thZ2UgfSBmcm9tICcuLi9tZXRhbW9kZWwvYXBpL2VwYWNrYWdlLmpzJztcclxuaW1wb3J0IHsgRUNsYXNzaWZpZXIgfSBmcm9tICcuLi9tZXRhbW9kZWwvYXBpL2VjbGFzc2lmaWVyLmpzJztcclxuaW1wb3J0IHsgRUNsYXNzIH0gZnJvbSAnLi4vbWV0YW1vZGVsL2FwaS9lY2xhc3MuanMnO1xyXG5pbXBvcnQgeyBFRW51bSB9IGZyb20gJy4uL21ldGFtb2RlbC9hcGkvZWVudW0uanMnO1xyXG5pbXBvcnQgeyBUR2VuZXJhdG9yUGFja2FnZSB9IGZyb20gJy4vdGdlbmVyYXRvci1wYWNrYWdlLmpzJztcclxuaW1wb3J0IHsgVEdlbmVyYXRvckZhY3RvcnkgfSBmcm9tICcuL3RnZW5lcmF0b3ItZmFjdG9yeS5qcyc7XHJcbmltcG9ydCB7IFRHZW5lcmF0b3JVdGlscyB9IGZyb20gJy4vdGdlbmVyYXRvci11dGlscy5qcyc7XHJcbmltcG9ydCB7IFRHZW5lcmF0b3JHZW4gfSBmcm9tICcuL3RnZW5lcmF0b3ItZ2VuLmpzJztcclxuaW1wb3J0IHsgVEdlbmVyYXRvckFwaSB9IGZyb20gJy4vdGdlbmVyYXRvci1hcGkuanMnO1xyXG5pbXBvcnQgeyBUR2VuZXJhdG9ySW1wbCB9IGZyb20gJy4vdGdlbmVyYXRvci1pbXBsLmpzJztcclxuaW1wb3J0IHsgVEdlbmVyYXRvckVudW0gfSBmcm9tICcuL3RnZW5lcmF0b3ItZW51bS5qcyc7XHJcbmltcG9ydCB7IFRHZW5VdGlscyBhcyBEVSB9IGZyb20gJy4vdGdlbi11dGlscy5qcyc7XHJcbmltcG9ydCB7IEVjb3JlUGFja2FnZSB9IGZyb20gJy4uL21ldGFtb2RlbC9lY29yZXBhY2thZ2UuanMnO1xyXG5pbXBvcnQgeyBUR2VuZXJhdG9yQmFycmVsSW5kZXhUcyB9IGZyb20gJy4vdGdlbmVyYXRvci1iYXJyZWwtaW5kZXguanMnO1xyXG5pbXBvcnQgeyBFQ2xhc3NJbXBsIH0gZnJvbSAnLi4vbWV0YW1vZGVsL2ltcGwvZWNsYXNzLWltcGwuanMnO1xyXG5pbXBvcnQgeyBFUmVmZXJlbmNlSW1wbCB9IGZyb20gJy4uL21ldGFtb2RlbC9pbXBsL2VyZWZlcmVuY2UtaW1wbC5qcyc7XHJcbmltcG9ydCB7IEVFbnVtSW1wbCB9IGZyb20gJy4uL21ldGFtb2RlbC9pbXBsL2VlbnVtLWltcGwuanMnO1xyXG5pbXBvcnQgeyBFbnZpcm9ubWVudCwgQ29uZGl0aW9uYWxJbXBvcnRzIH0gZnJvbSAnLi4vdXRpbHMvZW52aXJvbm1lbnQuanMnO1xyXG5pbXBvcnQgeyBUR2VuZXJhdG9yUGFja2FnZUluaXRpYWxpemVyIH0gZnJvbSAnLi90Z2VuZXJhdG9yLXBhY2thZ2UtaW5pdGlhbGl6ZXIuanMnO1xyXG5pbXBvcnQgeyBFT3BlcmF0aW9uIH0gZnJvbSAnLi4vbWV0YW1vZGVsL2FwaS9lb3BlcmF0aW9uLmpzJztcclxuaW1wb3J0IHsgQmFzaWNFTGlzdCB9IGZyb20gJy4uL21ldGFtb2RlbC9iYXNpY2VsaXN0LmpzJztcclxuaW1wb3J0IHsgRUxpc3QgfSBmcm9tICcuLi9tZXRhbW9kZWwvYXBpL2VsaXN0LmpzJztcclxuXHJcbi8vIERlYnVnIGZsYWcgLSBzZXQgdG8gdHJ1ZSB0byBlbmFibGUgZGV0YWlsZWQgbG9nZ2luZ1xyXG5jb25zdCBERUJVRyA9IGZhbHNlO1xyXG5cclxuLy8gRGVidWcgbG9nZ2luZyB1dGlsaXR5XHJcbmNvbnN0IGRlYnVnID0ge1xyXG4gIGxvZzogKG1lc3NhZ2U6IHN0cmluZywgLi4uYXJnczogYW55W10pID0+IHtcclxuICAgIGlmIChERUJVRykge1xyXG4gICAgICBjb25zb2xlLmxvZyhgW0RFQlVHXSAke21lc3NhZ2V9YCwgLi4uYXJncyk7XHJcbiAgICB9XHJcbiAgfSxcclxuICB0aW1lOiAobGFiZWw6IHN0cmluZykgPT4ge1xyXG4gICAgaWYgKERFQlVHKSB7XHJcbiAgICAgIGNvbnNvbGUudGltZShgW0RFQlVHXSAke2xhYmVsfWApO1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgdGltZUVuZDogKGxhYmVsOiBzdHJpbmcpID0+IHtcclxuICAgIGlmIChERUJVRykge1xyXG4gICAgICBjb25zb2xlLnRpbWVFbmQoYFtERUJVR10gJHtsYWJlbH1gKTtcclxuICAgIH1cclxuICB9LFxyXG4gIGdyb3VwOiAobGFiZWw6IHN0cmluZykgPT4ge1xyXG4gICAgaWYgKERFQlVHKSB7XHJcbiAgICAgIGNvbnNvbGUuZ3JvdXAoYFtERUJVR10gJHtsYWJlbH1gKTtcclxuICAgIH1cclxuICB9LFxyXG4gIGdyb3VwRW5kOiAoKSA9PiB7XHJcbiAgICBpZiAoREVCVUcpIHtcclxuICAgICAgY29uc29sZS5ncm91cEVuZCgpO1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgd2FybjogKG1lc3NhZ2U6IHN0cmluZywgLi4uYXJnczogYW55W10pID0+IHtcclxuICAgIGlmIChERUJVRykge1xyXG4gICAgICBjb25zb2xlLndhcm4oYFtERUJVRyBXQVJOXSAke21lc3NhZ2V9YCwgLi4uYXJncyk7XHJcbiAgICB9XHJcbiAgfSxcclxuICBlcnJvcjogKG1lc3NhZ2U6IHN0cmluZywgLi4uYXJnczogYW55W10pID0+IHtcclxuICAgIGlmIChERUJVRykge1xyXG4gICAgICBjb25zb2xlLmVycm9yKGBbREVCVUcgRVJST1JdICR7bWVzc2FnZX1gLCAuLi5hcmdzKTtcclxuICAgIH1cclxuICB9LFxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4cG9zZXMgc291cmNlIGNvZGUgZ2VuZXJhdGlvbi4gT25seSBhdmFpbGFibGUgaW4gTm9kZS5qcyBlbnZpcm9ubWVudC5cclxuICogQHBhcmFtIHBrZ1xyXG4gKiBAcGFyYW0gb3V0RGlyXHJcbiAqIEBwYXJhbSBvdmVyd3JpdGVJbXBsXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGUoXHJcbiAgcGtnOiBFUGFja2FnZSxcclxuICBvdXREaXI6IHN0cmluZyxcclxuICBvdmVyd3JpdGVJbXBsOiBib29sZWFuXHJcbik6IFByb21pc2U8dm9pZD4ge1xyXG4gIGRlYnVnLnRpbWUoJ1RvdGFsIEdlbmVyYXRpb24gVGltZScpO1xyXG4gIGRlYnVnLmxvZyhcclxuICAgICdTdGFydGluZyBjb2RlIGdlbmVyYXRpb24gZm9yIHBhY2thZ2U6JyxcclxuICAgIHBrZy5nZXROYW1lKCkgfHwgJ3VubmFtZWQgcGFja2FnZSdcclxuICApO1xyXG4gIGRlYnVnLmxvZygnT3V0cHV0IGRpcmVjdG9yeTonLCBvdXREaXIpO1xyXG4gIGRlYnVnLmxvZygnT3ZlcndyaXRlIGltcGxlbWVudGF0aW9uIGZpbGVzOicsIG92ZXJ3cml0ZUltcGwpO1xyXG5cclxuICBFbnZpcm9ubWVudC5yZXF1aXJlTm9kZUVudmlyb25tZW50KCdDb2RlIGdlbmVyYXRpb24nKTtcclxuXHJcbiAgY29uc3QgZ2VuZXJhdG9yID0gbmV3IFRHZW5lcmF0b3JNYWluKHBrZywgb3V0RGlyLCBvdmVyd3JpdGVJbXBsKTtcclxuICBhd2FpdCBnZW5lcmF0b3IuZ2VuZXJhdGUoKTtcclxuXHJcbiAgZGVidWcudGltZUVuZCgnVG90YWwgR2VuZXJhdGlvbiBUaW1lJyk7XHJcbiAgZGVidWcubG9nKCdDb2RlIGdlbmVyYXRpb24gY29tcGxldGVkIHN1Y2Nlc3NmdWxseScpO1xyXG59XHJcblxyXG4vKipcclxuICogR2VuZXJhdGVzIFR5cGVTY3JpcHQgc291cmNlIGNvZGUgZm9yIGFuIEVQYWNrYWdlIGFuZCBhbGwgc3VicGFja2FnZXMsIGluY2x1ZGluZ1xyXG4gKiB0aGUgZm9sbG93aW5nIGFydGlmYWN0czpcclxuICogICgxKSAqLXBhY2thZ2UudHMgZm9yIGVhY2ggRVBhY2thZ2UgKHNlZSBUTUZQYWNrYWdlU291cmNlR2VuZXJhdG9yLnRzKVxyXG4gKiAgKDIpICotZmFjdG9yeS50cyBmb3IgZWFjaCBFUGFja2FnZSAoc2VlIFRNRkZhY3RvcnlTb3VyY2VHZW5lcmF0b3IudHMpXHJcbiAqICAoMykgQVBJIGludGVyZmFjZXMgKHNlZSBUTUZBcGlTb3VyY2VHZW5lcmF0b3IudHMpXHJcbiAqICAoNCkgQWJzdHJhY3QgKkdlbi50cyBjbGFzc2VzIChzZWUgVE1GR2VuU291cmNlR2VuZXJhdG9yLnRzKVxyXG4gKiAgKDUpIE92ZXJ3cml0YWJsZSAqSW1wbC50cyBjbGFzc2VzIChzZWUgVE1GSW1wbFNvdXJjZUdlbmVyYXRvci50cylcclxuICogICg2KSBFbnVtcyAoc2VlIFRNRkVudW1Tb3VyY2VHZW5lcmF0b3IudHMpXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgVEdlbmVyYXRvck1haW4ge1xyXG4gIC8vIE5PVEU6IFRoZXNlIDUgYXJlIGFsbCBjb25zdGFudHMgY29tcHV0ZWQgZHVyaW5nIGluaXRpYWxpemF0aW9uXHJcbiAgcHVibGljIGJhcnJlbEZpbGVPdXREaXIhOiBzdHJpbmc7XHJcbiAgcHVibGljIHBrZ091dERpcjogc3RyaW5nO1xyXG4gIHB1YmxpYyBwa2dSb290T3V0RGlyOiBzdHJpbmc7XHJcbiAgcHVibGljIHBrZ0FwaU91dERpcjogc3RyaW5nO1xyXG4gIHB1YmxpYyBwa2dHZW5PdXREaXI6IHN0cmluZztcclxuICBwdWJsaWMgcGtnSW1wbE91dERpcjogc3RyaW5nO1xyXG5cclxuICAvLyBOT1RFOiBUaGVzZSAzIGFyZSByZWNvbXB1dGVkIGZvciBlYWNoIEVDbGFzcyFcclxuICBwcml2YXRlIGVDbGFzc0FwaUltcG9ydHMhOiBTZXQ8RUNsYXNzaWZpZXI+O1xyXG4gIHByaXZhdGUgZUNsYXNzR2VuSW1wb3J0cyE6IFNldDxFQ2xhc3NpZmllcj47XHJcbiAgcHJpdmF0ZSBlQ2xhc3NQa2dJbXBvcnRzITogU2V0PEVQYWNrYWdlPjtcclxuXHJcbiAgLy8gQ2FjaGVkIE5vZGUuanMgbW9kdWxlcyAobG9hZGVkIG9uY2UgcGVyIGluc3RhbmNlKVxyXG4gIHByaXZhdGUgZnM6IGFueSA9IG51bGw7XHJcbiAgcHJpdmF0ZSBwYXRoOiBhbnkgPSBudWxsO1xyXG4gIHByaXZhdGUgY2hpbGRQcm9jZXNzOiBhbnkgPSBudWxsO1xyXG5cclxuICBwdWJsaWMgY29uc3RydWN0b3IoXHJcbiAgICBwdWJsaWMgcGtnOiBFUGFja2FnZSxcclxuICAgIHB1YmxpYyBvdXREaXI6IHN0cmluZyxcclxuICAgIHB1YmxpYyBvdmVyd3JpdGVJbXBsOiBib29sZWFuID0gZmFsc2UsXHJcbiAgICBwdWJsaWMgYmFycmVsRmlsZURpcj86IHN0cmluZ1xyXG4gICkge1xyXG4gICAgZGVidWcubG9nKFxyXG4gICAgICAnSW5pdGlhbGl6aW5nIFRHZW5lcmF0b3JNYWluIGZvciBwYWNrYWdlOicsXHJcbiAgICAgIHBrZy5nZXROYW1lKCkgfHwgJ3VubmFtZWQnXHJcbiAgICApO1xyXG4gICAgZGVidWcubG9nKCdDb25zdHJ1Y3RvciBwYXJhbWV0ZXJzOicsIHtcclxuICAgICAgcGFja2FnZU5hbWU6IHBrZy5nZXROYW1lKCksXHJcbiAgICAgIG91dERpcixcclxuICAgICAgb3ZlcndyaXRlSW1wbCxcclxuICAgICAgYmFycmVsRmlsZURpcixcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEluaXRpYWxpemUgZGlyZWN0b3JpZXMgd2l0aG91dCBmaWxlIHN5c3RlbSBvcGVyYXRpb25zXHJcbiAgICB0aGlzLnBrZ091dERpciA9IHRoaXMub3V0RGlyICsgKHBrZy5nZXROYW1lKCkgPyAnLycgKyBwa2cuZ2V0TmFtZSgpIDogJycpO1xyXG4gICAgdGhpcy5wa2dSb290T3V0RGlyID0gdGhpcy5wa2dPdXREaXI7XHJcbiAgICB0aGlzLnBrZ0FwaU91dERpciA9IHRoaXMucGtnT3V0RGlyICsgRFUuQVBJX1BBVEg7XHJcbiAgICB0aGlzLnBrZ0dlbk91dERpciA9IHRoaXMucGtnT3V0RGlyICsgRFUuR0VOX1BBVEg7XHJcbiAgICB0aGlzLnBrZ0ltcGxPdXREaXIgPSB0aGlzLnBrZ091dERpciArIERVLklNUExfUEFUSDtcclxuXHJcbiAgICBkZWJ1Zy5sb2coJ0NvbXB1dGVkIGRpcmVjdG9yeSBwYXRoczonLCB7XHJcbiAgICAgIHBrZ091dERpcjogdGhpcy5wa2dPdXREaXIsXHJcbiAgICAgIHBrZ1Jvb3RPdXREaXI6IHRoaXMucGtnUm9vdE91dERpcixcclxuICAgICAgcGtnQXBpT3V0RGlyOiB0aGlzLnBrZ0FwaU91dERpcixcclxuICAgICAgcGtnR2VuT3V0RGlyOiB0aGlzLnBrZ0dlbk91dERpcixcclxuICAgICAgcGtnSW1wbE91dERpcjogdGhpcy5wa2dJbXBsT3V0RGlyLFxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gTm90ZTogYmFycmVsRmlsZU91dERpciB3aWxsIGJlIHNldCBkdXJpbmcgZ2VuZXJhdGUoKSB3aGVuIHBhdGggaXMgYXZhaWxhYmxlXHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZW5lcmF0ZXMgdHlwZXNjcmlwdCBzb3VyY2Vjb2RlIGZvciBhbGwgcGFja2FnZXMsIHJlY3Vyc2luZyBhbGwgc3VicGFja2FnZXMuXHJcbiAgICogT25seSBhdmFpbGFibGUgaW4gTm9kZS5qcyBlbnZpcm9ubWVudC5cclxuICAgKi9cclxuICBwdWJsaWMgYXN5bmMgZ2VuZXJhdGUoYXR0ZW1wdEZvcm1hdFdpdGhQcmV0dGllcj86IGJvb2xlYW4pOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGRlYnVnLnRpbWUoYEdlbmVyYXRpb24gZm9yIHBhY2thZ2U6ICR7dGhpcy5wa2cuZ2V0TmFtZSgpIHx8ICd1bm5hbWVkJ31gKTtcclxuICAgIGRlYnVnLmdyb3VwKGBHZW5lcmF0aW5nIHBhY2thZ2U6ICR7dGhpcy5wa2cuZ2V0TmFtZSgpIHx8ICd1bm5hbWVkJ31gKTtcclxuXHJcbiAgICBFbnZpcm9ubWVudC5yZXF1aXJlTm9kZUVudmlyb25tZW50KCdDb2RlIGdlbmVyYXRpb24nKTtcclxuXHJcbiAgICAvLyBMb2FkIE5vZGUuanMgbW9kdWxlc1xyXG4gICAgZGVidWcubG9nKCdMb2FkaW5nIE5vZGUuanMgbW9kdWxlcy4uLicpO1xyXG4gICAgYXdhaXQgdGhpcy5lbnN1cmVOb2RlTW9kdWxlc0xvYWRlZCgpO1xyXG5cclxuICAgIC8vIE5vdyB3ZSBjYW4gcmVzb2x2ZSBkaXJlY3RvcmllcyBhbmQgY3JlYXRlIHRoZW1cclxuICAgIGRlYnVnLmxvZygnSW5pdGlhbGl6aW5nIGRpcmVjdG9yaWVzLi4uJyk7XHJcbiAgICBhd2FpdCB0aGlzLmluaXRpYWxpemVEaXJlY3RvcmllcygpO1xyXG5cclxuICAgIC8vIENvdW50IGNsYXNzaWZpZXJzIGZvciBkZWJ1ZyBpbmZvXHJcbiAgICBjb25zdCBjbGFzc2lmaWVycyA9IHRoaXMucGtnLmdldEVDbGFzc2lmaWVycygpO1xyXG4gICAgY29uc3QgZUNsYXNzZXMgPSBjbGFzc2lmaWVycy5maWx0ZXIoKGMpID0+IGMgaW5zdGFuY2VvZiBFQ2xhc3NJbXBsKTtcclxuICAgIGNvbnN0IGVFbnVtcyA9IGNsYXNzaWZpZXJzLmZpbHRlcigoYykgPT4gYyBpbnN0YW5jZW9mIEVFbnVtSW1wbCk7XHJcbiAgICBjb25zdCBzdWJwYWNrYWdlcyA9IHRoaXMucGtnLmdldEVTdWJQYWNrYWdlcygpO1xyXG5cclxuICAgIGRlYnVnLmxvZygnUGFja2FnZSBjb250ZW50czonLCB7XHJcbiAgICAgIHRvdGFsQ2xhc3NpZmllcnM6IGNsYXNzaWZpZXJzLnNpemUoKSxcclxuICAgICAgZUNsYXNzZXM6IGVDbGFzc2VzLnNpemUoKSxcclxuICAgICAgZUVudW1zOiBlRW51bXMuc2l6ZSgpLFxyXG4gICAgICBzdWJwYWNrYWdlczogc3VicGFja2FnZXMuc2l6ZSgpLFxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gR2VuZXJhdGUgYWxsIHRoZSBmaWxlc1xyXG4gICAgZGVidWcubG9nKCdHZW5lcmF0aW5nIGNvcmUgZmlsZXMuLi4nKTtcclxuICAgIGlmICh0aGlzLmJhcnJlbEZpbGVEaXIpIHtcclxuICAgICAgZGVidWcubG9nKCdXcml0aW5nIGJhcnJlbCBmaWxlLi4uJyk7XHJcbiAgICAgIGF3YWl0IHRoaXMud3JpdGVCYXJyZWxGaWxlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgZGVidWcubG9nKCdXcml0aW5nIHBhY2thZ2UgZmlsZS4uLicpO1xyXG4gICAgYXdhaXQgdGhpcy53cml0ZVBhY2thZ2VGaWxlKCk7XHJcblxyXG4gICAgZGVidWcubG9nKCdXcml0aW5nIGZhY3RvcnkgZmlsZS4uLicpO1xyXG4gICAgYXdhaXQgdGhpcy53cml0ZUZhY3RvcnlGaWxlKCk7XHJcblxyXG4gICAgZGVidWcubG9nKCdXcml0aW5nIHV0aWxzIGZpbGUuLi4nKTtcclxuICAgIGF3YWl0IHRoaXMud3JpdGVVdGlsc0ZpbGUoKTtcclxuXHJcbiAgICAvLyBBZGQgdGhpcyBuZXcgc2VjdGlvbjpcclxuICAgIGRlYnVnLmxvZygnV3JpdGluZyBwYWNrYWdlIGluaXRpYWxpemVyIGZpbGUuLi4nKTtcclxuICAgIGF3YWl0IHRoaXMud3JpdGVQYWNrYWdlSW5pdGlhbGl6ZXJGaWxlKCk7XHJcblxyXG4gICAgZGVidWcubG9nKCdXcml0aW5nIHBhY2thZ2UgcmVnaXN0cnkgZmlsZS4uLicpO1xyXG4gICAgYXdhaXQgdGhpcy53cml0ZVBhY2thZ2VSZWdpc3RyeUZpbGUoKTtcclxuICAgIFxyXG5cclxuICAgIC8vIEdlbmVyYXRlIEVDbGFzcyBhcnRpZmFjdHNcclxuICAgIGRlYnVnLmxvZyhgUHJvY2Vzc2luZyAke2VDbGFzc2VzLnNpemUoKX0gRUNsYXNzKGVzKS4uLmApO1xyXG4gICAgZm9yIChjb25zdCBlQ2xhc3NpZmllciBvZiBjbGFzc2lmaWVycykge1xyXG4gICAgICBpZiAoZUNsYXNzaWZpZXIgaW5zdGFuY2VvZiBFQ2xhc3NJbXBsKSB7XHJcbiAgICAgICAgZGVidWcubG9nKGBHZW5lcmF0aW5nIGFydGlmYWN0cyBmb3IgRUNsYXNzOiAke2VDbGFzc2lmaWVyLmdldE5hbWUoKX1gKTtcclxuICAgICAgICBhd2FpdCB0aGlzLmdlbmVyYXRlQWxsRUNsYXNzQXJ0aWZhY3RzKGVDbGFzc2lmaWVyKTtcclxuICAgICAgfSBlbHNlIGlmIChlQ2xhc3NpZmllciBpbnN0YW5jZW9mIEVFbnVtSW1wbCkge1xyXG4gICAgICAgIGRlYnVnLmxvZyhgR2VuZXJhdGluZyBlbnVtIGZpbGUgZm9yOiAke2VDbGFzc2lmaWVyLmdldE5hbWUoKX1gKTtcclxuICAgICAgICBhd2FpdCB0aGlzLndyaXRlRW51bUZpbGUoZUNsYXNzaWZpZXIpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVhbCB3aXRoIHJlY3Vyc2l2ZSBzdWJwYWNrYWdlc1xyXG4gICAgZGVidWcubG9nKGBQcm9jZXNzaW5nICR7c3VicGFja2FnZXMuc2l6ZSgpfSBzdWJwYWNrYWdlKHMpLi4uYCk7XHJcbiAgICBmb3IgKGNvbnN0IHN1YnBhY2thZ2Ugb2Ygc3VicGFja2FnZXMpIHtcclxuICAgICAgZGVidWcubG9nKGBSZWN1cnNpdmVseSBnZW5lcmF0aW5nIHN1YnBhY2thZ2U6ICR7c3VicGFja2FnZS5nZXROYW1lKCl9YCk7XHJcbiAgICAgIGNvbnN0IHN1YkdlbmVyYXRvciA9IG5ldyBUR2VuZXJhdG9yTWFpbihcclxuICAgICAgICBzdWJwYWNrYWdlLFxyXG4gICAgICAgIHRoaXMucGtnUm9vdE91dERpcixcclxuICAgICAgICB0aGlzLm92ZXJ3cml0ZUltcGxcclxuICAgICAgKTtcclxuICAgICAgYXdhaXQgc3ViR2VuZXJhdG9yLmdlbmVyYXRlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRmluYWxseS4uLiBmb3JtYXQgdGhlIHNvdXJjZSBjb2RlIHdpdGggcHJldHRpZXJcclxuICAgIGlmIChhdHRlbXB0Rm9ybWF0V2l0aFByZXR0aWVyKSB7XHJcbiAgICAgIGRlYnVnLmxvZygnQXR0ZW1wdGluZyB0byBmb3JtYXQgY29kZSB3aXRoIFByZXR0aWVyLi4uJyk7XHJcbiAgICAgIGF3YWl0IHRoaXMudHJ5Rm9ybWF0V2l0aFByZXR0aWVyKCk7XHJcbiAgICB9XHJcblxyXG4gICAgZGVidWcuZ3JvdXBFbmQoKTtcclxuICAgIGRlYnVnLnRpbWVFbmQoYEdlbmVyYXRpb24gZm9yIHBhY2thZ2U6ICR7dGhpcy5wa2cuZ2V0TmFtZSgpIHx8ICd1bm5hbWVkJ31gKTtcclxuICAgIGRlYnVnLmxvZyhcclxuICAgICAgYENvbXBsZXRlZCBnZW5lcmF0aW9uIGZvciBwYWNrYWdlOiAke3RoaXMucGtnLmdldE5hbWUoKSB8fCAndW5uYW1lZCd9YFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBhc3luYyBnZW5lcmF0ZUFsbEVDbGFzc0FydGlmYWN0cyhlQ2xhc3NpZmllcjogRUNsYXNzKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICBkZWJ1Zy5ncm91cChgR2VuZXJhdGluZyBFQ2xhc3MgYXJ0aWZhY3RzOiAke2VDbGFzc2lmaWVyLmdldE5hbWUoKX1gKTtcclxuICAgIGRlYnVnLnRpbWUoYEVDbGFzcyBnZW5lcmF0aW9uOiAke2VDbGFzc2lmaWVyLmdldE5hbWUoKX1gKTtcclxuXHJcbiAgICBkZWJ1Zy5sb2coJ1NldHRpbmcgdXAgaW1wb3J0cy4uLicpO1xyXG4gICAgdGhpcy5zZXR1cEVDbGFzc0ltcG9ydHMoZUNsYXNzaWZpZXIpO1xyXG5cclxuICAgIGRlYnVnLmxvZygnSW1wb3J0IGFuYWx5c2lzIHJlc3VsdHM6Jywge1xyXG4gICAgICBhcGlJbXBvcnRzOiBBcnJheS5mcm9tKHRoaXMuZUNsYXNzQXBpSW1wb3J0cykubWFwKChjKSA9PiBjLmdldE5hbWUoKSksXHJcbiAgICAgIGdlbkltcG9ydHM6IEFycmF5LmZyb20odGhpcy5lQ2xhc3NHZW5JbXBvcnRzKS5tYXAoKGMpID0+IGMuZ2V0TmFtZSgpKSxcclxuICAgICAgcGFja2FnZUltcG9ydHM6IEFycmF5LmZyb20odGhpcy5lQ2xhc3NQa2dJbXBvcnRzKS5tYXAoKHApID0+IHAuZ2V0TmFtZSgpKSxcclxuICAgIH0pO1xyXG5cclxuICAgIGRlYnVnLmxvZygnV3JpdGluZyBBUEkgZmlsZS4uLicpO1xyXG4gICAgYXdhaXQgdGhpcy53cml0ZUVDbGFzc0FwaUZpbGUoZUNsYXNzaWZpZXIpO1xyXG5cclxuICAgIGRlYnVnLmxvZygnV3JpdGluZyBHZW4gZmlsZS4uLicpO1xyXG4gICAgYXdhaXQgdGhpcy53cml0ZUVDbGFzc0dlbkZpbGUoZUNsYXNzaWZpZXIpO1xyXG5cclxuICAgIGRlYnVnLmxvZygnV3JpdGluZyBJbXBsIGZpbGUuLi4nKTtcclxuICAgIGF3YWl0IHRoaXMud3JpdGVFQ2xhc3NJbXBsRmlsZShlQ2xhc3NpZmllcik7XHJcblxyXG4gICAgZGVidWcudGltZUVuZChgRUNsYXNzIGdlbmVyYXRpb246ICR7ZUNsYXNzaWZpZXIuZ2V0TmFtZSgpfWApO1xyXG4gICAgZGVidWcuZ3JvdXBFbmQoKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENoZWNrIGlmIGNvZGUgZ2VuZXJhdGlvbiBpcyBzdXBwb3J0ZWQgaW4gY3VycmVudCBlbnZpcm9ubWVudFxyXG4gICAqL1xyXG4gIHB1YmxpYyBzdGF0aWMgaXNHZW5lcmF0aW9uU3VwcG9ydGVkKCk6IGJvb2xlYW4ge1xyXG4gICAgY29uc3Qgc3VwcG9ydGVkID0gRW52aXJvbm1lbnQuaXNOb2RlO1xyXG4gICAgZGVidWcubG9nKCdHZW5lcmF0aW9uIHN1cHBvcnQgY2hlY2s6Jywgc3VwcG9ydGVkKTtcclxuICAgIHJldHVybiBzdXBwb3J0ZWQ7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZXQgbGlzdCBvZiBzdXBwb3J0ZWQgb3BlcmF0aW9ucyBpbiBjdXJyZW50IGVudmlyb25tZW50XHJcbiAgICovXHJcbiAgcHVibGljIHN0YXRpYyBnZXRTdXBwb3J0ZWRPcGVyYXRpb25zKCk6IHN0cmluZ1tdIHtcclxuICAgIGNvbnN0IG9wZXJhdGlvbnMgPSBbJ0luLW1lbW9yeSBnZW5lcmF0aW9uJ107XHJcblxyXG4gICAgaWYgKEVudmlyb25tZW50LmlzTm9kZSkge1xyXG4gICAgICBvcGVyYXRpb25zLnB1c2goXHJcbiAgICAgICAgJ0ZpbGUtYmFzZWQgZ2VuZXJhdGlvbicsXHJcbiAgICAgICAgJ0RpcmVjdG9yeSBjcmVhdGlvbicsXHJcbiAgICAgICAgJ1ByZXR0aWVyIGZvcm1hdHRpbmcnLFxyXG4gICAgICAgICdSZWN1cnNpdmUgcGFja2FnZSBwcm9jZXNzaW5nJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGRlYnVnLmxvZygnU3VwcG9ydGVkIG9wZXJhdGlvbnM6Jywgb3BlcmF0aW9ucyk7XHJcbiAgICByZXR1cm4gb3BlcmF0aW9ucztcclxuICB9XHJcblxyXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuICAvLyBQcml2YXRlIG1ldGhvZHNcclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBlbnN1cmVOb2RlTW9kdWxlc0xvYWRlZCgpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGRlYnVnLmxvZygnTG9hZGluZyBOb2RlLmpzIG1vZHVsZXMuLi4nKTtcclxuXHJcbiAgICBpZiAoIXRoaXMuZnMpIHtcclxuICAgICAgZGVidWcubG9nKCdMb2FkaW5nIGZzIG1vZHVsZS4uLicpO1xyXG4gICAgICB0aGlzLmZzID0gYXdhaXQgQ29uZGl0aW9uYWxJbXBvcnRzLmdldE5vZGVNb2R1bGUoJ2ZzJyk7XHJcbiAgICB9XHJcbiAgICBpZiAoIXRoaXMucGF0aCkge1xyXG4gICAgICBkZWJ1Zy5sb2coJ0xvYWRpbmcgcGF0aCBtb2R1bGUuLi4nKTtcclxuICAgICAgdGhpcy5wYXRoID0gYXdhaXQgQ29uZGl0aW9uYWxJbXBvcnRzLmdldE5vZGVNb2R1bGUoJ3BhdGgnKTtcclxuICAgIH1cclxuICAgIC8vIGNoaWxkUHJvY2VzcyBpcyBsb2FkZWQgb24tZGVtYW5kIGluIHRyeUZvcm1hdFdpdGhQcmV0dGllclxyXG5cclxuICAgIGRlYnVnLmxvZygnTm9kZS5qcyBtb2R1bGVzIGxvYWRlZCBzdWNjZXNzZnVsbHknKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgaW5pdGlhbGl6ZURpcmVjdG9yaWVzKCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgZGVidWcubG9nKCdJbml0aWFsaXppbmcgYW5kIGNyZWF0aW5nIGRpcmVjdG9yaWVzLi4uJyk7XHJcblxyXG4gICAgLy8gTm93IHdlIGNhbiB1c2UgcGF0aCBvcGVyYXRpb25zXHJcbiAgICB0aGlzLnBrZ1Jvb3RPdXREaXIgPSBhd2FpdCB0aGlzLnJlc29sdmVBbmRNYXliZUNyZWF0ZURpcihcclxuICAgICAgdGhpcy5wa2dPdXREaXIsXHJcbiAgICAgIGZhbHNlXHJcbiAgICApO1xyXG4gICAgdGhpcy5wa2dBcGlPdXREaXIgPSBhd2FpdCB0aGlzLnJlc29sdmVBbmRNYXliZUNyZWF0ZURpcihcclxuICAgICAgdGhpcy5wa2dPdXREaXIgKyBEVS5BUElfUEFUSCxcclxuICAgICAgdHJ1ZVxyXG4gICAgKTtcclxuICAgIHRoaXMucGtnR2VuT3V0RGlyID0gYXdhaXQgdGhpcy5yZXNvbHZlQW5kTWF5YmVDcmVhdGVEaXIoXHJcbiAgICAgIHRoaXMucGtnT3V0RGlyICsgRFUuR0VOX1BBVEgsXHJcbiAgICAgIHRydWVcclxuICAgICk7XHJcbiAgICB0aGlzLnBrZ0ltcGxPdXREaXIgPSBhd2FpdCB0aGlzLnJlc29sdmVBbmRNYXliZUNyZWF0ZURpcihcclxuICAgICAgdGhpcy5wa2dPdXREaXIgKyBEVS5JTVBMX1BBVEgsXHJcbiAgICAgIGZhbHNlXHJcbiAgICApO1xyXG5cclxuICAgIGlmICh0aGlzLmJhcnJlbEZpbGVEaXIpIHtcclxuICAgICAgdGhpcy5iYXJyZWxGaWxlT3V0RGlyID0gdGhpcy5wYXRoLnJlc29sdmUocHJvY2Vzcy5jd2QoKSwgdGhpcy5iYXJyZWxGaWxlRGlyKTtcclxuICAgICAgZGVidWcubG9nKCdCYXJyZWwgZmlsZSBvdXRwdXQgZGlyZWN0b3J5IHNldCB0bzonLCB0aGlzLmJhcnJlbEZpbGVPdXREaXIpO1xyXG4gICAgfVxyXG5cclxuICAgIGRlYnVnLmxvZygnRGlyZWN0b3J5IGluaXRpYWxpemF0aW9uIGNvbXBsZXRlZCcpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyB3cml0ZUJhcnJlbEZpbGUoKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICBkZWJ1Zy5sb2coJ0dlbmVyYXRpbmcgYmFycmVsIGZpbGUgY29udGVudC4uLicpO1xyXG4gICAgY29uc3QgZ2VuZXJhdG9yID0gbmV3IFRHZW5lcmF0b3JCYXJyZWxJbmRleFRzKCk7XHJcbiAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZ2VuZXJhdG9yLmdlbmVyYXRlKHRoaXMucGtnLCB0aGlzLmJhcnJlbEZpbGVPdXREaXIpO1xyXG4gICAgZGVidWcubG9nKCdXcml0aW5nIGJhcnJlbCBmaWxlIHRvOicsIHRoaXMuYmFycmVsRmlsZU91dERpcik7XHJcbiAgICBhd2FpdCB0aGlzLndyaXRlU291cmNlRmlsZShcclxuICAgICAgdGhpcy5iYXJyZWxGaWxlT3V0RGlyLFxyXG4gICAgICAnaW5kZXgudHMnLFxyXG4gICAgICBjb250ZW50LFxyXG4gICAgICB0cnVlXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyB3cml0ZVBhY2thZ2VGaWxlKCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgY29uc3QgZmlsZU5hbWUgPSBEVS5nZW5QYWNrYWdlRmlsZU5hbWUodGhpcy5wa2cpO1xyXG4gICAgZGVidWcubG9nKCdHZW5lcmF0aW5nIHBhY2thZ2UgZmlsZTonLCBmaWxlTmFtZSArICcudHMnKTtcclxuICAgIGNvbnN0IGdlbmVyYXRvciA9IG5ldyBUR2VuZXJhdG9yUGFja2FnZSgpO1xyXG4gICAgY29uc3QgY29udGVudCA9IGdlbmVyYXRvci5nZW5lcmF0ZVBhY2thZ2VDb250ZW50cyh0aGlzLnBrZyk7XHJcbiAgICBhd2FpdCB0aGlzLndyaXRlU291cmNlRmlsZShcclxuICAgICAgdGhpcy5wa2dSb290T3V0RGlyLFxyXG4gICAgICBmaWxlTmFtZSArICcudHMnLFxyXG4gICAgICBjb250ZW50LFxyXG4gICAgICB0cnVlXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyB3cml0ZUZhY3RvcnlGaWxlKCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgY29uc3QgZmlsZU5hbWUgPSBEVS5nZW5GYWN0b3J5RmlsZU5hbWUodGhpcy5wa2cpO1xyXG4gICAgZGVidWcubG9nKCdHZW5lcmF0aW5nIGZhY3RvcnkgZmlsZTonLCBmaWxlTmFtZSArICcudHMnKTtcclxuICAgIGNvbnN0IGdlbmVyYXRvciA9IG5ldyBUR2VuZXJhdG9yRmFjdG9yeSgpO1xyXG4gICAgY29uc3QgY29udGVudCA9IGdlbmVyYXRvci5nZW5lcmF0ZUZhY3RvcnlDb250ZW50cyh0aGlzLnBrZyk7XHJcbiAgICBhd2FpdCB0aGlzLndyaXRlU291cmNlRmlsZShcclxuICAgICAgdGhpcy5wa2dSb290T3V0RGlyLFxyXG4gICAgICBmaWxlTmFtZSArICcudHMnLFxyXG4gICAgICBjb250ZW50LFxyXG4gICAgICB0cnVlXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyB3cml0ZVV0aWxzRmlsZSgpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGNvbnN0IGZpbGVOYW1lID0gRFUuZ2VuVXRpbHNGaWxlTmFtZSh0aGlzLnBrZyk7XHJcbiAgICBkZWJ1Zy5sb2coJ0dlbmVyYXRpbmcgdXRpbHMgZmlsZTonLCBmaWxlTmFtZSArICcudHMnKTtcclxuICAgIGNvbnN0IGdlbmVyYXRvciA9IG5ldyBUR2VuZXJhdG9yVXRpbHMoKTtcclxuICAgIGNvbnN0IGNvbnRlbnQgPSBnZW5lcmF0b3IuZ2VuZXJhdGVVdGlsc0NvbnRlbnRzKHRoaXMucGtnKTtcclxuICAgIGF3YWl0IHRoaXMud3JpdGVTb3VyY2VGaWxlKFxyXG4gICAgICB0aGlzLnBrZ1Jvb3RPdXREaXIsXHJcbiAgICAgIGZpbGVOYW1lICsgJy50cycsXHJcbiAgICAgIGNvbnRlbnQsXHJcbiAgICAgIGZhbHNlXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXR1cEVDbGFzc0ltcG9ydHMoZUNsYXNzOiBFQ2xhc3MpOiB2b2lkIHtcclxuICAgIGRlYnVnLmxvZyhgU2V0dGluZyB1cCBpbXBvcnRzIGZvciBFQ2xhc3M6ICR7ZUNsYXNzLmdldE5hbWUoKX1gKTtcclxuXHJcbiAgICAvLyBEZXRlcm1pbmVzIHRoZSBzZXQgb2YgdHlwZXMgdGhhdCBuZWVkcyB0byBiZSBpbXBvcnRlZCB0byBzdXBwb3J0IHRoZSBFQ2xhc3NcclxuICAgIHRoaXMuZUNsYXNzQXBpSW1wb3J0cyA9IG5ldyBTZXQ8RUNsYXNzaWZpZXI+KCk7XHJcbiAgICB0aGlzLmVDbGFzc0dlbkltcG9ydHMgPSBuZXcgU2V0PEVDbGFzc2lmaWVyPigpO1xyXG4gICAgdGhpcy5lQ2xhc3NQa2dJbXBvcnRzID0gbmV3IFNldDxFUGFja2FnZT4oKTtcclxuXHJcbiAgICBkZWJ1Zy5sb2coJ0NvbGxlY3RpbmcgaW1wb3J0cy4uLicpO1xyXG4gICAgdGhpcy5jb2xsZWN0RUNsYXNzSW1wb3J0cyh0aGlzLnBrZywgZUNsYXNzKTtcclxuXHJcbiAgICBkZWJ1Zy5sb2coJ0ltcG9ydCBjb2xsZWN0aW9uIGNvbXBsZXRlZCcpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyB3cml0ZUVDbGFzc0FwaUZpbGUoZUNsYXNzOiBFQ2xhc3MpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGNvbnN0IGZpbGVuYW1lID0gRFUuZ2VuQ2xhc3NBcGlOYW1lKGVDbGFzcyk7XHJcbiAgICBkZWJ1Zy5sb2coYFdyaXRpbmcgQVBJIGZpbGUgZm9yICR7ZUNsYXNzLmdldE5hbWUoKX06ICR7ZmlsZW5hbWV9LnRzYCk7XHJcblxyXG4gICAgY29uc3QgYXBpR2VuZXJhdG9yID0gbmV3IFRHZW5lcmF0b3JBcGkoKTtcclxuICAgIGNvbnN0IHRzSW50ZXJmYWNlQ29udGVudCA9IGFwaUdlbmVyYXRvci5nZW5lcmF0ZShcclxuICAgICAgZUNsYXNzLFxyXG4gICAgICB0aGlzLmVDbGFzc0FwaUltcG9ydHNcclxuICAgICk7XHJcblxyXG4gICAgYXdhaXQgdGhpcy53cml0ZVNvdXJjZUZpbGUoXHJcbiAgICAgIHRoaXMucGtnQXBpT3V0RGlyLFxyXG4gICAgICBmaWxlbmFtZSArICcudHMnLFxyXG4gICAgICB0c0ludGVyZmFjZUNvbnRlbnQsXHJcbiAgICAgIHRydWVcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGFzeW5jIHdyaXRlRUNsYXNzR2VuRmlsZShlQ2xhc3M6IEVDbGFzcyk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgY29uc3QgZmlsZW5hbWUgPSBEVS5nZW5DbGFzc0dlbk5hbWUoZUNsYXNzKTtcclxuICAgIGRlYnVnLmxvZyhgV3JpdGluZyBHZW4gZmlsZSBmb3IgJHtlQ2xhc3MuZ2V0TmFtZSgpfTogJHtmaWxlbmFtZX0udHNgKTtcclxuXHJcbiAgICBjb25zdCBnZW5HZW5lcmF0b3IgPSBuZXcgVEdlbmVyYXRvckdlbigpO1xyXG4gICAgY29uc3QgdHNHZW5DbGFzc0NvbnRlbnQgPSBnZW5HZW5lcmF0b3IuZ2VuZXJhdGUoXHJcbiAgICAgIGVDbGFzcyxcclxuICAgICAgdGhpcy5lQ2xhc3NBcGlJbXBvcnRzLFxyXG4gICAgICB0aGlzLmVDbGFzc0dlbkltcG9ydHMsXHJcbiAgICAgIHRoaXMuZUNsYXNzUGtnSW1wb3J0c1xyXG4gICAgKTtcclxuXHJcbiAgICBhd2FpdCB0aGlzLndyaXRlU291cmNlRmlsZShcclxuICAgICAgdGhpcy5wa2dHZW5PdXREaXIsXHJcbiAgICAgIGZpbGVuYW1lICsgJy50cycsXHJcbiAgICAgIHRzR2VuQ2xhc3NDb250ZW50LFxyXG4gICAgICB0cnVlXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyB3cml0ZUVDbGFzc0ltcGxGaWxlKGVDbGFzczogRUNsYXNzKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICBjb25zdCBmaWxlbmFtZSA9IERVLmdlbkNsYXNzSW1wbE5hbWUoZUNsYXNzKTtcclxuICAgIGRlYnVnLmxvZyhgV3JpdGluZyBJbXBsIGZpbGUgZm9yICR7ZUNsYXNzLmdldE5hbWUoKX06ICR7ZmlsZW5hbWV9LnRzYCk7XHJcbiAgICBkZWJ1Zy5sb2coYE92ZXJ3cml0ZSBtb2RlOiAke3RoaXMub3ZlcndyaXRlSW1wbH1gKTtcclxuXHJcbiAgICBjb25zdCBpbXBsR2VuZXJhdG9yID0gbmV3IFRHZW5lcmF0b3JJbXBsKCk7XHJcbiAgICBjb25zdCB0c0ltcGxDbGFzc0NvbnRlbnQgPSBpbXBsR2VuZXJhdG9yLmdlbmVyYXRlKFxyXG4gICAgICBlQ2xhc3MsXHJcbiAgICAgIHRoaXMuZUNsYXNzQXBpSW1wb3J0c1xyXG4gICAgKTtcclxuXHJcbiAgICBhd2FpdCB0aGlzLndyaXRlU291cmNlRmlsZShcclxuICAgICAgdGhpcy5wa2dJbXBsT3V0RGlyLFxyXG4gICAgICBmaWxlbmFtZSArICcudHMnLFxyXG4gICAgICB0c0ltcGxDbGFzc0NvbnRlbnQsXHJcbiAgICAgIHRoaXMub3ZlcndyaXRlSW1wbFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgd3JpdGVFbnVtRmlsZShlY2xhc3NpZmllcjogRUVudW0pOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGNvbnN0IGZpbGVuYW1lID0gRFUuZ2VuQ2xhc3NBcGlOYW1lKGVjbGFzc2lmaWVyKSArICcudHMnO1xyXG4gICAgZGVidWcubG9nKGBXcml0aW5nIGVudW0gZmlsZSBmb3IgJHtlY2xhc3NpZmllci5nZXROYW1lKCl9OiAke2ZpbGVuYW1lfWApO1xyXG5cclxuICAgIGNvbnN0IGVudW1HZW5lcmF0b3IgPSBuZXcgVEdlbmVyYXRvckVudW0oKTtcclxuICAgIGNvbnN0IGVudW1Db250ZW50ID0gZW51bUdlbmVyYXRvci5nZW5lcmF0ZShlY2xhc3NpZmllcik7XHJcbiAgICBhd2FpdCB0aGlzLndyaXRlU291cmNlRmlsZSh0aGlzLnBrZ0FwaU91dERpciwgZmlsZW5hbWUsIGVudW1Db250ZW50LCB0cnVlKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgcmVzb2x2ZUFuZE1heWJlQ3JlYXRlRGlyKFxyXG4gICAgb3V0RGlyOiBzdHJpbmcsXHJcbiAgICBkZWxldGVBbGxJbkRpcjogYm9vbGVhblxyXG4gICk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICBhd2FpdCB0aGlzLmVuc3VyZU5vZGVNb2R1bGVzTG9hZGVkKCk7XHJcblxyXG4gICAgY29uc3QgcmVzb2x2ZWRPdXREaXIgPSB0aGlzLnBhdGgucmVzb2x2ZShwcm9jZXNzLmN3ZCgpLCBvdXREaXIpO1xyXG4gICAgZGVidWcubG9nKGBQcm9jZXNzaW5nIGRpcmVjdG9yeTogJHtvdXREaXJ9IC0+ICR7cmVzb2x2ZWRPdXREaXJ9YCk7XHJcbiAgICBkZWJ1Zy5sb2coYERlbGV0ZSBhbGwgZmlsZXMgaW4gZGlyZWN0b3J5OiAke2RlbGV0ZUFsbEluRGlyfWApO1xyXG5cclxuICAgIGlmICh0aGlzLmZzLmV4aXN0c1N5bmMocmVzb2x2ZWRPdXREaXIpKSB7XHJcbiAgICAgIGRlYnVnLmxvZygnRGlyZWN0b3J5IGV4aXN0cycpO1xyXG4gICAgICBpZiAoZGVsZXRlQWxsSW5EaXIpIHtcclxuICAgICAgICBkZWJ1Zy5sb2coJ0RlbGV0aW5nIGFsbCBmaWxlcyBpbiBkaXJlY3RvcnkuLi4nKTtcclxuICAgICAgICBhd2FpdCB0aGlzLmRlbGV0ZUZpbGVzSW5Gb2xkZXIocmVzb2x2ZWRPdXREaXIpO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBkZWJ1Zy5sb2coJ0RpcmVjdG9yeSBkb2VzIG5vdCBleGlzdCwgY3JlYXRpbmcuLi4nKTtcclxuICAgICAgdGhpcy5mcy5ta2RpclN5bmMocmVzb2x2ZWRPdXREaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xyXG4gICAgICBkZWJ1Zy5sb2coJ0RpcmVjdG9yeSBjcmVhdGVkIHN1Y2Nlc3NmdWxseScpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBvdXREaXI7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUcmF2ZXJzZXMgZW50aXJlIEVDbGFzcyBzdHJ1Y3R1cmUgYW5kIGNvbGxlY3RzIHRoZSBzZXQgb2YgdHlwZXMgdGhhdCBuZWVkXHJcbiAgICogdG8gYmUgaW1wb3J0ZWQsIGluY2x1ZGluZyBBUEksIEdlbiBhbmQgRVBhY2thZ2UgaW5zdGFuY2VzLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgY29sbGVjdEVDbGFzc0ltcG9ydHMocGtnOiBFUGFja2FnZSwgZUNsYXNzOiBFQ2xhc3MpOiB2b2lkIHtcclxuICAgIGRlYnVnLmdyb3VwKGBDb2xsZWN0aW5nIGltcG9ydHMgZm9yIEVDbGFzczogJHtlQ2xhc3MuZ2V0TmFtZSgpfWApO1xyXG5cclxuICAgIC8vIFN0YXJ0IHdpdGggaW1wb3J0aW5nIHN1cGVydHlwZXNcclxuICAgIGNvbnN0IHN1cGVyVHlwZXMgPSBlQ2xhc3MuZ2V0RVN1cGVyVHlwZXMoKTtcclxuICAgIGRlYnVnLmxvZyhgUHJvY2Vzc2luZyAke3N1cGVyVHlwZXMuc2l6ZSgpfSBzdXBlciB0eXBlKHMpLi4uYCk7XHJcbiAgICBmb3IgKGNvbnN0IHN1cGVyVHlwZSBvZiBzdXBlclR5cGVzKSB7XHJcbiAgICAgIGRlYnVnLmxvZyhgQWRkaW5nIHN1cGVyIHR5cGU6ICR7c3VwZXJUeXBlLmdldE5hbWUoKX1gKTtcclxuICAgICAgdGhpcy5lQ2xhc3NBcGlJbXBvcnRzLmFkZChzdXBlclR5cGUpO1xyXG4gICAgICBpZiAoIXN1cGVyVHlwZS5pc0ludGVyZmFjZSgpKSB7XHJcbiAgICAgICAgdGhpcy5lQ2xhc3NHZW5JbXBvcnRzLmFkZChzdXBlclR5cGUpO1xyXG4gICAgICAgIGRlYnVnLmxvZyhcclxuICAgICAgICAgIGBBZGRlZCB0byBHZW4gaW1wb3J0cyAobm90IGludGVyZmFjZSk6ICR7c3VwZXJUeXBlLmdldE5hbWUoKX1gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEFkZCBpbXBvcnRzIHRvIHN1cHBvcnQgRVN0cnVjdHVyYWxGZWF0dXJlc1xyXG4gICAgY29uc3QgZmVhdHVyZXMgPSBlQ2xhc3MuZ2V0RUFsbFN0cnVjdHVyYWxGZWF0dXJlcygpO1xyXG4gICAgZGVidWcubG9nKGBQcm9jZXNzaW5nICR7ZmVhdHVyZXMuc2l6ZSgpfSBzdHJ1Y3R1cmFsIGZlYXR1cmUocykuLi5gKTtcclxuICAgIGZvciAoY29uc3QgZmllbGQgb2YgZmVhdHVyZXMpIHtcclxuICAgICAgaWYgKGZpZWxkLmdldEVUeXBlKCkpIHtcclxuICAgICAgICB0aGlzLm1heWJlQWRkTWVtYmVySW1wb3J0cyhwa2csIGVDbGFzcywgZmllbGQuZ2V0RVR5cGUoKSEpO1xyXG4gICAgICAgIGlmIChmaWVsZCBpbnN0YW5jZW9mIEVSZWZlcmVuY2VJbXBsKSB7XHJcbiAgICAgICAgICBjb25zdCBvcHBvc2l0ZSA9IGZpZWxkLmdldEVPcHBvc2l0ZSgpO1xyXG4gICAgICAgICAgaWYgKG9wcG9zaXRlKSB7XHJcbiAgICAgICAgICAgIGRlYnVnLmxvZyhgUHJvY2Vzc2luZyBvcHBvc2l0ZSByZWZlcmVuY2U6ICR7b3Bwb3NpdGUuZ2V0TmFtZSgpfWApO1xyXG4gICAgICAgICAgICB0aGlzLm1heWJlQWRkTWVtYmVySW1wb3J0cyhcclxuICAgICAgICAgICAgICBwa2csXHJcbiAgICAgICAgICAgICAgZUNsYXNzLFxyXG4gICAgICAgICAgICAgIG9wcG9zaXRlLmdldEVDb250YWluaW5nQ2xhc3MoKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEFkZCBpbXBvcnRzIHRvIHN1cHBvcnQgRU9wZXJhdGlvbnNcclxuICAgIGNvbnN0IG9wZXJhdGlvbnNUb0ltcGxlbWVudCA9IHRoaXMuZW9wc1RvSW1wbGVtZW50KGVDbGFzcyk7XHJcbiAgICBkZWJ1Zy5sb2coYFByb2Nlc3NpbmcgJHtvcGVyYXRpb25zVG9JbXBsZW1lbnQuc2l6ZSgpfSBvcGVyYXRpb24ocykgZm9yICR7ZUNsYXNzLmdldE5hbWUoKX0uLi5gKTtcclxuICAgIGZvciAoY29uc3QgZW9wIG9mIG9wZXJhdGlvbnNUb0ltcGxlbWVudCkge1xyXG4gICAgICBpZiAoZW9wLmdldEVUeXBlKCkpXHJcbiAgICAgICAgdGhpcy5tYXliZUFkZE1lbWJlckltcG9ydHMocGtnLCBlQ2xhc3MsIGVvcC5nZXRFVHlwZSgpISk7XHJcbiAgICAgIGNvbnN0IHBhcmFtcyA9IGVvcC5nZXRFUGFyYW1ldGVycygpO1xyXG4gICAgICBmb3IgKGNvbnN0IHBhcmFtIG9mIHBhcmFtcykge1xyXG4gICAgICAgIGlmIChwYXJhbS5nZXRFVHlwZSgpKSB7XHJcbiAgICAgICAgICAvLyBtYWtlIHN1cmUgdG8gaW1wb3J0IGFueSBwYXJhbWV0ZXIgdHlwZSwgaWYgbmVjZXNzYXJ5XHJcbiAgICAgICAgICB0aGlzLm1heWJlQWRkTWVtYmVySW1wb3J0cyhwa2csIGVDbGFzcywgcGFyYW0uZ2V0RVR5cGUoKSEpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGRlYnVnLmdyb3VwRW5kKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGVvcHNUb0ltcGxlbWVudChlQ2xhc3M6IEVDbGFzcykgOiBFTGlzdDxFT3BlcmF0aW9uPntcclxuICAgIGxldCBvcGVyYXRpb25zVG9JbXBsZW1lbnQgPSBuZXcgQmFzaWNFTGlzdDxFT3BlcmF0aW9uPihlQ2xhc3MuZ2V0RU9wZXJhdGlvbnMoKS5lbGVtZW50cygpKTtcclxuICAgIGZvciAoY29uc3Qgc3Qgb2YgZUNsYXNzLmdldEVTdXBlclR5cGVzKCkpIHtcclxuICAgICAgaWYgKHN0LmlzSW50ZXJmYWNlKCkpIHtcclxuICAgICAgICBvcGVyYXRpb25zVG9JbXBsZW1lbnQuYWRkQWxsKHN0LmdldEVPcGVyYXRpb25zKCkuZWxlbWVudHMoKSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBvcGVyYXRpb25zVG9JbXBsZW1lbnQ7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBQb3NzaWJseSBhZGRzIHRoZSB0eXBlIGFuZCBwYWNrYWdlIG9mICdldHlwZScgdG8gdGhlIGxpc3Qgb2YgdGhpbmdzXHJcbiAgICogdG8gaW1wb3J0LlxyXG4gICAqL1xyXG4gIHByaXZhdGUgbWF5YmVBZGRNZW1iZXJJbXBvcnRzKFxyXG4gICAgdGhpc1BhY2thZ2U6IEVQYWNrYWdlLFxyXG4gICAgdGhpc0VDbGFzczogRUNsYXNzLFxyXG4gICAgY2FuZGlkYXRlOiBFQ2xhc3NpZmllclxyXG4gICk6IHZvaWQge1xyXG4gICAgZGVidWcubG9nKGBFdmFsdWF0aW5nIGltcG9ydCBjYW5kaWRhdGU6ICR7Y2FuZGlkYXRlPy5nZXROYW1lKCl9YCk7XHJcblxyXG4gICAgaWYgKGNhbmRpZGF0ZSBpbnN0YW5jZW9mIEVDbGFzc0ltcGwgfHwgY2FuZGlkYXRlIGluc3RhbmNlb2YgRUVudW1JbXBsKSB7XHJcbiAgICAgIGNvbnN0IGNhbmRpZGF0ZVBhY2thZ2UgPSBjYW5kaWRhdGUuZ2V0RVBhY2thZ2UoKTtcclxuICAgICAgZGVidWcubG9nKFxyXG4gICAgICAgIGBDYW5kaWRhdGUgcGFja2FnZTogJHtjYW5kaWRhdGVQYWNrYWdlLmdldE5hbWUoKX0sIHRoaXMgcGFja2FnZTogJHt0aGlzUGFja2FnZS5nZXROYW1lKCl9YFxyXG4gICAgICApO1xyXG5cclxuICAgICAgaWYgKGNhbmRpZGF0ZVBhY2thZ2UgIT09IHRoaXNQYWNrYWdlKSB7XHJcbiAgICAgICAgZGVidWcubG9nKGBBZGRpbmcgcGFja2FnZSBpbXBvcnQ6ICR7Y2FuZGlkYXRlUGFja2FnZS5nZXROYW1lKCl9YCk7XHJcbiAgICAgICAgdGhpcy5lQ2xhc3NQa2dJbXBvcnRzLmFkZChjYW5kaWRhdGVQYWNrYWdlKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGNhbmRpZGF0ZSAhPT0gdGhpc0VDbGFzcykge1xyXG4gICAgICAgIC8vIEVjb3JlIHR5cGVzIGFyZSBpbXBvcnRlZCBmb3IgZXZlcnl0aGluZ1xyXG4gICAgICAgIGlmIChjYW5kaWRhdGVQYWNrYWdlICE9PSBFY29yZVBhY2thZ2UuZUlOU1RBTkNFICYmICF0aGlzLmVDbGFzc0FwaUltcG9ydHMuaGFzKGNhbmRpZGF0ZSkpIHtcclxuICAgICAgICAgIGRlYnVnLmxvZyhgQWRkaW5nIEFQSSBpbXBvcnQ6ICR7Y2FuZGlkYXRlLmdldE5hbWUoKX1gKTtcclxuICAgICAgICAgIHRoaXMuZUNsYXNzQXBpSW1wb3J0cy5hZGQoY2FuZGlkYXRlKTtcclxuICAgICAgICB9IFxyXG4gICAgICAgIGlmIChjYW5kaWRhdGVQYWNrYWdlICE9PSBFY29yZVBhY2thZ2UuZUlOU1RBTkNFICYmICF0aGlzLmVDbGFzc0dlbkltcG9ydHMuaGFzKGNhbmRpZGF0ZSkpIHtcclxuICAgICAgICAgIGRlYnVnLmxvZyhgQWRkaW5nIEdlbiBpbXBvcnQgZm9yICR7dGhpc0VDbGFzcy5nZXROYW1lKCl9OiAke2NhbmRpZGF0ZS5nZXROYW1lKCl9YCk7XHJcbiAgICAgICAgICB0aGlzLmVDbGFzc0dlbkltcG9ydHMuYWRkKGNhbmRpZGF0ZSk7XHJcbiAgICAgICAgfSAgICAgICAgIFxyXG4gICAgICAgIFxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgZGVidWcubG9nKGBTa2lwcGluZyBFY29yZSB0eXBlOiAke2NhbmRpZGF0ZS5nZXROYW1lKCl9YCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGRlYnVnLmxvZyhcclxuICAgICAgICAgIGBTa2lwcGluZyBpbXBvcnQgKGFscmVhZHkgZXhpc3RzIG9yIGlzIHNlbGYpOiAke2NhbmRpZGF0ZS5nZXROYW1lKCl9YFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEFkZCB0aGlzIG1ldGhvZCB0byB0aGUgVEdlbmVyYXRvck1haW4gY2xhc3NcclxuICBwcml2YXRlIGFzeW5jIHdyaXRlUGFja2FnZUluaXRpYWxpemVyRmlsZSgpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIC8vIE9ubHkgZ2VuZXJhdGUgZm9yIHJvb3QgcGFja2FnZXMgKHBhY2thZ2VzIHdpdGhvdXQgYSBzdXBlciBwYWNrYWdlKVxyXG4gICAgaWYgKHRoaXMucGtnLmdldEVTdXBlclBhY2thZ2UoKSkge1xyXG4gICAgICBkZWJ1Zy5sb2coJ1NraXBwaW5nIHBhY2thZ2UgaW5pdGlhbGl6ZXIgZm9yICcgKyB0aGlzLnBrZy5nZXROYW1lKCkgKyAnIC0gbm90IGEgcm9vdCBwYWNrYWdlJyk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBnZW5lcmF0b3IgPSBuZXcgVEdlbmVyYXRvclBhY2thZ2VJbml0aWFsaXplcigpO1xyXG4gICAgY29uc3QgZmlsZU5hbWUgPSBUR2VuZXJhdG9yUGFja2FnZUluaXRpYWxpemVyLmdlbmVyYXRlRmlsZU5hbWUodGhpcy5wa2cpO1xyXG4gICAgZGVidWcubG9nKCdHZW5lcmF0aW5nIHBhY2thZ2UgaW5pdGlhbGl6ZXIgZmlsZTonLCBmaWxlTmFtZSArICcudHMnKTtcclxuXHJcbiAgICBjb25zdCBjb250ZW50ID0gZ2VuZXJhdG9yLmdlbmVyYXRlKHRoaXMucGtnKTtcclxuICAgIGF3YWl0IHRoaXMud3JpdGVTb3VyY2VGaWxlKFxyXG4gICAgICB0aGlzLnBrZ1Jvb3RPdXREaXIsXHJcbiAgICAgIGZpbGVOYW1lICsgJy50cycsXHJcbiAgICAgIGNvbnRlbnQsXHJcbiAgICAgIHRydWVcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGFzeW5jIHdyaXRlUGFja2FnZVJlZ2lzdHJ5RmlsZSgpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIC8vIE9ubHkgZ2VuZXJhdGUgZm9yIHJvb3QgcGFja2FnZXMgKHBhY2thZ2VzIHdpdGhvdXQgYSBzdXBlciBwYWNrYWdlKVxyXG4gICAgaWYgKHRoaXMucGtnLmdldEVTdXBlclBhY2thZ2UoKSkge1xyXG4gICAgICBkZWJ1Zy5sb2coJ1NraXBwaW5nIHBhY2thZ2UgcmVnaXN0cnkgZm9yICcgKyB0aGlzLnBrZy5nZXROYW1lKCkgKyAnIC0gbm90IGEgcm9vdCBwYWNrYWdlJyk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBkZWJ1Zy5sb2coJ0dlbmVyYXRpbmcgcGFja2FnZSByZWdpc3RyeSBmaWxlOiBwYWNrYWdlLXJlZ2lzdHJ5LnRzJyk7XHJcblxyXG4gICAgY29uc3QgY29udGVudCA9IHRoaXMuZ2VuZXJhdGVQYWNrYWdlUmVnaXN0cnlDb250ZW50KCk7XHJcbiAgICBhd2FpdCB0aGlzLndyaXRlU291cmNlRmlsZShcclxuICAgICAgdGhpcy5wa2dSb290T3V0RGlyLFxyXG4gICAgICAncGFja2FnZS1yZWdpc3RyeS50cycsXHJcbiAgICAgIGNvbnRlbnQsXHJcbiAgICAgIHRydWVcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdlbmVyYXRlUGFja2FnZVJlZ2lzdHJ5Q29udGVudCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIGBpbXBvcnQgeyBUSnNvbiwgRUNsYXNzSW1wbCwgRUZhY3RvcnkgfSBmcm9tICdAdHJpcHNuZWsvdG1mJztcclxuaW1wb3J0IHR5cGUgeyBFUGFja2FnZUltcGwgfSBmcm9tICdAdHJpcHNuZWsvdG1mJztcclxuXHJcbi8qKlxyXG4gKiBSZWdpc3RyeSB0byB0cmFjayB3aGljaCBwYWNrYWdlcyBoYXZlIGJlZW4gaW5pdGlhbGl6ZWQgYW5kIHJlZ2lzdGVyZWQgd2l0aCBUSnNvbi5cclxuICogVGhpcyBlbmFibGVzIGluY3JlbWVudGFsIGluaXRpYWxpemF0aW9uIHdoaWxlIHByZXZlbnRpbmcgZHVwbGljYXRlIHdvcmsuXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgUGFja2FnZVJlZ2lzdHJ5IHtcclxuICBwcml2YXRlIHN0YXRpYyBpbml0aWFsaXplZFBhY2thZ2VzID0gbmV3IFNldDxzdHJpbmc+KCk7XHJcbiAgcHJpdmF0ZSBzdGF0aWMgcmVnaXN0ZXJlZFdpdGhUSnNvbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xyXG4gIHByaXZhdGUgc3RhdGljIGZhY3RvcnlDbGFzc2VzID0gbmV3IE1hcDxzdHJpbmcsICgpID0+IGFueT4oKTtcclxuXHJcbiAgLyoqXHJcbiAgICogTWFyayBhIHBhY2thZ2UgYXMgaW5pdGlhbGl6ZWQgKGNvbnRlbnRzIGNyZWF0ZWQgYW5kIHJlbGF0aW9uc2hpcHMgc2V0IHVwKVxyXG4gICAqL1xyXG4gIHN0YXRpYyBtYXJrSW5pdGlhbGl6ZWQocGFja2FnZU5hbWU6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5pbml0aWFsaXplZFBhY2thZ2VzLmFkZChwYWNrYWdlTmFtZSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDaGVjayBpZiBhIHBhY2thZ2UgaGFzIGJlZW4gaW5pdGlhbGl6ZWRcclxuICAgKi9cclxuICBzdGF0aWMgaXNJbml0aWFsaXplZChwYWNrYWdlTmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5pbml0aWFsaXplZFBhY2thZ2VzLmhhcyhwYWNrYWdlTmFtZSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSZWdpc3RlciBhIGZhY3RvcnkgY2xhc3MgY29uc3RydWN0b3IgZm9yIGEgcGFja2FnZVxyXG4gICAqL1xyXG4gIHN0YXRpYyByZWdpc3RlckZhY3RvcnlDbGFzcyhcclxuICAgIHBhY2thZ2VOYW1lOiBzdHJpbmcsXHJcbiAgICBmYWN0b3J5R2V0dGVyOiAoKSA9PiBhbnlcclxuICApOiB2b2lkIHtcclxuICAgIHRoaXMuZmFjdG9yeUNsYXNzZXMuc2V0KHBhY2thZ2VOYW1lLCBmYWN0b3J5R2V0dGVyKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldCB0aGUgZmFjdG9yeSBmb3IgYSBwYWNrYWdlIGFuZCBlbnN1cmUgaXQncyBpbml0aWFsaXplZFxyXG4gICAqL1xyXG4gIHN0YXRpYyBnZXRGYWN0b3J5KHBhY2thZ2VOYW1lOiBzdHJpbmcpOiBFRmFjdG9yeSB8IG51bGwge1xyXG4gICAgY29uc3QgZmFjdG9yeUdldHRlciA9IHRoaXMuZmFjdG9yeUNsYXNzZXMuZ2V0KHBhY2thZ2VOYW1lKTtcclxuICAgIGlmIChmYWN0b3J5R2V0dGVyKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgRmFjdG9yeUNsYXNzID0gZmFjdG9yeUdldHRlcigpO1xyXG4gICAgICAgIHJldHVybiBGYWN0b3J5Q2xhc3M/LmVJTlNUQU5DRSB8fCBudWxsO1xyXG4gICAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmVnaXN0ZXIgYSBwYWNrYWdlIHdpdGggVEpzb24gaWYgbm90IGFscmVhZHkgcmVnaXN0ZXJlZFxyXG4gICAqL1xyXG4gIHN0YXRpYyByZWdpc3RlcldpdGhUSnNvbihwYWNrYWdlTmFtZTogc3RyaW5nLCBwa2c6IEVQYWNrYWdlSW1wbCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMucmVnaXN0ZXJlZFdpdGhUSnNvbi5oYXMocGFja2FnZU5hbWUpKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnJlZ2lzdGVyZWRXaXRoVEpzb24uYWRkKHBhY2thZ2VOYW1lKTtcclxuXHJcbiAgICAvLyBFbnN1cmUgZmFjdG9yeSBpcyByZWdpc3RlcmVkIHdpdGggcGFja2FnZVxyXG4gICAgY29uc3QgZmFjdG9yeSA9IHRoaXMuZ2V0RmFjdG9yeShwYWNrYWdlTmFtZSk7XHJcbiAgICBpZiAoZmFjdG9yeSAmJiAhcGtnLmdldEVGYWN0b3J5SW5zdGFuY2UoKSkge1xyXG4gICAgICBwa2cuc2V0RUZhY3RvcnlJbnN0YW5jZShmYWN0b3J5KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWNvbXB1dGUgYWxsIGxpc3RzIGZvciBFQ2xhc3MgaW5zdGFuY2VzXHJcbiAgICBmb3IgKGNvbnN0IGUgb2YgcGtnLmdldEVDbGFzc2lmaWVycygpKSB7XHJcbiAgICAgIGlmIChlIGluc3RhbmNlb2YgRUNsYXNzSW1wbCkge1xyXG4gICAgICAgIGUucmVjb21wdXRlQWxsTGlzdHMoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlZ2lzdGVyIHdpdGggVEpzb25cclxuICAgIFRKc29uLmFkZFBhY2thZ2VzKFtwa2ddKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENoZWNrIGlmIGEgcGFja2FnZSBoYXMgYmVlbiByZWdpc3RlcmVkIHdpdGggVEpzb25cclxuICAgKi9cclxuICBzdGF0aWMgaXNSZWdpc3RlcmVkV2l0aFRKc29uKHBhY2thZ2VOYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLnJlZ2lzdGVyZWRXaXRoVEpzb24uaGFzKHBhY2thZ2VOYW1lKTtcclxuICB9XHJcbn1cclxuYDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFdyaXRlcyB0aGUgc291cmNlY29kZSBmaWxlIHRvIHRoZSBmaWxlIHN5c3RlbS5cclxuICAgKiBAcGFyYW0gb3V0RGlyXHJcbiAgICogQHBhcmFtIGZpbGVuYW1lXHJcbiAgICogQHBhcmFtIGNvbnRlbnRcclxuICAgKiBAcGFyYW0gb3ZlcndyaXRlXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBhc3luYyB3cml0ZVNvdXJjZUZpbGUoXHJcbiAgICBvdXREaXI6IHN0cmluZyxcclxuICAgIGZpbGVuYW1lOiBzdHJpbmcsXHJcbiAgICBjb250ZW50OiBzdHJpbmcsXHJcbiAgICBvdmVyd3JpdGU6IGJvb2xlYW5cclxuICApOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGF3YWl0IHRoaXMuZW5zdXJlTm9kZU1vZHVsZXNMb2FkZWQoKTtcclxuXHJcbiAgICBjb25zdCBmaWxlUGF0aCA9IHRoaXMucGF0aC5yZXNvbHZlKHByb2Nlc3MuY3dkKCksIG91dERpciArICcvJyArIGZpbGVuYW1lKTtcclxuICAgIGRlYnVnLmxvZyhgV3JpdGluZyBmaWxlOiAke2ZpbGVQYXRofWApO1xyXG4gICAgZGVidWcubG9nKFxyXG4gICAgICBgT3ZlcndyaXRlOiAke292ZXJ3cml0ZX0sIENvbnRlbnQgbGVuZ3RoOiAke2NvbnRlbnQubGVuZ3RofSBjaGFyYWN0ZXJzYFxyXG4gICAgKTtcclxuXHJcbiAgICBpZiAob3ZlcndyaXRlIHx8ICF0aGlzLmZzLmV4aXN0c1N5bmMoZmlsZVBhdGgpKSB7XHJcbiAgICAgIHRoaXMuZnMud3JpdGVGaWxlU3luYyhmaWxlUGF0aCwgY29udGVudCwgJ3V0ZjgnKTtcclxuICAgICAgZGVidWcubG9nKGBGaWxlIHdyaXR0ZW4gc3VjY2Vzc2Z1bGx5OiAke2ZpbGVuYW1lfWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgZGVidWcubG9nKGBGaWxlIHNraXBwZWQgKGFscmVhZHkgZXhpc3RzLCBvdmVyd3JpdGU9ZmFsc2UpOiAke2ZpbGVuYW1lfWApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhc3luYyBkZWxldGVGaWxlc0luRm9sZGVyKGRpcmVjdG9yeVBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgYXdhaXQgdGhpcy5lbnN1cmVOb2RlTW9kdWxlc0xvYWRlZCgpO1xyXG5cclxuICAgIGRlYnVnLmxvZyhgRGVsZXRpbmcgZmlsZXMgaW4gZm9sZGVyOiAke2RpcmVjdG9yeVBhdGh9YCk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgY29uc3QgZmlsZXMgPSB0aGlzLmZzLnJlYWRkaXJTeW5jKGRpcmVjdG9yeVBhdGgpO1xyXG4gICAgICBkZWJ1Zy5sb2coYEZvdW5kICR7ZmlsZXMubGVuZ3RofSBmaWxlKHMpIHRvIGRlbGV0ZWApO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGNvbnN0IGZpbGVQYXRoID0gdGhpcy5wYXRoLmpvaW4oZGlyZWN0b3J5UGF0aCwgZmlsZSk7XHJcbiAgICAgICAgICB0aGlzLmZzLnVubGlua1N5bmMoZmlsZVBhdGgpO1xyXG4gICAgICAgICAgZGVidWcubG9nKGBEZWxldGVkIGZpbGU6ICR7ZmlsZX1gKTtcclxuICAgICAgICB9IGNhdGNoIChlcnIpIHtcclxuICAgICAgICAgIC8vIFN3YWxsb3cgaW5kaXZpZHVhbCBmaWxlIGRlbGV0aW9uIGVycm9ycyBhcyBwZXIgb3JpZ2luYWwgbG9naWNcclxuICAgICAgICAgIGRlYnVnLndhcm4oYEZhaWxlZCB0byBkZWxldGUgZmlsZSAke2ZpbGV9OmAsIGVycik7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGRlYnVnLmxvZygnRmlsZSBkZWxldGlvbiBjb21wbGV0ZWQnKTtcclxuICAgIH0gY2F0Y2ggKGVycikge1xyXG4gICAgICBkZWJ1Zy5lcnJvcihgRmFpbGVkIHRvIHJlYWQgZGlyZWN0b3J5ICR7ZGlyZWN0b3J5UGF0aH06YCwgZXJyKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXN5bmMgdHJ5Rm9ybWF0V2l0aFByZXR0aWVyKCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgZGVidWcubG9nKCdBdHRlbXB0aW5nIHRvIGZvcm1hdCBjb2RlIHdpdGggUHJldHRpZXIuLi4nKTtcclxuXHJcbiAgICAvLyBGYWxsYmFjayB0byBjb21tYW5kIGxpbmUgcHJldHRpZXJcclxuICAgIHRyeSB7XHJcbiAgICAgIGlmICghdGhpcy5jaGlsZFByb2Nlc3MpIHtcclxuICAgICAgICBkZWJ1Zy5sb2coJ0xvYWRpbmcgY2hpbGRfcHJvY2VzcyBtb2R1bGUuLi4nKTtcclxuICAgICAgICB0aGlzLmNoaWxkUHJvY2VzcyA9IGF3YWl0IENvbmRpdGlvbmFsSW1wb3J0cy5nZXROb2RlTW9kdWxlKFxyXG4gICAgICAgICAgJ2NoaWxkX3Byb2Nlc3MnXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRm9ybWF0IG1haW4gb3V0cHV0IGRpcmVjdG9yeVxyXG4gICAgICBjb25zdCBtYWluUGF0aCA9IHRoaXMucGF0aC5yZXNvbHZlKHByb2Nlc3MuY3dkKCksIHRoaXMub3V0RGlyKTtcclxuICAgICAgZGVidWcubG9nKGBGb3JtYXR0aW5nIG1haW4gZGlyZWN0b3J5IHdpdGggQ0xJOiAke21haW5QYXRofWApO1xyXG4gICAgICB0aGlzLmNoaWxkUHJvY2Vzcy5leGVjU3luYyhgcHJldHRpZXIgLS13cml0ZSBcIiR7bWFpblBhdGh9XCJgKTtcclxuICAgICAgZGVidWcubG9nKCdNYWluIGRpcmVjdG9yeSBmb3JtYXR0ZWQgc3VjY2Vzc2Z1bGx5Jyk7XHJcblxyXG4gICAgICAvLyBGb3JtYXQgYmFycmVsIGZpbGUgZGlyZWN0b3J5IGlmIGl0IGV4aXN0c1xyXG4gICAgICBpZiAodGhpcy5iYXJyZWxGaWxlRGlyKSB7XHJcbiAgICAgICAgY29uc3QgYmFycmVsUGF0aCA9IHRoaXMucGF0aC5yZXNvbHZlKHByb2Nlc3MuY3dkKCksIHRoaXMuYmFycmVsRmlsZU91dERpcik7XHJcbiAgICAgICAgZGVidWcubG9nKGBGb3JtYXR0aW5nIGJhcnJlbCBkaXJlY3Rvcnkgd2l0aCBDTEk6ICR7YmFycmVsUGF0aH1gKTtcclxuICAgICAgICB0aGlzLmNoaWxkUHJvY2Vzcy5leGVjU3luYyhgcHJldHRpZXIgLS13cml0ZSBcIiR7YmFycmVsUGF0aH1cImApO1xyXG4gICAgICAgIGRlYnVnLmxvZygnQmFycmVsIGRpcmVjdG9yeSBmb3JtYXR0ZWQgc3VjY2Vzc2Z1bGx5Jyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGRlYnVnLmxvZygnQ0xJIFByZXR0aWVyIGZvcm1hdHRpbmcgY29tcGxldGVkIHN1Y2Nlc3NmdWxseScpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgZGVidWcud2FybignUHJldHRpZXIgZm9ybWF0dGluZyBmYWlsZWQ6JywgKGVycm9yIGFzIEVycm9yKS5tZXNzYWdlKTtcclxuICAgICAgZGVidWcud2FybignTWFrZSBzdXJlIHByZXR0aWVyIGlzIGluc3RhbGxlZDogbnBtIGluc3RhbGwgLWcgcHJldHRpZXInKTtcclxuICAgIH1cclxuICB9XHJcbn0iXX0=