Created
October 5, 2015 21:34
-
-
Save jvilk/a025f599d4e96d52ba4a to your computer and use it in GitHub Desktop.
TypeScript Source Map Bug
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <reference path="../vendor/DefinitelyTyped/node/node.d.ts" /> | |
/* | |
* Doppioh is DoppioJVM's answer to javah, although we realize the 'h' no longer | |
* has a meaning. | |
* | |
* Given a class or package name, Doppioh will generate JavaScript or TypeScript | |
* templates for the native methods of that class or package. | |
* | |
* Options: | |
* -classpath Where to search for classes/packages. | |
* -d [dir] Output directory | |
* -js JavaScript template [default] | |
* -ts [dir] TypeScript template, where 'dir' is a path to DoppioJVM's | |
* TypeScript definition files. | |
*/ | |
var optparse = require('../src/option_parser'); | |
var path = require('path'); | |
var fs = require('fs'); | |
var util = require('../src/util'); | |
var ClassData = require('../src/ClassData'); | |
/** | |
* Initializes the option parser with the options for the `doppioh` command. | |
*/ | |
function setupOptparse() { | |
optparse.describe({ | |
standard: { | |
classpath: { | |
alias: 'cp', | |
description: 'JVM classpath, "path1:...:pathN"', | |
has_value: true | |
}, | |
help: { alias: 'h', description: 'print this help message' }, | |
directory: { | |
alias: 'd', | |
description: 'Output directory', | |
has_value: true | |
}, | |
javascript: { | |
alias: 'js', | |
description: 'Generate JavaScript templates [default=true]' | |
}, | |
typescript: { | |
alias: 'ts', | |
description: 'Generate TypeScript templates, -ts path/to/doppio/interfaces', | |
has_value: true | |
}, | |
force_headers: { | |
alias: 'f', | |
description: '[TypeScript only] Forces doppioh to generate TypeScript headers for specified JVM classes, e.g. -f java.lang.String:java.lang.Object', | |
has_value: true | |
} | |
} | |
}); | |
} | |
function printEraseableLine(line) { | |
// Undocumented functions. | |
if (process.stdout['clearLine']) { | |
process.stdout.clearLine(); | |
process.stdout.cursorTo(0); | |
process.stdout.write(line); | |
} | |
} | |
function printHelp() { | |
process.stdout.write("Usage: doppioh [flags] class_or_package_name\n" + optparse.show_help() + "\n"); | |
} | |
setupOptparse(); | |
// Remove "node" and "path/to/doppioh.js". | |
var argv = optparse.parse(process.argv.slice(2)); | |
if (argv.standard.help || process.argv.length === 2) { | |
printHelp(); | |
process.exit(1); | |
} | |
if (!argv.standard.classpath) | |
argv.standard.classpath = '.'; | |
if (!argv.standard.directory) | |
argv.standard.directory = '.'; | |
function findFile(fileName) { | |
var i; | |
for (i = 0; i < classpath.length; i++) { | |
if (fs.existsSync(path.join(classpath[i], fileName))) { | |
return path.join(classpath[i], fileName); | |
} | |
else if (fs.existsSync(path.join(classpath[i], fileName + '.class'))) { | |
return path.join(classpath[i], fileName + '.class'); | |
} | |
} | |
} | |
var cache = {}; | |
function findClass(descriptor) { | |
if (cache[descriptor] !== undefined) { | |
return cache[descriptor]; | |
} | |
var rv; | |
try { | |
switch (descriptor[0]) { | |
case 'L': | |
rv = new ClassData.ReferenceClassData(fs.readFileSync(findFile(util.descriptor2typestr(descriptor) + ".class"))); | |
// Resolve the class. | |
var superClassRef = rv.getSuperClassReference(), interfaceClassRefs = rv.getInterfaceClassReferences(), superClass = null, interfaceClasses = []; | |
if (superClassRef !== null) { | |
superClass = findClass(superClassRef.name); | |
} | |
if (interfaceClassRefs.length > 0) { | |
interfaceClasses = interfaceClassRefs.map(function (iface) { return findClass(iface.name); }); | |
} | |
rv.setResolved(superClass, interfaceClasses); | |
break; | |
case '[': | |
rv = new ClassData.ArrayClassData(descriptor.slice(1), null); | |
break; | |
default: | |
rv = new ClassData.PrimitiveClassData(descriptor, null); | |
break; | |
} | |
cache[descriptor] = rv; | |
return rv; | |
} | |
catch (e) { | |
throw new Error("Unable to read class file for " + descriptor + ": " + e + "\n" + e.stack); | |
} | |
} | |
function getFiles(dirName) { | |
var rv = [], files = fs.readdirSync(dirName), i, file; | |
for (i = 0; i < files.length; i++) { | |
file = path.join(dirName, files[i]); | |
if (fs.statSync(file).isDirectory()) { | |
rv = rv.concat(getFiles(file)); | |
} | |
else if (file.indexOf('.class') === (file.length - 6)) { | |
rv.push(file); | |
} | |
} | |
return rv; | |
} | |
function processClassData(stream, template, classData) { | |
var fixedClassName = classData.getInternalName().replace(/\//g, '_'), nativeFound = false; | |
// Shave off L and ; | |
fixedClassName = fixedClassName.substring(1, fixedClassName.length - 1); | |
var methods = classData.getMethods(); | |
methods.forEach(function (method) { | |
if (method.accessFlags.isNative()) { | |
if (!nativeFound) { | |
template.classStart(stream, fixedClassName); | |
nativeFound = true; | |
} | |
template.method(stream, classData.getInternalName(), method.signature, method.accessFlags.isStatic(), method.parameterTypes, method.returnType); | |
} | |
}); | |
if (nativeFound) { | |
template.classEnd(stream, fixedClassName); | |
} | |
} | |
/** | |
* TypeScript output template. | |
*/ | |
var TSTemplate = (function () { | |
function TSTemplate(outputPath, interfacePath) { | |
var _this = this; | |
this.interfacePath = interfacePath; | |
this.headerCount = 0; | |
this.headerSet = {}; | |
this.classesSeen = []; | |
this.headerPath = path.resolve(argv.standard.directory, "JVMTypes.d.ts"); | |
this.generateQueue = []; | |
this.relativeInterfacePath = path.relative(outputPath, interfacePath); | |
// Parse existing types file for existing definitions. We'll remake them. | |
try { | |
var existingHeaders = fs.readFileSync(this.headerPath).toString(), searchIdx = 0, clsName; | |
// Pass 1: Classes. | |
while ((searchIdx = existingHeaders.indexOf("export class ", searchIdx)) > -1) { | |
clsName = existingHeaders.slice(searchIdx + 13, existingHeaders.indexOf(" ", searchIdx + 13)); | |
if (clsName.indexOf("JVMArray") !== 0) { | |
this.generateClassDefinition(this.tstype2jvmtype(clsName)); | |
} | |
searchIdx++; | |
} | |
searchIdx = 0; | |
// Pass 2: Interfaces. | |
while ((searchIdx = existingHeaders.indexOf("export interface ", searchIdx)) > -1) { | |
clsName = existingHeaders.slice(searchIdx + 17, existingHeaders.indexOf(" ", searchIdx + 17)); | |
this.generateClassDefinition(this.tstype2jvmtype(clsName)); | |
searchIdx++; | |
} | |
} | |
catch (e) { | |
// Ignore. | |
console.log("Error parsing exiting file: " + e); | |
} | |
this.headerStream = fs.createWriteStream(this.headerPath); | |
this.headersStart(); | |
// Generate required types. | |
this.generateArrayDefinition(); | |
this.generateClassDefinition('Ljava/lang/Throwable;'); | |
if (argv.standard.force_headers) { | |
var clses = argv.standard.force_headers.split(':'); | |
clses.forEach(function (clsName) { | |
_this.generateClassDefinition(util.int_classname(clsName)); | |
}); | |
} | |
} | |
TSTemplate.prototype.headersStart = function () { | |
var _this = this; | |
this.headerStream.write("// TypeScript declaration file for JVM types. Automatically generated by doppioh.\n// http://github.com/plasma-umass/doppio\n" + fs.readdirSync(path.resolve(this.interfacePath, "src")).map(function (item) { | |
return (item.indexOf('.ts') !== -1 && item[0] !== '.') ? "import " + item.slice(0, item.indexOf('.')) + " = require(\"" + path.join(_this.relativeInterfacePath, 'src', item.slice(0, item.indexOf('.'))) + "\");\n" : ''; | |
}).join("") + "\n\ndeclare module JVMTypes {\n"); | |
}; | |
TSTemplate.prototype.getExtension = function () { return 'ts'; }; | |
TSTemplate.prototype.fileStart = function (stream) { | |
// Reference all of the doppio interfaces. | |
var srcInterfacePath = path.join(this.interfacePath, 'src'), files = fs.readdirSync(srcInterfacePath), i, file; | |
stream.write("import JVMTypes = require(\"./JVMTypes\");\n"); | |
for (i = 0; i < files.length; i++) { | |
file = files[i]; | |
if (file.substring(file.length - 4) === 'd.ts') { | |
// Strip off '.d.ts'. | |
var modName = file.substring(0, file.length - 5); | |
stream.write('import ' + modName + ' = require("' + path.join(this.relativeInterfacePath, 'src', modName).replace(/\\/g, '/') + '");\n'); | |
} | |
} | |
stream.write("\ndeclare var registerNatives: (natives: any) => void;\n"); | |
}; | |
TSTemplate.prototype.fileEnd = function (stream) { | |
var i; | |
// Export everything! | |
stream.write("\n// Export line. This is what DoppioJVM sees.\nregisterNatives({"); | |
for (i = 0; i < this.classesSeen.length; i++) { | |
var kls = this.classesSeen[i]; | |
if (i > 0) | |
stream.write(','); | |
stream.write("\n '" + kls.replace(/_/g, '/') + "': " + kls); | |
} | |
stream.write("\n});\n"); | |
}; | |
/** | |
* Emits TypeScript type declarations. Separated from fileEnd, since one can | |
* use doppioh to emit headers only. | |
*/ | |
TSTemplate.prototype.headersEnd = function () { | |
this._processGenerateQueue(); | |
// Print newline to clear eraseable line. | |
printEraseableLine("Processed " + this.headerCount + " classes.\n"); | |
this.headerStream.end("}\nexport = JVMTypes;\n", function () { }); | |
}; | |
TSTemplate.prototype.classStart = function (stream, className) { | |
stream.write("\nclass " + className + " {\n"); | |
this.classesSeen.push(className); | |
this.generateClassDefinition("L" + className.replace(/_/g, "/") + ";"); | |
}; | |
TSTemplate.prototype.classEnd = function (stream, className) { | |
stream.write("\n}\n"); | |
}; | |
TSTemplate.prototype.method = function (stream, classDesc, methodName, isStatic, argTypes, rType) { | |
var _this = this; | |
var trueRtype = this.jvmtype2tstype(rType), rval = ""; | |
if (trueRtype === 'number') { | |
rval = "0"; | |
} | |
else if (trueRtype !== 'void') { | |
rval = "null"; | |
} | |
argTypes.concat([rType]).forEach(function (type) { | |
_this.generateClassDefinition(type); | |
}); | |
stream.write("\n public static '" + methodName + "'(thread: threading.JVMThread" + (isStatic ? '' : ", javaThis: " + this.jvmtype2tstype(classDesc)) + (argTypes.length === 0 ? '' : ', ' + argTypes.map(function (type, i) { return ("arg" + i + ": " + _this.jvmtype2tstype(type)); }).join(", ")) + "): " + this.jvmtype2tstype(rType) + " {\n thread.throwNewException('Ljava/lang/UnsatisfiedLinkError;', 'Native method not implemented.');" + (rval !== '' ? "\n return " + rval + ";" : '') + "\n }\n"); | |
}; | |
/** | |
* Converts a typestring to its equivalent TypeScript type. | |
*/ | |
TSTemplate.prototype.jvmtype2tstype = function (desc, prefix) { | |
if (prefix === void 0) { prefix = true; } | |
switch (desc[0]) { | |
case '[': | |
return (prefix ? 'JVMTypes.' : '') + ("JVMArray<" + this.jvmtype2tstype(desc.slice(1), prefix) + ">"); | |
case 'L': | |
// Ensure all converted reference types get generated headers. | |
this.generateClassDefinition(desc); | |
return (prefix ? 'JVMTypes.' : '') + util.descriptor2typestr(desc).replace(/_/g, '__').replace(/\//g, '_'); | |
case 'J': | |
return 'gLong'; | |
case 'V': | |
return 'void'; | |
default: | |
// Primitives. | |
return 'number'; | |
} | |
}; | |
/** | |
* Converts a TypeScript type into its equivalent JVM type. | |
*/ | |
TSTemplate.prototype.tstype2jvmtype = function (tsType) { | |
if (tsType.indexOf('JVMArray') === 0) { | |
return "[" + this.tstype2jvmtype(tsType.slice(9, tsType.length - 1)); | |
} | |
else if (tsType === 'number') { | |
throw new Error("Ambiguous."); | |
} | |
else if (tsType === 'void') { | |
return 'V'; | |
} | |
else { | |
// _ => /, and // => _ since we encode underscores as double underscores. | |
return "L" + tsType.replace(/_/g, '/').replace(/\/\//g, '_') + ";"; | |
} | |
}; | |
/** | |
* Generates a TypeScript class definition for the given class object. | |
*/ | |
TSTemplate.prototype.generateClassDefinition = function (desc) { | |
if (this.headerSet[desc] !== undefined || util.is_primitive_type(desc)) { | |
// Already generated, or is a primitive. | |
return; | |
} | |
else if (desc[0] === '[') { | |
// Ensure component type is created. | |
return this.generateClassDefinition(desc.slice(1)); | |
} | |
else { | |
// Mark this class as queued for headerification. We use a queue instead | |
// of a recursive scheme to avoid stack overflows. | |
this.headerSet[desc] = true; | |
this.generateQueue.push(findClass(desc)); | |
} | |
}; | |
TSTemplate.prototype._processHeader = function (cls) { | |
var _this = this; | |
var desc = cls.getInternalName(), interfaces = cls.getInterfaceClassReferences().map(function (iface) { return iface.name; }), superClass = cls.getSuperClassReference(), methods = cls.getMethods().concat(cls.getMirandaAndDefaultMethods()), fields = cls.getFields(), methodsSeen = {}, injectedFields = cls.getInjectedFields(), injectedMethods = cls.getInjectedMethods(), injectedStaticMethods = cls.getInjectedStaticMethods(); | |
printEraseableLine("[" + this.headerCount++ + "] Processing header for " + util.descriptor2typestr(desc) + "..."); | |
if (cls.accessFlags.isInterface()) { | |
// Interfaces map to TypeScript interfaces. | |
this.headerStream.write(" export interface " + this.jvmtype2tstype(desc, false)); | |
} | |
else { | |
this.headerStream.write(" export class " + this.jvmtype2tstype(desc, false)); | |
} | |
// Note: Interface classes have java.lang.Object as a superclass. | |
// While java_lang_Object is a class, TypeScript will extract an interface | |
// for the class under-the-covers and extract it, correctly providing us | |
// with injected JVM methods on interface types (e.g. getClass()). | |
if (superClass !== null) { | |
this.headerStream.write(" extends " + this.jvmtype2tstype(superClass.name, false)); | |
} | |
if (interfaces.length > 0) { | |
if (cls.accessFlags.isInterface()) { | |
// Interfaces can extend multiple interfaces, and can extend classes! | |
// Add a comma after the guaranteed "java_lang_Object". | |
this.headerStream.write(", "); | |
} | |
else { | |
// Classes can implement multiple interfaces. | |
this.headerStream.write(" implements "); | |
} | |
this.headerStream.write("" + interfaces.map(function (ifaceName) { return _this.jvmtype2tstype(ifaceName, false); }).join(", ")); | |
} | |
this.headerStream.write(" {\n"); | |
Object.keys(injectedFields).forEach(function (name) { return _this._outputInjectedField(name, injectedFields[name], _this.headerStream); }); | |
Object.keys(injectedMethods).forEach(function (name) { return _this._outputInjectedMethod(name, injectedMethods[name], _this.headerStream); }); | |
Object.keys(injectedStaticMethods).forEach(function (name) { return _this._outputInjectedStaticMethod(name, injectedStaticMethods[name], _this.headerStream); }); | |
fields.forEach(function (f) { return _this._outputField(f, _this.headerStream); }); | |
methods.forEach(function (m) { return _this._outputMethod(m, _this.headerStream); }); | |
cls.getUninheritedDefaultMethods().forEach(function (m) { return _this._outputMethod(m, _this.headerStream); }); | |
this.headerStream.write(" }\n"); | |
}; | |
/** | |
* Outputs a method signature for the given method on the given stream. | |
* NOTE: We require a class argument because default interface methods are | |
* defined on classes, not on the interfaces they belong to. | |
*/ | |
TSTemplate.prototype._outputMethod = function (m, stream, nonVirtualOnly) { | |
var _this = this; | |
if (nonVirtualOnly === void 0) { nonVirtualOnly = false; } | |
var argTypes = m.parameterTypes, rType = m.returnType, args = "", cbSig = "e?: java_lang_Throwable" + (rType === 'V' ? "" : ", rv?: " + this.jvmtype2tstype(rType, false)), methodSig, methodFlags = "public" + (m.accessFlags.isStatic() ? ' static' : ''); | |
if (argTypes.length > 0) { | |
// Arguments are a giant tuple type. | |
// NOTE: Long / doubles take up two argument slots. The second argument is always NULL. | |
args = "args: [" + argTypes.map(function (type, i) { return ("" + _this.jvmtype2tstype(type, false) + ((type === "J" || type === "D") ? ', any' : '')); }).join(", ") + "], "; | |
} | |
methodSig = "(thread: threading.JVMThread, " + args + "cb?: (" + cbSig + ") => void): void"; | |
// A quick note about methods: It's illegal to have two methods with the | |
// same signature in the same class, even if one is static and the other | |
// isn't. | |
if (m.cls.accessFlags.isInterface()) { | |
if (m.accessFlags.isStatic()) { | |
} | |
else { | |
// Virtual only, TypeScript interface syntax. | |
stream.write(" \"" + m.signature + "\"" + methodSig + ";\n"); | |
} | |
} | |
else { | |
if (!nonVirtualOnly) { | |
stream.write(" " + methodFlags + " \"" + m.signature + "\"" + methodSig + ";\n"); | |
} | |
stream.write(" " + methodFlags + " \"" + m.fullSignature + "\"" + methodSig + ";\n"); | |
} | |
}; | |
/** | |
* Outputs the field's type for the given field on the given stream. | |
*/ | |
TSTemplate.prototype._outputField = function (f, stream) { | |
var fieldType = f.rawDescriptor, cls = f.cls; | |
if (cls.accessFlags.isInterface()) { | |
// XXX: Ignore static interface fields for now, as reconciling them with TypeScript's | |
// type system would be messy. | |
return; | |
} | |
if (f.accessFlags.isStatic()) { | |
stream.write(" public static \"" + util.descriptor2typestr(cls.getInternalName()) + "/" + f.name + "\": " + this.jvmtype2tstype(fieldType, false) + ";\n"); | |
} | |
else { | |
stream.write(" public \"" + util.descriptor2typestr(cls.getInternalName()) + "/" + f.name + "\": " + this.jvmtype2tstype(fieldType, false) + ";\n"); | |
} | |
}; | |
/** | |
* Outputs information on a field injected by the JVM. | |
*/ | |
TSTemplate.prototype._outputInjectedField = function (name, type, stream) { | |
stream.write(" public " + name + ": " + type + ";\n"); | |
}; | |
/** | |
* Output information on a method injected by the JVM. | |
*/ | |
TSTemplate.prototype._outputInjectedMethod = function (name, type, stream) { | |
stream.write(" public " + name + type + ";\n"); | |
}; | |
/** | |
* Output information on a static method injected by the JVM. | |
*/ | |
TSTemplate.prototype._outputInjectedStaticMethod = function (name, type, stream) { | |
stream.write(" public static " + name + type + ";\n"); | |
}; | |
TSTemplate.prototype._processGenerateQueue = function () { | |
while (this.generateQueue.length > 0) { | |
this._processHeader(this.generateQueue.pop()); | |
} | |
}; | |
/** | |
* Generates the generic JVM array type definition. | |
*/ | |
TSTemplate.prototype.generateArrayDefinition = function () { | |
this.headerStream.write(" export class JVMArray<T> extends java_lang_Object {\n /**\n * NOTE: Our arrays are either JS arrays, or TypedArrays for primitive\n * types.\n */\n public array: T[];\n public getClass(): ClassData.ArrayClassData<T>;\n /**\n * Create a new JVM array of this type that starts at start, and ends at\n * end. End defaults to the end of the array.\n */\n public slice(start: number, end?: number): JVMArray<T>;\n }\n"); | |
}; | |
return TSTemplate; | |
})(); | |
/** | |
* JavaScript output template. | |
*/ | |
var JSTemplate = (function () { | |
function JSTemplate() { | |
this.firstMethod = true; | |
this.firstClass = true; | |
} | |
JSTemplate.prototype.getExtension = function () { return 'js'; }; | |
JSTemplate.prototype.fileStart = function (stream) { | |
stream.write("// This entire object is exported. Feel free to define private helper functions above it.\nregisterNatives({"); | |
}; | |
JSTemplate.prototype.fileEnd = function (stream) { | |
stream.write("\n});\n"); | |
}; | |
JSTemplate.prototype.classStart = function (stream, className) { | |
this.firstMethod = true; | |
if (this.firstClass) { | |
this.firstClass = false; | |
} | |
else { | |
stream.write(",\n"); | |
} | |
stream.write("\n '" + className.replace(/_/g, '/') + "': {\n"); | |
}; | |
JSTemplate.prototype.classEnd = function (stream, className) { | |
stream.write("\n\n }"); | |
}; | |
JSTemplate.prototype.method = function (stream, classDesc, methodName, isStatic, argTypes, rType) { | |
// Construct the argument signature, figured out from the methodName. | |
var argSig = 'thread', i; | |
if (!isStatic) { | |
argSig += ', javaThis'; | |
} | |
for (i = 0; i < argTypes.length; i++) { | |
argSig += ', arg' + i; | |
} | |
if (this.firstMethod) { | |
this.firstMethod = false; | |
} | |
else { | |
// End the previous method. | |
stream.write(',\n'); | |
} | |
stream.write("\n '" + methodName + "': function(" + argSig + ") {"); | |
stream.write("\n thread.throwNewException('Ljava/lang/UnsatisfiedLinkError;', 'Native method not implemented.');"); | |
stream.write("\n }"); | |
}; | |
return JSTemplate; | |
})(); | |
if (!fs.existsSync(argv.standard.directory)) { | |
fs.mkdirSync(argv.standard.directory); | |
} | |
var classpath = argv.standard.classpath.split(':'), targetName = argv.className.replace(/\//g, '_').replace(/\./g, '_'), className = argv.className.replace(/\./g, '/'), template, stream, targetLocation; | |
targetLocation = findFile(className); | |
if (typeof targetLocation !== 'string') { | |
console.error('Unable to find location: ' + className); | |
process.exit(0); | |
} | |
template = argv.standard.typescript ? new TSTemplate(argv.standard.directory, argv.standard.typescript) : new JSTemplate(); | |
stream = fs.createWriteStream(path.join(argv.standard.directory, targetName + '.' + template.getExtension())); | |
template.fileStart(stream); | |
if (fs.statSync(targetLocation).isDirectory()) { | |
getFiles(targetLocation).forEach(function (cname) { | |
processClassData(stream, template, new ClassData.ReferenceClassData(fs.readFileSync(cname))); | |
}); | |
} | |
else { | |
processClassData(stream, template, new ClassData.ReferenceClassData(fs.readFileSync(targetLocation))); | |
} | |
template.fileEnd(stream); | |
if (argv.standard.typescript) { | |
template.headersEnd(); | |
} | |
stream.end(new Buffer(''), function () { }); | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9wcGlvaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2NvbnNvbGUvZG9wcGlvaC50cyJdLCJuYW1lcyI6WyJzZXR1cE9wdHBhcnNlIiwicHJpbnRFcmFzZWFibGVMaW5lIiwicHJpbnRIZWxwIiwiZmluZEZpbGUiLCJmaW5kQ2xhc3MiLCJnZXRGaWxlcyIsInByb2Nlc3NDbGFzc0RhdGEiLCJUU1RlbXBsYXRlIiwiVFNUZW1wbGF0ZS5jb25zdHJ1Y3RvciIsIlRTVGVtcGxhdGUuaGVhZGVyc1N0YXJ0IiwiVFNUZW1wbGF0ZS5nZXRFeHRlbnNpb24iLCJUU1RlbXBsYXRlLmZpbGVTdGFydCIsIlRTVGVtcGxhdGUuZmlsZUVuZCIsIlRTVGVtcGxhdGUuaGVhZGVyc0VuZCIsIlRTVGVtcGxhdGUuY2xhc3NTdGFydCIsIlRTVGVtcGxhdGUuY2xhc3NFbmQiLCJUU1RlbXBsYXRlLm1ldGhvZCIsIlRTVGVtcGxhdGUuanZtdHlwZTJ0c3R5cGUiLCJUU1RlbXBsYXRlLnRzdHlwZTJqdm10eXBlIiwiVFNUZW1wbGF0ZS5nZW5lcmF0ZUNsYXNzRGVmaW5pdGlvbiIsIlRTVGVtcGxhdGUuX3Byb2Nlc3NIZWFkZXIiLCJUU1RlbXBsYXRlLl9vdXRwdXRNZXRob2QiLCJUU1RlbXBsYXRlLl9vdXRwdXRGaWVsZCIsIlRTVGVtcGxhdGUuX291dHB1dEluamVjdGVkRmllbGQiLCJUU1RlbXBsYXRlLl9vdXRwdXRJbmplY3RlZE1ldGhvZCIsIlRTVGVtcGxhdGUuX291dHB1dEluamVjdGVkU3RhdGljTWV0aG9kIiwiVFNUZW1wbGF0ZS5fcHJvY2Vzc0dlbmVyYXRlUXVldWUiLCJUU1RlbXBsYXRlLmdlbmVyYXRlQXJyYXlEZWZpbml0aW9uIiwiSlNUZW1wbGF0ZSIsIkpTVGVtcGxhdGUuY29uc3RydWN0b3IiLCJKU1RlbXBsYXRlLmdldEV4dGVuc2lvbiIsIkpTVGVtcGxhdGUuZmlsZVN0YXJ0IiwiSlNUZW1wbGF0ZS5maWxlRW5kIiwiSlNUZW1wbGF0ZS5jbGFzc1N0YXJ0IiwiSlNUZW1wbGF0ZS5jbGFzc0VuZCIsIkpTVGVtcGxhdGUubWV0aG9kIl0sIm1hcHBpbmdzIjoiQUFBQSxpRUFBaUU7QUFDakU7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILElBQU8sUUFBUSxXQUFXLHNCQUFzQixDQUFDLENBQUM7QUFDbEQsSUFBTyxJQUFJLFdBQVcsTUFBTSxDQUFDLENBQUM7QUFDOUIsSUFBTyxFQUFFLFdBQVcsSUFBSSxDQUFDLENBQUM7QUFDMUIsSUFBTyxJQUFJLFdBQVcsYUFBYSxDQUFDLENBQUM7QUFDckMsSUFBTyxTQUFTLFdBQVcsa0JBQWtCLENBQUMsQ0FBQztBQUsvQzs7R0FFRztBQUNIO0lBQ0VBLFFBQVFBLENBQUNBLFFBQVFBLENBQUNBO1FBQ2hCQSxRQUFRQSxFQUFFQTtZQUNSQSxTQUFTQSxFQUFFQTtnQkFDVEEsS0FBS0EsRUFBRUEsSUFBSUE7Z0JBQ1hBLFdBQVdBLEVBQUVBLGtDQUFrQ0E7Z0JBQy9DQSxTQUFTQSxFQUFFQSxJQUFJQTthQUNoQkE7WUFDREEsSUFBSUEsRUFBRUEsRUFBRUEsS0FBS0EsRUFBRUEsR0FBR0EsRUFBRUEsV0FBV0EsRUFBRUEseUJBQXlCQSxFQUFFQTtZQUM1REEsU0FBU0EsRUFBRUE7Z0JBQ1RBLEtBQUtBLEVBQUVBLEdBQUdBO2dCQUNWQSxXQUFXQSxFQUFFQSxrQkFBa0JBO2dCQUMvQkEsU0FBU0EsRUFBRUEsSUFBSUE7YUFDaEJBO1lBQ0RBLFVBQVVBLEVBQUVBO2dCQUNWQSxLQUFLQSxFQUFFQSxJQUFJQTtnQkFDWEEsV0FBV0EsRUFBRUEsOENBQThDQTthQUM1REE7WUFDREEsVUFBVUEsRUFBRUE7Z0JBQ1ZBLEtBQUtBLEVBQUVBLElBQUlBO2dCQUNYQSxXQUFXQSxFQUFFQSw4REFBOERBO2dCQUMzRUEsU0FBU0EsRUFBRUEsSUFBSUE7YUFDaEJBO1lBQ0RBLGFBQWFBLEVBQUVBO2dCQUNiQSxLQUFLQSxFQUFFQSxHQUFHQTtnQkFDVkEsV0FBV0EsRUFBRUEsc0lBQXNJQTtnQkFDbkpBLFNBQVNBLEVBQUVBLElBQUlBO2FBQ2hCQTtTQUNGQTtLQUNGQSxDQUFDQSxDQUFDQTtBQUNMQSxDQUFDQTtBQUVELDRCQUE0QixJQUFZO0lBQ3RDQywwQkFBMEJBO0lBQzFCQSxFQUFFQSxDQUFDQSxDQUFRQSxPQUFPQSxDQUFDQSxNQUFPQSxDQUFDQSxXQUFXQSxDQUFDQSxDQUFDQSxDQUFDQSxDQUFDQTtRQUNqQ0EsT0FBT0EsQ0FBQ0EsTUFBT0EsQ0FBQ0EsU0FBU0EsRUFBRUEsQ0FBQ0E7UUFDNUJBLE9BQU9BLENBQUNBLE1BQU9BLENBQUNBLFFBQVFBLENBQUNBLENBQUNBLENBQUNBLENBQUNBO1FBQ25DQSxPQUFPQSxDQUFDQSxNQUFNQSxDQUFDQSxLQUFLQSxDQUFDQSxJQUFJQSxDQUFDQSxDQUFDQTtJQUM3QkEsQ0FBQ0E7QUFDSEEsQ0FBQ0E7QUFFRDtJQUNFQyxPQUFPQSxDQUFDQSxNQUFNQSxDQUFDQSxLQUFLQSxDQUFDQSxnREFBZ0RBLEdBQUdBLFFBQVFBLENBQUNBLFNBQVNBLEVBQUVBLEdBQUdBLElBQUlBLENBQUNBLENBQUNBO0FBQ3ZHQSxDQUFDQTtBQUVELGFBQWEsRUFBRSxDQUFDO0FBRWhCLDBDQUEwQztBQUMxQyxJQUFJLElBQUksR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFFakQsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNwRCxTQUFTLEVBQUUsQ0FBQztJQUNaLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDbEIsQ0FBQztBQUNELEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUM7SUFBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsR0FBRyxHQUFHLENBQUM7QUFDNUQsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQztJQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxHQUFHLEdBQUcsQ0FBQztBQUU1RCxrQkFBa0IsUUFBZ0I7SUFDaENDLElBQUlBLENBQVNBLENBQUNBO0lBQ2RBLEdBQUdBLENBQUNBLENBQUNBLENBQUNBLEdBQUdBLENBQUNBLEVBQUVBLENBQUNBLEdBQUdBLFNBQVNBLENBQUNBLE1BQU1BLEVBQUVBLENBQUNBLEVBQUVBLEVBQUVBLENBQUNBO1FBQ3RDQSxFQUFFQSxDQUFDQSxDQUFDQSxFQUFFQSxDQUFDQSxVQUFVQSxDQUFDQSxJQUFJQSxDQUFDQSxJQUFJQSxDQUFDQSxTQUFTQSxDQUFDQSxDQUFDQSxDQUFDQSxFQUFFQSxRQUFRQSxDQUFDQSxDQUFDQSxDQUFDQSxDQUFDQSxDQUFDQTtZQUNyREEsTUFBTUEsQ0FBQ0EsSUFBSUEsQ0FBQ0EsSUFBSUEsQ0FBQ0EsU0FBU0EsQ0FBQ0EsQ0FBQ0EsQ0FBQ0EsRUFBRUEsUUFBUUEsQ0FBQ0EsQ0FBQ0E7UUFDM0NBLENBQUNBO1FBQUNBLElBQUlBLENBQUNBLEVBQUVBLENBQUNBLENBQUNBLEVBQUVBLENBQUNBLFVBQVVBLENBQUNBLElBQUlBLENBQUNBLElBQUlBLENBQUNBLFNBQVNBLENBQUNBLENBQUNBLENBQUNBLEVBQUVBLFFBQVFBLEdBQUdBLFFBQVFBLENBQUNBLENBQUNBLENBQUNBLENBQUNBLENBQUNBO1lBQ3ZFQSxNQUFNQSxDQUFDQSxJQUFJQSxDQUFDQSxJQUFJQSxDQUFDQSxTQUFTQSxDQUFDQSxDQUFDQSxDQUFDQSxFQUFFQSxRQUFRQSxHQUFHQSxRQUFRQSxDQUFDQSxDQUFDQTtRQUN0REEsQ0FBQ0E7SUFDSEEsQ0FBQ0E7QUFDSEEsQ0FBQ0E7QUFFRCxJQUFJLEtBQUssR0FBMEMsRUFBRSxDQUFDO0FBQ3RELG1CQUFtQixVQUFrQjtJQUNuQ0MsRUFBRUEsQ0FBQ0EsQ0FBQ0EsS0FBS0EsQ0FBQ0EsVUFBVUEsQ0FBQ0EsS0FBS0EsU0FBU0EsQ0FBQ0EsQ0FBQ0Es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LFFBQVEsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDM0IsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDOUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxVQUFDLEtBQWE7UUFDN0MsZ0JBQWdCLENBQUMsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMvRixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFBQyxJQUFJLENBQUMsQ0FBQztJQUNOLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxRQUFRLEVBQUUsSUFBSSxTQUFTLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDeEcsQ0FBQztBQUNELFFBQVEsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDekIsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQ2YsUUFBUyxDQUFDLFVBQVUsRUFBRSxDQUFDO0FBQ3ZDLENBQUM7QUFDRCxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLGNBQU8sQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLy8gPHJlZmVyZW5jZSBwYXRoPVwiLi4vdmVuZG9yL0RlZmluaXRlbHlUeXBlZC9ub2RlL25vZGUuZC50c1wiIC8+XG4vKlxuICogRG9wcGlvaCBpcyBEb3BwaW9KVk0ncyBhbnN3ZXIgdG8gamF2YWgsIGFsdGhvdWdoIHdlIHJlYWxpemUgdGhlICdoJyBubyBsb25nZXJcbiAqIGhhcyBhIG1lYW5pbmcuXG4gKlxuICogR2l2ZW4gYSBjbGFzcyBvciBwYWNrYWdlIG5hbWUsIERvcHBpb2ggd2lsbCBnZW5lcmF0ZSBKYXZhU2NyaXB0IG9yIFR5cGVTY3JpcHRcbiAqIHRlbXBsYXRlcyBmb3IgdGhlIG5hdGl2ZSBtZXRob2RzIG9mIHRoYXQgY2xhc3Mgb3IgcGFja2FnZS5cbiAqXG4gKiBPcHRpb25zOlxuICogLWNsYXNzcGF0aCBXaGVyZSB0byBzZWFyY2ggZm9yIGNsYXNzZXMvcGFja2FnZXMuXG4gKiAtZCBbZGlyXSAgIE91dHB1dCBkaXJlY3RvcnlcbiAqIC1qcyAgICAgICAgSmF2YVNjcmlwdCB0ZW1wbGF0ZSBbZGVmYXVsdF1cbiAqIC10cyBbZGlyXSAgVHlwZVNjcmlwdCB0ZW1wbGF0ZSwgd2hlcmUgJ2RpcicgaXMgYSBwYXRoIHRvIERvcHBpb0pWTSdzXG4gKiAgICAgICAgICAgIFR5cGVTY3JpcHQgZGVmaW5pdGlvbiBmaWxlcy5cbiAqL1xuaW1wb3J0IG9wdHBhcnNlID0gcmVxdWlyZSgnLi4vc3JjL29wdGlvbl9wYXJzZXInKTtcbmltcG9ydCBwYXRoID0gcmVxdWlyZSgncGF0aCcpO1xuaW1wb3J0IGZzID0gcmVxdWlyZSgnZnMnKTtcbmltcG9ydCB1dGlsID0gcmVxdWlyZSgnLi4vc3JjL3V0aWwnKTtcbmltcG9ydCBDbGFzc0RhdGEgPSByZXF1aXJlKCcuLi9zcmMvQ2xhc3NEYXRhJyk7XG5pbXBvcnQgQ29uc3RhbnRQb29sID0gcmVxdWlyZSgnLi4vc3JjL0NvbnN0YW50UG9vbCcpO1xuaW1wb3J0IG1ldGhvZHMgPSByZXF1aXJlKCcuLi9zcmMvbWV0aG9kcycpO1xuaW1wb3J0IEpWTVR5cGVzID0gcmVxdWlyZSgnLi4vaW5jbHVkZXMvSlZNVHlwZXMnKTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyB0aGUgb3B0aW9uIHBhcnNlciB3aXRoIHRoZSBvcHRpb25zIGZvciB0aGUgYGRvcHBpb2hgIGNvbW1hbmQuXG4gKi9cbmZ1bmN0aW9uIHNldHVwT3B0cGFyc2UoKSB7XG4gIG9wdHBhcnNlLmRlc2NyaWJlKHtcbiAgICBzdGFuZGFyZDoge1xuICAgICAgY2xhc3NwYXRoOiB7XG4gICAgICAgIGFsaWFzOiAnY3AnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ0pWTSBjbGFzc3BhdGgsIFwicGF0aDE6Li4uOnBhdGhOXCInLFxuICAgICAgICBoYXNfdmFsdWU6IHRydWVcbiAgICAgIH0sXG4gICAgICBoZWxwOiB7IGFsaWFzOiAnaCcsIGRlc2NyaXB0aW9uOiAncHJpbnQgdGhpcyBoZWxwIG1lc3NhZ2UnIH0sXG4gICAgICBkaXJlY3Rvcnk6IHtcbiAgICAgICAgYWxpYXM6ICdkJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdPdXRwdXQgZGlyZWN0b3J5JyxcbiAgICAgICAgaGFzX3ZhbHVlOiB0cnVlXG4gICAgICB9LFxuICAgICAgamF2YXNjcmlwdDoge1xuICAgICAgICBhbGlhczogJ2pzJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdHZW5lcmF0ZSBKYXZhU2NyaXB0IHRlbXBsYXRlcyBbZGVmYXVsdD10cnVlXSdcbiAgICAgIH0sXG4gICAgICB0eXBlc2NyaXB0OiB7XG4gICAgICAgIGFsaWFzOiAndHMnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ0dlbmVyYXRlIFR5cGVTY3JpcHQgdGVtcGxhdGVzLCAtdHMgcGF0aC90by9kb3BwaW8vaW50ZXJmYWNlcycsXG4gICAgICAgIGhhc192YWx1ZTogdHJ1ZVxuICAgICAgfSxcbiAgICAgIGZvcmNlX2hlYWRlcnM6IHtcbiAgICAgICAgYWxpYXM6ICdmJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdbVHlwZVNjcmlwdCBvbmx5XSBGb3JjZXMgZG9wcGlvaCB0byBnZW5lcmF0ZSBUeXBlU2NyaXB0IGhlYWRlcnMgZm9yIHNwZWNpZmllZCBKVk0gY2xhc3NlcywgZS5nLiAtZiBqYXZhLmxhbmcuU3RyaW5nOmphdmEubGFuZy5PYmplY3QnLFxuICAgICAgICBoYXNfdmFsdWU6IHRydWVcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBwcmludEVyYXNlYWJsZUxpbmUobGluZTogc3RyaW5nKTogdm9pZCB7XG4gIC8vIFVuZG9jdW1lbnRlZCBmdW5jdGlvbnMuXG4gIGlmICgoPGFueT4gcHJvY2Vzcy5zdGRvdXQpWydjbGVhckxpbmUnXSkge1xuICAgICg8YW55PiBwcm9jZXNzLnN0ZG91dCkuY2xlYXJMaW5lKCk7XG4gICAgKDxhbnk+IHByb2Nlc3Muc3Rkb3V0KS5jdXJzb3JUbygwKTtcbiAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShsaW5lKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBwcmludEhlbHAoKTogdm9pZCB7XG4gIHByb2Nlc3Muc3Rkb3V0LndyaXRlKFwiVXNhZ2U6IGRvcHBpb2ggW2ZsYWdzXSBjbGFzc19vcl9wYWNrYWdlX25hbWVcXG5cIiArIG9wdHBhcnNlLnNob3dfaGVscCgpICsgXCJcXG5cIik7XG59XG5cbnNldHVwT3B0cGFyc2UoKTtcblxuLy8gUmVtb3ZlIFwibm9kZVwiIGFuZCBcInBhdGgvdG8vZG9wcGlvaC5qc1wiLlxudmFyIGFyZ3YgPSBvcHRwYXJzZS5wYXJzZShwcm9jZXNzLmFyZ3Yuc2xpY2UoMikpO1xuXG5pZiAoYXJndi5zdGFuZGFyZC5oZWxwIHx8IHByb2Nlc3MuYXJndi5sZW5ndGggPT09IDIpIHtcbiAgcHJpbnRIZWxwKCk7XG4gIHByb2Nlc3MuZXhpdCgxKTtcbn1cbmlmICghYXJndi5zdGFuZGFyZC5jbGFzc3BhdGgpIGFyZ3Yuc3RhbmRhcmQuY2xhc3NwYXRoID0gJy4nO1xuaWYgKCFhcmd2LnN0YW5kYXJkLmRpcmVjdG9yeSkgYXJndi5zdGFuZGFyZC5kaXJlY3RvcnkgPSAnLic7XG5cbmZ1bmN0aW9uIGZpbmRGaWxlKGZpbGVOYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICB2YXIgaTogbnVtYmVyO1xuICBmb3IgKGkgPSAwOyBpIDwgY2xhc3NwYXRoLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKGZzLmV4aXN0c1N5bmMocGF0aC5qb2luKGNsYXNzcGF0aFtpXSwgZmlsZU5hbWUpKSkge1xuICAgICAgcmV0dXJuIHBhdGguam9pbihjbGFzc3BhdGhbaV0sIGZpbGVOYW1lKTtcbiAgICB9IGVsc2UgaWYgKGZzLmV4aXN0c1N5bmMocGF0aC5qb2luKGNsYXNzcGF0aFtpXSwgZmlsZU5hbWUgKyAnLmNsYXNzJykpKSB7XG4gICAgICByZXR1cm4gcGF0aC5qb2luKGNsYXNzcGF0aFtpXSwgZmlsZU5hbWUgKyAnLmNsYXNzJyk7XG4gICAgfVxuICB9XG59XG5cbnZhciBjYWNoZToge1tkZXNjOiBzdHJpbmddOiBDbGFzc0RhdGEuQ2xhc3NEYXRhfSA9IHt9O1xuZnVuY3Rpb24gZmluZENsYXNzKGRlc2NyaXB0b3I6IHN0cmluZyk6IENsYXNzRGF0YS5DbGFzc0RhdGEge1xuICBpZiAoY2FjaGVbZGVzY3JpcHRvcl0gIT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBjYWNoZVtkZXNjcmlwdG9yXTtcbiAgfVxuXG4gIHZhciBydjogQ2xhc3NEYXRhLkNsYXNzRGF0YTtcbiAgdHJ5IHtcbiAgICBzd2l0Y2goZGVzY3JpcHRvclswXSkge1xuICAgICAgY2FzZSAnTCc6XG4gICAgICAgIHJ2ID0gbmV3IENsYXNzRGF0YS5SZWZlcmVuY2VDbGFzc0RhdGEoZnMucmVhZEZpbGVTeW5jKGZpbmRGaWxlKHV0aWwuZGVzY3JpcHRvcjJ0eXBlc3RyKGRlc2NyaXB0b3IpICsgXCIuY2xhc3NcIikpKTtcbiAgICAgICAgLy8gUmVzb2x2ZSB0aGUgY2xhc3MuXG4gICAgICAgIHZhciBzdXBlckNsYXNzUmVmID0gKDxDbGFzc0RhdGEuUmVmZXJlbmNlQ2xhc3NEYXRhPEpWTVR5cGVzLmphdmFfbGFuZ19PYmplY3Q+PiBydikuZ2V0U3VwZXJDbGFzc1JlZmVyZW5jZSgpLFxuICAgICAgICAgIGludGVyZmFjZUNsYXNzUmVmcyA9ICg8Q2xhc3NEYXRhLlJlZmVyZW5jZUNsYXNzRGF0YTxKVk1UeXBlcy5qYXZhX2xhbmdfT2JqZWN0Pj4gcnYpLmdldEludGVyZmFjZUNsYXNzUmVmZXJlbmNlcygpLFxuICAgICAgICAgIHN1cGVyQ2xhc3M6IENsYXNzRGF0YS5SZWZlcmVuY2VDbGFzc0RhdGE8SlZNVHlwZXMuamF2YV9sYW5nX09iamVjdD4gPSBudWxsLFxuICAgICAgICAgIGludGVyZmFjZUNsYXNzZXM6IENsYXNzRGF0YS5SZWZlcmVuY2VDbGFzc0RhdGE8SlZNVHlwZXMuamF2YV9sYW5nX09iamVjdD5bXSA9IFtdO1xuICAgICAgICBpZiAoc3VwZXJDbGFzc1JlZiAhPT0gbnVsbCkge1xuICAgICAgICAgIHN1cGVyQ2xhc3MgPSA8Q2xhc3NEYXRhLlJlZmVyZW5jZUNsYXNzRGF0YTxKVk1UeXBlcy5qYXZhX2xhbmdfT2JqZWN0Pj4gZmluZENsYXNzKHN1cGVyQ2xhc3NSZWYubmFtZSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGludGVyZmFjZUNsYXNzUmVmcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgaW50ZXJmYWNlQ2xhc3NlcyA9IGludGVyZmFjZUNsYXNzUmVmcy5tYXAoKGlmYWNlOiBDb25zdGFudFBvb2wuQ2xhc3NSZWZlcmVuY2UpID0+IDxDbGFzc0RhdGEuUmVmZXJlbmNlQ2xhc3NEYXRhPEpWTVR5cGVzLmphdmFfbGFuZ19PYmplY3Q+PiBmaW5kQ2xhc3MoaWZhY2UubmFtZSkpO1xuICAgICAgICB9XG4gICAgICAgICg8Q2xhc3NEYXRhLlJlZmVyZW5jZUNsYXNzRGF0YTxKVk1UeXBlcy5qYXZhX2xhbmdfT2JqZWN0Pj4gcnYpLnNldFJlc29sdmVkKHN1cGVyQ2xhc3MsIGludGVyZmFjZUNsYXNzZXMpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ1snOlxuICAgICAgICBydiA9IG5ldyBDbGFzc0RhdGEuQXJyYXlDbGFzc0RhdGEoZGVzY3JpcHRvci5zbGljZSgxKSwgbnVsbCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcnYgPSBuZXcgQ2xhc3NEYXRhLlByaW1pdGl2ZUNsYXNzRGF0YShkZXNjcmlwdG9yLCBudWxsKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIGNhY2hlW2Rlc2NyaXB0b3JdID0gcnY7XG4gICAgcmV0dXJuIHJ2O1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gcmVhZCBjbGFzcyBmaWxlIGZvciAke2Rlc2NyaXB0b3J9OiAke2V9XFxuJHtlLnN0YWNrfWApO1xuICB9XG59XG5cbmZ1bmN0aW9uIGdldEZpbGVzKGRpck5hbWU6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgdmFyIHJ2OiBzdHJpbmdbXSA9IFtdLCBmaWxlcyA9IGZzLnJlYWRkaXJTeW5jKGRpck5hbWUpLCBpOiBudW1iZXIsIGZpbGU6IHN0cmluZztcbiAgZm9yIChpID0gMDsgaSA8IGZpbGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgZmlsZSA9IHBhdGguam9pbihkaXJOYW1lLCBmaWxlc1tpXSk7XG4gICAgaWYgKGZzLnN0YXRTeW5jKGZpbGUpLmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgIHJ2ID0gcnYuY29uY2F0KGdldEZpbGVzKGZpbGUpKTtcbiAgICB9IGVsc2UgaWYgKGZpbGUuaW5kZXhPZignLmNsYXNzJykgPT09IChmaWxlLmxlbmd0aCAtIDYpKSB7XG4gICAgICBydi5wdXNoKGZpbGUpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcnY7XG59XG5cbmZ1bmN0aW9uIHByb2Nlc3NDbGFzc0RhdGEoc3RyZWFtOiBOb2RlSlMuV3JpdGFibGVTdHJlYW0sIHRlbXBsYXRlOiBJVGVtcGxhdGUsIGNsYXNzRGF0YTogQ2xhc3NEYXRhLlJlZmVyZW5jZUNsYXNzRGF0YTxKVk1UeXBlcy5qYXZhX2xhbmdfT2JqZWN0Pikge1xuICB2YXIgZml4ZWRDbGFzc05hbWU6IHN0cmluZyA9IGNsYXNzRGF0YS5nZXRJbnRlcm5hbE5hbWUoKS5yZXBsYWNlKC9cXC8vZywgJ18nKSxcbiAgICBuYXRpdmVGb3VuZDogYm9vbGVhbiA9IGZhbHNlO1xuICAvLyBTaGF2ZSBvZmYgTCBhbmQgO1xuICBmaXhlZENsYXNzTmFtZSA9IGZpeGVkQ2xhc3NOYW1lLnN1YnN0cmluZygxLCBmaXhlZENsYXNzTmFtZS5sZW5ndGggLSAxKTtcblxuICB2YXIgbWV0aG9kcyA9IGNsYXNzRGF0YS5nZXRNZXRob2RzKCk7XG4gIG1ldGhvZHMuZm9yRWFjaCgobWV0aG9kOiBtZXRob2RzLk1ldGhvZCkgPT4ge1xuICAgIGlmIChtZXRob2QuYWNjZXNzRmxhZ3MuaXNOYXRpdmUoKSkge1xuICAgICAgaWYgKCFuYXRpdmVGb3VuZCkge1xuICAgICAgICB0ZW1wbGF0ZS5jbGFzc1N0YXJ0KHN0cmVhbSwgZml4ZWRDbGFzc05hbWUpO1xuICAgICAgICBuYXRpdmVGb3VuZCA9IHRydWU7XG4gICAgICB9XG4gICAgICB0ZW1wbGF0ZS5tZXRob2Qoc3RyZWFtLCBjbGFzc0RhdGEuZ2V0SW50ZXJuYWxOYW1lKCksIG1ldGhvZC5zaWduYXR1cmUsIG1ldGhvZC5hY2Nlc3NGbGFncy5pc1N0YXRpYygpLCBtZXRob2QucGFyYW1ldGVyVHlwZXMsIG1ldGhvZC5yZXR1cm5UeXBlKTtcbiAgICB9XG4gIH0pO1xuXG4gIGlmIChuYXRpdmVGb3VuZCkge1xuICAgIHRlbXBsYXRlLmNsYXNzRW5kKHN0cmVhbSwgZml4ZWRDbGFzc05hbWUpO1xuICB9XG59XG5cbi8qKlxuICogQSBEb3BwaW9oIG91dHB1dCB0ZW1wbGF0ZS5cbiAqL1xuaW50ZXJmYWNlIElUZW1wbGF0ZSB7XG4gIGdldEV4dGVuc2lvbigpOiBzdHJpbmc7XG4gIGZpbGVTdGFydChzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSk6IHZvaWQ7XG4gIGZpbGVFbmQoc3RyZWFtOiBOb2RlSlMuV3JpdGFibGVTdHJlYW0pOiB2b2lkO1xuICBjbGFzc1N0YXJ0KHN0cmVhbTogTm9kZUpTLldyaXRhYmxlU3RyZWFtLCBjbGFzc05hbWU6IHN0cmluZyk6IHZvaWQ7XG4gIGNsYXNzRW5kKHN0cmVhbTogTm9kZUpTLldyaXRhYmxlU3RyZWFtLCBjbGFzc05hbWU6IHN0cmluZyk6IHZvaWQ7XG4gIG1ldGhvZChzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSwgY2xhc3NEZXNjOiBzdHJpbmcsIG1ldGhvZE5hbWU6IHN0cmluZywgaXNTdGF0aWM6IGJvb2xlYW4sIGFyZ1R5cGVzOiBzdHJpbmdbXSwgcnY6IHN0cmluZyk6IHZvaWQ7XG59XG5cbi8qKlxuICogVHlwZVNjcmlwdCBvdXRwdXQgdGVtcGxhdGUuXG4gKi9cbmNsYXNzIFRTVGVtcGxhdGUgaW1wbGVtZW50cyBJVGVtcGxhdGUge1xuICBwcml2YXRlIGhlYWRlckNvdW50OiBudW1iZXIgPSAwO1xuICBwcml2YXRlIHJlbGF0aXZlSW50ZXJmYWNlUGF0aDogc3RyaW5nO1xuICBwcml2YXRlIGhlYWRlclNldDogeyBbY2xzTmFtZTogc3RyaW5nXTogYm9vbGVhbn0gPSB7fTtcbiAgcHJpdmF0ZSBjbGFzc2VzU2Vlbjogc3RyaW5nW10gPSBbXTtcbiAgcHJpdmF0ZSBoZWFkZXJQYXRoOiBzdHJpbmcgPSBwYXRoLnJlc29sdmUoYXJndi5zdGFuZGFyZC5kaXJlY3RvcnksIFwiSlZNVHlwZXMuZC50c1wiKTtcbiAgcHJpdmF0ZSBoZWFkZXJTdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbTtcbiAgcHJpdmF0ZSBnZW5lcmF0ZVF1ZXVlOiBDbGFzc0RhdGEuUmVmZXJlbmNlQ2xhc3NEYXRhPEpWTVR5cGVzLmphdmFfbGFuZ19PYmplY3Q+W10gPSBbXTtcbiAgY29uc3RydWN0b3Iob3V0cHV0UGF0aDogc3RyaW5nLCBwcml2YXRlIGludGVyZmFjZVBhdGg6IHN0cmluZykge1xuICAgIHRoaXMucmVsYXRpdmVJbnRlcmZhY2VQYXRoID0gcGF0aC5yZWxhdGl2ZShvdXRwdXRQYXRoLCBpbnRlcmZhY2VQYXRoKTtcblxuICAgIC8vIFBhcnNlIGV4aXN0aW5nIHR5cGVzIGZpbGUgZm9yIGV4aXN0aW5nIGRlZmluaXRpb25zLiBXZSdsbCByZW1ha2UgdGhlbS5cbiAgICB0cnkge1xuICAgICAgdmFyIGV4aXN0aW5nSGVhZGVycyA9IGZzLnJlYWRGaWxlU3luYyh0aGlzLmhlYWRlclBhdGgpLnRvU3RyaW5nKCksXG4gICAgICAgIHNlYXJjaElkeCA9IDAsIGNsc05hbWU6IHN0cmluZztcbiAgICAgIC8vIFBhc3MgMTogQ2xhc3Nlcy5cbiAgICAgIHdoaWxlICgoc2VhcmNoSWR4ID0gZXhpc3RpbmdIZWFkZXJzLmluZGV4T2YoXCJleHBvcnQgY2xhc3MgXCIsIHNlYXJjaElkeCkpID4gLTEpIHtcbiAgICAgICAgY2xzTmFtZSA9IGV4aXN0aW5nSGVhZGVycy5zbGljZShzZWFyY2hJZHggKyAxMywgZXhpc3RpbmdIZWFkZXJzLmluZGV4T2YoXCIgXCIsIHNlYXJjaElkeCArIDEzKSk7XG4gICAgICAgIGlmIChjbHNOYW1lLmluZGV4T2YoXCJKVk1BcnJheVwiKSAhPT0gMCkge1xuICAgICAgICAgIHRoaXMuZ2VuZXJhdGVDbGFzc0RlZmluaXRpb24odGhpcy50c3R5cGUyanZtdHlwZShjbHNOYW1lKSk7XG4gICAgICAgIH1cbiAgICAgICAgc2VhcmNoSWR4Kys7XG4gICAgICB9XG4gICAgICBzZWFyY2hJZHggPSAwO1xuICAgICAgLy8gUGFzcyAyOiBJbnRlcmZhY2VzLlxuICAgICAgd2hpbGUgKChzZWFyY2hJZHggPSBleGlzdGluZ0hlYWRlcnMuaW5kZXhPZihcImV4cG9ydCBpbnRlcmZhY2UgXCIsIHNlYXJjaElkeCkpID4gLTEpIHtcbiAgICAgICAgY2xzTmFtZSA9IGV4aXN0aW5nSGVhZGVycy5zbGljZShzZWFyY2hJZHggKyAxNywgZXhpc3RpbmdIZWFkZXJzLmluZGV4T2YoXCIgXCIsIHNlYXJjaElkeCArIDE3KSk7XG4gICAgICAgIHRoaXMuZ2VuZXJhdGVDbGFzc0RlZmluaXRpb24odGhpcy50c3R5cGUyanZtdHlwZShjbHNOYW1lKSk7XG4gICAgICAgIHNlYXJjaElkeCsrO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIC8vIElnbm9yZS5cbiAgICAgIGNvbnNvbGUubG9nKFwiRXJyb3IgcGFyc2luZyBleGl0aW5nIGZpbGU6IFwiICsgZSk7XG4gICAgfVxuXG4gICAgdGhpcy5oZWFkZXJTdHJlYW0gPSBmcy5jcmVhdGVXcml0ZVN0cmVhbSh0aGlzLmhlYWRlclBhdGgpO1xuICAgIHRoaXMuaGVhZGVyc1N0YXJ0KCk7XG4gICAgLy8gR2VuZXJhdGUgcmVxdWlyZWQgdHlwZXMuXG4gICAgdGhpcy5nZW5lcmF0ZUFycmF5RGVmaW5pdGlvbigpO1xuICAgIHRoaXMuZ2VuZXJhdGVDbGFzc0RlZmluaXRpb24oJ0xqYXZhL2xhbmcvVGhyb3dhYmxlOycpO1xuICAgIGlmIChhcmd2LnN0YW5kYXJkLmZvcmNlX2hlYWRlcnMpIHtcbiAgICAgIHZhciBjbHNlcyA9IGFyZ3Yuc3RhbmRhcmQuZm9yY2VfaGVhZGVycy5zcGxpdCgnOicpO1xuICAgICAgY2xzZXMuZm9yRWFjaCgoY2xzTmFtZTogc3RyaW5nKSA9PiB7XG4gICAgICAgIHRoaXMuZ2VuZXJhdGVDbGFzc0RlZmluaXRpb24odXRpbC5pbnRfY2xhc3NuYW1lKGNsc05hbWUpKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuICBwdWJsaWMgaGVhZGVyc1N0YXJ0KCk6IHZvaWQge1xuICAgIHRoaXMuaGVhZGVyU3RyZWFtLndyaXRlKGAvLyBUeXBlU2NyaXB0IGRlY2xhcmF0aW9uIGZpbGUgZm9yIEpWTSB0eXBlcy4gQXV0b21hdGljYWxseSBnZW5lcmF0ZWQgYnkgZG9wcGlvaC5cbi8vIGh0dHA6Ly9naXRodWIuY29tL3BsYXNtYS11bWFzcy9kb3BwaW9cbiR7ZnMucmVhZGRpclN5bmMocGF0aC5yZXNvbHZlKHRoaXMuaW50ZXJmYWNlUGF0aCwgXCJzcmNcIikpLm1hcCgoaXRlbTogc3RyaW5nKSA9PlxuICAgIChpdGVtLmluZGV4T2YoJy50cycpICE9PSAtMSAmJiBpdGVtWzBdICE9PSAnLicpID8gYGltcG9ydCAke2l0ZW0uc2xpY2UoMCwgaXRlbS5pbmRleE9mKCcuJykpfSA9IHJlcXVpcmUoXCIke3BhdGguam9pbih0aGlzLnJlbGF0aXZlSW50ZXJmYWNlUGF0aCwgJ3NyYycsIGl0ZW0uc2xpY2UoMCwgaXRlbS5pbmRleE9mKCcuJykpKX1cIik7XFxuYCA6ICcnXG4pLmpvaW4oXCJcIil9XG5cbmRlY2xhcmUgbW9kdWxlIEpWTVR5cGVzIHtcXG5gKTtcbiAgfVxuXG4gIHB1YmxpYyBnZXRFeHRlbnNpb24oKTogc3RyaW5nIHsgcmV0dXJuICd0cyc7IH1cbiAgcHVibGljIGZpbGVTdGFydChzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSk6IHZvaWQge1xuICAgIC8vIFJlZmVyZW5jZSBhbGwgb2YgdGhlIGRvcHBpbyBpbnRlcmZhY2VzLlxuICAgIHZhciBzcmNJbnRlcmZhY2VQYXRoOiBzdHJpbmcgPSBwYXRoLmpvaW4odGhpcy5pbnRlcmZhY2VQYXRoLCAnc3JjJyksXG4gICAgICBmaWxlcyA9IGZzLnJlYWRkaXJTeW5jKHNyY0ludGVyZmFjZVBhdGgpLFxuICAgICAgaTogbnVtYmVyLCBmaWxlOiBzdHJpbmc7XG4gICAgc3RyZWFtLndyaXRlKGBpbXBvcnQgSlZNVHlwZXMgPSByZXF1aXJlKFwiLi9KVk1UeXBlc1wiKTtcXG5gKTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgZmlsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGZpbGUgPSBmaWxlc1tpXTtcbiAgICAgIGlmIChmaWxlLnN1YnN0cmluZyhmaWxlLmxlbmd0aCAtIDQpID09PSAnZC50cycpIHtcbiAgICAgICAgLy8gU3RyaXAgb2ZmICcuZC50cycuXG4gICAgICAgIHZhciBtb2ROYW1lID0gZmlsZS5zdWJzdHJpbmcoMCwgZmlsZS5sZW5ndGggLSA1KTtcbiAgICAgICAgc3RyZWFtLndyaXRlKCdpbXBvcnQgJyArIG1vZE5hbWUgKyAnID0gcmVxdWlyZShcIicgKyBwYXRoLmpvaW4odGhpcy5yZWxhdGl2ZUludGVyZmFjZVBhdGgsICdzcmMnLCBtb2ROYW1lKS5yZXBsYWNlKC9cXFxcL2csICcvJykgKyAnXCIpO1xcbicpO1xuICAgICAgfVxuICAgIH1cbiAgICBzdHJlYW0ud3JpdGUoYFxcbmRlY2xhcmUgdmFyIHJlZ2lzdGVyTmF0aXZlczogKG5hdGl2ZXM6IGFueSkgPT4gdm9pZDtcXG5gKTtcbiAgfVxuICBwdWJsaWMgZmlsZUVuZChzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSk6IHZvaWQge1xuICAgIHZhciBpOiBudW1iZXI7XG4gICAgLy8gRXhwb3J0IGV2ZXJ5dGhpbmchXG4gICAgc3RyZWFtLndyaXRlKFwiXFxuLy8gRXhwb3J0IGxpbmUuIFRoaXMgaXMgd2hhdCBEb3BwaW9KVk0gc2Vlcy5cXG5yZWdpc3Rlck5hdGl2ZXMoe1wiKTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgdGhpcy5jbGFzc2VzU2Vlbi5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGtscyA9IHRoaXMuY2xhc3Nlc1NlZW5baV07XG4gICAgICBpZiAoaSA+IDApIHN0cmVhbS53cml0ZSgnLCcpO1xuICAgICAgc3RyZWFtLndyaXRlKFwiXFxuICAnXCIgKyBrbHMucmVwbGFjZSgvXy9nLCAnLycpICsgXCInOiBcIiArIGtscyk7XG4gICAgfVxuICAgIHN0cmVhbS53cml0ZShcIlxcbn0pO1xcblwiKTtcbiAgfVxuICAvKipcbiAgICogRW1pdHMgVHlwZVNjcmlwdCB0eXBlIGRlY2xhcmF0aW9ucy4gU2VwYXJhdGVkIGZyb20gZmlsZUVuZCwgc2luY2Ugb25lIGNhblxuICAgKiB1c2UgZG9wcGlvaCB0byBlbWl0IGhlYWRlcnMgb25seS5cbiAgICovXG4gIHB1YmxpYyBoZWFkZXJzRW5kKCk6IHZvaWQge1xuICAgIHRoaXMuX3Byb2Nlc3NHZW5lcmF0ZVF1ZXVlKCk7XG4gICAgLy8gUHJpbnQgbmV3bGluZSB0byBjbGVhciBlcmFzZWFibGUgbGluZS5cbiAgICBwcmludEVyYXNlYWJsZUxpbmUoYFByb2Nlc3NlZCAke3RoaXMuaGVhZGVyQ291bnR9IGNsYXNzZXMuXFxuYCk7XG4gICAgdGhpcy5oZWFkZXJTdHJlYW0uZW5kKGB9XG5leHBvcnQgPSBKVk1UeXBlcztcXG5gLCAoKSA9PiB7fSk7XG4gIH1cbiAgcHVibGljIGNsYXNzU3RhcnQoc3RyZWFtOiBOb2RlSlMuV3JpdGFibGVTdHJlYW0sIGNsYXNzTmFtZTogc3RyaW5nKTogdm9pZCB7XG4gICAgc3RyZWFtLndyaXRlKFwiXFxuY2xhc3MgXCIgKyBjbGFzc05hbWUgKyBcIiB7XFxuXCIpO1xuICAgIHRoaXMuY2xhc3Nlc1NlZW4ucHVzaChjbGFzc05hbWUpO1xuICAgIHRoaXMuZ2VuZXJhdGVDbGFzc0RlZmluaXRpb24oYEwke2NsYXNzTmFtZS5yZXBsYWNlKC9fL2csIFwiL1wiKX07YCk7XG4gIH1cbiAgcHVibGljIGNsYXNzRW5kKHN0cmVhbTogTm9kZUpTLldyaXRhYmxlU3RyZWFtLCBjbGFzc05hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgIHN0cmVhbS53cml0ZShcIlxcbn1cXG5cIik7XG4gIH1cbiAgcHVibGljIG1ldGhvZChzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSwgY2xhc3NEZXNjOiBzdHJpbmcsIG1ldGhvZE5hbWU6IHN0cmluZywgaXNTdGF0aWM6IGJvb2xlYW4sIGFyZ1R5cGVzOiBzdHJpbmdbXSwgclR5cGU6IHN0cmluZyk6IHZvaWQge1xuICAgIHZhciB0cnVlUnR5cGUgPSB0aGlzLmp2bXR5cGUydHN0eXBlKHJUeXBlKSwgcnZhbCA9IFwiXCI7XG4gICAgaWYgKHRydWVSdHlwZSA9PT0gJ251bWJlcicpIHtcbiAgICAgIHJ2YWwgPSBcIjBcIjtcbiAgICB9IGVsc2UgaWYgKHRydWVSdHlwZSAhPT0gJ3ZvaWQnKSB7XG4gICAgICBydmFsID0gXCJudWxsXCI7XG4gICAgfVxuXG4gICAgYXJnVHlwZXMuY29uY2F0KFtyVHlwZV0pLmZvckVhY2goKHR5cGU6IHN0cmluZykgPT4ge1xuICAgICAgdGhpcy5nZW5lcmF0ZUNsYXNzRGVmaW5pdGlvbih0eXBlKTtcbiAgICB9KTtcblxuICAgIHN0cmVhbS53cml0ZShgXG4gIHB1YmxpYyBzdGF0aWMgJyR7bWV0aG9kTmFtZX0nKHRocmVhZDogdGhyZWFkaW5nLkpWTVRocmVhZCR7aXNTdGF0aWMgPyAnJyA6IGAsIGphdmFUaGlzOiAke3RoaXMuanZtdHlwZTJ0c3R5cGUoY2xhc3NEZXNjKX1gfSR7YXJnVHlwZXMubGVuZ3RoID09PSAwID8gJycgOiAnLCAnICsgYXJnVHlwZXMubWFwKCh0eXBlOiBzdHJpbmcsIGk6IG51bWJlcikgPT4gYGFyZyR7aX06ICR7dGhpcy5qdm10eXBlMnRzdHlwZSh0eXBlKX1gKS5qb2luKFwiLCBcIil9KTogJHt0aGlzLmp2bXR5cGUydHN0eXBlKHJUeXBlKX0ge1xuICAgIHRocmVhZC50aHJvd05ld0V4Y2VwdGlvbignTGphdmEvbGFuZy9VbnNhdGlzZmllZExpbmtFcnJvcjsnLCAnTmF0aXZlIG1ldGhvZCBub3QgaW1wbGVtZW50ZWQuJyk7JHtydmFsICE9PSAnJyA/IGBcXG4gICAgcmV0dXJuICR7cnZhbH07YCA6ICcnfVxuICB9XFxuYCk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgYSB0eXBlc3RyaW5nIHRvIGl0cyBlcXVpdmFsZW50IFR5cGVTY3JpcHQgdHlwZS5cbiAgICovXG4gIHByaXZhdGUganZtdHlwZTJ0c3R5cGUoZGVzYzogc3RyaW5nLCBwcmVmaXg6IGJvb2xlYW4gPSB0cnVlKTogc3RyaW5nIHtcbiAgICBzd2l0Y2goZGVzY1swXSkge1xuICAgICAgY2FzZSAnWyc6XG4gICAgICByZXR1cm4gKHByZWZpeCA/ICdKVk1UeXBlcy4nIDogJycpICsgYEpWTUFycmF5PCR7dGhpcy5qdm10eXBlMnRzdHlwZShkZXNjLnNsaWNlKDEpLCBwcmVmaXgpfT5gO1xuICAgICAgY2FzZSAnTCc6XG4gICAgICAvLyBFbnN1cmUgYWxsIGNvbnZlcnRlZCByZWZlcmVuY2UgdHlwZXMgZ2V0IGdlbmVyYXRlZCBoZWFkZXJzLlxuICAgICAgdGhpcy5nZW5lcmF0ZUNsYXNzRGVmaW5pdGlvbihkZXNjKTtcbiAgICAgIHJldHVybiAgKHByZWZpeCA/ICdKVk1UeXBlcy4nIDogJycpICsgdXRpbC5kZXNjcmlwdG9yMnR5cGVzdHIoZGVzYykucmVwbGFjZSgvXy9nLCAnX18nKS5yZXBsYWNlKC9cXC8vZywgJ18nKTtcbiAgICAgIGNhc2UgJ0onOlxuICAgICAgcmV0dXJuICdnTG9uZyc7XG4gICAgICBjYXNlICdWJzpcbiAgICAgIHJldHVybiAndm9pZCc7XG4gICAgICBkZWZhdWx0OlxuICAgICAgLy8gUHJpbWl0aXZlcy5cbiAgICAgIHJldHVybiAnbnVtYmVyJztcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgYSBUeXBlU2NyaXB0IHR5cGUgaW50byBpdHMgZXF1aXZhbGVudCBKVk0gdHlwZS5cbiAgICovXG4gIHByaXZhdGUgdHN0eXBlMmp2bXR5cGUodHNUeXBlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmICh0c1R5cGUuaW5kZXhPZignSlZNQXJyYXknKSA9PT0gMCkge1xuICAgICAgcmV0dXJuIGBbJHt0aGlzLnRzdHlwZTJqdm10eXBlKHRzVHlwZS5zbGljZSg5LCB0c1R5cGUubGVuZ3RoIC0gMSkpfWA7XG4gICAgfSBlbHNlIGlmICh0c1R5cGUgPT09ICdudW1iZXInKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJBbWJpZ3VvdXMuXCIpO1xuICAgIH0gZWxzZSBpZiAodHNUeXBlID09PSAndm9pZCcpIHtcbiAgICAgIHJldHVybiAnVic7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIF8gPT4gLywgYW5kIC8vID0+IF8gc2luY2Ugd2UgZW5jb2RlIHVuZGVyc2NvcmVzIGFzIGRvdWJsZSB1bmRlcnNjb3Jlcy5cbiAgICAgIHJldHVybiBgTCR7dHNUeXBlLnJlcGxhY2UoL18vZywgJy8nKS5yZXBsYWNlKC9cXC9cXC8vZywgJ18nKX07YDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGVzIGEgVHlwZVNjcmlwdCBjbGFzcyBkZWZpbml0aW9uIGZvciB0aGUgZ2l2ZW4gY2xhc3Mgb2JqZWN0LlxuICAgKi9cbiAgcHJpdmF0ZSBnZW5lcmF0ZUNsYXNzRGVmaW5pdGlvbihkZXNjOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5oZWFkZXJTZXRbZGVzY10gIT09IHVuZGVmaW5lZCB8fCB1dGlsLmlzX3ByaW1pdGl2ZV90eXBlKGRlc2MpKSB7XG4gICAgICAvLyBBbHJlYWR5IGdlbmVyYXRlZCwgb3IgaXMgYSBwcmltaXRpdmUuXG4gICAgICByZXR1cm47XG4gICAgfSBlbHNlIGlmIChkZXNjWzBdID09PSAnWycpIHtcbiAgICAgIC8vIEVuc3VyZSBjb21wb25lbnQgdHlwZSBpcyBjcmVhdGVkLlxuICAgICAgcmV0dXJuIHRoaXMuZ2VuZXJhdGVDbGFzc0RlZmluaXRpb24oZGVzYy5zbGljZSgxKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIE1hcmsgdGhpcyBjbGFzcyBhcyBxdWV1ZWQgZm9yIGhlYWRlcmlmaWNhdGlvbi4gV2UgdXNlIGEgcXVldWUgaW5zdGVhZFxuICAgICAgLy8gb2YgYSByZWN1cnNpdmUgc2NoZW1lIHRvIGF2b2lkIHN0YWNrIG92ZXJmbG93cy5cbiAgICAgIHRoaXMuaGVhZGVyU2V0W2Rlc2NdID0gdHJ1ZTtcbiAgICAgIHRoaXMuZ2VuZXJhdGVRdWV1ZS5wdXNoKDxDbGFzc0RhdGEuUmVmZXJlbmNlQ2xhc3NEYXRhPEpWTVR5cGVzLmphdmFfbGFuZ19PYmplY3Q+PiBmaW5kQ2xhc3MoZGVzYykpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgX3Byb2Nlc3NIZWFkZXIoY2xzOiBDbGFzc0RhdGEuUmVmZXJlbmNlQ2xhc3NEYXRhPEpWTVR5cGVzLmphdmFfbGFuZ19PYmplY3Q+KTogdm9pZCB7XG4gICAgICB2YXIgZGVzYyA9IGNscy5nZXRJbnRlcm5hbE5hbWUoKSxcbiAgICAgICAgaW50ZXJmYWNlcyA9IGNscy5nZXRJbnRlcmZhY2VDbGFzc1JlZmVyZW5jZXMoKS5tYXAoKGlmYWNlOiBDb25zdGFudFBvb2wuQ2xhc3NSZWZlcmVuY2UpID0+IGlmYWNlLm5hbWUpLFxuICAgICAgICBzdXBlckNsYXNzID0gY2xzLmdldFN1cGVyQ2xhc3NSZWZlcmVuY2UoKSxcbiAgICAgICAgbWV0aG9kcyA9IGNscy5nZXRNZXRob2RzKCkuY29uY2F0KGNscy5nZXRNaXJhbmRhQW5kRGVmYXVsdE1ldGhvZHMoKSksXG4gICAgICAgIGZpZWxkcyA9IGNscy5nZXRGaWVsZHMoKSxcbiAgICAgICAgbWV0aG9kc1NlZW46IHsgW25hbWU6IHN0cmluZ106IGJvb2xlYW4gfSA9IHt9LFxuICAgICAgICBpbmplY3RlZEZpZWxkcyA9IGNscy5nZXRJbmplY3RlZEZpZWxkcygpLFxuICAgICAgICBpbmplY3RlZE1ldGhvZHMgPSBjbHMuZ2V0SW5qZWN0ZWRNZXRob2RzKCksXG4gICAgICAgIGluamVjdGVkU3RhdGljTWV0aG9kcyA9IGNscy5nZXRJbmplY3RlZFN0YXRpY01ldGhvZHMoKTtcbiAgICAgIHByaW50RXJhc2VhYmxlTGluZShgWyR7dGhpcy5oZWFkZXJDb3VudCsrfV0gUHJvY2Vzc2luZyBoZWFkZXIgZm9yICR7dXRpbC5kZXNjcmlwdG9yMnR5cGVzdHIoZGVzYyl9Li4uYCk7XG5cbiAgICAgIGlmIChjbHMuYWNjZXNzRmxhZ3MuaXNJbnRlcmZhY2UoKSkge1xuICAgICAgICAvLyBJbnRlcmZhY2VzIG1hcCB0byBUeXBlU2NyaXB0IGludGVyZmFjZXMuXG4gICAgICAgIHRoaXMuaGVhZGVyU3RyZWFtLndyaXRlKGAgIGV4cG9ydCBpbnRlcmZhY2UgJHt0aGlzLmp2bXR5cGUydHN0eXBlKGRlc2MsIGZhbHNlKX1gKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuaGVhZGVyU3RyZWFtLndyaXRlKGAgIGV4cG9ydCBjbGFzcyAke3RoaXMuanZtdHlwZTJ0c3R5cGUoZGVzYywgZmFsc2UpfWApO1xuICAgICAgfVxuXG4gICAgICAvLyBOb3RlOiBJbnRlcmZhY2UgY2xhc3NlcyBoYXZlIGphdmEubGFuZy5PYmplY3QgYXMgYSBzdXBlcmNsYXNzLlxuICAgICAgLy8gV2hpbGUgamF2YV9sYW5nX09iamVjdCBpcyBhIGNsYXNzLCBUeXBlU2NyaXB0IHdpbGwgZXh0cmFjdCBhbiBpbnRlcmZhY2VcbiAgICAgIC8vIGZvciB0aGUgY2xhc3MgdW5kZXItdGhlLWNvdmVycyBhbmQgZXh0cmFjdCBpdCwgY29ycmVjdGx5IHByb3ZpZGluZyB1c1xuICAgICAgLy8gd2l0aCBpbmplY3RlZCBKVk0gbWV0aG9kcyBvbiBpbnRlcmZhY2UgdHlwZXMgKGUuZy4gZ2V0Q2xhc3MoKSkuXG4gICAgICBpZiAoc3VwZXJDbGFzcyAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmhlYWRlclN0cmVhbS53cml0ZShgIGV4dGVuZHMgJHt0aGlzLmp2bXR5cGUydHN0eXBlKHN1cGVyQ2xhc3MubmFtZSwgZmFsc2UpfWApO1xuICAgICAgfVxuXG4gICAgICBpZiAoaW50ZXJmYWNlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGlmIChjbHMuYWNjZXNzRmxhZ3MuaXNJbnRlcmZhY2UoKSkge1xuICAgICAgICAgIC8vIEludGVyZmFjZXMgY2FuIGV4dGVuZCBtdWx0aXBsZSBpbnRlcmZhY2VzLCBhbmQgY2FuIGV4dGVuZCBjbGFzc2VzIVxuICAgICAgICAgIC8vIEFkZCBhIGNvbW1hIGFmdGVyIHRoZSBndWFyYW50ZWVkIFwiamF2YV9sYW5nX09iamVjdFwiLlxuICAgICAgICAgIHRoaXMuaGVhZGVyU3RyZWFtLndyaXRlKGAsIGApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIENsYXNzZXMgY2FuIGltcGxlbWVudCBtdWx0aXBsZSBpbnRlcmZhY2VzLlxuICAgICAgICAgIHRoaXMuaGVhZGVyU3RyZWFtLndyaXRlKGAgaW1wbGVtZW50cyBgKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmhlYWRlclN0cmVhbS53cml0ZShgJHtpbnRlcmZhY2VzLm1hcCgoaWZhY2VOYW1lOiBzdHJpbmcpID0+IHRoaXMuanZtdHlwZTJ0c3R5cGUoaWZhY2VOYW1lLCBmYWxzZSkpLmpvaW4oXCIsIFwiKX1gKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5oZWFkZXJTdHJlYW0ud3JpdGUoYCB7XFxuYCk7XG4gICAgICBPYmplY3Qua2V5cyhpbmplY3RlZEZpZWxkcykuZm9yRWFjaCgobmFtZTogc3RyaW5nKSA9PiB0aGlzLl9vdXRwdXRJbmplY3RlZEZpZWxkKG5hbWUsIGluamVjdGVkRmllbGRzW25hbWVdLCB0aGlzLmhlYWRlclN0cmVhbSkpO1xuICAgICAgT2JqZWN0LmtleXMoaW5qZWN0ZWRNZXRob2RzKS5mb3JFYWNoKChuYW1lOiBzdHJpbmcpID0+IHRoaXMuX291dHB1dEluamVjdGVkTWV0aG9kKG5hbWUsIGluamVjdGVkTWV0aG9kc1tuYW1lXSwgdGhpcy5oZWFkZXJTdHJlYW0pKTtcbiAgICAgIE9iamVjdC5rZXlzKGluamVjdGVkU3RhdGljTWV0aG9kcykuZm9yRWFjaCgobmFtZTogc3RyaW5nKSA9PiB0aGlzLl9vdXRwdXRJbmplY3RlZFN0YXRpY01ldGhvZChuYW1lLCBpbmplY3RlZFN0YXRpY01ldGhvZHNbbmFtZV0sIHRoaXMuaGVhZGVyU3RyZWFtKSk7XG4gICAgICBmaWVsZHMuZm9yRWFjaCgoZikgPT4gdGhpcy5fb3V0cHV0RmllbGQoZiwgdGhpcy5oZWFkZXJTdHJlYW0pKTtcbiAgICAgIG1ldGhvZHMuZm9yRWFjaCgobSkgPT4gdGhpcy5fb3V0cHV0TWV0aG9kKG0sIHRoaXMuaGVhZGVyU3RyZWFtKSk7XG4gICAgICBjbHMuZ2V0VW5pbmhlcml0ZWREZWZhdWx0TWV0aG9kcygpLmZvckVhY2goKG0pID0+IHRoaXMuX291dHB1dE1ldGhvZChtLCB0aGlzLmhlYWRlclN0cmVhbSkpO1xuICAgICAgdGhpcy5oZWFkZXJTdHJlYW0ud3JpdGUoYCAgfVxcbmApO1xuICB9XG5cbiAgLyoqXG4gICAqIE91dHB1dHMgYSBtZXRob2Qgc2lnbmF0dXJlIGZvciB0aGUgZ2l2ZW4gbWV0aG9kIG9uIHRoZSBnaXZlbiBzdHJlYW0uXG4gICAqIE5PVEU6IFdlIHJlcXVpcmUgYSBjbGFzcyBhcmd1bWVudCBiZWNhdXNlIGRlZmF1bHQgaW50ZXJmYWNlIG1ldGhvZHMgYXJlXG4gICAqIGRlZmluZWQgb24gY2xhc3Nlcywgbm90IG9uIHRoZSBpbnRlcmZhY2VzIHRoZXkgYmVsb25nIHRvLlxuICAgKi9cbiAgcHJpdmF0ZSBfb3V0cHV0TWV0aG9kKG06IG1ldGhvZHMuTWV0aG9kLCBzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSwgbm9uVmlydHVhbE9ubHk6IGJvb2xlYW4gPSBmYWxzZSkge1xuICAgIHZhciBhcmdUeXBlcyA9IG0ucGFyYW1ldGVyVHlwZXMsXG4gICAgICByVHlwZSA9IG0ucmV0dXJuVHlwZSwgYXJnczogc3RyaW5nID0gXCJcIixcbiAgICAgIGNiU2lnID0gYGU/OiBqYXZhX2xhbmdfVGhyb3dhYmxlJHtyVHlwZSA9PT0gJ1YnID8gXCJcIiA6IGAsIHJ2PzogJHt0aGlzLmp2bXR5cGUydHN0eXBlKHJUeXBlLCBmYWxzZSl9YH1gLFxuICAgICAgbWV0aG9kU2lnOiBzdHJpbmcsIG1ldGhvZEZsYWdzID0gYHB1YmxpYyR7bS5hY2Nlc3NGbGFncy5pc1N0YXRpYygpID8gJyBzdGF0aWMnIDogJyd9YDtcblxuICAgIGlmIChhcmdUeXBlcy5sZW5ndGggPiAwKSB7XG4gICAgICAvLyBBcmd1bWVudHMgYXJlIGEgZ2lhbnQgdHVwbGUgdHlwZS5cbiAgICAgIC8vIE5PVEU6IExvbmcgLyBkb3VibGVzIHRha2UgdXAgdHdvIGFyZ3VtZW50IHNsb3RzLiBUaGUgc2Vjb25kIGFyZ3VtZW50IGlzIGFsd2F5cyBOVUxMLlxuICAgICAgYXJncyA9IFwiYXJnczogW1wiICsgYXJnVHlwZXMubWFwKCh0eXBlOiBzdHJpbmcsIGk6IG51bWJlcikgPT4gYCR7dGhpcy5qdm10eXBlMnRzdHlwZSh0eXBlLCBmYWxzZSl9JHsodHlwZSA9PT0gXCJKXCIgfHwgdHlwZSA9PT0gXCJEXCIpID8gJywgYW55JyA6ICcnfWApLmpvaW4oXCIsIFwiKSArIFwiXSwgXCI7XG4gICAgfVxuXG4gICAgbWV0aG9kU2lnID0gYCh0aHJlYWQ6IHRocmVhZGluZy5KVk1UaHJlYWQsICR7YXJnc31jYj86ICgke2NiU2lnfSkgPT4gdm9pZCk6IHZvaWRgO1xuXG4gICAgLy8gQSBxdWljayBub3RlIGFib3V0IG1ldGhvZHM6IEl0J3MgaWxsZWdhbCB0byBoYXZlIHR3byBtZXRob2RzIHdpdGggdGhlXG4gICAgLy8gc2FtZSBzaWduYXR1cmUgaW4gdGhlIHNhbWUgY2xhc3MsIGV2ZW4gaWYgb25lIGlzIHN0YXRpYyBhbmQgdGhlIG90aGVyXG4gICAgLy8gaXNuJ3QuXG4gICAgaWYgKG0uY2xzLmFjY2Vzc0ZsYWdzLmlzSW50ZXJmYWNlKCkpIHtcbiAgICAgIGlmIChtLmFjY2Vzc0ZsYWdzLmlzU3RhdGljKCkpIHtcbiAgICAgICAgLy8gWFhYOiBXZSBpZ25vcmUgc3RhdGljIGludGVyZmFjZSBtZXRob2RzIHJpZ2h0IG5vdywgYXMgcmVjb25jaWxpbmcgdGhlbSB3aXRoIFR5cGVTY3JpcHQnc1xuICAgICAgICAvLyB0eXBlIHN5c3RlbSB3b3VsZCBiZSBtZXNzeS4gQWxzbywgdGhleSBhcmUgYnJhbmQgbmV3IGluIEphdmEgOC5cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFZpcnR1YWwgb25seSwgVHlwZVNjcmlwdCBpbnRlcmZhY2Ugc3ludGF4LlxuICAgICAgICBzdHJlYW0ud3JpdGUoYCAgICBcIiR7bS5zaWduYXR1cmV9XCIke21ldGhvZFNpZ307XFxuYCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICghbm9uVmlydHVhbE9ubHkpIHtcbiAgICAgICAgc3RyZWFtLndyaXRlKGAgICAgJHttZXRob2RGbGFnc30gXCIke20uc2lnbmF0dXJlfVwiJHttZXRob2RTaWd9O1xcbmApO1xuICAgICAgfVxuICAgICAgc3RyZWFtLndyaXRlKGAgICAgJHttZXRob2RGbGFnc30gXCIke20uZnVsbFNpZ25hdHVyZX1cIiR7bWV0aG9kU2lnfTtcXG5gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogT3V0cHV0cyB0aGUgZmllbGQncyB0eXBlIGZvciB0aGUgZ2l2ZW4gZmllbGQgb24gdGhlIGdpdmVuIHN0cmVhbS5cbiAgICovXG4gIHByaXZhdGUgX291dHB1dEZpZWxkKGY6IG1ldGhvZHMuRmllbGQsIHN0cmVhbTogTm9kZUpTLldyaXRhYmxlU3RyZWFtKSB7XG4gICAgdmFyIGZpZWxkVHlwZSA9IGYucmF3RGVzY3JpcHRvciwgY2xzID0gZi5jbHM7XG4gICAgaWYgKGNscy5hY2Nlc3NGbGFncy5pc0ludGVyZmFjZSgpKSB7XG4gICAgICAvLyBYWFg6IElnbm9yZSBzdGF0aWMgaW50ZXJmYWNlIGZpZWxkcyBmb3Igbm93LCBhcyByZWNvbmNpbGluZyB0aGVtIHdpdGggVHlwZVNjcmlwdCdzXG4gICAgICAvLyB0eXBlIHN5c3RlbSB3b3VsZCBiZSBtZXNzeS5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoZi5hY2Nlc3NGbGFncy5pc1N0YXRpYygpKSB7XG4gICAgICBzdHJlYW0ud3JpdGUoYCAgICBwdWJsaWMgc3RhdGljIFwiJHt1dGlsLmRlc2NyaXB0b3IydHlwZXN0cihjbHMuZ2V0SW50ZXJuYWxOYW1lKCkpfS8ke2YubmFtZX1cIjogJHt0aGlzLmp2bXR5cGUydHN0eXBlKGZpZWxkVHlwZSwgZmFsc2UpfTtcXG5gKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3RyZWFtLndyaXRlKGAgICAgcHVibGljIFwiJHt1dGlsLmRlc2NyaXB0b3IydHlwZXN0cihjbHMuZ2V0SW50ZXJuYWxOYW1lKCkpfS8ke2YubmFtZX1cIjogJHt0aGlzLmp2bXR5cGUydHN0eXBlKGZpZWxkVHlwZSwgZmFsc2UpfTtcXG5gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogT3V0cHV0cyBpbmZvcm1hdGlvbiBvbiBhIGZpZWxkIGluamVjdGVkIGJ5IHRoZSBKVk0uXG4gICAqL1xuICBwcml2YXRlIF9vdXRwdXRJbmplY3RlZEZpZWxkKG5hbWU6IHN0cmluZywgdHlwZTogc3RyaW5nLCBzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSkge1xuICAgIHN0cmVhbS53cml0ZShgICAgIHB1YmxpYyAke25hbWV9OiAke3R5cGV9O1xcbmApO1xuICB9XG5cbiAgLyoqXG4gICAqIE91dHB1dCBpbmZvcm1hdGlvbiBvbiBhIG1ldGhvZCBpbmplY3RlZCBieSB0aGUgSlZNLlxuICAgKi9cbiAgcHJpdmF0ZSBfb3V0cHV0SW5qZWN0ZWRNZXRob2QobmFtZTogc3RyaW5nLCB0eXBlOiBzdHJpbmcsIHN0cmVhbTogTm9kZUpTLldyaXRhYmxlU3RyZWFtKSB7XG4gICAgc3RyZWFtLndyaXRlKGAgICAgcHVibGljICR7bmFtZX0ke3R5cGV9O1xcbmApO1xuICB9XG5cbiAgLyoqXG4gICAqIE91dHB1dCBpbmZvcm1hdGlvbiBvbiBhIHN0YXRpYyBtZXRob2QgaW5qZWN0ZWQgYnkgdGhlIEpWTS5cbiAgICovXG4gIHByaXZhdGUgX291dHB1dEluamVjdGVkU3RhdGljTWV0aG9kKG5hbWU6IHN0cmluZywgdHlwZTogc3RyaW5nLCBzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSkge1xuICAgIHN0cmVhbS53cml0ZShgICAgIHB1YmxpYyBzdGF0aWMgJHtuYW1lfSR7dHlwZX07XFxuYCk7XG4gIH1cblxuICBwcml2YXRlIF9wcm9jZXNzR2VuZXJhdGVRdWV1ZSgpOiB2b2lkIHtcbiAgICB3aGlsZSAodGhpcy5nZW5lcmF0ZVF1ZXVlLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMuX3Byb2Nlc3NIZWFkZXIodGhpcy5nZW5lcmF0ZVF1ZXVlLnBvcCgpKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGVzIHRoZSBnZW5lcmljIEpWTSBhcnJheSB0eXBlIGRlZmluaXRpb24uXG4gICAqL1xuICBwcml2YXRlIGdlbmVyYXRlQXJyYXlEZWZpbml0aW9uKCk6IHZvaWQge1xuICAgIHRoaXMuaGVhZGVyU3RyZWFtLndyaXRlKGAgIGV4cG9ydCBjbGFzcyBKVk1BcnJheTxUPiBleHRlbmRzIGphdmFfbGFuZ19PYmplY3Qge1xuICAgIC8qKlxuICAgICAqIE5PVEU6IE91ciBhcnJheXMgYXJlIGVpdGhlciBKUyBhcnJheXMsIG9yIFR5cGVkQXJyYXlzIGZvciBwcmltaXRpdmVcbiAgICAgKiB0eXBlcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXJyYXk6IFRbXTtcbiAgICBwdWJsaWMgZ2V0Q2xhc3MoKTogQ2xhc3NEYXRhLkFycmF5Q2xhc3NEYXRhPFQ+O1xuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhIG5ldyBKVk0gYXJyYXkgb2YgdGhpcyB0eXBlIHRoYXQgc3RhcnRzIGF0IHN0YXJ0LCBhbmQgZW5kcyBhdFxuICAgICAqIGVuZC4gRW5kIGRlZmF1bHRzIHRvIHRoZSBlbmQgb2YgdGhlIGFycmF5LlxuICAgICAqL1xuICAgIHB1YmxpYyBzbGljZShzdGFydDogbnVtYmVyLCBlbmQ/OiBudW1iZXIpOiBKVk1BcnJheTxUPjtcbiAgfVxcbmApO1xuICB9XG59XG5cbi8qKlxuICogSmF2YVNjcmlwdCBvdXRwdXQgdGVtcGxhdGUuXG4gKi9cbmNsYXNzIEpTVGVtcGxhdGUgaW1wbGVtZW50cyBJVGVtcGxhdGUge1xuICBwcml2YXRlIGZpcnN0TWV0aG9kOiBib29sZWFuID0gdHJ1ZTtcbiAgcHJpdmF0ZSBmaXJzdENsYXNzOiBib29sZWFuID0gdHJ1ZTtcbiAgcHVibGljIGdldEV4dGVuc2lvbigpOiBzdHJpbmcgeyByZXR1cm4gJ2pzJzsgfVxuICBwdWJsaWMgZmlsZVN0YXJ0KHN0cmVhbTogTm9kZUpTLldyaXRhYmxlU3RyZWFtKTogdm9pZCB7XG4gICAgc3RyZWFtLndyaXRlKFwiLy8gVGhpcyBlbnRpcmUgb2JqZWN0IGlzIGV4cG9ydGVkLiBGZWVsIGZyZWUgdG8gZGVmaW5lIHByaXZhdGUgaGVscGVyIGZ1bmN0aW9ucyBhYm92ZSBpdC5cXG5yZWdpc3Rlck5hdGl2ZXMoe1wiKTtcbiAgfVxuICBwdWJsaWMgZmlsZUVuZChzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSk6IHZvaWQge1xuICAgIHN0cmVhbS53cml0ZShcIlxcbn0pO1xcblwiKTtcbiAgfVxuICBwdWJsaWMgY2xhc3NTdGFydChzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSwgY2xhc3NOYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmZpcnN0TWV0aG9kID0gdHJ1ZTtcbiAgICBpZiAodGhpcy5maXJzdENsYXNzKSB7XG4gICAgICB0aGlzLmZpcnN0Q2xhc3MgPSBmYWxzZTtcbiAgICB9IGVsc2Uge1xuICAgICAgc3RyZWFtLndyaXRlKFwiLFxcblwiKTtcbiAgICB9XG4gICAgc3RyZWFtLndyaXRlKFwiXFxuICAnXCIgKyBjbGFzc05hbWUucmVwbGFjZSgvXy9nLCAnLycpICsgXCInOiB7XFxuXCIpO1xuICB9XG4gIHB1YmxpYyBjbGFzc0VuZChzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSwgY2xhc3NOYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBzdHJlYW0ud3JpdGUoXCJcXG5cXG4gIH1cIik7XG4gIH1cbiAgcHVibGljIG1ldGhvZChzdHJlYW06IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSwgY2xhc3NEZXNjOiBzdHJpbmcsIG1ldGhvZE5hbWU6IHN0cmluZywgaXNTdGF0aWM6IGJvb2xlYW4sIGFyZ1R5cGVzOiBzdHJpbmdbXSwgclR5cGU6IHN0cmluZyk6IHZvaWQge1xuICAgIC8vIENvbnN0cnVjdCB0aGUgYXJndW1lbnQgc2lnbmF0dXJlLCBmaWd1cmVkIG91dCBmcm9tIHRoZSBtZXRob2ROYW1lLlxuICAgIHZhciBhcmdTaWc6IHN0cmluZyA9ICd0aHJlYWQnLCBpOiBudW1iZXI7XG4gICAgaWYgKCFpc1N0YXRpYykge1xuICAgICAgYXJnU2lnICs9ICcsIGphdmFUaGlzJztcbiAgICB9XG4gICAgZm9yIChpID0gMDsgaSA8IGFyZ1R5cGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBhcmdTaWcgKz0gJywgYXJnJyArIGk7XG4gICAgfVxuICAgIGlmICh0aGlzLmZpcnN0TWV0aG9kKSB7XG4gICAgICB0aGlzLmZpcnN0TWV0aG9kID0gZmFsc2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEVuZCB0aGUgcHJldmlvdXMgbWV0aG9kLlxuICAgICAgc3RyZWFtLndyaXRlKCcsXFxuJyk7XG4gICAgfVxuICAgIHN0cmVhbS53cml0ZShcIlxcbiAgICAnXCIgKyBtZXRob2ROYW1lICsgXCInOiBmdW5jdGlvbihcIiArIGFyZ1NpZyArIFwiKSB7XCIpO1xuICAgIHN0cmVhbS53cml0ZShcIlxcbiAgICAgIHRocmVhZC50aHJvd05ld0V4Y2VwdGlvbignTGphdmEvbGFuZy9VbnNhdGlzZmllZExpbmtFcnJvcjsnLCAnTmF0aXZlIG1ldGhvZCBub3QgaW1wbGVtZW50ZWQuJyk7XCIpO1xuICAgIHN0cmVhbS53cml0ZShcIlxcbiAgICB9XCIpO1xuICB9XG59XG5cbmlmICghZnMuZXhpc3RzU3luYyhhcmd2LnN0YW5kYXJkLmRpcmVjdG9yeSkpIHtcbiAgZnMubWtkaXJTeW5jKGFyZ3Yuc3RhbmRhcmQuZGlyZWN0b3J5KTtcbn1cblxudmFyIGNsYXNzcGF0aDogc3RyaW5nW10gPSBhcmd2LnN0YW5kYXJkLmNsYXNzcGF0aC5zcGxpdCgnOicpLFxuICB0YXJnZXROYW1lOiBzdHJpbmcgPSBhcmd2LmNsYXNzTmFtZS5yZXBsYWNlKC9cXC8vZywgJ18nKS5yZXBsYWNlKC9cXC4vZywgJ18nKSxcbiAgY2xhc3NOYW1lOiBzdHJpbmcgPSBhcmd2LmNsYXNzTmFtZS5yZXBsYWNlKC9cXC4vZywgJy8nKSxcbiAgdGVtcGxhdGU6IElUZW1wbGF0ZSxcbiAgc3RyZWFtOiBOb2RlSlMuV3JpdGFibGVTdHJlYW0sXG4gIHRhcmdldExvY2F0aW9uOiBzdHJpbmc7XG5cbnRhcmdldExvY2F0aW9uID0gZmluZEZpbGUoY2xhc3NOYW1lKTtcbmlmICh0eXBlb2YgdGFyZ2V0TG9jYXRpb24gIT09ICdzdHJpbmcnKSB7XG4gIGNvbnNvbGUuZXJyb3IoJ1VuYWJsZSB0byBmaW5kIGxvY2F0aW9uOiAnICsgY2xhc3NOYW1lKTtcbiAgcHJvY2Vzcy5leGl0KDApO1xufVxuXG50ZW1wbGF0ZSA9IGFyZ3Yuc3RhbmRhcmQudHlwZXNjcmlwdCA/IG5ldyBUU1RlbXBsYXRlKGFyZ3Yuc3RhbmRhcmQuZGlyZWN0b3J5LCBhcmd2LnN0YW5kYXJkLnR5cGVzY3JpcHQpIDogbmV3IEpTVGVtcGxhdGUoKTtcbnN0cmVhbSA9IGZzLmNyZWF0ZVdyaXRlU3RyZWFtKHBhdGguam9pbihhcmd2LnN0YW5kYXJkLmRpcmVjdG9yeSwgdGFyZ2V0TmFtZSArICcuJyArIHRlbXBsYXRlLmdldEV4dGVuc2lvbigpKSk7XG5cbnRlbXBsYXRlLmZpbGVTdGFydChzdHJlYW0pO1xuaWYgKGZzLnN0YXRTeW5jKHRhcmdldExvY2F0aW9uKS5pc0RpcmVjdG9yeSgpKSB7XG4gIGdldEZpbGVzKHRhcmdldExvY2F0aW9uKS5mb3JFYWNoKChjbmFtZTogc3RyaW5nKSA9PiB7XG4gICAgcHJvY2Vzc0NsYXNzRGF0YShzdHJlYW0sIHRlbXBsYXRlLCBuZXcgQ2xhc3NEYXRhLlJlZmVyZW5jZUNsYXNzRGF0YShmcy5yZWFkRmlsZVN5bmMoY25hbWUpKSk7XG4gIH0pO1xufSBlbHNlIHtcbiAgcHJvY2Vzc0NsYXNzRGF0YShzdHJlYW0sIHRlbXBsYXRlLCBuZXcgQ2xhc3NEYXRhLlJlZmVyZW5jZUNsYXNzRGF0YShmcy5yZWFkRmlsZVN5bmModGFyZ2V0TG9jYXRpb24pKSk7XG59XG50ZW1wbGF0ZS5maWxlRW5kKHN0cmVhbSk7XG5pZiAoYXJndi5zdGFuZGFyZC50eXBlc2NyaXB0KSB7XG4gICg8VFNUZW1wbGF0ZT4gdGVtcGxhdGUpLmhlYWRlcnNFbmQoKTtcbn1cbnN0cmVhbS5lbmQobmV3IEJ1ZmZlcignJyksICgpID0+IHt9KTtcbiJdfQ== |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <reference path="../vendor/DefinitelyTyped/node/node.d.ts" /> | |
/* | |
* Doppioh is DoppioJVM's answer to javah, although we realize the 'h' no longer | |
* has a meaning. | |
* | |
* Given a class or package name, Doppioh will generate JavaScript or TypeScript | |
* templates for the native methods of that class or package. | |
* | |
* Options: | |
* -classpath Where to search for classes/packages. | |
* -d [dir] Output directory | |
* -js JavaScript template [default] | |
* -ts [dir] TypeScript template, where 'dir' is a path to DoppioJVM's | |
* TypeScript definition files. | |
*/ | |
import optparse = require('../src/option_parser'); | |
import path = require('path'); | |
import fs = require('fs'); | |
import util = require('../src/util'); | |
import ClassData = require('../src/ClassData'); | |
import ConstantPool = require('../src/ConstantPool'); | |
import methods = require('../src/methods'); | |
import JVMTypes = require('../includes/JVMTypes'); | |
/** | |
* Initializes the option parser with the options for the `doppioh` command. | |
*/ | |
function setupOptparse() { | |
optparse.describe({ | |
standard: { | |
classpath: { | |
alias: 'cp', | |
description: 'JVM classpath, "path1:...:pathN"', | |
has_value: true | |
}, | |
help: { alias: 'h', description: 'print this help message' }, | |
directory: { | |
alias: 'd', | |
description: 'Output directory', | |
has_value: true | |
}, | |
javascript: { | |
alias: 'js', | |
description: 'Generate JavaScript templates [default=true]' | |
}, | |
typescript: { | |
alias: 'ts', | |
description: 'Generate TypeScript templates, -ts path/to/doppio/interfaces', | |
has_value: true | |
}, | |
force_headers: { | |
alias: 'f', | |
description: '[TypeScript only] Forces doppioh to generate TypeScript headers for specified JVM classes, e.g. -f java.lang.String:java.lang.Object', | |
has_value: true | |
} | |
} | |
}); | |
} | |
function printEraseableLine(line: string): void { | |
// Undocumented functions. | |
if ((<any> process.stdout)['clearLine']) { | |
(<any> process.stdout).clearLine(); | |
(<any> process.stdout).cursorTo(0); | |
process.stdout.write(line); | |
} | |
} | |
function printHelp(): void { | |
process.stdout.write("Usage: doppioh [flags] class_or_package_name\n" + optparse.show_help() + "\n"); | |
} | |
setupOptparse(); | |
// Remove "node" and "path/to/doppioh.js". | |
var argv = optparse.parse(process.argv.slice(2)); | |
if (argv.standard.help || process.argv.length === 2) { | |
printHelp(); | |
process.exit(1); | |
} | |
if (!argv.standard.classpath) argv.standard.classpath = '.'; | |
if (!argv.standard.directory) argv.standard.directory = '.'; | |
function findFile(fileName: string): string { | |
var i: number; | |
for (i = 0; i < classpath.length; i++) { | |
if (fs.existsSync(path.join(classpath[i], fileName))) { | |
return path.join(classpath[i], fileName); | |
} else if (fs.existsSync(path.join(classpath[i], fileName + '.class'))) { | |
return path.join(classpath[i], fileName + '.class'); | |
} | |
} | |
} | |
var cache: {[desc: string]: ClassData.ClassData} = {}; | |
function findClass(descriptor: string): ClassData.ClassData { | |
if (cache[descriptor] !== undefined) { | |
return cache[descriptor]; | |
} | |
var rv: ClassData.ClassData; | |
try { | |
switch(descriptor[0]) { | |
case 'L': | |
rv = new ClassData.ReferenceClassData(fs.readFileSync(findFile(util.descriptor2typestr(descriptor) + ".class"))); | |
// Resolve the class. | |
var superClassRef = (<ClassData.ReferenceClassData<JVMTypes.java_lang_Object>> rv).getSuperClassReference(), | |
interfaceClassRefs = (<ClassData.ReferenceClassData<JVMTypes.java_lang_Object>> rv).getInterfaceClassReferences(), | |
superClass: ClassData.ReferenceClassData<JVMTypes.java_lang_Object> = null, | |
interfaceClasses: ClassData.ReferenceClassData<JVMTypes.java_lang_Object>[] = []; | |
if (superClassRef !== null) { | |
superClass = <ClassData.ReferenceClassData<JVMTypes.java_lang_Object>> findClass(superClassRef.name); | |
} | |
if (interfaceClassRefs.length > 0) { | |
interfaceClasses = interfaceClassRefs.map((iface: ConstantPool.ClassReference) => <ClassData.ReferenceClassData<JVMTypes.java_lang_Object>> findClass(iface.name)); | |
} | |
(<ClassData.ReferenceClassData<JVMTypes.java_lang_Object>> rv).setResolved(superClass, interfaceClasses); | |
break; | |
case '[': | |
rv = new ClassData.ArrayClassData(descriptor.slice(1), null); | |
break; | |
default: | |
rv = new ClassData.PrimitiveClassData(descriptor, null); | |
break; | |
} | |
cache[descriptor] = rv; | |
return rv; | |
} catch (e) { | |
throw new Error(`Unable to read class file for ${descriptor}: ${e}\n${e.stack}`); | |
} | |
} | |
function getFiles(dirName: string): string[] { | |
var rv: string[] = [], files = fs.readdirSync(dirName), i: number, file: string; | |
for (i = 0; i < files.length; i++) { | |
file = path.join(dirName, files[i]); | |
if (fs.statSync(file).isDirectory()) { | |
rv = rv.concat(getFiles(file)); | |
} else if (file.indexOf('.class') === (file.length - 6)) { | |
rv.push(file); | |
} | |
} | |
return rv; | |
} | |
function processClassData(stream: NodeJS.WritableStream, template: ITemplate, classData: ClassData.ReferenceClassData<JVMTypes.java_lang_Object>) { | |
var fixedClassName: string = classData.getInternalName().replace(/\//g, '_'), | |
nativeFound: boolean = false; | |
// Shave off L and ; | |
fixedClassName = fixedClassName.substring(1, fixedClassName.length - 1); | |
var methods = classData.getMethods(); | |
methods.forEach((method: methods.Method) => { | |
if (method.accessFlags.isNative()) { | |
if (!nativeFound) { | |
template.classStart(stream, fixedClassName); | |
nativeFound = true; | |
} | |
template.method(stream, classData.getInternalName(), method.signature, method.accessFlags.isStatic(), method.parameterTypes, method.returnType); | |
} | |
}); | |
if (nativeFound) { | |
template.classEnd(stream, fixedClassName); | |
} | |
} | |
/** | |
* A Doppioh output template. | |
*/ | |
interface ITemplate { | |
getExtension(): string; | |
fileStart(stream: NodeJS.WritableStream): void; | |
fileEnd(stream: NodeJS.WritableStream): void; | |
classStart(stream: NodeJS.WritableStream, className: string): void; | |
classEnd(stream: NodeJS.WritableStream, className: string): void; | |
method(stream: NodeJS.WritableStream, classDesc: string, methodName: string, isStatic: boolean, argTypes: string[], rv: string): void; | |
} | |
/** | |
* TypeScript output template. | |
*/ | |
class TSTemplate implements ITemplate { | |
private headerCount: number = 0; | |
private relativeInterfacePath: string; | |
private headerSet: { [clsName: string]: boolean} = {}; | |
private classesSeen: string[] = []; | |
private headerPath: string = path.resolve(argv.standard.directory, "JVMTypes.d.ts"); | |
private headerStream: NodeJS.WritableStream; | |
private generateQueue: ClassData.ReferenceClassData<JVMTypes.java_lang_Object>[] = []; | |
constructor(outputPath: string, private interfacePath: string) { | |
this.relativeInterfacePath = path.relative(outputPath, interfacePath); | |
// Parse existing types file for existing definitions. We'll remake them. | |
try { | |
var existingHeaders = fs.readFileSync(this.headerPath).toString(), | |
searchIdx = 0, clsName: string; | |
// Pass 1: Classes. | |
while ((searchIdx = existingHeaders.indexOf("export class ", searchIdx)) > -1) { | |
clsName = existingHeaders.slice(searchIdx + 13, existingHeaders.indexOf(" ", searchIdx + 13)); | |
if (clsName.indexOf("JVMArray") !== 0) { | |
this.generateClassDefinition(this.tstype2jvmtype(clsName)); | |
} | |
searchIdx++; | |
} | |
searchIdx = 0; | |
// Pass 2: Interfaces. | |
while ((searchIdx = existingHeaders.indexOf("export interface ", searchIdx)) > -1) { | |
clsName = existingHeaders.slice(searchIdx + 17, existingHeaders.indexOf(" ", searchIdx + 17)); | |
this.generateClassDefinition(this.tstype2jvmtype(clsName)); | |
searchIdx++; | |
} | |
} catch (e) { | |
// Ignore. | |
console.log("Error parsing exiting file: " + e); | |
} | |
this.headerStream = fs.createWriteStream(this.headerPath); | |
this.headersStart(); | |
// Generate required types. | |
this.generateArrayDefinition(); | |
this.generateClassDefinition('Ljava/lang/Throwable;'); | |
if (argv.standard.force_headers) { | |
var clses = argv.standard.force_headers.split(':'); | |
clses.forEach((clsName: string) => { | |
this.generateClassDefinition(util.int_classname(clsName)); | |
}); | |
} | |
} | |
public headersStart(): void { | |
this.headerStream.write(`// TypeScript declaration file for JVM types. Automatically generated by doppioh. | |
// http://github.com/plasma-umass/doppio | |
${fs.readdirSync(path.resolve(this.interfacePath, "src")).map((item: string) => | |
(item.indexOf('.ts') !== -1 && item[0] !== '.') ? `import ${item.slice(0, item.indexOf('.'))} = require("${path.join(this.relativeInterfacePath, 'src', item.slice(0, item.indexOf('.')))}");\n` : '' | |
).join("")} | |
declare module JVMTypes {\n`); | |
} | |
public getExtension(): string { return 'ts'; } | |
public fileStart(stream: NodeJS.WritableStream): void { | |
// Reference all of the doppio interfaces. | |
var srcInterfacePath: string = path.join(this.interfacePath, 'src'), | |
files = fs.readdirSync(srcInterfacePath), | |
i: number, file: string; | |
stream.write(`import JVMTypes = require("./JVMTypes");\n`); | |
for (i = 0; i < files.length; i++) { | |
file = files[i]; | |
if (file.substring(file.length - 4) === 'd.ts') { | |
// Strip off '.d.ts'. | |
var modName = file.substring(0, file.length - 5); | |
stream.write('import ' + modName + ' = require("' + path.join(this.relativeInterfacePath, 'src', modName).replace(/\\/g, '/') + '");\n'); | |
} | |
} | |
stream.write(`\ndeclare var registerNatives: (natives: any) => void;\n`); | |
} | |
public fileEnd(stream: NodeJS.WritableStream): void { | |
var i: number; | |
// Export everything! | |
stream.write("\n// Export line. This is what DoppioJVM sees.\nregisterNatives({"); | |
for (i = 0; i < this.classesSeen.length; i++) { | |
var kls = this.classesSeen[i]; | |
if (i > 0) stream.write(','); | |
stream.write("\n '" + kls.replace(/_/g, '/') + "': " + kls); | |
} | |
stream.write("\n});\n"); | |
} | |
/** | |
* Emits TypeScript type declarations. Separated from fileEnd, since one can | |
* use doppioh to emit headers only. | |
*/ | |
public headersEnd(): void { | |
this._processGenerateQueue(); | |
// Print newline to clear eraseable line. | |
printEraseableLine(`Processed ${this.headerCount} classes.\n`); | |
this.headerStream.end(`} | |
export = JVMTypes;\n`, () => {}); | |
} | |
public classStart(stream: NodeJS.WritableStream, className: string): void { | |
stream.write("\nclass " + className + " {\n"); | |
this.classesSeen.push(className); | |
this.generateClassDefinition(`L${className.replace(/_/g, "/")};`); | |
} | |
public classEnd(stream: NodeJS.WritableStream, className: string): void { | |
stream.write("\n}\n"); | |
} | |
public method(stream: NodeJS.WritableStream, classDesc: string, methodName: string, isStatic: boolean, argTypes: string[], rType: string): void { | |
var trueRtype = this.jvmtype2tstype(rType), rval = ""; | |
if (trueRtype === 'number') { | |
rval = "0"; | |
} else if (trueRtype !== 'void') { | |
rval = "null"; | |
} | |
argTypes.concat([rType]).forEach((type: string) => { | |
this.generateClassDefinition(type); | |
}); | |
stream.write(` | |
public static '${methodName}'(thread: threading.JVMThread${isStatic ? '' : `, javaThis: ${this.jvmtype2tstype(classDesc)}`}${argTypes.length === 0 ? '' : ', ' + argTypes.map((type: string, i: number) => `arg${i}: ${this.jvmtype2tstype(type)}`).join(", ")}): ${this.jvmtype2tstype(rType)} { | |
thread.throwNewException('Ljava/lang/UnsatisfiedLinkError;', 'Native method not implemented.');${rval !== '' ? `\n return ${rval};` : ''} | |
}\n`); | |
} | |
/** | |
* Converts a typestring to its equivalent TypeScript type. | |
*/ | |
private jvmtype2tstype(desc: string, prefix: boolean = true): string { | |
switch(desc[0]) { | |
case '[': | |
return (prefix ? 'JVMTypes.' : '') + `JVMArray<${this.jvmtype2tstype(desc.slice(1), prefix)}>`; | |
case 'L': | |
// Ensure all converted reference types get generated headers. | |
this.generateClassDefinition(desc); | |
return (prefix ? 'JVMTypes.' : '') + util.descriptor2typestr(desc).replace(/_/g, '__').replace(/\//g, '_'); | |
case 'J': | |
return 'gLong'; | |
case 'V': | |
return 'void'; | |
default: | |
// Primitives. | |
return 'number'; | |
} | |
} | |
/** | |
* Converts a TypeScript type into its equivalent JVM type. | |
*/ | |
private tstype2jvmtype(tsType: string): string { | |
if (tsType.indexOf('JVMArray') === 0) { | |
return `[${this.tstype2jvmtype(tsType.slice(9, tsType.length - 1))}`; | |
} else if (tsType === 'number') { | |
throw new Error("Ambiguous."); | |
} else if (tsType === 'void') { | |
return 'V'; | |
} else { | |
// _ => /, and // => _ since we encode underscores as double underscores. | |
return `L${tsType.replace(/_/g, '/').replace(/\/\//g, '_')};`; | |
} | |
} | |
/** | |
* Generates a TypeScript class definition for the given class object. | |
*/ | |
private generateClassDefinition(desc: string): void { | |
if (this.headerSet[desc] !== undefined || util.is_primitive_type(desc)) { | |
// Already generated, or is a primitive. | |
return; | |
} else if (desc[0] === '[') { | |
// Ensure component type is created. | |
return this.generateClassDefinition(desc.slice(1)); | |
} else { | |
// Mark this class as queued for headerification. We use a queue instead | |
// of a recursive scheme to avoid stack overflows. | |
this.headerSet[desc] = true; | |
this.generateQueue.push(<ClassData.ReferenceClassData<JVMTypes.java_lang_Object>> findClass(desc)); | |
} | |
} | |
private _processHeader(cls: ClassData.ReferenceClassData<JVMTypes.java_lang_Object>): void { | |
var desc = cls.getInternalName(), | |
interfaces = cls.getInterfaceClassReferences().map((iface: ConstantPool.ClassReference) => iface.name), | |
superClass = cls.getSuperClassReference(), | |
methods = cls.getMethods().concat(cls.getMirandaAndDefaultMethods()), | |
fields = cls.getFields(), | |
methodsSeen: { [name: string]: boolean } = {}, | |
injectedFields = cls.getInjectedFields(), | |
injectedMethods = cls.getInjectedMethods(), | |
injectedStaticMethods = cls.getInjectedStaticMethods(); | |
printEraseableLine(`[${this.headerCount++}] Processing header for ${util.descriptor2typestr(desc)}...`); | |
if (cls.accessFlags.isInterface()) { | |
// Interfaces map to TypeScript interfaces. | |
this.headerStream.write(` export interface ${this.jvmtype2tstype(desc, false)}`); | |
} else { | |
this.headerStream.write(` export class ${this.jvmtype2tstype(desc, false)}`); | |
} | |
// Note: Interface classes have java.lang.Object as a superclass. | |
// While java_lang_Object is a class, TypeScript will extract an interface | |
// for the class under-the-covers and extract it, correctly providing us | |
// with injected JVM methods on interface types (e.g. getClass()). | |
if (superClass !== null) { | |
this.headerStream.write(` extends ${this.jvmtype2tstype(superClass.name, false)}`); | |
} | |
if (interfaces.length > 0) { | |
if (cls.accessFlags.isInterface()) { | |
// Interfaces can extend multiple interfaces, and can extend classes! | |
// Add a comma after the guaranteed "java_lang_Object". | |
this.headerStream.write(`, `); | |
} else { | |
// Classes can implement multiple interfaces. | |
this.headerStream.write(` implements `); | |
} | |
this.headerStream.write(`${interfaces.map((ifaceName: string) => this.jvmtype2tstype(ifaceName, false)).join(", ")}`); | |
} | |
this.headerStream.write(` {\n`); | |
Object.keys(injectedFields).forEach((name: string) => this._outputInjectedField(name, injectedFields[name], this.headerStream)); | |
Object.keys(injectedMethods).forEach((name: string) => this._outputInjectedMethod(name, injectedMethods[name], this.headerStream)); | |
Object.keys(injectedStaticMethods).forEach((name: string) => this._outputInjectedStaticMethod(name, injectedStaticMethods[name], this.headerStream)); | |
fields.forEach((f) => this._outputField(f, this.headerStream)); | |
methods.forEach((m) => this._outputMethod(m, this.headerStream)); | |
cls.getUninheritedDefaultMethods().forEach((m) => this._outputMethod(m, this.headerStream)); | |
this.headerStream.write(` }\n`); | |
} | |
/** | |
* Outputs a method signature for the given method on the given stream. | |
* NOTE: We require a class argument because default interface methods are | |
* defined on classes, not on the interfaces they belong to. | |
*/ | |
private _outputMethod(m: methods.Method, stream: NodeJS.WritableStream, nonVirtualOnly: boolean = false) { | |
var argTypes = m.parameterTypes, | |
rType = m.returnType, args: string = "", | |
cbSig = `e?: java_lang_Throwable${rType === 'V' ? "" : `, rv?: ${this.jvmtype2tstype(rType, false)}`}`, | |
methodSig: string, methodFlags = `public${m.accessFlags.isStatic() ? ' static' : ''}`; | |
if (argTypes.length > 0) { | |
// Arguments are a giant tuple type. | |
// NOTE: Long / doubles take up two argument slots. The second argument is always NULL. | |
args = "args: [" + argTypes.map((type: string, i: number) => `${this.jvmtype2tstype(type, false)}${(type === "J" || type === "D") ? ', any' : ''}`).join(", ") + "], "; | |
} | |
methodSig = `(thread: threading.JVMThread, ${args}cb?: (${cbSig}) => void): void`; | |
// A quick note about methods: It's illegal to have two methods with the | |
// same signature in the same class, even if one is static and the other | |
// isn't. | |
if (m.cls.accessFlags.isInterface()) { | |
if (m.accessFlags.isStatic()) { | |
// XXX: We ignore static interface methods right now, as reconciling them with TypeScript's | |
// type system would be messy. Also, they are brand new in Java 8. | |
} else { | |
// Virtual only, TypeScript interface syntax. | |
stream.write(` "${m.signature}"${methodSig};\n`); | |
} | |
} else { | |
if (!nonVirtualOnly) { | |
stream.write(` ${methodFlags} "${m.signature}"${methodSig};\n`); | |
} | |
stream.write(` ${methodFlags} "${m.fullSignature}"${methodSig};\n`); | |
} | |
} | |
/** | |
* Outputs the field's type for the given field on the given stream. | |
*/ | |
private _outputField(f: methods.Field, stream: NodeJS.WritableStream) { | |
var fieldType = f.rawDescriptor, cls = f.cls; | |
if (cls.accessFlags.isInterface()) { | |
// XXX: Ignore static interface fields for now, as reconciling them with TypeScript's | |
// type system would be messy. | |
return; | |
} | |
if (f.accessFlags.isStatic()) { | |
stream.write(` public static "${util.descriptor2typestr(cls.getInternalName())}/${f.name}": ${this.jvmtype2tstype(fieldType, false)};\n`); | |
} else { | |
stream.write(` public "${util.descriptor2typestr(cls.getInternalName())}/${f.name}": ${this.jvmtype2tstype(fieldType, false)};\n`); | |
} | |
} | |
/** | |
* Outputs information on a field injected by the JVM. | |
*/ | |
private _outputInjectedField(name: string, type: string, stream: NodeJS.WritableStream) { | |
stream.write(` public ${name}: ${type};\n`); | |
} | |
/** | |
* Output information on a method injected by the JVM. | |
*/ | |
private _outputInjectedMethod(name: string, type: string, stream: NodeJS.WritableStream) { | |
stream.write(` public ${name}${type};\n`); | |
} | |
/** | |
* Output information on a static method injected by the JVM. | |
*/ | |
private _outputInjectedStaticMethod(name: string, type: string, stream: NodeJS.WritableStream) { | |
stream.write(` public static ${name}${type};\n`); | |
} | |
private _processGenerateQueue(): void { | |
while (this.generateQueue.length > 0) { | |
this._processHeader(this.generateQueue.pop()); | |
} | |
} | |
/** | |
* Generates the generic JVM array type definition. | |
*/ | |
private generateArrayDefinition(): void { | |
this.headerStream.write(` export class JVMArray<T> extends java_lang_Object { | |
/** | |
* NOTE: Our arrays are either JS arrays, or TypedArrays for primitive | |
* types. | |
*/ | |
public array: T[]; | |
public getClass(): ClassData.ArrayClassData<T>; | |
/** | |
* Create a new JVM array of this type that starts at start, and ends at | |
* end. End defaults to the end of the array. | |
*/ | |
public slice(start: number, end?: number): JVMArray<T>; | |
}\n`); | |
} | |
} | |
/** | |
* JavaScript output template. | |
*/ | |
class JSTemplate implements ITemplate { | |
private firstMethod: boolean = true; | |
private firstClass: boolean = true; | |
public getExtension(): string { return 'js'; } | |
public fileStart(stream: NodeJS.WritableStream): void { | |
stream.write("// This entire object is exported. Feel free to define private helper functions above it.\nregisterNatives({"); | |
} | |
public fileEnd(stream: NodeJS.WritableStream): void { | |
stream.write("\n});\n"); | |
} | |
public classStart(stream: NodeJS.WritableStream, className: string): void { | |
this.firstMethod = true; | |
if (this.firstClass) { | |
this.firstClass = false; | |
} else { | |
stream.write(",\n"); | |
} | |
stream.write("\n '" + className.replace(/_/g, '/') + "': {\n"); | |
} | |
public classEnd(stream: NodeJS.WritableStream, className: string): void { | |
stream.write("\n\n }"); | |
} | |
public method(stream: NodeJS.WritableStream, classDesc: string, methodName: string, isStatic: boolean, argTypes: string[], rType: string): void { | |
// Construct the argument signature, figured out from the methodName. | |
var argSig: string = 'thread', i: number; | |
if (!isStatic) { | |
argSig += ', javaThis'; | |
} | |
for (i = 0; i < argTypes.length; i++) { | |
argSig += ', arg' + i; | |
} | |
if (this.firstMethod) { | |
this.firstMethod = false; | |
} else { | |
// End the previous method. | |
stream.write(',\n'); | |
} | |
stream.write("\n '" + methodName + "': function(" + argSig + ") {"); | |
stream.write("\n thread.throwNewException('Ljava/lang/UnsatisfiedLinkError;', 'Native method not implemented.');"); | |
stream.write("\n }"); | |
} | |
} | |
if (!fs.existsSync(argv.standard.directory)) { | |
fs.mkdirSync(argv.standard.directory); | |
} | |
var classpath: string[] = argv.standard.classpath.split(':'), | |
targetName: string = argv.className.replace(/\//g, '_').replace(/\./g, '_'), | |
className: string = argv.className.replace(/\./g, '/'), | |
template: ITemplate, | |
stream: NodeJS.WritableStream, | |
targetLocation: string; | |
targetLocation = findFile(className); | |
if (typeof targetLocation !== 'string') { | |
console.error('Unable to find location: ' + className); | |
process.exit(0); | |
} | |
template = argv.standard.typescript ? new TSTemplate(argv.standard.directory, argv.standard.typescript) : new JSTemplate(); | |
stream = fs.createWriteStream(path.join(argv.standard.directory, targetName + '.' + template.getExtension())); | |
template.fileStart(stream); | |
if (fs.statSync(targetLocation).isDirectory()) { | |
getFiles(targetLocation).forEach((cname: string) => { | |
processClassData(stream, template, new ClassData.ReferenceClassData(fs.readFileSync(cname))); | |
}); | |
} else { | |
processClassData(stream, template, new ClassData.ReferenceClassData(fs.readFileSync(targetLocation))); | |
} | |
template.fileEnd(stream); | |
if (argv.standard.typescript) { | |
(<TSTemplate> template).headersEnd(); | |
} | |
stream.end(new Buffer(''), () => {}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment