UNPKG

@selfage/generator_cli

Version:

Code generation for message, service, and database.

213 lines 37.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateService = generateService; exports.generateRemoteCallsGroup = generateRemoteCallsGroup; exports.generateRemoteCall = generateRemoteCall; const output_content_builder_1 = require("./output_content_builder"); const util_1 = require("./util"); let PRIMITIVE_TYPE_BYTES = "bytes"; let PRIMITIVE_TYPES = new Set([PRIMITIVE_TYPE_BYTES]); function generateService(definitionModulePath, serviceDefinition, outputContentMap) { let contentBuilder = output_content_builder_1.TsContentBuilder.get(outputContentMap, definitionModulePath); if (!serviceDefinition.name) { throw new Error(`"name" is missing on a service.`); } if (!serviceDefinition.path) { throw new Error(`"path" is missing on service ${serviceDefinition.name}.`); } contentBuilder.importFromServiceDescriptor(`ServiceDescriptor`); contentBuilder.push(` export let ${(0, util_1.toUppercaseSnaked)(serviceDefinition.name)}: ServiceDescriptor = { name: "${serviceDefinition.name}", path: "${serviceDefinition.path}", } `); } function generateRemoteCallsGroup(definitionModulePath, remoteCallsGroupDefinition, definitionResolver, outputContentMap) { let descriptorContentBuilder = output_content_builder_1.TsContentBuilder.get(outputContentMap, definitionModulePath); if (!remoteCallsGroupDefinition.service) { throw new Error(`"service" is missing on remote calls group ${remoteCallsGroupDefinition.name}.`); } let definition = definitionResolver.resolve(`When looking for service definition for remote calls group ${remoteCallsGroupDefinition.name},`, remoteCallsGroupDefinition.service, remoteCallsGroupDefinition.importService); if (definition.kind !== "Service") { throw new Error(`Service name ${remoteCallsGroupDefinition.service} on remote calls group ${remoteCallsGroupDefinition.name} is not a service.`); } let serviceName = (0, util_1.toUppercaseSnaked)(remoteCallsGroupDefinition.service); descriptorContentBuilder.importFromDefinition(remoteCallsGroupDefinition.importService, serviceName); if (!remoteCallsGroupDefinition.outputClient) { throw new Error(`"outputClient" is missing on remote calls group ${remoteCallsGroupDefinition.name}.`); } let clientContentBuilder = output_content_builder_1.TsContentBuilder.get(outputContentMap, definitionModulePath, remoteCallsGroupDefinition.outputClient); if (!remoteCallsGroupDefinition.outputHandler) { throw new Error(`"outputHandler" is missing on remote calls group ${remoteCallsGroupDefinition.name}.`); } let handlerContentBuilder = output_content_builder_1.TsContentBuilder.get(outputContentMap, definitionModulePath, remoteCallsGroupDefinition.outputHandler); if (!remoteCallsGroupDefinition.calls) { throw new Error(`"calls" is either missing or not an array on remote calls group ${remoteCallsGroupDefinition.name}.`); } for (let remoteCall of remoteCallsGroupDefinition.calls) { remoteCall.path = (remoteCallsGroupDefinition.path ?? "") + remoteCall.path; generateRemoteCall(definitionModulePath, remoteCall, serviceName, definitionResolver, descriptorContentBuilder, clientContentBuilder, handlerContentBuilder); } } function generateRemoteCall(definitionModulePath, remoteCallDefinition, serviceName, definitionResolver, descriptorContentBuilder, clientContentBuilder, handlerContentBuilder) { if (!remoteCallDefinition.name) { throw new Error(`"name" is missing on a RemoteCall.`); } let loggingPrefix = `When generating descriptor for remote call ${remoteCallDefinition.name},`; let bodyDescriptor = ""; if (!remoteCallDefinition.body) { throw new Error(`${loggingPrefix} "body" is missing.`); } if (PRIMITIVE_TYPES.has(remoteCallDefinition.body)) { descriptorContentBuilder.importFromServiceDescriptor("PrimitveTypeForBody"); bodyDescriptor = ` body: { primitiveType: PrimitveTypeForBody.${remoteCallDefinition.body.toUpperCase()}, },`; } else { let requesBodytDefinition = definitionResolver.resolve(loggingPrefix, remoteCallDefinition.body, remoteCallDefinition.importBody); if (requesBodytDefinition.kind !== "Message") { throw new Error(`${loggingPrefix} request body ${remoteCallDefinition.body} is not a message.`); } let requestBodyDescriptorName = (0, util_1.toUppercaseSnaked)(remoteCallDefinition.body); descriptorContentBuilder.importFromDefinition(remoteCallDefinition.importBody, requestBodyDescriptorName); bodyDescriptor = ` body: { messageType: ${requestBodyDescriptorName}, },`; } let metadataDescriptor = ""; if (remoteCallDefinition.metadata) { if (!remoteCallDefinition.metadata.type) { throw new Error(`${loggingPrefix} "type" is missing in the "metadata" field.`); } let metadataDefinition = definitionResolver.resolve(loggingPrefix, remoteCallDefinition.metadata.type, remoteCallDefinition.metadata.import); if (metadataDefinition.kind !== "Message") { throw new Error(`${loggingPrefix} metadata type ${remoteCallDefinition.metadata.type} is not a message.`); } let metadataDescriptorName = (0, util_1.toUppercaseSnaked)(remoteCallDefinition.metadata.type); descriptorContentBuilder.importFromDefinition(remoteCallDefinition.metadata.import, metadataDescriptorName); if (!remoteCallDefinition.metadata.key) { throw new Error(`${loggingPrefix} "key" is missing in the "metadata" field.`); } metadataDescriptor = ` metadata: { key: "${remoteCallDefinition.metadata.key}", type: ${metadataDescriptorName}, },`; } let authKey = ""; if (remoteCallDefinition.authKey) { authKey = ` authKey: "${remoteCallDefinition.authKey}",`; } if (!remoteCallDefinition.response) { throw new Error(`${loggingPrefix} "response" is missing.`); } let responseDefinition = definitionResolver.resolve(loggingPrefix, remoteCallDefinition.response, remoteCallDefinition.importResponse); if (responseDefinition.kind !== "Message") { throw new Error(`${loggingPrefix} response type ${remoteCallDefinition.response} is not a message.`); } let responseDescriptorName = (0, util_1.toUppercaseSnaked)(remoteCallDefinition.response); descriptorContentBuilder.importFromDefinition(remoteCallDefinition.importResponse, responseDescriptorName); let responseDescriptor = ` response: { messageType: ${responseDescriptorName}, },`; descriptorContentBuilder.importFromServiceDescriptor("RemoteCallDescriptor"); let remoteCallDescriptorName = (0, util_1.toUppercaseSnaked)(remoteCallDefinition.name); descriptorContentBuilder.push(` export let ${remoteCallDescriptorName}: RemoteCallDescriptor = { name: "${remoteCallDefinition.name}", service: ${serviceName}, path: "${remoteCallDefinition.path}",${bodyDescriptor}${metadataDescriptor}${authKey}${responseDescriptor} } `); generateClient(definitionModulePath, remoteCallDefinition, clientContentBuilder); generateHandler(definitionModulePath, remoteCallDefinition, handlerContentBuilder); } function generateClient(definitionModulePath, remoteCallDefinition, clientContentBuilder) { let loggingPrefix = `When generating client for ${remoteCallDefinition.name},`; let bodyParam = ""; if (PRIMITIVE_TYPES.has(remoteCallDefinition.body)) { if (remoteCallDefinition.body === PRIMITIVE_TYPE_BYTES) { bodyParam = ` body: Blob,`; } else { throw new Error(`${loggingPrefix} there is a new primitive type needs to be handled for its request body.`); } } else { clientContentBuilder.importFromDefinition(remoteCallDefinition.importBody, remoteCallDefinition.body); bodyParam = ` body: ${remoteCallDefinition.body},`; } let metadataParam = ""; let metdataVariable = ""; if (remoteCallDefinition.metadata) { clientContentBuilder.importFromDefinition(remoteCallDefinition.metadata.import, remoteCallDefinition.metadata.type); metadataParam = ` metadata: ${remoteCallDefinition.metadata.type},`; metdataVariable = ` metadata,`; } clientContentBuilder.importFromDefinition(remoteCallDefinition.importResponse, remoteCallDefinition.response); let remoteCallDescriptorName = (0, util_1.toUppercaseSnaked)(remoteCallDefinition.name); clientContentBuilder.importFromDefinition(definitionModulePath, remoteCallDescriptorName); clientContentBuilder.importFromServiceClientRequestInterface("ClientRequestInterface"); clientContentBuilder.push(` export function new${remoteCallDefinition.name}Request(${bodyParam}${metadataParam} ): ClientRequestInterface<${remoteCallDefinition.response}> { return { descriptor: ${remoteCallDescriptorName}, body,${metdataVariable} }; } `); } function generateHandler(definitionModulePath, remoteCallDefinition, handlerContentBuilder) { let loggingPrefix = `When generating handler for ${remoteCallDefinition.name},`; let bodyParam = ""; if (PRIMITIVE_TYPES.has(remoteCallDefinition.body)) { if (remoteCallDefinition.body === PRIMITIVE_TYPE_BYTES) { handlerContentBuilder.importFromStream("Readable"); bodyParam = ` body: Readable,`; } else { throw new Error(`${loggingPrefix} there is a new primitive type needs to be handled for its request body.`); } } else { handlerContentBuilder.importFromDefinition(remoteCallDefinition.importBody, remoteCallDefinition.body); bodyParam = ` body: ${remoteCallDefinition.body},`; } let metadataParam = ""; if (remoteCallDefinition.metadata) { handlerContentBuilder.importFromDefinition(remoteCallDefinition.metadata.import, remoteCallDefinition.metadata.type); metadataParam = ` metadata: ${remoteCallDefinition.metadata.type},`; } let authStrParam = ""; if (remoteCallDefinition.authKey) { authStrParam = ` authStr: string,`; } let remoteCallDescriptorName = (0, util_1.toUppercaseSnaked)(remoteCallDefinition.name); handlerContentBuilder.importFromDefinition(definitionModulePath, remoteCallDescriptorName); handlerContentBuilder.importFromDefinition(remoteCallDefinition.importResponse, remoteCallDefinition.response); handlerContentBuilder.importFromServiceRemoteCallHandlerInterface("RemoteCallHandlerInterface"); handlerContentBuilder.push(` export abstract class ${remoteCallDefinition.name}HandlerInterface implements RemoteCallHandlerInterface { public descriptor = ${remoteCallDescriptorName}; public abstract handle( loggingPrefix: string,${bodyParam}${metadataParam}${authStrParam} ): Promise<${remoteCallDefinition.response}>; } `); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZV9nZW5lcmF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzZXJ2aWNlX2dlbmVyYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQWVBLDBDQXNCQztBQUVELDREQXNFQztBQUVELGdEQW9JQztBQTdPRCxxRUFHa0M7QUFDbEMsaUNBQTJDO0FBRTNDLElBQUksb0JBQW9CLEdBQUcsT0FBTyxDQUFDO0FBQ25DLElBQUksZUFBZSxHQUFHLElBQUksR0FBRyxDQUFTLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxDQUFDO0FBRTlELFNBQWdCLGVBQWUsQ0FDN0Isb0JBQTRCLEVBQzVCLGlCQUFvQyxFQUNwQyxnQkFBbUQ7SUFFbkQsSUFBSSxjQUFjLEdBQUcseUNBQWdCLENBQUMsR0FBRyxDQUN2QyxnQkFBZ0IsRUFDaEIsb0JBQW9CLENBQ3JCLENBQUM7SUFDRixJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO0lBQ3JELENBQUM7SUFDRCxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsaUJBQWlCLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUM3RSxDQUFDO0lBQ0QsY0FBYyxDQUFDLDJCQUEyQixDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDaEUsY0FBYyxDQUFDLElBQUksQ0FBQzthQUNULElBQUEsd0JBQWlCLEVBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDO1dBQzNDLGlCQUFpQixDQUFDLElBQUk7V0FDdEIsaUJBQWlCLENBQUMsSUFBSTs7Q0FFaEMsQ0FBQyxDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQWdCLHdCQUF3QixDQUN0QyxvQkFBNEIsRUFDNUIsMEJBQXNELEVBQ3RELGtCQUFzQyxFQUN0QyxnQkFBbUQ7SUFFbkQsSUFBSSx3QkFBd0IsR0FB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QUFDLElBQUksR0FBRyxDQUFDO0lBQ3BELENBQUM7SUFFRCxJQUFJLFlBQVksR0FBRyxFQUFFLENBQUM7SUFDdEIsSUFBSSxvQkFBb0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNqQyxZQUFZLEdBQUc7cUJBQ0UsQ0FBQztJQUNwQixDQUFDO0lBRUQsSUFBSSx3QkFBd0IsR0FBRyxJQUFBLHdCQUFpQixFQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzVFLHFCQUFxQixDQUFDLG9CQUFvQixDQUN4QyxvQkFBb0IsRUFDcEIsd0JBQXdCLENBQ3pCLENBQUM7SUFDRixxQkFBcUIsQ0FBQyxvQkFBb0IsQ0FDeEMsb0JBQW9CLENBQUMsY0FBYyxFQUNuQyxvQkFBb0IsQ0FBQyxRQUFRLENBQzlCLENBQUM7SUFDRixxQkFBcUIsQ0FBQywyQ0FBMkMsQ0FDL0QsNEJBQTRCLENBQzdCLENBQUM7SUFDRixxQkFBcUIsQ0FBQyxJQUFJLENBQUM7d0JBQ0wsb0JBQW9CLENBQUMsSUFBSTt3QkFDekIsd0JBQXdCOzs0QkFFcEIsU0FBUyxHQUFHLGFBQWEsR0FBRyxZQUFZO2VBQ3JELG9CQUFvQixDQUFDLFFBQVE7O0NBRTNDLENBQUMsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBSZW1vdGVDYWxsRGVmaW5pdGlvbixcbiAgUmVtb3RlQ2FsbHNHcm91cERlZmluaXRpb24sXG4gIFNlcnZpY2VEZWZpbml0aW9uLFxufSBmcm9tIFwiLi9kZWZpbml0aW9uXCI7XG5pbXBvcnQgeyBEZWZpbml0aW9uUmVzb2x2ZXIgfSBmcm9tIFwiLi9kZWZpbml0aW9uX3Jlc29sdmVyXCI7XG5pbXBvcnQge1xuICBPdXRwdXRDb250ZW50QnVpbGRlcixcbiAgVHNDb250ZW50QnVpbGRlcixcbn0gZnJvbSBcIi4vb3V0cHV0X2NvbnRlbnRfYnVpbGRlclwiO1xuaW1wb3J0IHsgdG9VcHBlcmNhc2VTbmFrZWQgfSBmcm9tIFwiLi91dGlsXCI7XG5cbmxldCBQUklNSVRJVkVfVFlQRV9CWVRFUyA9IFwiYnl0ZXNcIjtcbmxldCBQUklNSVRJVkVfVFlQRVMgPSBuZXcgU2V0PHN0cmluZz4oW1BSSU1JVElWRV9UWVBFX0JZVEVTXSk7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZVNlcnZpY2UoXG4gIGRlZmluaXRpb25Nb2R1bGVQYXRoOiBzdHJpbmcsXG4gIHNlcnZpY2VEZWZpbml0aW9uOiBTZXJ2aWNlRGVmaW5pdGlvbixcbiAgb3V0cHV0Q29udGVudE1hcDogTWFwPHN0cmluZywgT3V0cHV0Q29udGVudEJ1aWxkZXI+LFxuKTogdm9pZCB7XG4gIGxldCBjb250ZW50QnVpbGRlciA9IFRzQ29udGVudEJ1aWxkZXIuZ2V0KFxuICAgIG91dHB1dENvbnRlbnRNYXAsXG4gICAgZGVmaW5pdGlvbk1vZHVsZVBhdGgsXG4gICk7XG4gIGlmICghc2VydmljZURlZmluaXRpb24ubmFtZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgXCJuYW1lXCIgaXMgbWlzc2luZyBvbiBhIHNlcnZpY2UuYCk7XG4gIH1cbiAgaWYgKCFzZXJ2aWNlRGVmaW5pdGlvbi5wYXRoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBcInBhdGhcIiBpcyBtaXNzaW5nIG9uIHNlcnZpY2UgJHtzZXJ2aWNlRGVmaW5pdGlvbi5uYW1lfS5gKTtcbiAgfVxuICBjb250ZW50QnVpbGRlci5pbXBvcnRGcm9tU2VydmljZURlc2NyaXB0b3IoYFNlcnZpY2VEZXNjcmlwdG9yYCk7XG4gIGNvbnRlbnRCdWlsZGVyLnB1c2goYFxuZXhwb3J0IGxldCAke3RvVXBwZXJjYXNlU25ha2VkKHNlcnZpY2VEZWZpbml0aW9uLm5hbWUpfTogU2VydmljZURlc2NyaXB0b3IgPSB7XG4gIG5hbWU6IFwiJHtzZXJ2aWNlRGVmaW5pdGlvbi5uYW1lfVwiLFxuICBwYXRoOiBcIiR7c2VydmljZURlZmluaXRpb24ucGF0aH1cIixcbn1cbmApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVSZW1vdGVDYWxsc0dyb3VwKFxuICBkZWZpbml0aW9uTW9kdWxlUGF0aDogc3RyaW5nLFxuICByZW1vdGVDYWxsc0dyb3VwRGVmaW5pdGlvbjogUmVtb3RlQ2FsbHNHcm91cERlZmluaXRpb24sXG4gIGRlZmluaXRpb25SZXNvbHZlcjogRGVmaW5pdGlvblJlc29sdmVyLFxuICBvdXRwdXRDb250ZW50TWFwOiBNYXA8c3RyaW5nLCBPdXRwdXRDb250ZW50QnVpbGRlcj4sXG4pOiB2b2lkIHtcbiAgbGV0IGRlc2NyaXB0b3JDb250ZW50QnVpbGRlciA9IFRzQ29udGVudEJ1aWxkZXIuZ2V0KFxuICAgIG91dHB1dENvbnRlbnRNYXAsXG4gICAgZGVmaW5pdGlvbk1vZHVsZVBhdGgsXG4gICk7XG4gIGlmICghcmVtb3RlQ2FsbHNHcm91cERlZmluaXRpb24uc2VydmljZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBcInNlcnZpY2VcIiBpcyBtaXNzaW5nIG9uIHJlbW90ZSBjYWxscyBncm91cCAke3JlbW90ZUNhbGxzR3JvdXBEZWZpbml0aW9uLm5hbWV9LmAsXG4gICAgKTtcbiAgfVxuICBsZXQgZGVmaW5pdGlvbiA9IGRlZmluaXRpb25SZXNvbHZlci5yZXNvbHZlKFxuICAgIGBXaGVuIGxvb2tpbmcgZm9yIHNlcnZpY2UgZGVmaW5pdGlvbiBmb3IgcmVtb3RlIGNhbGxzIGdyb3VwICR7cmVtb3RlQ2FsbHNHcm91cERlZmluaXRpb24ubmFtZX0sYCxcbiAgICByZW1vdGVDYWxsc0dyb3VwRGVmaW5pdGlvbi5zZXJ2aWNlLFxuICAgIHJlbW90ZUNhbGxzR3JvdXBEZWZpbml0aW9uLmltcG9ydFNlcnZpY2UsXG4gICk7XG4gIGlmIChkZWZpbml0aW9uLmtpbmQgIT09IFwiU2VydmljZVwiKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYFNlcnZpY2UgbmFtZSAke3JlbW90ZUNhbGxzR3JvdXBEZWZpbml0aW9uLnNlcnZpY2V9IG9uIHJlbW90ZSBjYWxscyBncm91cCAke3JlbW90ZUNhbGxzR3JvdXBEZWZpbml0aW9uLm5hbWV9IGlzIG5vdCBhIHNlcnZpY2UuYCxcbiAgICApO1xuICB9XG4gIGxldCBzZXJ2aWNlTmFtZSA9IHRvVXBwZXJjYXNlU25ha2VkKHJlbW90ZUNhbGxzR3JvdXBEZWZpbml0aW9uLnNlcnZpY2UpO1xuICBkZXNjcmlwdG9yQ29udGVudEJ1aWxkZXIuaW1wb3J0RnJvbURlZmluaXRpb24oXG4gICAgcmVtb3RlQ2FsbHNHcm91cERlZmluaXRpb24uaW1wb3J0U2VydmljZSxcbiAgICBzZXJ2aWNlTmFtZSxcbiAgKTtcblxuICBpZiAoIXJlbW90ZUNhbGxzR3JvdXBEZWZpbml0aW9uLm91dHB1dENsaWVudCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBcIm91dHB1dENsaWVudFwiIGlzIG1pc3Npbmcgb24gcmVtb3RlIGNhbGxzIGdyb3VwICR7cmVtb3RlQ2FsbHNHcm91cERlZmluaXRpb24ubmFtZX0uYCxcbiAgICApO1xuICB9XG4gIGxldCBjbGllbnRDb250ZW50QnVpbGRlciA9IFRzQ29udGVudEJ1aWxkZXIuZ2V0KFxuICAgIG91dHB1dENvbnRlbnRNYXAsXG4gICAgZGVmaW5pdGlvbk1vZHVsZVBhdGgsXG4gICAgcmVtb3RlQ2FsbHNHcm91cERlZmluaXRpb24ub3V0cHV0Q2xpZW50LFxuICApO1xuXG4gIGlmICghcmVtb3RlQ2FsbHNHcm91cERlZmluaXRpb24ub3V0cHV0SGFuZGxlcikge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBcIm91dHB1dEhhbmRsZXJcIiBpcyBtaXNzaW5nIG9uIHJlbW90ZSBjYWxscyBncm91cCAke3JlbW90ZUNhbGxzR3JvdXBEZWZpbml0aW9uLm5hbWV9LmAsXG4gICAgKTtcbiAgfVxuICBsZXQgaGFuZGxlckNvbnRlbnRCdWlsZGVyID0gVHNDb250ZW50QnVpbGRlci5nZXQoXG4gICAgb3V0cHV0Q29udGVudE1hcCxcbiAgICBkZWZpbml0aW9uTW9kdWxlUGF0aCxcbiAgICByZW1vdGVDYWxsc0dyb3VwRGVmaW5pdGlvbi5vdXRwdXRIYW5kbGVyLFxuICApO1xuXG4gIGlmICghcmVtb3RlQ2FsbHNHcm91cERlZmluaXRpb24uY2FsbHMpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgXCJjYWxsc1wiIGlzIGVpdGhlciBtaXNzaW5nIG9yIG5vdCBhbiBhcnJheSBvbiByZW1vdGUgY2FsbHMgZ3JvdXAgJHtyZW1vdGVDYWxsc0dyb3VwRGVmaW5pdGlvbi5uYW1lfS5gLFxuICAgICk7XG4gIH1cbiAgZm9yIChsZXQgcmVtb3RlQ2FsbCBvZiByZW1vdGVDYWxsc0dyb3VwRGVmaW5pdGlvbi5jYWxscykge1xuICAgIHJlbW90ZUNhbGwucGF0aCA9IChyZW1vdGVDYWxsc0dyb3VwRGVmaW5pdGlvbi5wYXRoID8/IFwiXCIpICsgcmVtb3RlQ2FsbC5wYXRoO1xuICAgIGdlbmVyYXRlUmVtb3RlQ2FsbChcbiAgICAgIGRlZmluaXRpb25Nb2R1bGVQYXRoLFxuICAgICAgcmVtb3RlQ2FsbCxcbiAgICAgIHNlcnZpY2VOYW1lLFxuICAgICAgZGVmaW5pdGlvblJlc29sdmVyLFxuICAgICAgZGVzY3JpcHRvckNvbnRlbnRCdWlsZGVyLFxuICAgICAgY2xpZW50Q29udGVudEJ1aWxkZXIsXG4gICAgICBoYW5kbGVyQ29udGVudEJ1aWxkZXIsXG4gICAgKTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVSZW1vdGVDYWxsKFxuICBkZWZpbml0aW9uTW9kdWxlUGF0aDogc3RyaW5nLFxuICByZW1vdGVDYWxsRGVmaW5pdGlvbjogUmVtb3RlQ2FsbERlZmluaXRpb24sXG4gIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gIGRlZmluaXRpb25SZXNvbHZlcjogRGVmaW5pdGlvblJlc29sdmVyLFxuICBkZXNjcmlwdG9yQ29udGVudEJ1aWxkZXI6IFRzQ29udGVudEJ1aWxkZXIsXG4gIGNsaWVudENvbnRlbnRCdWlsZGVyOiBUc0NvbnRlbnRCdWlsZGVyLFxuICBoYW5kbGVyQ29udGVudEJ1aWxkZXI6IFRzQ29udGVudEJ1aWxkZXIsXG4pOiB2b2lkIHtcbiAgaWYgKCFyZW1vdGVDYWxsRGVmaW5pdGlvbi5uYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBcIm5hbWVcIiBpcyBtaXNzaW5nIG9uIGEgUmVtb3RlQ2FsbC5gKTtcbiAgfVxuICBsZXQgbG9nZ2luZ1ByZWZpeCA9IGBXaGVuIGdlbmVyYXRpbmcgZGVzY3JpcHRvciBmb3IgcmVtb3RlIGNhbGwgJHtyZW1vdGVDYWxsRGVmaW5pdGlvbi5uYW1lfSxgO1xuICBsZXQgYm9keURlc2NyaXB0b3IgPSBcIlwiO1xuICBpZiAoIXJlbW90ZUNhbGxEZWZpbml0aW9uLmJvZHkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7bG9nZ2luZ1ByZWZpeH0gXCJib2R5XCIgaXMgbWlzc2luZy5gKTtcbiAgfVxuICBpZiAoUFJJTUlUSVZFX1RZUEVTLmhhcyhyZW1vdGVDYWxsRGVmaW5pdGlvbi5ib2R5KSkge1xuICAgIGRlc2NyaXB0b3JDb250ZW50QnVpbGRlci5pbXBvcnRGcm9tU2VydmljZURlc2NyaXB0b3IoXCJQcmltaXR2ZVR5cGVGb3JCb2R5XCIpO1xuICAgIGJvZHlEZXNjcmlwdG9yID0gYFxuICBib2R5OiB7XG4gICAgcHJpbWl0aXZlVHlwZTogUHJpbWl0dmVUeXBlRm9yQm9keS4ke3JlbW90ZUNhbGxEZWZpbml0aW9uLmJvZHkudG9VcHBlckNhc2UoKX0sXG4gIH0sYDtcbiAgfSBlbHNlIHtcbiAgICBsZXQgcmVxdWVzQm9keXREZWZpbml0aW9uID0gZGVmaW5pdGlvblJlc29sdmVyLnJlc29sdmUoXG4gICAgICBsb2dnaW5nUHJlZml4LFxuICAgICAgcmVtb3RlQ2FsbERlZmluaXRpb24uYm9keSxcbiAgICAgIHJlbW90ZUNhbGxEZWZpbml0aW9uLmltcG9ydEJvZHksXG4gICAgKTtcbiAgICBpZiAocmVxdWVzQm9keXREZWZpbml0aW9uLmtpbmQgIT09IFwiTWVzc2FnZVwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGAke2xvZ2dpbmdQcmVmaXh9IHJlcXVlc3QgYm9keSAke3JlbW90ZUNhbGxEZWZpbml0aW9uLmJvZHl9IGlzIG5vdCBhIG1lc3NhZ2UuYCxcbiAgICAgICk7XG4gICAgfVxuICAgIGxldCByZXF1ZXN0Qm9keURlc2NyaXB0b3JOYW1lID0gdG9VcHBlcmNhc2VTbmFrZWQoXG4gICAgICByZW1vdGVDYWxsRGVmaW5pdGlvbi5ib2R5LFxuICAgICk7XG4gICAgZGVzY3JpcHRvckNvbnRlbnRCdWlsZGVyLmltcG9ydEZyb21EZWZpbml0aW9uKFxuICAgICAgcmVtb3RlQ2FsbERlZmluaXRpb24uaW1wb3J0Qm9keSxcbiAgICAgIHJlcXVlc3RCb2R5RGVzY3JpcHRvck5hbWUsXG4gICAgKTtcbiAgICBib2R5RGVzY3JpcHRvciA9IGBcbiAgYm9keToge1xuICAgIG1lc3NhZ2VUeXBlOiAke3JlcXVlc3RCb2R5RGVzY3JpcHRvck5hbWV9LFxuICB9LGA7XG4gIH1cblxuICBsZXQgbWV0YWRhdGFEZXNjcmlwdG9yID0gXCJcIjtcbiAgaWYgKHJlbW90ZUNhbGxEZWZpbml0aW9uLm1ldGFkYXRhKSB7XG4gICAgaWYgKCFyZW1vdGVDYWxsRGVmaW5pdGlvbi5tZXRhZGF0YS50eXBlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGAke2xvZ2dpbmdQcmVmaXh9IFwidHlwZVwiIGlzIG1pc3NpbmcgaW4gdGhlIFwibWV0YWRhdGFcIiBmaWVsZC5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgbGV0IG1ldGFkYXRhRGVmaW5pdGlvbiA9IGRlZmluaXRpb25SZXNvbHZlci5yZXNvbHZlKFxuICAgICAgbG9nZ2luZ1ByZWZpeCxcbiAgICAgIHJlbW90ZUNhbGxEZWZpbml0aW9uLm1ldGFkYXRhLnR5cGUsXG4gICAgICByZW1vdGVDYWxsRGVmaW5pdGlvbi5tZXRhZGF0YS5pbXBvcnQsXG4gICAgKTtcbiAgICBpZiAobWV0YWRhdGFEZWZpbml0aW9uLmtpbmQgIT09IFwiTWVzc2FnZVwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGAke2xvZ2dpbmdQcmVmaXh9IG1ldGFkYXRhIHR5cGUgJHtyZW1vdGVDYWxsRGVmaW5pdGlvbi5tZXRhZGF0YS50eXBlfSBpcyBub3QgYSBtZXNzYWdlLmAsXG4gICAgICApO1xuICAgIH1cbiAgICBsZXQgbWV0YWRhdGFEZXNjcmlwdG9yTmFtZSA9IHRvVXBwZXJjYXNlU25ha2VkKFxuICAgICAgcmVtb3RlQ2FsbERlZmluaXRpb24ubWV0YWRhdGEudHlwZSxcbiAgICApO1xuICAgIGRlc2NyaXB0b3JDb250ZW50QnVpbGRlci5pbXBvcnRGcm9tRGVmaW5pdGlvbihcbiAgICAgIHJlbW90ZUNhbGxEZWZpbml0aW9uLm1ldGFkYXRhLmltcG9ydCxcbiAgICAgIG1ldGFkYXRhRGVzY3JpcHRvck5hbWUsXG4gICAgKTtcbiAgICBpZiAoIXJlbW90ZUNhbGxEZWZpbml0aW9uLm1ldGFkYXRhLmtleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtsb2dnaW5nUHJlZml4fSBcImtleVwiIGlzIG1pc3NpbmcgaW4gdGhlIFwibWV0YWRhdGFcIiBmaWVsZC5gLFxuICAgICAgKTtcbiAgICB9XG4gICAgbWV0YWRhdGFEZXNjcmlwdG9yID0gYFxuICBtZXRhZGF0YToge1xuICAgIGtleTogXCIke3JlbW90ZUNhbGxEZWZpbml0aW9uLm1ldGFkYXRhLmtleX1cIixcbiAgICB0eXBlOiAke21ldGFkYXRhRGVzY3JpcHRvck5hbWV9LFxuICB9LGA7XG4gIH1cblxuICBsZXQgYXV0aEtleSA9IFwiXCI7XG4gIGlmIChyZW1vdGVDYWxsRGVmaW5pdGlvbi5hdXRoS2V5KSB7XG4gICAgYXV0aEtleSA9IGBcbiAgYXV0aEtleTogXCIke3JlbW90ZUNhbGxEZWZpbml0aW9uLmF1dGhLZXl9XCIsYDtcbiAgfVxuXG4gIGlmICghcmVtb3RlQ2FsbERlZmluaXRpb24ucmVzcG9uc2UpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7bG9nZ2luZ1ByZWZpeH0gXCJyZXNwb25zZVwiIGlzIG1pc3NpbmcuYCk7XG4gIH1cbiAgbGV0IHJlc3BvbnNlRGVmaW5pdGlvbiA9IGRlZmluaXRpb25SZXNvbHZlci5yZXNvbHZlKFxuICAgIGxvZ2dpbmdQcmVmaXgsXG4gICAgcmVtb3RlQ2FsbERlZmluaXRpb24ucmVzcG9uc2UsXG4gICAgcmVtb3RlQ2FsbERlZmluaXRpb24uaW1wb3J0UmVzcG9uc2UsXG4gICk7XG4gIGlmIChyZXNwb25zZURlZmluaXRpb24ua2luZCAhPT0gXCJNZXNzYWdlXCIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtsb2dnaW5nUHJlZml4fSByZXNwb25zZSB0eXBlICR7cmVtb3RlQ2FsbERlZmluaXRpb24ucmVzcG9uc2V9IGlzIG5vdCBhIG1lc3NhZ2UuYCxcbiAgICApO1xuICB9XG4gIGxldCByZXNwb25zZURlc2NyaXB0b3JOYW1lID0gdG9VcHBlcmNhc2VTbmFrZWQocmVtb3RlQ2FsbERlZmluaXRpb24ucmVzcG9uc2UpO1xuICBkZXNjcmlwdG9yQ29udGVudEJ1aWxkZXIuaW1wb3J0RnJvbURlZmluaXRpb24oXG4gICAgcmVtb3RlQ2FsbERlZmluaXRpb24uaW1wb3J0UmVzcG9uc2UsXG4gICAgcmVzcG9uc2VEZXNjcmlwdG9yTmFtZSxcbiAgKTtcbiAgbGV0IHJlc3BvbnNlRGVzY3JpcHRvciA9IGBcbiAgcmVzcG9uc2U6IHtcbiAgICBtZXNzYWdlVHlwZTogJHtyZXNwb25zZURlc2NyaXB0b3JOYW1lfSxcbiAgfSxgO1xuXG4gIGRlc2NyaXB0b3JDb250ZW50QnVpbGRlci5pbXBvcnRGcm9tU2VydmljZURlc2NyaXB0b3IoXCJSZW1vdGVDYWxsRGVzY3JpcHRvclwiKTtcbiAgbGV0IHJlbW90ZUNhbGxEZXNjcmlwdG9yTmFtZSA9IHRvVXBwZXJjYXNlU25ha2VkKHJlbW90ZUNhbGxEZWZpbml0aW9uLm5hbWUpO1xuICBkZXNjcmlwdG9yQ29udGVudEJ1aWxkZXIucHVzaChgXG5leHBvcnQgbGV0ICR7cmVtb3RlQ2FsbERlc2NyaXB0b3JOYW1lfTogUmVtb3RlQ2FsbERlc2NyaXB0b3IgPSB7XG4gIG5hbWU6IFwiJHtyZW1vdGVDYWxsRGVmaW5pdGlvbi5uYW1lfVwiLFxuICBzZXJ2aWNlOiAke3NlcnZpY2VOYW1lfSxcbiAgcGF0aDogXCIke3JlbW90ZUNhbGxEZWZpbml0aW9uLnBhdGh9XCIsJHtib2R5RGVzY3JpcHRvcn0ke21ldGFkYXRhRGVzY3JpcHRvcn0ke2F1dGhLZXl9JHtyZXNwb25zZURlc2NyaXB0b3J9XG59XG5gKTtcblxuICBnZW5lcmF0ZUNsaWVudChcbiAgICBkZWZpbml0aW9uTW9kdWxlUGF0aCxcbiAgICByZW1vdGVDYWxsRGVmaW5pdGlvbixcbiAgICBjbGllbnRDb250ZW50QnVpbGRlcixcbiAgKTtcbiAgZ2VuZXJhdGVIYW5kbGVyKFxuICAgIGRlZmluaXRpb25Nb2R1bGVQYXRoLFxuICAgIHJlbW90ZUNhbGxEZWZpbml0aW9uLFxuICAgIGhhbmRsZXJDb250ZW50QnVpbGRlcixcbiAgKTtcbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVDbGllbnQoXG4gIGRlZmluaXRpb25Nb2R1bGVQYXRoOiBzdHJpbmcsXG4gIHJlbW90ZUNhbGxEZWZpbml0aW9uOiBSZW1vdGVDYWxsRGVmaW5pdGlvbixcbiAgY2xpZW50Q29udGVudEJ1aWxkZXI6IFRzQ29udGVudEJ1aWxkZXIsXG4pOiB2b2lkIHtcbiAgbGV0IGxvZ2dpbmdQcmVmaXggPSBgV2hlbiBnZW5lcmF0aW5nIGNsaWVudCBmb3IgJHtyZW1vdGVDYWxsRGVmaW5pdGlvbi5uYW1lfSxgO1xuICBsZXQgYm9keVBhcmFtID0gXCJcIjtcbiAgaWYgKFBSSU1JVElWRV9UWVBFUy5oYXMocmVtb3RlQ2FsbERlZmluaXRpb24uYm9keSkpIHtcbiAgICBpZiAocmVtb3RlQ2FsbERlZmluaXRpb24uYm9keSA9PT0gUFJJTUlUSVZFX1RZUEVfQllURVMpIHtcbiAgICAgIGJvZHlQYXJhbSA9IGBcbiAgYm9keTogQmxvYixgO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGAke2xvZ2dpbmdQcmVmaXh9IHRoZXJlIGlzIGEgbmV3IHByaW1pdGl2ZSB0eXBlIG5lZWRzIHRvIGJlIGhhbmRsZWQgZm9yIGl0cyByZXF1ZXN0IGJvZHkuYCxcbiAgICAgICk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGNsaWVudENvbnRlbnRCdWlsZGVyLmltcG9ydEZyb21EZWZpbml0aW9uKFxuICAgICAgcmVtb3RlQ2FsbERlZmluaXRpb24uaW1wb3J0Qm9keSxcbiAgICAgIHJlbW90ZUNhbGxEZWZpbml0aW9uLmJvZHksXG4gICAgKTtcbiAgICBib2R5UGFyYW0gPSBgXG4gIGJvZHk6ICR7cmVtb3RlQ2FsbERlZmluaXRpb24uYm9keX0sYDtcbiAgfVxuXG4gIGxldCBtZXRhZGF0YVBhcmFtID0gXCJcIjtcbiAgbGV0IG1ldGRhdGFWYXJpYWJsZSA9IFwiXCI7XG4gIGlmIChyZW1vdGVDYWxsRGVmaW5pdGlvbi5tZXRhZGF0YSkge1xuICAgIGNsaWVudENvbnRlbnRCdWlsZGVyLmltcG9ydEZyb21EZWZpbml0aW9uKFxuICAgICAgcmVtb3RlQ2FsbERlZmluaXRpb24ubWV0YWRhdGEuaW1wb3J0LFxuICAgICAgcmVtb3RlQ2FsbERlZmluaXRpb24ubWV0YWRhdGEudHlwZSxcbiAgICApO1xuICAgIG1ldGFkYXRhUGFyYW0gPSBgXG4gIG1ldGFkYXRhOiAke3JlbW90ZUNhbGxEZWZpbml0aW9uLm1ldGFkYXRhLnR5cGV9LGA7XG4gICAgbWV0ZGF0YVZhcmlhYmxlID0gYFxuICAgICAgbWV0YWRhdGEsYDtcbiAgfVxuXG4gIGNsaWVudENvbnRlbnRCdWlsZGVyLmltcG9ydEZyb21EZWZpbml0aW9uKFxuICAgIHJlbW90ZUNhbGxEZWZpbml0aW9uLmltcG9ydFJlc3BvbnNlLFxuICAgIHJlbW90ZUNhbGxEZWZpbml0aW9uLnJlc3BvbnNlLFxuICApO1xuICBsZXQgcmVtb3RlQ2FsbERlc2NyaXB0b3JOYW1lID0gdG9VcHBlcmNhc2VTbmFrZWQocmVtb3RlQ2FsbERlZmluaXRpb24ubmFtZSk7XG4gIGNsaWVudENvbnRlbnRCdWlsZGVyLmltcG9ydEZyb21EZWZpbml0aW9uKFxuICAgIGRlZmluaXRpb25Nb2R1bGVQYXRoLFxuICAgIHJlbW90ZUNhbGxEZXNjcmlwdG9yTmFtZSxcbiAgKTtcbiAgY2xpZW50Q29udGVudEJ1aWxkZXIuaW1wb3J0RnJvbVNlcnZpY2VDbGllbnRSZXF1ZXN0SW50ZXJmYWNlKFxuICAgIFwiQ2xpZW50UmVxdWVzdEludGVyZmFjZVwiLFxuICApO1xuICBjbGllbnRDb250ZW50QnVpbGRlci5wdXNoKGBcbmV4cG9ydCBmdW5jdGlvbiBuZXcke3JlbW90ZUNhbGxEZWZpbml0aW9uLm5hbWV9UmVxdWVzdCgke2JvZHlQYXJhbX0ke21ldGFkYXRhUGFyYW19XG4pOiBDbGllbnRSZXF1ZXN0SW50ZXJmYWNlPCR7cmVtb3RlQ2FsbERlZmluaXRpb24ucmVzcG9uc2V9PiB7XG4gIHJldHVybiB7XG4gICAgZGVzY3JpcHRvcjogJHtyZW1vdGVDYWxsRGVzY3JpcHRvck5hbWV9LFxuICAgIGJvZHksJHttZXRkYXRhVmFyaWFibGV9XG4gIH07XG59XG5gKTtcbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVIYW5kbGVyKFxuICBkZWZpbml0aW9uTW9kdWxlUGF0aDogc3RyaW5nLFxuICByZW1vdGVDYWxsRGVmaW5pdGlvbjogUmVtb3RlQ2FsbERlZmluaXRpb24sXG4gIGhhbmRsZXJDb250ZW50QnVpbGRlcjogVHNDb250ZW50QnVpbGRlcixcbik6IHZvaWQge1xuICBsZXQgbG9nZ2luZ1ByZWZpeCA9IGBXaGVuIGdlbmVyYXRpbmcgaGFuZGxlciBmb3IgJHtyZW1vdGVDYWxsRGVmaW5pdGlvbi5uYW1lfSxgO1xuICBsZXQgYm9keVBhcmFtID0gXCJcIjtcbiAgaWYgKFBSSU1JVElWRV9UWVBFUy5oYXMocmVtb3RlQ2FsbERlZmluaXRpb24uYm9keSkpIHtcbiAgICBpZiAocmVtb3RlQ2FsbERlZmluaXRpb24uYm9keSA9PT0gUFJJTUlUSVZFX1RZUEVfQllURVMpIHtcbiAgICAgIGhhbmRsZXJDb250ZW50QnVpbGRlci5pbXBvcnRGcm9tU3RyZWFtKFwiUmVhZGFibGVcIik7XG4gICAgICBib2R5UGFyYW0gPSBgXG4gICAgYm9keTogUmVhZGFibGUsYDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtsb2dnaW5nUHJlZml4fSB0aGVyZSBpcyBhIG5ldyBwcmltaXRpdmUgdHlwZSBuZWVkcyB0byBiZSBoYW5kbGVkIGZvciBpdHMgcmVxdWVzdCBib2R5LmAsXG4gICAgICApO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBoYW5kbGVyQ29udGVudEJ1aWxkZXIuaW1wb3J0RnJvbURlZmluaXRpb24oXG4gICAgICByZW1vdGVDYWxsRGVmaW5pdGlvbi5pbXBvcnRCb2R5LFxuICAgICAgcmVtb3RlQ2FsbERlZmluaXRpb24uYm9keSxcbiAgICApO1xuICAgIGJvZHlQYXJhbSA9IGBcbiAgICBib2R5OiAke3JlbW90ZUNhbGxEZWZpbml0aW9uLmJvZHl9LGA7XG4gIH1cblxuICBsZXQgbWV0YWRhdGFQYXJhbSA9IFwiXCI7XG4gIGlmIChyZW1vdGVDYWxsRGVmaW5pdGlvbi5tZXRhZGF0YSkge1xuICAgIGhhbmRsZXJDb250ZW50QnVpbGRlci5pbXBvcnRGcm9tRGVmaW5pdGlvbihcbiAgICAgIHJlbW90ZUNhbGxEZWZpbml0aW9uLm1ldGFkYXRhLmltcG9ydCxcbiAgICAgIHJlbW90ZUNhbGxEZWZpbml0aW9uLm1ldGFkYXRhLnR5cGUsXG4gICAgKTtcbiAgICBtZXRhZGF0YVBhcmFtID0gYFxuICAgIG1ldGFkYXRhOiAke3JlbW90ZUNhbGxEZWZpbml0aW9uLm1ldGFkYXRhLnR5cGV9LGA7XG4gIH1cblxuICBsZXQgYXV0aFN0clBhcmFtID0gXCJcIjtcbiAgaWYgKHJlbW90ZUNhbGxEZWZpbml0aW9uLmF1dGhLZXkpIHtcbiAgICBhdXRoU3RyUGFyYW0gPSBgXG4gICAgYXV0aFN0cjogc3RyaW5nLGA7XG4gIH1cblxuICBsZXQgcmVtb3RlQ2FsbERlc2NyaXB0b3JOYW1lID0gdG9VcHBlcmNhc2VTbmFrZWQocmVtb3RlQ2FsbERlZmluaXRpb24ubmFtZSk7XG4gIGhhbmRsZXJDb250ZW50QnVpbGRlci5pbXBvcnRGcm9tRGVmaW5pdGlvbihcbiAgICBkZWZpbml0aW9uTW9kdWxlUGF0aCxcbiAgICByZW1vdGVDYWxsRGVzY3JpcHRvck5hbWUsXG4gICk7XG4gIGhhbmRsZXJDb250ZW50QnVpbGRlci5pbXBvcnRGcm9tRGVmaW5pdGlvbihcbiAgICByZW1vdGVDYWxsRGVmaW5pdGlvbi5pbXBvcnRSZXNwb25zZSxcbiAgICByZW1vdGVDYWxsRGVmaW5pdGlvbi5yZXNwb25zZSxcbiAgKTtcbiAgaGFuZGxlckNvbnRlbnRCdWlsZGVyLmltcG9ydEZyb21TZXJ2aWNlUmVtb3RlQ2FsbEhhbmRsZXJJbnRlcmZhY2UoXG4gICAgXCJSZW1vdGVDYWxsSGFuZGxlckludGVyZmFjZVwiLFxuICApO1xuICBoYW5kbGVyQ29udGVudEJ1aWxkZXIucHVzaChgXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgJHtyZW1vdGVDYWxsRGVmaW5pdGlvbi5uYW1lfUhhbmRsZXJJbnRlcmZhY2UgaW1wbGVtZW50cyBSZW1vdGVDYWxsSGFuZGxlckludGVyZmFjZSB7XG4gIHB1YmxpYyBkZXNjcmlwdG9yID0gJHtyZW1vdGVDYWxsRGVzY3JpcHRvck5hbWV9O1xuICBwdWJsaWMgYWJzdHJhY3QgaGFuZGxlKFxuICAgIGxvZ2dpbmdQcmVmaXg6IHN0cmluZywke2JvZHlQYXJhbX0ke21ldGFkYXRhUGFyYW19JHthdXRoU3RyUGFyYW19XG4gICk6IFByb21pc2U8JHtyZW1vdGVDYWxsRGVmaW5pdGlvbi5yZXNwb25zZX0+O1xufVxuYCk7XG59XG4iXX0=