@ngx-i18nsupport/ngx-i18nsupport-lib
Version:
A Typescript library to work with Angular generated i18n files (xliff, xmb)
336 lines • 37.8 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { ParsedMessage } from './parsed-message';
import { EMPTY_TAG, END_TAG, ICU_MESSAGE, ICU_MESSAGE_REF, ParsedMesageTokenizer, PLACEHOLDER, START_TAG, TEXT } from './parsed-message-tokenizer';
import { DOMParser } from 'xmldom';
import { format, isNullOrUndefined } from 'util';
import { DOMUtilities } from './dom-utilities';
import { ParsedMessagePartICUMessage } from './parsed-message-part-icu-message';
/**
* Created by roobm on 10.05.2017.
* A message parser can parse the xml content of a translatable message.
* It generates a ParsedMessage from it.
* @abstract
*/
export class AbstractMessageParser {
/**
* Parse XML to ParsedMessage.
* @param {?} xmlElement the xml representation
* @param {?} sourceMessage optional original message that will be translated by normalized new one
* Throws an error if normalized xml is not well formed.
* @return {?}
*/
createNormalizedMessageFromXML(xmlElement, sourceMessage) {
/** @type {?} */
const message = new ParsedMessage(this, sourceMessage);
if (xmlElement) {
message.setXmlRepresentation(xmlElement);
this.addPartsOfNodeToMessage(xmlElement, message, false);
}
return message;
}
/**
* Parse XML string to ParsedMessage.
* @param {?} xmlString the xml representation without root element, e.g. this is <ph x></ph> an example.
* @param {?} sourceMessage optional original message that will be translated by normalized new one
* Throws an error if normalized xml is not well formed.
* @return {?}
*/
createNormalizedMessageFromXMLString(xmlString, sourceMessage) {
/** @type {?} */
const doc = new DOMParser().parseFromString('<dummy>' + xmlString + '</dummy>', 'text/xml');
/** @type {?} */
const xmlElement = (/** @type {?} */ (doc.childNodes.item(0)));
return this.createNormalizedMessageFromXML(xmlElement, sourceMessage);
}
/**
* recursively run through a node and add all identified parts to the message.
* @private
* @param {?} node node
* @param {?} message message to be generated.
* @param {?} includeSelf if true, add node by itself, otherwise only children.
* @return {?}
*/
addPartsOfNodeToMessage(node, message, includeSelf) {
/** @type {?} */
let processChildren = true;
if (includeSelf) {
if (node.nodeType === node.TEXT_NODE) {
message.addText(node.textContent);
return;
}
if (node.nodeType === node.ELEMENT_NODE) {
processChildren = this.processStartElement((/** @type {?} */ (node)), message);
}
}
if (processChildren) {
/** @type {?} */
const icuMessageText = this.getICUMessageText(node);
/** @type {?} */
let isICU = !isNullOrUndefined(icuMessageText);
if (isICU) {
try {
message.addICUMessage(icuMessageText);
}
catch (error) {
// if it is not parsable, handle it as non ICU
console.log('non ICU message: ', icuMessageText, error);
isICU = false;
}
}
if (!isICU) {
/** @type {?} */
const children = node.childNodes;
for (let i = 0; i < children.length; i++) {
this.addPartsOfNodeToMessage(children.item(i), message, true);
}
}
}
if (node.nodeType === node.ELEMENT_NODE) {
this.processEndElement((/** @type {?} */ (node)), message);
}
}
/**
* Return the ICU message content of the node, if it is an ICU Message.
* @protected
* @param {?} node node
* @return {?} message or null, if it is no ICU Message.
*/
getICUMessageText(node) {
/** @type {?} */
const children = node.childNodes;
if (children.length === 0) {
return null;
}
/** @type {?} */
const firstChild = children.item(0);
if (firstChild.nodeType === firstChild.TEXT_NODE) {
if (this.isICUMessageStart(firstChild.textContent)) {
return DOMUtilities.getXMLContent((/** @type {?} */ (node)));
}
else {
return null;
}
}
else {
return null;
}
}
/**
* Test, wether text is beginning of ICU Message.
* @param {?} text text
* @return {?}
*/
isICUMessageStart(text) {
return ParsedMessagePartICUMessage.looksLikeICUMessage(text);
// return text.startsWith('{VAR_PLURAL') || text.startsWith('{VAR_SELECT');
}
/**
* Parse normalized string to ParsedMessage.
* @param {?} normalizedString normalized string
* @param {?} sourceMessage optional original message that will be translated by normalized new one
* @return {?} a new parsed message.
* Throws an error if normalized string is not well formed.
*/
parseNormalizedString(normalizedString, sourceMessage) {
/** @type {?} */
const message = new ParsedMessage(this, sourceMessage);
/** @type {?} */
const openTags = [];
/** @type {?} */
let tokens;
try {
tokens = new ParsedMesageTokenizer().tokenize(normalizedString);
}
catch (error) {
throw new Error(format('unexpected error while parsing message: "%s" (parsed "%")', error.message, normalizedString));
}
tokens.forEach((/**
* @param {?} token
* @return {?}
*/
(token) => {
/** @type {?} */
let disp = null;
switch (token.type) {
case TEXT:
message.addText(token.value.text);
break;
case START_TAG:
message.addStartTag(token.value.name, token.value.idcounter);
openTags.push(token.value.name);
break;
case END_TAG:
message.addEndTag(token.value.name);
if (openTags.length === 0 || openTags[openTags.length - 1] !== token.value.name) {
// oops, not well formed
throw new Error(format('unexpected close tag "%s" (parsed "%s")', token.value.name, normalizedString));
}
openTags.pop();
break;
case EMPTY_TAG:
message.addEmptyTag(token.value.name, token.value.idcounter);
break;
case PLACEHOLDER:
disp = (sourceMessage) ? sourceMessage.getPlaceholderDisp(token.value.idcounter) : null;
message.addPlaceholder(token.value.idcounter, disp);
break;
case ICU_MESSAGE_REF:
disp = (sourceMessage) ? sourceMessage.getICUMessageRefDisp(token.value.idcounter) : null;
message.addICUMessageRef(token.value.idcounter, disp);
break;
case ICU_MESSAGE:
throw new Error(format('<ICUMessage/> not allowed here, use parseICUMessage instead (parsed "%")', normalizedString));
default:
break;
}
}));
if (openTags.length > 0) {
// oops, not well closed tags
throw new Error(format('missing close tag "%s" (parsed "%s")', openTags[openTags.length - 1], normalizedString));
}
message.setXmlRepresentation(this.createXmlRepresentation(message));
return message;
}
/**
* Parse a string, that is an ICU message, to ParsedMessage.
* @param {?} icuMessageString the message, like '{x, plural, =0 {nothing} =1 {one} other {many}}'.
* @param {?} sourceMessage optional original message that will be translated by normalized new one
* @return {?} a new parsed message.
* Throws an error if icuMessageString has not the correct syntax.
*/
parseICUMessage(icuMessageString, sourceMessage) {
/** @type {?} */
const message = new ParsedMessage(this, sourceMessage);
message.addICUMessage(icuMessageString);
return message;
}
/**
* Helper function: Parse ID from a name.
* name optionally ends with _<number>. This is the idcount.
* E.g. name="TAG_IMG" returns 0
* name = "TAG_IMG_1" returns 1
* @protected
* @param {?} name name
* @return {?} id count
*/
parseIdCountFromName(name) {
/** @type {?} */
const regex = /.*_([0-9]*)/;
/** @type {?} */
const match = regex.exec(name);
if (isNullOrUndefined(match) || match[1] === '') {
return 0;
}
else {
/** @type {?} */
const num = match[1];
return parseInt(num, 10);
}
}
/**
* Create the native xml for a message.
* Parts are already set here.
* @protected
* @param {?} message message
* @return {?}
*/
createXmlRepresentation(message) {
/** @type {?} */
const root = new DOMParser().parseFromString('<dummy/>', 'text/xml');
/** @type {?} */
const rootElem = root.getElementsByTagName('dummy').item(0);
this.addXmlRepresentationToRoot(message, rootElem);
return rootElem;
}
/**
* @protected
* @param {?} part
* @param {?} rootElem
* @return {?}
*/
createXmlRepresentationOfTextPart(part, rootElem) {
return rootElem.ownerDocument.createTextNode(part.asDisplayString());
}
}
if (false) {
/**
* Handle this node.
* This is called before the children are done.
* @abstract
* @protected
* @param {?} elementNode elementNode
* @param {?} message message to be altered
* @return {?} true, if children should be processed too, false otherwise (children ignored then)
*/
AbstractMessageParser.prototype.processStartElement = function (elementNode, message) { };
/**
* Handle end of this node.
* This is called after all children are processed.
* @abstract
* @protected
* @param {?} elementNode elementNode
* @param {?} message message to be altered
* @return {?}
*/
AbstractMessageParser.prototype.processEndElement = function (elementNode, message) { };
/**
* @abstract
* @protected
* @param {?} message
* @param {?} rootElem
* @return {?}
*/
AbstractMessageParser.prototype.addXmlRepresentationToRoot = function (message, rootElem) { };
/**
* the xml used for start tag in the message.
* @abstract
* @protected
* @param {?} part part
* @param {?} rootElem rootElem
* @param {?=} id id number in xliff2
* @return {?}
*/
AbstractMessageParser.prototype.createXmlRepresentationOfStartTagPart = function (part, rootElem, id) { };
/**
* the xml used for end tag in the message.
* @abstract
* @protected
* @param {?} part part
* @param {?} rootElem rootElem
* @return {?}
*/
AbstractMessageParser.prototype.createXmlRepresentationOfEndTagPart = function (part, rootElem) { };
/**
* the xml used for empty tag in the message.
* @abstract
* @protected
* @param {?} part part
* @param {?} rootElem rootElem
* @param {?=} id id number in xliff2
* @return {?}
*/
AbstractMessageParser.prototype.createXmlRepresentationOfEmptyTagPart = function (part, rootElem, id) { };
/**
* the xml used for placeholder in the message.
* @abstract
* @protected
* @param {?} part part
* @param {?} rootElem rootElem
* @param {?=} id id number in xliff2
* @return {?}
*/
AbstractMessageParser.prototype.createXmlRepresentationOfPlaceholderPart = function (part, rootElem, id) { };
/**
* the xml used for icu message refs in the message.
* @abstract
* @protected
* @param {?} part part
* @param {?} rootElem rootElem
* @return {?}
*/
AbstractMessageParser.prototype.createXmlRepresentationOfICUMessageRefPart = function (part, rootElem) { };
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWJzdHJhY3QtbWVzc2FnZS1wYXJzZXIuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9Abmd4LWkxOG5zdXBwb3J0L25neC1pMThuc3VwcG9ydC1saWIvIiwic291cmNlcyI6WyJpbXBsL2Fic3RyYWN0LW1lc3NhZ2UtcGFyc2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQUMsYUFBYSxFQUFDLE1BQU0sa0JBQWtCLENBQUM7QUFDL0MsT0FBTyxFQUNILFNBQVMsRUFDVCxPQUFPLEVBQUUsV0FBVyxFQUFFLGVBQWUsRUFBRSxxQkFBcUIsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLElBQUksRUFFN0YsTUFBTSw0QkFBNEIsQ0FBQztBQUVwQyxPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0sUUFBUSxDQUFDO0FBS2pDLE9BQU8sRUFBQyxNQUFNLEVBQUUsaUJBQWlCLEVBQUMsTUFBTSxNQUFNLENBQUM7QUFDL0MsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBRzdDLE9BQU8sRUFBQywyQkFBMkIsRUFBQyxNQUFNLG1DQUFtQyxDQUFDOzs7Ozs7O0FBTTlFLE1BQU0sT0FBZ0IscUJBQXFCOzs7Ozs7OztJQVFoQyw4QkFBOEIsQ0FBQyxVQUFtQixFQUFFLGFBQTRCOztjQUM3RSxPQUFPLEdBQWtCLElBQUksYUFBYSxDQUFDLElBQUksRUFBRSxhQUFhLENBQUM7UUFDckUsSUFBSSxVQUFVLEVBQUU7WUFDWixPQUFPLENBQUMsb0JBQW9CLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDekMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLFVBQVUsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7U0FDNUQ7UUFDRCxPQUFPLE9BQU8sQ0FBQztJQUNuQixDQUFDOzs7Ozs7OztJQVFELG9DQUFvQyxDQUFDLFNBQWlCLEVBQUUsYUFBNEI7O2NBQzFFLEdBQUcsR0FBYSxJQUFJLFNBQVMsRUFBRSxDQUFDLGVBQWUsQ0FBQyxTQUFT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cEIsQ0FBQzs7Ozs7OztJQUlTLGlDQUFpQyxDQUFDLElBQTJCLEVBQUUsUUFBaUI7UUFDdEYsT0FBTyxRQUFRLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUMsQ0FBQztJQUN6RSxDQUFDO0NBdUNKOzs7Ozs7Ozs7OztJQTVKRywwRkFBOEY7Ozs7Ozs7Ozs7SUFROUYsd0ZBQW1GOzs7Ozs7OztJQXlHbkYsOEZBQXlGOzs7Ozs7Ozs7O0lBWXpGLDBHQUFnSTs7Ozs7Ozs7O0lBT2hJLG9HQUErRzs7Ozs7Ozs7OztJQVEvRywwR0FBZ0k7Ozs7Ozs7Ozs7SUFRaEksNkdBQXNJOzs7Ozs7Ozs7SUFPdEksMkdBQTZIIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtQYXJzZWRNZXNzYWdlfSBmcm9tICcuL3BhcnNlZC1tZXNzYWdlJztcclxuaW1wb3J0IHtcclxuICAgIEVNUFRZX1RBRyxcclxuICAgIEVORF9UQUcsIElDVV9NRVNTQUdFLCBJQ1VfTUVTU0FHRV9SRUYsIFBhcnNlZE1lc2FnZVRva2VuaXplciwgUExBQ0VIT0xERVIsIFNUQVJUX1RBRywgVEVYVCxcclxuICAgIFRva2VuXHJcbn0gZnJvbSAnLi9wYXJzZWQtbWVzc2FnZS10b2tlbml6ZXInO1xyXG5pbXBvcnQge1BhcnNlZE1lc3NhZ2VQYXJ0VGV4dH0gZnJvbSAnLi9wYXJzZWQtbWVzc2FnZS1wYXJ0LXRleHQnO1xyXG5pbXBvcnQge0RPTVBhcnNlcn0gZnJvbSAneG1sZG9tJztcclxuaW1wb3J0IHtQYXJzZWRNZXNzYWdlUGFydFN0YXJ0VGFnfSBmcm9tICcuL3BhcnNlZC1tZXNzYWdlLXBhcnQtc3RhcnQtdGFnJztcclxuaW1wb3J0IHtQYXJzZWRNZXNzYWdlUGFydFBsYWNlaG9sZGVyfSBmcm9tICcuL3BhcnNlZC1tZXNzYWdlLXBhcnQtcGxhY2Vob2xkZXInO1xyXG5pbXBvcnQge1BhcnNlZE1lc3NhZ2VQYXJ0RW5kVGFnfSBmcm9tICcuL3BhcnNlZC1tZXNzYWdlLXBhcnQtZW5kLXRhZyc7XHJcbmltcG9ydCB7SU1lc3NhZ2VQYXJzZXJ9IGZyb20gJy4vaS1tZXNzYWdlLXBhcnNlcic7XHJcbmltcG9ydCB7Zm9ybWF0LCBpc051bGxPclVuZGVmaW5lZH0gZnJvbSAndXRpbCc7XHJcbmltcG9ydCB7RE9NVXRpbGl0aWVzfSBmcm9tICcuL2RvbS11dGlsaXRpZXMnO1xyXG5pbXBvcnQge1BhcnNlZE1lc3NhZ2VQYXJ0RW1wdHlUYWd9IGZyb20gJy4vcGFyc2VkLW1lc3NhZ2UtcGFydC1lbXB0eS10YWcnO1xyXG5pbXBvcnQge1BhcnNlZE1lc3NhZ2VQYXJ0SUNVTWVzc2FnZVJlZn0gZnJvbSAnLi9wYXJzZWQtbWVzc2FnZS1wYXJ0LWljdS1tZXNzYWdlLXJlZic7XHJcbmltcG9ydCB7UGFyc2VkTWVzc2FnZVBhcnRJQ1VNZXNzYWdlfSBmcm9tICcuL3BhcnNlZC1tZXNzYWdlLXBhcnQtaWN1LW1lc3NhZ2UnO1xyXG4vKipcclxuICogQ3JlYXRlZCBieSByb29ibSBvbiAxMC4wNS4yMDE3LlxyXG4gKiBBIG1lc3NhZ2UgcGFyc2VyIGNhbiBwYXJzZSB0aGUgeG1sIGNvbnRlbnQgb2YgYSB0cmFuc2xhdGFibGUgbWVzc2FnZS5cclxuICogSXQgZ2VuZXJhdGVzIGEgUGFyc2VkTWVzc2FnZSBmcm9tIGl0LlxyXG4gKi9cclxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEFic3RyYWN0TWVzc2FnZVBhcnNlciBpbXBsZW1lbnRzIElNZXNzYWdlUGFyc2VyIHtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFBhcnNlIFhNTCB0byBQYXJzZWRNZXNzYWdlLlxyXG4gICAgICogQHBhcmFtIHhtbEVsZW1lbnQgdGhlIHhtbCByZXByZXNlbnRhdGlvblxyXG4gICAgICogQHBhcmFtIHNvdXJjZU1lc3NhZ2Ugb3B0aW9uYWwgb3JpZ2luYWwgbWVzc2FnZSB0aGF0IHdpbGwgYmUgdHJhbnNsYXRlZCBieSBub3JtYWxpemVkIG5ldyBvbmVcclxuICAgICAqIFRocm93cyBhbiBlcnJvciBpZiBub3JtYWxpemVkIHhtbCBpcyBub3Qgd2VsbCBmb3JtZWQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBjcmVhdGVOb3JtYWxpemVkTWVzc2FnZUZyb21YTUwoeG1sRWxlbWVudDogRWxlbWVudCwgc291cmNlTWVzc2FnZTogUGFyc2VkTWVzc2FnZSk6IFBhcnNlZE1lc3NhZ2Uge1xyXG4gICAgICAgIGNvbnN0IG1lc3NhZ2U6IFBhcnNlZE1lc3NhZ2UgPSBuZXcgUGFyc2VkTWVzc2FnZSh0aGlzLCBzb3VyY2VNZXNzYWdlKTtcclxuICAgICAgICBpZiAoeG1sRWxlbWVudCkge1xyXG4gICAgICAgICAgICBtZXNzYWdlLnNldFhtbFJlcHJlc2VudGF0aW9uKHhtbEVsZW1lbnQpO1xyXG4gICAgICAgICAgICB0aGlzLmFkZFBhcnRzT2ZOb2RlVG9NZXNzYWdlKHhtbEVsZW1lbnQsIG1lc3NhZ2UsIGZhbHNlKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIG1lc3NhZ2U7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBQYXJzZSBYTUwgc3RyaW5nIHRvIFBhcnNlZE1lc3NhZ2UuXHJcbiAgICAgKiBAcGFyYW0geG1sU3RyaW5nIHRoZSB4bWwgcmVwcmVzZW50YXRpb24gd2l0aG91dCByb290IGVsZW1lbnQsIGUuZy4gdGhpcyBpcyA8cGggeD48L3BoPiBhbiBleGFtcGxlLlxyXG4gICAgICogQHBhcmFtIHNvdXJjZU1lc3NhZ2Ugb3B0aW9uYWwgb3JpZ2luYWwgbWVzc2FnZSB0aGF0IHdpbGwgYmUgdHJhbnNsYXRlZCBieSBub3JtYWxpemVkIG5ldyBvbmVcclxuICAgICAqIFRocm93cyBhbiBlcnJvciBpZiBub3JtYWxpemVkIHhtbCBpcyBub3Qgd2VsbCBmb3JtZWQuXHJcbiAgICAgKi9cclxuICAgIGNyZWF0ZU5vcm1hbGl6ZWRNZXNzYWdlRnJvbVhNTFN0cmluZyh4bWxTdHJpbmc6IHN0cmluZywgc291cmNlTWVzc2FnZTogUGFyc2VkTWVzc2FnZSk6IFBhcnNlZE1lc3NhZ2Uge1xyXG4gICAgICAgIGNvbnN0IGRvYzogRG9jdW1lbnQgPSBuZXcgRE9NUGFyc2VyKCkucGFyc2VGcm9tU3RyaW5nKCc8ZHVtbXk+JyArIHhtbFN0cmluZyArICc8L2R1bW15PicsICd0ZXh0L3htbCcpO1xyXG4gICAgICAgIGNvbnN0IHhtbEVsZW1lbnQ6IEVsZW1lbnQgPSA8RWxlbWVudD4gZG9jLmNoaWxkTm9kZXMuaXRlbSgwKTtcclxuICAgICAgICByZXR1cm4gdGhpcy5jcmVhdGVOb3JtYWxpemVkTWVzc2FnZUZyb21YTUwoeG1sRWxlbWVudCwgc291cmNlTWVzc2FnZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiByZWN1cnNpdmVseSBydW4gdGhyb3VnaCBhIG5vZGUgYW5kIGFkZCBhbGwgaWRlbnRpZmllZCBwYXJ0cyB0byB0aGUgbWVzc2FnZS5cclxuICAgICAqIEBwYXJhbSBub2RlIG5vZGVcclxuICAgICAqIEBwYXJhbSBtZXNzYWdlIG1lc3NhZ2UgdG8gYmUgZ2VuZXJhdGVkLlxyXG4gICAgICogQHBhcmFtIGluY2x1ZGVTZWxmIGlmIHRydWUsIGFkZCBub2RlIGJ5IGl0c2VsZiwgb3RoZXJ3aXNlIG9ubHkgY2hpbGRyZW4uXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgYWRkUGFydHNPZk5vZGVUb01lc3NhZ2Uobm9kZTogTm9kZSwgbWVzc2FnZTogUGFyc2VkTWVzc2FnZSwgaW5jbHVkZVNlbGY6IGJvb2xlYW4pIHtcclxuICAgICAgICBsZXQgcHJvY2Vzc0NoaWxkcmVuID0gdHJ1ZTtcclxuICAgICAgICBpZiAoaW5jbHVkZVNlbGYpIHtcclxuICAgICAgICAgICAgaWYgKG5vZGUubm9kZVR5cGUgPT09IG5vZGUuVEVYVF9OT0RFKSB7XHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlLmFkZFRleHQobm9kZS50ZXh0Q29udGVudCk7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgaWYgKG5vZGUubm9kZVR5cGUgPT09IG5vZGUuRUxFTUVOVF9OT0RFKSB7XHJcbiAgICAgICAgICAgICAgICBwcm9jZXNzQ2hpbGRyZW4gPSB0aGlzLnByb2Nlc3NTdGFydEVsZW1lbnQoPEVsZW1lbnQ+IG5vZGUsIG1lc3NhZ2UpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChwcm9jZXNzQ2hpbGRyZW4pIHtcclxuICAgICAgICAgICAgY29uc3QgaWN1TWVzc2FnZVRleHQgPSB0aGlzLmdldElDVU1lc3NhZ2VUZXh0KG5vZGUpO1xyXG4gICAgICAgICAgICBsZXQgaXNJQ1UgPSAhaXNOdWxsT3JVbmRlZmluZWQoaWN1TWVzc2FnZVRleHQpO1xyXG4gICAgICAgICAgICBpZiAoaXNJQ1UpIHtcclxuICAgICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZS5hZGRJQ1VNZXNzYWdlKGljdU1lc3NhZ2VUZXh0KTtcclxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gaWYgaXQgaXMgbm90IHBhcnNhYmxlLCBoYW5kbGUgaXQgYXMgbm9uIElDVVxyXG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdub24gSUNVIG1lc3NhZ2U6ICcsIGljdU1lc3NhZ2VUZXh0LCBlcnJvcik7XHJcbiAgICAgICAgICAgICAgICAgICAgaXNJQ1UgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBpZiAoIWlzSUNVKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBjaGlsZHJlbiA9IG5vZGUuY2hpbGROb2RlcztcclxuICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZFBhcnRzT2ZOb2RlVG9NZXNzYWdlKGNoaWxkcmVuLml0ZW0oaSksIG1lc3NhZ2UsIHRydWUpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChub2RlLm5vZGVUeXBlID09PSBub2RlLkVMRU1FTlRfTk9ERSkge1xyXG4gICAgICAgICAgICB0aGlzLnByb2Nlc3NFbmRFbGVtZW50KDxFbGVtZW50PiBub2RlLCBtZXNzYWdlKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm4gdGhlIElDVSBtZXNzYWdlIGNvbnRlbnQgb2YgdGhlIG5vZGUsIGlmIGl0IGlzIGFuIElDVSBNZXNzYWdlLlxyXG4gICAgICogQHBhcmFtIG5vZGUgbm9kZVxyXG4gICAgICogQHJldHVybiBtZXNzYWdlIG9yIG51bGwsIGlmIGl0IGlzIG5vIElDVSBNZXNzYWdlLlxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgZ2V0SUNVTWVzc2FnZVRleHQobm9kZTogTm9kZSk6IHN0cmluZyB7XHJcbiAgICAgICAgY29uc3QgY2hpbGRyZW4gPSBub2RlLmNoaWxkTm9kZXM7XHJcbiAgICAgICAgaWYgKGNoaWxkcmVuLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgZmlyc3RDaGlsZCA9IGNoaWxkcmVuLml0ZW0oMCk7XHJcbiAgICAgICAgaWYgKGZpcnN0Q2hpbGQubm9kZVR5cGUgPT09IGZpcnN0Q2hpbGQuVEVYVF9OT0RFKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLmlzSUNVTWVzc2FnZVN0YXJ0KGZpcnN0Q2hpbGQudGV4dENvbnRlbnQpKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gRE9NVXRpbGl0aWVzLmdldFhNTENvbnRlbnQoPEVsZW1lbnQ+IG5vZGUpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUZXN0LCB3ZXRoZXIgdGV4dCBpcyBiZWdpbm5pbmcgb2YgSUNVIE1lc3NhZ2UuXHJcbiAgICAgKiBAcGFyYW0gdGV4dCB0ZXh0XHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBpc0lDVU1lc3NhZ2VTdGFydCh0ZXh0OiBzdHJpbmcpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gUGFyc2VkTWVzc2FnZVBhcnRJQ1VNZXNzYWdlLmxvb2tzTGlrZUlDVU1lc3NhZ2UodGV4dCk7XHJcbi8vICAgICAgICByZXR1cm4gdGV4dC5zdGFydHNXaXRoKCd7VkFSX1BMVVJBTCcpIHx8IHRleHQuc3RhcnRzV2l0aCgne1ZBUl9TRUxFQ1QnKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEhhbmRsZSB0aGlzIG5vZGUuXHJcbiAgICAgKiBUaGlzIGlzIGNhbGxlZCBiZWZvcmUgdGhlIGNoaWxkcmVuIGFyZSBkb25lLlxyXG4gICAgICogQHBhcmFtIGVsZW1lbnROb2RlIGVsZW1lbnROb2RlXHJcbiAgICAgKiBAcGFyYW0gbWVzc2FnZSBtZXNzYWdlIHRvIGJlIGFsdGVyZWRcclxuICAgICAqIEByZXR1cm4gdHJ1ZSwgaWYgY2hpbGRyZW4gc2hvdWxkIGJlIHByb2Nlc3NlZCB0b28sIGZhbHNlIG90aGVyd2lzZSAoY2hpbGRyZW4gaWdub3JlZCB0aGVuKVxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3QgcHJvY2Vzc1N0YXJ0RWxlbWVudChlbGVtZW50Tm9kZTogRWxlbWVudCwgbWVzc2FnZTogUGFyc2VkTWVzc2FnZSk6IGJvb2xlYW47XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBIYW5kbGUgZW5kIG9mIHRoaXMgbm9kZS5cclxuICAgICAqIFRoaXMgaXMgY2FsbGVkIGFmdGVyIGFsbCBjaGlsZHJlbiBhcmUgcHJvY2Vzc2VkLlxyXG4gICAgICogQHBhcmFtIGVsZW1lbnROb2RlIGVsZW1lbnROb2RlXHJcbiAgICAgKiBAcGFyYW0gbWVzc2FnZSBtZXNzYWdlIHRvIGJlIGFsdGVyZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IHByb2Nlc3NFbmRFbGVtZW50KGVsZW1lbnROb2RlOiBFbGVtZW50LCBtZXNzYWdlOiBQYXJzZWRNZXNzYWdlKTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFBhcnNlIG5vcm1hbGl6ZWQgc3RyaW5nIHRvIFBhcnNlZE1lc3NhZ2UuXHJcbiAgICAgKiBAcGFyYW0gbm9ybWFsaXplZFN0cmluZyBub3JtYWxpemVkIHN0cmluZ1xyXG4gICAgICogQHBhcmFtIHNvdXJjZU1lc3NhZ2Ugb3B0aW9uYWwgb3JpZ2luYWwgbWVzc2FnZSB0aGF0IHdpbGwgYmUgdHJhbnNsYXRlZCBieSBub3JtYWxpemVkIG5ldyBvbmVcclxuICAgICAqIEByZXR1cm4gYSBuZXcgcGFyc2VkIG1lc3NhZ2UuXHJcbiAgICAgKiBUaHJvd3MgYW4gZXJyb3IgaWYgbm9ybWFsaXplZCBzdHJpbmcgaXMgbm90IHdlbGwgZm9ybWVkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgcGFyc2VOb3JtYWxpemVkU3RyaW5nKG5vcm1hbGl6ZWRTdHJpbmc6IHN0cmluZywgc291cmNlTWVzc2FnZTogUGFyc2VkTWVzc2FnZSk6IFBhcnNlZE1lc3NhZ2Uge1xyXG4gICAgICAgIGNvbnN0IG1lc3NhZ2U6IFBhcnNlZE1lc3NhZ2UgPSBuZXcgUGFyc2VkTWVzc2FnZSh0aGlzLCBzb3VyY2VNZXNzYWdlKTtcclxuICAgICAgICBjb25zdCBvcGVuVGFncyA9IFtdO1xyXG4gICAgICAgIGxldCB0b2tlbnM6IFRva2VuW107XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgdG9rZW5zID0gbmV3IFBhcnNlZE1lc2FnZVRva2VuaXplcigpLnRva2VuaXplKG5vcm1hbGl6ZWRTdHJpbmcpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihmb3JtYXQoJ3VuZXhwZWN0ZWQgZXJyb3Igd2hpbGUgcGFyc2luZyBtZXNzYWdlOiBcIiVzXCIgKHBhcnNlZCBcIiVcIiknLCBlcnJvci5tZXNzYWdlLCBub3JtYWxpemVkU3RyaW5nKSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRva2Vucy5mb3JFYWNoKCh0b2tlbjogVG9rZW4pID0+IHtcclxuICAgICAgICAgICAgbGV0IGRpc3A6IHN0cmluZyA9IG51bGw7XHJcbiAgICAgICAgICAgIHN3aXRjaCAodG9rZW4udHlwZSkge1xyXG4gICAgICAgICAgICAgICAgY2FzZSBURVhUOlxyXG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UuYWRkVGV4dCh0b2tlbi52YWx1ZS50ZXh0KTtcclxuICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgIGNhc2UgU1RBUlRfVEFHOlxyXG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UuYWRkU3RhcnRUYWcodG9rZW4udmFsdWUubmFtZSwgdG9rZW4udmFsdWUuaWRjb3VudGVyKTtcclxuICAgICAgICAgICAgICAgICAgICBvcGVuVGFncy5wdXNoKHRva2VuLnZhbHVlLm5hbWUpO1xyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSBFTkRfVEFHOlxyXG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UuYWRkRW5kVGFnKHRva2VuLnZhbHVlLm5hbWUpO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChvcGVuVGFncy5sZW5ndGggPT09IDAgfHwgb3BlblRhZ3Nbb3BlblRhZ3MubGVuZ3RoIC0gMV0gIT09IHRva2VuLnZhbHVlLm5hbWUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gb29wcywgbm90IHdlbGwgZm9ybWVkXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihmb3JtYXQoJ3VuZXhwZWN0ZWQgY2xvc2UgdGFnIFwiJXNcIiAocGFyc2VkIFwiJXNcIiknLCB0b2tlbi52YWx1ZS5uYW1lLCBub3JtYWxpemVkU3RyaW5nKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIG9wZW5UYWdzLnBvcCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSBFTVBUWV9UQUc6XHJcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZS5hZGRFbXB0eVRhZyh0b2tlbi52YWx1ZS5uYW1lLCB0b2tlbi52YWx1ZS5pZGNvdW50ZXIpO1xyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSBQTEFDRUhPTERFUjpcclxuICAgICAgICAgICAgICAgICAgICBkaXNwID0gKHNvdXJjZU1lc3NhZ2UpID8gc291cmNlTWVzc2FnZS5nZXRQbGFjZWhvbGRlckRpc3AodG9rZW4udmFsdWUuaWRjb3VudGVyKSA6IG51bGw7XHJcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZS5hZGRQbGFjZWhvbGRlcih0b2tlbi52YWx1ZS5pZGNvdW50ZXIsIGRpc3ApO1xyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSBJQ1VfTUVTU0FHRV9SRUY6XHJcbiAgICAgICAgICAgICAgICAgICAgZGlzcCA9IChzb3VyY2VNZXNzYWdlKSA/IHNvdXJjZU1lc3NhZ2UuZ2V0SUNVTWVzc2FnZVJlZkRpc3AodG9rZW4udmFsdWUuaWRjb3VudGVyKSA6IG51bGw7XHJcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZS5hZGRJQ1VNZXNzYWdlUmVmKHRva2VuLnZhbHVlLmlkY291bnRlciwgZGlzcCk7XHJcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICBjYXNlIElDVV9NRVNTQUdFOlxyXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihmb3JtYXQoJzxJQ1VNZXNzYWdlLz4gbm90IGFsbG93ZWQgaGVyZSwgdXNlIHBhcnNlSUNVTWVzc2FnZSBpbnN0ZWFkIChwYXJzZWQgXCIlXCIpJywgbm9ybWFsaXplZFN0cmluZykpO1xyXG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIGlmIChvcGVuVGFncy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgIC8vIG9vcHMsIG5vdCB3ZWxsIGNsb3NlZCB0YWdzXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihmb3JtYXQoJ21pc3NpbmcgY2xvc2UgdGFnIFwiJXNcIiAocGFyc2VkIFwiJXNcIiknLCBvcGVuVGFnc1tvcGVuVGFncy5sZW5ndGggLSAxXSwgbm9ybWFsaXplZFN0cmluZykpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBtZXNzYWdlLnNldFhtbFJlcHJlc2VudGF0aW9uKHRoaXMuY3JlYXRlWG1sUmVwcmVzZW50YXRpb24obWVzc2FnZSkpO1xyXG4gICAgICAgIHJldHVybiBtZXNzYWdlO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUGFyc2UgYSBzdHJpbmcsIHRoYXQgaXMgYW4gSUNVIG1lc3NhZ2UsIHRvIFBhcnNlZE1lc3NhZ2UuXHJcbiAgICAgKiBAcGFyYW0gaWN1TWVzc2FnZVN0cmluZyB0aGUgbWVzc2FnZSwgbGlrZSAne3gsIHBsdXJhbCwgPTAge25vdGhpbmd9ID0xIHtvbmV9IG90aGVyIHttYW55fX0nLlxyXG4gICAgICogQHBhcmFtIHNvdXJjZU1lc3NhZ2Ugb3B0aW9uYWwgb3JpZ2luYWwgbWVzc2FnZSB0aGF0IHdpbGwgYmUgdHJhbnNsYXRlZCBieSBub3JtYWxpemVkIG5ldyBvbmVcclxuICAgICAqIEByZXR1cm4gYSBuZXcgcGFyc2VkIG1lc3NhZ2UuXHJcbiAgICAgKiBUaHJvd3MgYW4gZXJyb3IgaWYgaWN1TWVzc2FnZVN0cmluZyBoYXMgbm90IHRoZSBjb3JyZWN0IHN5bnRheC5cclxuICAgICAqL1xyXG4gICAgcGFyc2VJQ1VNZXNzYWdlKGljdU1lc3NhZ2VTdHJpbmc6IHN0cmluZywgc291cmNlTWVzc2FnZTogUGFyc2VkTWVzc2FnZSk6IFBhcnNlZE1lc3NhZ2Uge1xyXG4gICAgICAgIGNvbnN0IG1lc3NhZ2U6IFBhcnNlZE1lc3NhZ2UgPSBuZXcgUGFyc2VkTWVzc2FnZSh0aGlzLCBzb3VyY2VNZXNzYWdlKTtcclxuICAgICAgICBtZXNzYWdlLmFkZElDVU1lc3NhZ2UoaWN1TWVzc2FnZVN0cmluZyk7XHJcbiAgICAgICAgcmV0dXJuIG1lc3NhZ2U7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBIZWxwZXIgZnVuY3Rpb246IFBhcnNlIElEIGZyb20gYSBuYW1lLlxyXG4gICAgICogbmFtZSBvcHRpb25hbGx5IGVuZHMgd2l0aCBfPG51bWJlcj4uIFRoaXMgaXMgdGhlIGlkY291bnQuXHJcbiAgICAgKiBFLmcuIG5hbWU9XCJUQUdfSU1HXCIgcmV0dXJucyAwXHJcbiAgICAgKiBuYW1lID0gXCJUQUdfSU1HXzFcIiByZXR1cm5zIDFcclxuICAgICAqIEBwYXJhbSBuYW1lIG5hbWVcclxuICAgICAqIEByZXR1cm4gaWQgY291bnRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHBhcnNlSWRDb3VudEZyb21OYW1lKG5hbWU6IHN0cmluZyk6IG51bWJlciB7XHJcbiAgICAgICAgY29uc3QgcmVnZXggPSAvLipfKFswLTldKikvO1xyXG4gICAgICAgIGNvbnN0IG1hdGNoID0gcmVnZXguZXhlYyhuYW1lKTtcclxuICAgICAgICBpZiAoaXNOdWxsT3JVbmRlZmluZWQobWF0Y2gpIHx8IG1hdGNoWzFdID09PSAnJykge1xyXG4gICAgICAgICAgICByZXR1cm4gMDtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBjb25zdCBudW0gPSBtYXRjaFsxXTtcclxuICAgICAgICAgICAgcmV0dXJuIHBhcnNlSW50KG51bSwgMTApO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENyZWF0ZSB0aGUgbmF0aXZlIHhtbCBmb3IgYSBtZXNzYWdlLlxyXG4gICAgICogUGFydHMgYXJlIGFscmVhZHkgc2V0IGhlcmUuXHJcbiAgICAgKiBAcGFyYW0gbWVzc2FnZSBtZXNzYWdlXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBjcmVhdGVYbWxSZXByZXNlbnRhdGlvbihtZXNzYWdlOiBQYXJzZWRNZXNzYWdlKTogRWxlbWVudCB7XHJcbiAgICAgICAgY29uc3Qgcm9vdDogRG9jdW1lbnQgPSBuZXcgRE9NUGFyc2VyKCkucGFyc2VGcm9tU3RyaW5nKCc8ZHVtbXkvPicsICd0ZXh0L3htbCcpO1xyXG4gICAgICAgIGNvbnN0IHJvb3RFbGVtOiBFbGVtZW50ID0gcm9vdC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnZHVtbXknKS5pdGVtKDApO1xyXG4gICAgICAgIHRoaXMuYWRkWG1sUmVwcmVzZW50YXRpb25Ub1Jvb3QobWVzc2FnZSwgcm9vdEVsZW0pO1xyXG4gICAgICAgIHJldHVybiByb290RWxlbTtcclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3QgYWRkWG1sUmVwcmVzZW50YXRpb25Ub1Jvb3QobWVzc2FnZTogUGFyc2VkTWVzc2FnZSwgcm9vdEVsZW06IEVsZW1lbnQpO1xyXG5cclxuICAgIHByb3RlY3RlZCBjcmVhdGVYbWxSZXByZXNlbnRhdGlvbk9mVGV4dFBhcnQocGFydDogUGFyc2VkTWVzc2FnZVBhcnRUZXh0LCByb290RWxlbTogRWxlbWVudCk6IE5vZGUge1xyXG4gICAgICAgIHJldHVybiByb290RWxlbS5vd25lckRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHBhcnQuYXNEaXNwbGF5U3RyaW5nKCkpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogdGhlIHhtbCB1c2VkIGZvciBzdGFydCB0YWcgaW4gdGhlIG1lc3NhZ2UuXHJcbiAgICAgKiBAcGFyYW0gcGFydCBwYXJ0XHJcbiAgICAgKiBAcGFyYW0gcm9vdEVsZW0gcm9vdEVsZW1cclxuICAgICAqIEBwYXJhbSBpZCBpZCBudW1iZXIgaW4geGxpZmYyXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCBjcmVhdGVYbWxSZXByZXNlbnRhdGlvbk9mU3RhcnRUYWdQYXJ0KHBhcnQ6IFBhcnNlZE1lc3NhZ2VQYXJ0U3RhcnRUYWcsIHJvb3RFbGVtOiBFbGVtZW50LCBpZD86IG51bWJlcik6IE5vZGU7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiB0aGUgeG1sIHVzZWQgZm9yIGVuZCB0YWcgaW4gdGhlIG1lc3NhZ2UuXHJcbiAgICAgKiBAcGFyYW0gcGFydCBwYXJ0XHJcbiAgICAgKiBAcGFyYW0gcm9vdEVsZW0gcm9vdEVsZW1cclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGNyZWF0ZVhtbFJlcHJlc2VudGF0aW9uT2ZFbmRUYWdQYXJ0KHBhcnQ6IFBhcnNlZE1lc3NhZ2VQYXJ0RW5kVGFnLCByb290RWxlbTogRWxlbWVudCk6IE5vZGU7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiB0aGUgeG1sIHVzZWQgZm9yIGVtcHR5IHRhZyBpbiB0aGUgbWVzc2FnZS5cclxuICAgICAqIEBwYXJhbSBwYXJ0IHBhcnRcclxuICAgICAqIEBwYXJhbSByb290RWxlbSByb290RWxlbVxyXG4gICAgICogQHBhcmFtIGlkIGlkIG51bWJlciBpbiB4bGlmZjJcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGNyZWF0ZVhtbFJlcHJlc2VudGF0aW9uT2ZFbXB0eVRhZ1BhcnQocGFydDogUGFyc2VkTWVzc2FnZVBhcnRFbXB0eVRhZywgcm9vdEVsZW06IEVsZW1lbnQsIGlkPzogbnVtYmVyKTogTm9kZTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIHRoZSB4bWwgdXNlZCBmb3IgcGxhY2Vob2xkZXIgaW4gdGhlIG1lc3NhZ2UuXHJcbiAgICAgKiBAcGFyYW0gcGFydCBwYXJ0XHJcbiAgICAgKiBAcGFyYW0gcm9vdEVsZW0gcm9vdEVsZW1cclxuICAgICAqIEBwYXJhbSBpZCBpZCBudW1iZXIgaW4geGxpZmYyXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCBjcmVhdGVYbWxSZXByZXNlbnRhdGlvbk9mUGxhY2Vob2xkZXJQYXJ0KHBhcnQ6IFBhcnNlZE1lc3NhZ2VQYXJ0UGxhY2Vob2xkZXIsIHJvb3RFbGVtOiBFbGVtZW50LCBpZD86IG51bWJlcik6IE5vZGU7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiB0aGUgeG1sIHVzZWQgZm9yIGljdSBtZXNzYWdlIHJlZnMgaW4gdGhlIG1lc3NhZ2UuXHJcbiAgICAgKiBAcGFyYW0gcGFydCBwYXJ0XHJcbiAgICAgKiBAcGFyYW0gcm9vdEVsZW0gcm9vdEVsZW1cclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGNyZWF0ZVhtbFJlcHJlc2VudGF0aW9uT2ZJQ1VNZXNzYWdlUmVmUGFydChwYXJ0OiBQYXJzZWRNZXNzYWdlUGFydElDVU1lc3NhZ2VSZWYsIHJvb3RFbGVtOiBFbGVtZW50KTogTm9kZTtcclxufVxyXG4iXX0=