Skip to content

Instantly share code, notes, and snippets.

@jvilk
Created October 5, 2015 21:34
Show Gist options
  • Save jvilk/a025f599d4e96d52ba4a to your computer and use it in GitHub Desktop.
Save jvilk/a025f599d4e96d52ba4a to your computer and use it in GitHub Desktop.
TypeScript Source Map Bug
/// <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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9wcGlvaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2NvbnNvbGUvZG9wcGlvaC50cyJdLCJuYW1lcyI6WyJzZXR1cE9wdHBhcnNlIiwicHJpbnRFcmFzZWFibGVMaW5lIiwicHJpbnRIZWxwIiwiZmluZEZpbGUiLCJmaW5kQ2xhc3MiLCJnZXRGaWxlcyIsInByb2Nlc3NDbGFzc0RhdGEiLCJUU1RlbXBsYXRlIiwiVFNUZW1wbGF0ZS5jb25zdHJ1Y3RvciIsIlRTVGVtcGxhdGUuaGVhZGVyc1N0YXJ0IiwiVFNUZW1wbGF0ZS5nZXRFeHRlbnNpb24iLCJUU1RlbXBsYXRlLmZpbGVTdGFydCIsIlRTVGVtcGxhdGUuZmlsZUVuZCIsIlRTVGVtcGxhdGUuaGVhZGVyc0VuZCIsIlRTVGVtcGxhdGUuY2xhc3NTdGFydCIsIlRTVGVtcGxhdGUuY2xhc3NFbmQiLCJUU1RlbXBsYXRlLm1ldGhvZCIsIlRTVGVtcGxhdGUuanZtdHlwZTJ0c3R5cGUiLCJUU1RlbXBsYXRlLnRzdHlwZTJqdm10eXBlIiwiVFNUZW1wbGF0ZS5nZW5lcmF0ZUNsYXNzRGVmaW5pdGlvbiIsIlRTVGVtcGxhdGUuX3Byb2Nlc3NIZWFkZXIiLCJUU1RlbXBsYXRlLl9vdXRwdXRNZXRob2QiLCJUU1RlbXBsYXRlLl9vdXRwdXRGaWVsZCIsIlRTVGVtcGxhdGUuX291dHB1dEluamVjdGVkRmllbGQiLCJUU1RlbXBsYXRlLl9vdXRwdXRJbmplY3RlZE1ldGhvZCIsIlRTVGVtcGxhdGUuX291dHB1dEluamVjdGVkU3RhdGljTWV0aG9kIiwiVFNUZW1wbGF0ZS5fcHJvY2Vzc0dlbmVyYXRlUXVldWUiLCJUU1RlbXBsYXRlLmdlbmVyYXRlQXJyYXlEZWZpbml0aW9uIiwiSlNUZW1wbGF0ZSIsIkpTVGVtcGxhdGUuY29uc3RydWN0b3IiLCJKU1RlbXBsYXRlLmdldEV4dGVuc2lvbiIsIkpTVGVtcGxhdGUuZmlsZVN0YXJ0IiwiSlNUZW1wbGF0ZS5maWxlRW5kIiwiSlNUZW1wbGF0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Q0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQztJQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxHQUFHLEdBQUcsQ0FBQztBQUU1RCxrQkFBa0IsUUFBZ0I7SUFDaENDLElBQUlBLENBQVNBLENBQUNBO0lBQ2RBLEdBQUdBLENBQUNBLENBQUNBLENBQUNBLEdBQUdBLENBQUNBLEVBQUVBLENBQUNBLEdBQUdBLFNBQVNBLENBQUNBLE1BQU1BLEVBQUVBLENBQUNBLEVBQUVBLEVBQUVBLENBQUNBO1FBQ3RDQSxFQUFFQSxDQUFDQSxDQUFDQSxFQUFFQSxDQUFDQSxVQUFVQSxDQUFDQSxJQUFJQSxDQUFDQSxJQUFJQSxDQUFDQSxTQUFTQSxDQUFDQSxDQUFDQSxDQUFDQSxFQUFFQSxRQUFRQSxDQUFDQSxDQUFDQSxDQUFDQSxDQUFDQSxDQUFDQTtZQUNyREEsTUFBTUEsQ0FBQ0EsSUFBSUEsQ0FBQ0EsSUFBSUEsQ0FBQ0EsU0FBU0EsQ0FBQ0EsQ0FBQ0EsQ0FBQ0EsRUFBRUEsUUFBUUEsQ0FBQ0EsQ0FBQ0E7UUFDM0NBLENBQUNBO1FBQUNBLElBQUlBLENBQUNBLEVBQUVBLENBQUNBLENBQUNBLEVBQUVBLENBQUNBLFVBQVVBLENBQUNBLElBQUlBLENBQUNBLElBQUlBLENBQUNBLFNBQVNBLENBQUNBLENBQUNBLENBQUNBLEVBQUVBLFFBQVFBLEdBQUdBLFFBQVFBLENBQUNBLENBQUNBLENBQUNBLENBQUNBLENBQUNBO1lBQ3ZFQSxNQUFNQSxDQUFDQSxJQUFJQSxDQUFDQSxJQUFJQSxDQUFDQSxTQUFTQSxDQUFDQSxDQUFDQSxDQUFDQSxFQUFFQSxRQUFRQSxHQUFHQSxRQUFRQSxDQUFDQSxDQUFDQTtRQUN0REEsQ0FBQ0E7SUFDSEEsQ0FBQ0E7QUFDSEEsQ0FBQ0E7QUFFRCxJQUFJLEtBQUssR0FBMEMsRUFBRSxDQUFDO0FBQ3RELG1CQUFtQixVQUFrQjtJQUNuQ0MsRUFBRUEsQ0FBQ0EsQ0FBQ0EsS0FBS0EsQ0FBQ0EsVUFBVUEsQ0FBQ0EsS0FBS0EsU0FBU0EsQ0FBQ0EsQ0FBQ0Es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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==
/// <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