UNPKG

@ngx-i18nsupport/ngx-i18nsupport-lib

Version:

A Typescript library to work with Angular generated i18n files (xliff, xmb)

458 lines 42.7 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import * as tslib_1 from "tslib"; import { FORMAT_XTB, FILETYPE_XTB, FORMAT_XMB } from '../api/constants'; import { format } from 'util'; import { DOMUtilities } from './dom-utilities'; import { AbstractTranslationMessagesFile } from './abstract-translation-messages-file'; import { XtbTransUnit } from './xtb-trans-unit'; /** * Created by martin on 23.05.2017. * xtb-File access. * xtb is the translated counterpart to xmb. */ var /** * Created by martin on 23.05.2017. * xtb-File access. * xtb is the translated counterpart to xmb. */ XtbFile = /** @class */ (function (_super) { tslib_1.__extends(XtbFile, _super); /** * Create an xmb-File from source. * @param _translationMessageFileFactory factory to create a translation file (xtb) for the xmb file * @param xmlString file content * @param path Path to file * @param encoding optional encoding of the xml. * This is read from the file, but if you know it before, you can avoid reading the file twice. * @param optionalMaster in case of xmb the master file, that contains the original texts. * (this is used to support state infos, that are based on comparing original with translated version) * @return XmbFile */ function XtbFile(_translationMessageFileFactory, xmlString, path, encoding, optionalMaster) { var _this = _super.call(this) || this; _this._translationMessageFileFactory = _translationMessageFileFactory; _this._warnings = []; _this._numberOfTransUnitsWithMissingId = 0; _this.initializeFromContent(xmlString, path, encoding, optionalMaster); return _this; } /** * @private * @param {?} xmlString * @param {?} path * @param {?} encoding * @param {?=} optionalMaster * @return {?} */ XtbFile.prototype.initializeFromContent = /** * @private * @param {?} xmlString * @param {?} path * @param {?} encoding * @param {?=} optionalMaster * @return {?} */ function (xmlString, path, encoding, optionalMaster) { this.parseContent(xmlString, path, encoding); if (this._parsedDocument.getElementsByTagName('translationbundle').length !== 1) { throw new Error(format('File "%s" seems to be no xtb file (should contain a translationbundle element)', path)); } if (optionalMaster) { try { this._masterFile = this._translationMessageFileFactory.createFileFromFileContent(FORMAT_XMB, optionalMaster.xmlContent, optionalMaster.path, optionalMaster.encoding); // check, wether this can be the master ... /** @type {?} */ var numberInMaster = this._masterFile.numberOfTransUnits(); /** @type {?} */ var myNumber = this.numberOfTransUnits(); if (numberInMaster !== myNumber) { this._warnings.push(format('%s trans units found in master, but this file has %s. Check if it is the correct master', numberInMaster, myNumber)); } } catch (error) { throw new Error(format('File "%s" seems to be no xmb file. An xtb file needs xmb as master file.', optionalMaster.path)); } } return this; }; /** * @protected * @return {?} */ XtbFile.prototype.initializeTransUnits = /** * @protected * @return {?} */ function () { this.transUnits = []; /** @type {?} */ var transUnitsInFile = this._parsedDocument.getElementsByTagName('translation'); for (var i = 0; i < transUnitsInFile.length; i++) { /** @type {?} */ var msg = transUnitsInFile.item(i); /** @type {?} */ var id = msg.getAttribute('id'); if (!id) { this._warnings.push(format('oops, msg without "id" found in master, please check file %s', this._filename)); } /** @type {?} */ var masterUnit = null; if (this._masterFile) { masterUnit = this._masterFile.transUnitWithId(id); } this.transUnits.push(new XtbTransUnit(msg, id, this, (/** @type {?} */ (masterUnit)))); } }; /** * File format as it is used in config files. * Currently 'xlf', 'xlf2', 'xmb', 'xtb' * Returns one of the constants FORMAT_.. */ /** * File format as it is used in config files. * Currently 'xlf', 'xlf2', 'xmb', 'xtb' * Returns one of the constants FORMAT_.. * @return {?} */ XtbFile.prototype.i18nFormat = /** * File format as it is used in config files. * Currently 'xlf', 'xlf2', 'xmb', 'xtb' * Returns one of the constants FORMAT_.. * @return {?} */ function () { return FORMAT_XTB; }; /** * File type. * Here 'XTB' */ /** * File type. * Here 'XTB' * @return {?} */ XtbFile.prototype.fileType = /** * File type. * Here 'XTB' * @return {?} */ function () { return FILETYPE_XTB; }; /** * return tag names of all elements that have mixed content. * These elements will not be beautified. * Typical candidates are source and target. */ /** * return tag names of all elements that have mixed content. * These elements will not be beautified. * Typical candidates are source and target. * @protected * @return {?} */ XtbFile.prototype.elementsWithMixedContent = /** * return tag names of all elements that have mixed content. * These elements will not be beautified. * Typical candidates are source and target. * @protected * @return {?} */ function () { return ['translation']; }; /** * Get source language. * Unsupported in xmb/xtb. * Try to guess it from master filename if any.. * @return source language. */ /** * Get source language. * Unsupported in xmb/xtb. * Try to guess it from master filename if any.. * @return {?} source language. */ XtbFile.prototype.sourceLanguage = /** * Get source language. * Unsupported in xmb/xtb. * Try to guess it from master filename if any.. * @return {?} source language. */ function () { if (this._masterFile) { return this._masterFile.sourceLanguage(); } else { return null; } }; /** * Edit the source language. * Unsupported in xmb/xtb. * @param language language */ /** * Edit the source language. * Unsupported in xmb/xtb. * @param {?} language language * @return {?} */ XtbFile.prototype.setSourceLanguage = /** * Edit the source language. * Unsupported in xmb/xtb. * @param {?} language language * @return {?} */ function (language) { // do nothing, xtb has no notation for this. }; /** * Get target language. * @return target language. */ /** * Get target language. * @return {?} target language. */ XtbFile.prototype.targetLanguage = /** * Get target language. * @return {?} target language. */ function () { /** @type {?} */ var translationbundleElem = DOMUtilities.getFirstElementByTagName(this._parsedDocument, 'translationbundle'); if (translationbundleElem) { return translationbundleElem.getAttribute('lang'); } else { return null; } }; /** * Edit the target language. * @param language language */ /** * Edit the target language. * @param {?} language language * @return {?} */ XtbFile.prototype.setTargetLanguage = /** * Edit the target language. * @param {?} language language * @return {?} */ function (language) { /** @type {?} */ var translationbundleElem = DOMUtilities.getFirstElementByTagName(this._parsedDocument, 'translationbundle'); if (translationbundleElem) { translationbundleElem.setAttribute('lang', language); } }; /** * Add a new trans-unit to this file. * The trans unit stems from another file. * It copies the source content of the tu to the target content too, * depending on the values of isDefaultLang and copyContent. * So the source can be used as a dummy translation. * (used by xliffmerge) * @param foreignTransUnit the trans unit to be imported. * @param isDefaultLang Flag, wether file contains the default language. * Then source and target are just equal. * The content will be copied. * State will be final. * @param copyContent Flag, wether to copy content or leave it empty. * Wben true, content will be copied from source. * When false, content will be left empty (if it is not the default language). * @param importAfterElement optional (since 1.10) other transunit (part of this file), that should be used as ancestor. * Newly imported trans unit is then inserted directly after this element. * If not set or not part of this file, new unit will be imported at the end. * If explicity set to null, new unit will be imported at the start. * @return the newly imported trans unit (since version 1.7.0) * @throws an error if trans-unit with same id already is in the file. */ /** * Add a new trans-unit to this file. * The trans unit stems from another file. * It copies the source content of the tu to the target content too, * depending on the values of isDefaultLang and copyContent. * So the source can be used as a dummy translation. * (used by xliffmerge) * @throws an error if trans-unit with same id already is in the file. * @param {?} foreignTransUnit the trans unit to be imported. * @param {?} isDefaultLang Flag, wether file contains the default language. * Then source and target are just equal. * The content will be copied. * State will be final. * @param {?} copyContent Flag, wether to copy content or leave it empty. * Wben true, content will be copied from source. * When false, content will be left empty (if it is not the default language). * @param {?=} importAfterElement optional (since 1.10) other transunit (part of this file), that should be used as ancestor. * Newly imported trans unit is then inserted directly after this element. * If not set or not part of this file, new unit will be imported at the end. * If explicity set to null, new unit will be imported at the start. * @return {?} the newly imported trans unit (since version 1.7.0) */ XtbFile.prototype.importNewTransUnit = /** * Add a new trans-unit to this file. * The trans unit stems from another file. * It copies the source content of the tu to the target content too, * depending on the values of isDefaultLang and copyContent. * So the source can be used as a dummy translation. * (used by xliffmerge) * @throws an error if trans-unit with same id already is in the file. * @param {?} foreignTransUnit the trans unit to be imported. * @param {?} isDefaultLang Flag, wether file contains the default language. * Then source and target are just equal. * The content will be copied. * State will be final. * @param {?} copyContent Flag, wether to copy content or leave it empty. * Wben true, content will be copied from source. * When false, content will be left empty (if it is not the default language). * @param {?=} importAfterElement optional (since 1.10) other transunit (part of this file), that should be used as ancestor. * Newly imported trans unit is then inserted directly after this element. * If not set or not part of this file, new unit will be imported at the end. * If explicity set to null, new unit will be imported at the start. * @return {?} the newly imported trans unit (since version 1.7.0) */ function (foreignTransUnit, isDefaultLang, copyContent, importAfterElement) { if (this.transUnitWithId(foreignTransUnit.id)) { throw new Error(format('tu with id %s already exists in file, cannot import it', foreignTransUnit.id)); } /** @type {?} */ var newMasterTu = ((/** @type {?} */ (foreignTransUnit))).cloneWithSourceAsTarget(isDefaultLang, copyContent, this); /** @type {?} */ var translationbundleElem = DOMUtilities.getFirstElementByTagName(this._parsedDocument, 'translationbundle'); if (!translationbundleElem) { throw new Error(format('File "%s" seems to be no xtb file (should contain a translationbundle element)', this._filename)); } /** @type {?} */ var translationElement = translationbundleElem.ownerDocument.createElement('translation'); translationElement.setAttribute('id', foreignTransUnit.id); /** @type {?} */ var newContent = (copyContent || isDefaultLang) ? foreignTransUnit.sourceContent() : ''; if (!((/** @type {?} */ (foreignTransUnit))).isICUMessage(newContent)) { newContent = this.getNewTransUnitTargetPraefix() + newContent + this.getNewTransUnitTargetSuffix(); } DOMUtilities.replaceContentWithXMLContent(translationElement, newContent); /** @type {?} */ var newTu = new XtbTransUnit(translationElement, foreignTransUnit.id, this, newMasterTu); /** @type {?} */ var inserted = false; /** @type {?} */ var isAfterElementPartOfFile = false; if (!!importAfterElement) { /** @type {?} */ var insertionPoint = this.transUnitWithId(importAfterElement.id); if (!!insertionPoint) { isAfterElementPartOfFile = true; } } if (importAfterElement === undefined || (importAfterElement && !isAfterElementPartOfFile)) { translationbundleElem.appendChild(newTu.asXmlElement()); inserted = true; } else if (importAfterElement === null) { /** @type {?} */ var firstTranslationElement = DOMUtilities.getFirstElementByTagName(this._parsedDocument, 'translation'); if (firstTranslationElement) { DOMUtilities.insertBefore(newTu.asXmlElement(), firstTranslationElement); inserted = true; } else { // no trans-unit, empty file, so add to bundle at end translationbundleElem.appendChild(newTu.asXmlElement()); inserted = true; } } else { /** @type {?} */ var refUnitElement = DOMUtilities.getElementByTagNameAndId(this._parsedDocument, 'translation', importAfterElement.id); if (refUnitElement) { DOMUtilities.insertAfter(newTu.asXmlElement(), refUnitElement); inserted = true; } } if (inserted) { this.lazyInitializeTransUnits(); this.transUnits.push(newTu); this.countNumbers(); return newTu; } else { return null; } }; /** * Create a new translation file for this file for a given language. * Normally, this is just a copy of the original one. * But for XMB the translation file has format 'XTB'. * @param lang Language code * @param filename expected filename to store file * @param isDefaultLang Flag, wether file contains the default language. * Then source and target are just equal. * The content will be copied. * State will be final. * @param copyContent Flag, wether to copy content or leave it empty. * Wben true, content will be copied from source. * When false, content will be left empty (if it is not the default language). */ /** * Create a new translation file for this file for a given language. * Normally, this is just a copy of the original one. * But for XMB the translation file has format 'XTB'. * @param {?} lang Language code * @param {?} filename expected filename to store file * @param {?} isDefaultLang Flag, wether file contains the default language. * Then source and target are just equal. * The content will be copied. * State will be final. * @param {?} copyContent Flag, wether to copy content or leave it empty. * Wben true, content will be copied from source. * When false, content will be left empty (if it is not the default language). * @return {?} */ XtbFile.prototype.createTranslationFileForLang = /** * Create a new translation file for this file for a given language. * Normally, this is just a copy of the original one. * But for XMB the translation file has format 'XTB'. * @param {?} lang Language code * @param {?} filename expected filename to store file * @param {?} isDefaultLang Flag, wether file contains the default language. * Then source and target are just equal. * The content will be copied. * State will be final. * @param {?} copyContent Flag, wether to copy content or leave it empty. * Wben true, content will be copied from source. * When false, content will be left empty (if it is not the default language). * @return {?} */ function (lang, filename, isDefaultLang, copyContent) { throw new Error(format('File "%s", xtb files are not translatable, they are already translations', filename)); }; return XtbFile; }(AbstractTranslationMessagesFile)); /** * Created by martin on 23.05.2017. * xtb-File access. * xtb is the translated counterpart to xmb. */ export { XtbFile }; if (false) { /** * @type {?} * @private */ XtbFile.prototype._masterFile; /** * @type {?} * @private */ XtbFile.prototype._translationMessageFileFactory; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieHRiLWZpbGUuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9Abmd4LWkxOG5zdXBwb3J0L25neC1pMThuc3VwcG9ydC1saWIvIiwic291cmNlcyI6WyJpbXBsL3h0Yi1maWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBR0EsT0FBTyxFQUFDLFVBQVUsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFDLE1BQU0sa0JBQWtCLENBQUM7QUFDdEUsT0FBTyxFQUFDLE1BQU0sRUFBQyxNQUFNLE1BQU0sQ0FBQztBQUM1QixPQUFPLEVBQUMsWUFBWSxFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDN0MsT0FBTyxFQUFDLCtCQUErQixFQUFDLE1BQU0sc0NBQXNDLENBQUM7QUFDckYsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLGtCQUFrQixDQUFDOzs7Ozs7QUFROUM7Ozs7OztJQUE2QixtQ0FBK0I7SUFNeEQ7Ozs7Ozs7Ozs7T0FVRztJQUNILGlCQUFvQiw4QkFBK0QsRUFDdkUsU0FBaUIsRUFBRSxJQUFZLEVBQUUsUUFBZ0IsRUFDakQsY0FBdUU7UUFGbkYsWUFHSSxpQkFBTyxTQUlWO1FBUG1CLG9DQUE4QixHQUE5Qiw4QkFBOEIsQ0FBaUM7UUFJL0UsS0FBSSxDQUFDLFNBQVMsR0FBRyxFQUFFLENBQUM7UUFDcEIsS0FBSSxDQUFDLGdDQUFnQyxHQUFHLENBQUMsQ0FBQztRQUMxQyxLQUFJLENBQUMscUJBQXFCLENBQUMsU0FBUyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsY0FBYyxDQUFDLENBQUM7O0lBQzFFLENBQUM7Ozs7Ozs7OztJQUVPLHVDQUFxQjs7Ozs7Ozs7SUFBN0IsVUFBOEIsU0FBaUIsRUFBRSxJQUFZLEVBQUUsUUFBZ0IsRUFDakQsY0FBdUU7UUFDakcsSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzdDLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxvQkFBb0IsQ0FBQyxtQkFBbUIs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Ozs7O0lBQW5DLFVBQW9DLElBQVksRUFBRSxRQUFnQixFQUFFLGFBQXNCLEVBQUUsV0FBb0I7UUFFNUcsTUFBTSxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsMEVBQTBFLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUNsSCxDQUFDO0lBQ0wsY0FBQztBQUFELENBQUMsQUFoUEQsQ0FBNkIsK0JBQStCLEdBZ1AzRDs7Ozs7Ozs7Ozs7O0lBNU9HLDhCQUE4Qzs7Ozs7SUFhbEMsaURBQXVFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtJVHJhbnNsYXRpb25NZXNzYWdlc0ZpbGVGYWN0b3J5fSBmcm9tICcuLi9hcGkvaS10cmFuc2xhdGlvbi1tZXNzYWdlcy1maWxlLWZhY3RvcnknO1xyXG5pbXBvcnQge0lUcmFuc2xhdGlvbk1lc3NhZ2VzRmlsZX0gZnJvbSAnLi4vYXBpL2ktdHJhbnNsYXRpb24tbWVzc2FnZXMtZmlsZSc7XHJcbmltcG9ydCB7SVRyYW5zVW5pdH0gZnJvbSAnLi4vYXBpL2ktdHJhbnMtdW5pdCc7XHJcbmltcG9ydCB7Rk9STUFUX1hUQiwgRklMRVRZUEVfWFRCLCBGT1JNQVRfWE1CfSBmcm9tICcuLi9hcGkvY29uc3RhbnRzJztcclxuaW1wb3J0IHtmb3JtYXR9IGZyb20gJ3V0aWwnO1xyXG5pbXBvcnQge0RPTVV0aWxpdGllc30gZnJvbSAnLi9kb20tdXRpbGl0aWVzJztcclxuaW1wb3J0IHtBYnN0cmFjdFRyYW5zbGF0aW9uTWVzc2FnZXNGaWxlfSBmcm9tICcuL2Fic3RyYWN0LXRyYW5zbGF0aW9uLW1lc3NhZ2VzLWZpbGUnO1xyXG5pbXBvcnQge1h0YlRyYW5zVW5pdH0gZnJvbSAnLi94dGItdHJhbnMtdW5pdCc7XHJcbmltcG9ydCB7QWJzdHJhY3RUcmFuc1VuaXR9IGZyb20gJy4vYWJzdHJhY3QtdHJhbnMtdW5pdCc7XHJcbi8qKlxyXG4gKiBDcmVhdGVkIGJ5IG1hcnRpbiBvbiAyMy4wNS4yMDE3LlxyXG4gKiB4dGItRmlsZSBhY2Nlc3MuXHJcbiAqIHh0YiBpcyB0aGUgdHJhbnNsYXRlZCBjb3VudGVycGFydCB0byB4bWIuXHJcbiAqL1xyXG5cclxuZXhwb3J0IGNsYXNzIFh0YkZpbGUgZXh0ZW5kcyBBYnN0cmFjdFRyYW5zbGF0aW9uTWVzc2FnZXNGaWxlIGltcGxlbWVudHMgSVRyYW5zbGF0aW9uTWVzc2FnZXNGaWxlIHtcclxuXHJcbiAgICAvLyBhdHRhY2hlZCBtYXN0ZXIgZmlsZSwgaWYgYW55XHJcbiAgICAvLyB1c2VkIGFzIHNvdXJjZSB0byBkZXRlcm1pbmUgc3RhdGUgLi4uXHJcbiAgICBwcml2YXRlIF9tYXN0ZXJGaWxlOiBJVHJhbnNsYXRpb25NZXNzYWdlc0ZpbGU7IC8vIGFuIHhtYi1maWxlXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDcmVhdGUgYW4geG1iLUZpbGUgZnJvbSBzb3VyY2UuXHJcbiAgICAgKiBAcGFyYW0gX3RyYW5zbGF0aW9uTWVzc2FnZUZpbGVGYWN0b3J5IGZhY3RvcnkgdG8gY3JlYXRlIGEgdHJhbnNsYXRpb24gZmlsZSAoeHRiKSBmb3IgdGhlIHhtYiBmaWxlXHJcbiAgICAgKiBAcGFyYW0geG1sU3RyaW5nIGZpbGUgY29udGVudFxyXG4gICAgICogQHBhcmFtIHBhdGggUGF0aCB0byBmaWxlXHJcbiAgICAgKiBAcGFyYW0gZW5jb2Rpbmcgb3B0aW9uYWwgZW5jb2Rpbmcgb2YgdGhlIHhtbC5cclxuICAgICAqIFRoaXMgaXMgcmVhZCBmcm9tIHRoZSBmaWxlLCBidXQgaWYgeW91IGtub3cgaXQgYmVmb3JlLCB5b3UgY2FuIGF2b2lkIHJlYWRpbmcgdGhlIGZpbGUgdHdpY2UuXHJcbiAgICAgKiBAcGFyYW0gb3B0aW9uYWxNYXN0ZXIgaW4gY2FzZSBvZiB4bWIgdGhlIG1hc3RlciBmaWxlLCB0aGF0IGNvbnRhaW5zIHRoZSBvcmlnaW5hbCB0ZXh0cy5cclxuICAgICAqICh0aGlzIGlzIHVzZWQgdG8gc3VwcG9ydCBzdGF0ZSBpbmZvcywgdGhhdCBhcmUgYmFzZWQgb24gY29tcGFyaW5nIG9yaWdpbmFsIHdpdGggdHJhbnNsYXRlZCB2ZXJzaW9uKVxyXG4gICAgICogQHJldHVybiBYbWJGaWxlXHJcbiAgICAgKi9cclxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgX3RyYW5zbGF0aW9uTWVzc2FnZUZpbGVGYWN0b3J5OiBJVHJhbnNsYXRpb25NZXNzYWdlc0ZpbGVGYWN0b3J5LFxyXG4gICAgICAgICAgICAgICAgeG1sU3RyaW5nOiBzdHJpbmcsIHBhdGg6IHN0cmluZywgZW5jb2Rpbmc6IHN0cmluZyxcclxuICAgICAgICAgICAgICAgIG9wdGlvbmFsTWFzdGVyPzogeyB4bWxDb250ZW50OiBzdHJpbmcsIHBhdGg6IHN0cmluZywgZW5jb2Rpbmc6IHN0cmluZyB9KSB7XHJcbiAgICAgICAgc3VwZXIoKTtcclxuICAgICAgICB0aGlzLl93YXJuaW5ncyA9IFtdO1xyXG4gICAgICAgIHRoaXMuX251bWJlck9mVHJhbnNVbml0c1dpdGhNaXNzaW5nSWQgPSAwO1xyXG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZUZyb21Db250ZW50KHhtbFN0cmluZywgcGF0aCwgZW5jb2RpbmcsIG9wdGlvbmFsTWFzdGVyKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGluaXRpYWxpemVGcm9tQ29udGVudCh4bWxTdHJpbmc6IHN0cmluZywgcGF0aDogc3RyaW5nLCBlbmNvZGluZzogc3RyaW5nLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uYWxNYXN0ZXI/OiB7IHhtbENvbnRlbnQ6IHN0cmluZywgcGF0aDogc3RyaW5nLCBlbmNvZGluZzogc3RyaW5nIH0pOiBYdGJGaWxlIHtcclxuICAgICAgICB0aGlzLnBhcnNlQ29udGVudCh4bWxTdHJpbmcsIHBhdGgsIGVuY29kaW5nKTtcclxuICAgICAgICBpZiAodGhpcy5fcGFyc2VkRG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3RyYW5zbGF0aW9uYnVuZGxlJykubGVuZ3RoICE9PSAxKSB7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihmb3JtYXQoJ0ZpbGUgXCIlc1wiIHNlZW1zIHRvIGJlIG5vIHh0YiBmaWxlIChzaG91bGQgY29udGFpbiBhIHRyYW5zbGF0aW9uYnVuZGxlIGVsZW1lbnQpJywgcGF0aCkpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAob3B0aW9uYWxNYXN0ZXIpIHtcclxuICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIHRoaXMuX21hc3RlckZpbGUgPSB0aGlzLl90cmFuc2xhdGlvbk1lc3NhZ2VGaWxlRmFjdG9yeS5jcmVhdGVGaWxlRnJvbUZpbGVDb250ZW50KFxyXG4gICAgICAgICAgICAgICAgICAgIEZPUk1BVF9YTUIsXHJcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9uYWxNYXN0ZXIueG1sQ29udGVudCxcclxuICAgICAgICAgICAgICAgICAgICBvcHRpb25hbE1hc3Rlci5wYXRoLFxyXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbmFsTWFzdGVyLmVuY29kaW5nKTtcclxuICAgICAgICAgICAgICAgIC8vIGNoZWNrLCB3ZXRoZXIgdGhpcyBjYW4gYmUgdGhlIG1hc3RlciAuLi5cclxuICAgICAgICAgICAgICAgIGNvbnN0IG51bWJlckluTWFzdGVyID0gdGhpcy5fbWFzdGVyRmlsZS5udW1iZXJPZlRyYW5zVW5pdHMoKTtcclxuICAgICAgICAgICAgICAgIGNvbnN0IG15TnVtYmVyID0gdGhpcy5udW1iZXJPZlRyYW5zVW5pdHMoKTtcclxuICAgICAgICAgICAgICAgIGlmIChudW1iZXJJbk1hc3RlciAhPT0gbXlOdW1iZXIpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLl93YXJuaW5ncy5wdXNoKGZvcm1hdChcclxuICAgICAgICAgICAgICAgICAgICAgICAgJyVzIHRyYW5zIHVuaXRzIGZvdW5kIGluIG1hc3RlciwgYnV0IHRoaXMgZmlsZSBoYXMgJXMuIENoZWNrIGlmIGl0IGlzIHRoZSBjb3JyZWN0IG1hc3RlcicsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlckluTWFzdGVyLCBteU51bWJlcikpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGZvcm1hdCgnRmlsZSBcIiVzXCIgc2VlbXMgdG8gYmUgbm8geG1iIGZpbGUuIEFuIHh0YiBmaWxlIG5lZWRzIHhtYiBhcyBtYXN0ZXIgZmlsZS4nLCBvcHRpb25hbE1hc3Rlci5wYXRoKSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGluaXRpYWxpemVUcmFuc1VuaXRzKCkge1xyXG4gICAgICAgIHRoaXMudHJhbnNVbml0cyA9IFtdO1xyXG4gICAgICAgIGNvbnN0IHRyYW5zVW5pdHNJbkZpbGUgPSB0aGlzLl9wYXJzZWREb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgndHJhbnNsYXRpb24nKTtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRyYW5zVW5pdHNJbkZpbGUubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgICAgY29uc3QgbXNnID0gdHJhbnNVbml0c0luRmlsZS5pdGVtKGkpO1xyXG4gICAgICAgICAgICBjb25zdCBpZCA9IG1zZy5nZXRBdHRyaWJ1dGUoJ2lkJyk7XHJcbiAgICAgICAgICAgIGlmICghaWQpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMuX3dhcm5pbmdzLnB1c2goZm9ybWF0KCdvb3BzLCBtc2cgd2l0aG91dCBcImlkXCIgZm91bmQgaW4gbWFzdGVyLCBwbGVhc2UgY2hlY2sgZmlsZSAlcycsIHRoaXMuX2ZpbGVuYW1lKSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgbGV0IG1hc3RlclVuaXQ6IElUcmFuc1VuaXQgPSBudWxsO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5fbWFzdGVyRmlsZSkge1xyXG4gICAgICAgICAgICAgICAgbWFzdGVyVW5pdCA9IHRoaXMuX21hc3RlckZpbGUudHJhbnNVbml0V2l0aElkKGlkKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB0aGlzLnRyYW5zVW5pdHMucHVzaChuZXcgWHRiVHJhbnNVbml0KG1zZywgaWQsIHRoaXMsIDxBYnN0cmFjdFRyYW5zVW5pdD4gbWFzdGVyVW5pdCkpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEZpbGUgZm9ybWF0IGFzIGl0IGlzIHVzZWQgaW4gY29uZmlnIGZpbGVzLlxyXG4gICAgICogQ3VycmVudGx5ICd4bGYnLCAneGxmMicsICd4bWInLCAneHRiJ1xyXG4gICAgICogUmV0dXJucyBvbmUgb2YgdGhlIGNvbnN0YW50cyBGT1JNQVRfLi5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGkxOG5Gb3JtYXQoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gRk9STUFUX1hUQjtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEZpbGUgdHlwZS5cclxuICAgICAqIEhlcmUgJ1hUQidcclxuICAgICAqL1xyXG4gICAgcHVibGljIGZpbGVUeXBlKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIEZJTEVUWVBFX1hUQjtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIHJldHVybiB0YWcgbmFtZXMgb2YgYWxsIGVsZW1lbnRzIHRoYXQgaGF2ZSBtaXhlZCBjb250ZW50LlxyXG4gICAgICogVGhlc2UgZWxlbWVudHMgd2lsbCBub3QgYmUgYmVhdXRpZmllZC5cclxuICAgICAqIFR5cGljYWwgY2FuZGlkYXRlcyBhcmUgc291cmNlIGFuZCB0YXJnZXQuXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBlbGVtZW50c1dpdGhNaXhlZENvbnRlbnQoKTogc3RyaW5nW10ge1xyXG4gICAgICAgIHJldHVybiBbJ3RyYW5zbGF0aW9uJ107XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXQgc291cmNlIGxhbmd1YWdlLlxyXG4gICAgICogVW5zdXBwb3J0ZWQgaW4geG1iL3h0Yi5cclxuICAgICAqIFRyeSB0byBndWVzcyBpdCBmcm9tIG1hc3RlciBmaWxlbmFtZSBpZiBhbnkuLlxyXG4gICAgICogQHJldHVybiBzb3VyY2UgbGFuZ3VhZ2UuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzb3VyY2VMYW5ndWFnZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIGlmICh0aGlzLl9tYXN0ZXJGaWxlKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9tYXN0ZXJGaWxlLnNvdXJjZUxhbmd1YWdlKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRWRpdCB0aGUgc291cmNlIGxhbmd1YWdlLlxyXG4gICAgICogVW5zdXBwb3J0ZWQgaW4geG1iL3h0Yi5cclxuICAgICAqIEBwYXJhbSBsYW5ndWFnZSBsYW5ndWFnZVxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgc2V0U291cmNlTGFuZ3VhZ2UobGFuZ3VhZ2U6IHN0cmluZykge1xyXG4gICAgICAgIC8vIGRvIG5vdGhpbmcsIHh0YiBoYXMgbm8gbm90YXRpb24gZm9yIHRoaXMuXHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXQgdGFyZ2V0IGxhbmd1YWdlLlxyXG4gICAgICogQHJldHVybiB0YXJnZXQgbGFuZ3VhZ2UuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyB0YXJnZXRMYW5ndWFnZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIGNvbnN0IHRyYW5zbGF0aW9uYnVuZGxlRWxlbSA9IERPTVV0aWxpdGllcy5nZXRGaXJzdEVsZW1lbnRCeVRhZ05hbWUodGhpcy5fcGFyc2VkRG9jdW1lbnQsICd0cmFuc2xhdGlvbmJ1bmRsZScpO1xyXG4gICAgICAgIGlmICh0cmFuc2xhdGlvbmJ1bmRsZUVsZW0pIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRyYW5zbGF0aW9uYnVuZGxlRWxlbS5nZXRBdHRyaWJ1dGUoJ2xhbmcnKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBFZGl0IHRoZSB0YXJnZXQgbGFuZ3VhZ2UuXHJcbiAgICAgKiBAcGFyYW0gbGFuZ3VhZ2UgbGFuZ3VhZ2VcclxuICAgICAqL1xyXG4gICAgcHVibGljIHNldFRhcmdldExhbmd1YWdlKGxhbmd1YWdlOiBzdHJpbmcpIHtcclxuICAgICAgICBjb25zdCB0cmFuc2xhdGlvbmJ1bmRsZUVsZW0gPSBET01VdGlsaXRpZXMuZ2V0Rmlyc3RFbGVtZW50QnlUYWdOYW1lKHRoaXMuX3BhcnNlZERvY3VtZW50LCAndHJhbnNsYXRpb25idW5kbGUnKTtcclxuICAgICAgICBpZiAodHJhbnNsYXRpb25idW5kbGVFbGVtKSB7XHJcbiAgICAgICAgICAgIHRyYW5zbGF0aW9uYnVuZGxlRWxlbS5zZXRBdHRyaWJ1dGUoJ2xhbmcnLCBsYW5ndWFnZSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQWRkIGEgbmV3IHRyYW5zLXVuaXQgdG8gdGhpcyBmaWxlLlxyXG4gICAgICogVGhlIHRyYW5zIHVuaXQgc3RlbXMgZnJvbSBhbm90aGVyIGZpbGUuXHJcbiAgICAgKiBJdCBjb3BpZXMgdGhlIHNvdXJjZSBjb250ZW50IG9mIHRoZSB0dSB0byB0aGUgdGFyZ2V0IGNvbnRlbnQgdG9vLFxyXG4gICAgICogZGVwZW5kaW5nIG9uIHRoZSB2YWx1ZXMgb2YgaXNEZWZhdWx0TGFuZyBhbmQgY29weUNvbnRlbnQuXHJcbiAgICAgKiBTbyB0aGUgc291cmNlIGNhbiBiZSB1c2VkIGFzIGEgZHVtbXkgdHJhbnNsYXRpb24uXHJcbiAgICAgKiAodXNlZCBieSB4bGlmZm1lcmdlKVxyXG4gICAgICogQHBhcmFtIGZvcmVpZ25UcmFuc1VuaXQgdGhlIHRyYW5zIHVuaXQgdG8gYmUgaW1wb3J0ZWQuXHJcbiAgICAgKiBAcGFyYW0gaXNEZWZhdWx0TGFuZyBGbGFnLCB3ZXRoZXIgZmlsZSBjb250YWlucyB0aGUgZGVmYXVsdCBsYW5ndWFnZS5cclxuICAgICAqIFRoZW4gc291cmNlIGFuZCB0YXJnZXQgYXJlIGp1c3QgZXF1YWwuXHJcbiAgICAgKiBUaGUgY29udGVudCB3aWxsIGJlIGNvcGllZC5cclxuICAgICAqIFN0YXRlIHdpbGwgYmUgZmluYWwuXHJcbiAgICAgKiBAcGFyYW0gY29weUNvbnRlbnQgRmxhZywgd2V0aGVyIHRvIGNvcHkgY29udGVudCBvciBsZWF2ZSBpdCBlbXB0eS5cclxuICAgICAqIFdiZW4gdHJ1ZSwgY29udGVudCB3aWxsIGJlIGNvcGllZCBmcm9tIHNvdXJjZS5cclxuICAgICAqIFdoZW4gZmFsc2UsIGNvbnRlbnQgd2lsbCBiZSBsZWZ0IGVtcHR5IChpZiBpdCBpcyBub3QgdGhlIGRlZmF1bHQgbGFuZ3VhZ2UpLlxyXG4gICAgICogQHBhcmFtIGltcG9ydEFmdGVyRWxlbWVudCBvcHRpb25hbCAoc2luY2UgMS4xMCkgb3RoZXIgdHJhbnN1bml0IChwYXJ0IG9mIHRoaXMgZmlsZSksIHRoYXQgc2hvdWxkIGJlIHVzZWQgYXMgYW5jZXN0b3IuXHJcbiAgICAgKiBOZXdseSBpbXBvcnRlZCB0cmFucyB1bml0IGlzIHRoZW4gaW5zZXJ0ZWQgZGlyZWN0bHkgYWZ0ZXIgdGhpcyBlbGVtZW50LlxyXG4gICAgICogSWYgbm90IHNldCBvciBub3QgcGFydCBvZiB0aGlzIGZpbGUsIG5ldyB1bml0IHdpbGwgYmUgaW1wb3J0ZWQgYXQgdGhlIGVuZC5cclxuICAgICAqIElmIGV4cGxpY2l0eSBzZXQgdG8gbnVsbCwgbmV3IHVuaXQgd2lsbCBiZSBpbXBvcnRlZCBhdCB0aGUgc3RhcnQuXHJcbiAgICAgKiBAcmV0dXJuIHRoZSBuZXdseSBpbXBvcnRlZCB0cmFucyB1bml0IChzaW5jZSB2ZXJzaW9uIDEuNy4wKVxyXG4gICAgICogQHRocm93cyBhbiBlcnJvciBpZiB0cmFucy11bml0IHdpdGggc2FtZSBpZCBhbHJlYWR5IGlzIGluIHRoZSBmaWxlLlxyXG4gICAgICovXHJcbiAgICBpbXBvcnROZXdUcmFuc1VuaXQoZm9yZWlnblRyYW5zVW5pdDogSVRyYW5zVW5pdCwgaXNEZWZhdWx0TGFuZzogYm9vbGVhbiwgY29weUNvbnRlbnQ6IGJvb2xlYW4sIGltcG9ydEFmdGVyRWxlbWVudD86IElUcmFuc1VuaXQpXHJcbiAgICAgICAgOiBJVHJhbnNVbml0IHtcclxuICAgICAgICBpZiAodGhpcy50cmFuc1VuaXRXaXRoSWQoZm9yZWlnblRyYW5zVW5pdC5pZCkpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGZvcm1hdCgndHUgd2l0aCBpZCAlcyBhbHJlYWR5IGV4aXN0cyBpbiBmaWxlLCBjYW5ub3QgaW1wb3J0IGl0JywgZm9yZWlnblRyYW5zVW5pdC5pZCkpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBuZXdNYXN0ZXJUdSA9ICg8QWJzdHJhY3RUcmFuc1VuaXQ+IGZvcmVpZ25UcmFuc1VuaXQpLmNsb25lV2l0aFNvdXJjZUFzVGFyZ2V0KGlzRGVmYXVsdExhbmcsIGNvcHlDb250ZW50LCB0aGlzKTtcclxuICAgICAgICBjb25zdCB0cmFuc2xhdGlvbmJ1bmRsZUVsZW0gPSBET01VdGlsaXRpZXMuZ2V0Rmlyc3RFbGVtZW50QnlUYWdOYW1lKHRoaXMuX3BhcnNlZERvY3VtZW50LCAndHJhbnNsYXRpb25idW5kbGUnKTtcclxuICAgICAgICBpZiAoIXRyYW5zbGF0aW9uYnVuZGxlRWxlbSkge1xyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoZm9ybWF0KCdGaWxlIFwiJXNcIiBzZWVtcyB0byBiZSBubyB4dGIgZmlsZSAoc2hvdWxkIGNvbnRhaW4gYSB0cmFuc2xhdGlvbmJ1bmRsZSBlbGVtZW50KScsIHRoaXMuX2ZpbGVuYW1lKSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHRyYW5zbGF0aW9uRWxlbWVudCA9IHRyYW5zbGF0aW9uYnVuZGxlRWxlbS5vd25lckRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3RyYW5zbGF0aW9uJyk7XHJcbiAgICAgICAgdHJhbnNsYXRpb25FbGVtZW50LnNldEF0dHJpYnV0ZSgnaWQnLCBmb3JlaWduVHJhbnNVbml0LmlkKTtcclxuICAgICAgICBsZXQgbmV3Q29udGVudCA9IChjb3B5Q29udGVudCB8fCBpc0RlZmF1bHRMYW5nKSA/IGZvcmVpZ25UcmFuc1VuaXQuc291cmNlQ29udGVudCgpIDogJyc7XHJcbiAgICAgICAgaWYgKCEoPEFic3RyYWN0VHJhbnNVbml0PiBmb3JlaWduVHJhbnNVbml0KS5pc0lDVU1lc3NhZ2UobmV3Q29udGVudCkpIHtcclxuICAgICAgICAgICAgbmV3Q29udGVudCA9IHRoaXMuZ2V0TmV3VHJhbnNVbml0VGFyZ2V0UHJhZWZpeCgpICsgbmV3Q29udGVudCArIHRoaXMuZ2V0TmV3VHJhbnNVbml0VGFyZ2V0U3VmZml4KCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIERPTVV0aWxpdGllcy5yZXBsYWNlQ29udGVudFdpdGhYTUxDb250ZW50KHRyYW5zbGF0aW9uRWxlbWVudCwgbmV3Q29udGVudCk7XHJcbiAgICAgICAgY29uc3QgbmV3VHUgPSBuZXcgWHRiVHJhbnNVbml0KHRyYW5zbGF0aW9uRWxlbWVudCwgZm9yZWlnblRyYW5zVW5pdC5pZCwgdGhpcywgbmV3TWFzdGVyVHUpO1xyXG4gICAgICAgIGxldCBpbnNlcnRlZCA9IGZhbHNlO1xyXG4gICAgICAgIGxldCBpc0FmdGVyRWxlbWVudFBhcnRPZkZpbGUgPSBmYWxzZTtcclxuICAgICAgICBpZiAoISFpbXBvcnRBZnRlckVsZW1lbnQpIHtcclxuICAgICAgICAgICAgY29uc3QgaW5zZXJ0aW9uUG9pbnQgPSB0aGlzLnRyYW5zVW5pdFdpdGhJZChpbXBvcnRBZnRlckVsZW1lbnQuaWQpO1xyXG4gICAgICAgICAgICBpZiAoISFpbnNlcnRpb25Qb2ludCkge1xyXG4gICAgICAgICAgICAgICAgaXNBZnRlckVsZW1lbnRQYXJ0T2ZGaWxlID0gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoaW1wb3J0QWZ0ZXJFbGVtZW50ID09PSB1bmRlZmluZWQgfHwgKGltcG9ydEFmdGVyRWxlbWVudCAmJiAhaXNBZnRlckVsZW1lbnRQYXJ0T2ZGaWxlKSkge1xyXG4gICAgICAgICAgICB0cmFuc2xhdGlvbmJ1bmRsZUVsZW0uYXBwZW5kQ2hpbGQobmV3VHUuYXNYbWxFbGVtZW50KCkpO1xyXG4gICAgICAgICAgICBpbnNlcnRlZCA9IHRydWU7XHJcbiAgICAgICAgfSBlbHNlIGlmIChpbXBvcnRBZnRlckVsZW1lbnQgPT09IG51bGwpIHtcclxuICAgICAgICAgICAgY29uc3QgZmlyc3RUcmFuc2xhdGlvbkVsZW1lbnQgPSBET01VdGlsaXRpZXMuZ2V0Rmlyc3RFbGVtZW50QnlUYWdOYW1lKHRoaXMuX3BhcnNlZERvY3VtZW50LCAndHJhbnNsYXRpb24nKTtcclxuICAgICAgICAgICAgaWYgKGZpcnN0VHJhbnNsYXRpb25FbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICBET01VdGlsaXRpZXMuaW5zZXJ0QmVmb3JlKG5ld1R1LmFzWG1sRWxlbWVudCgpLCBmaXJzdFRyYW5zbGF0aW9uRWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICBpbnNlcnRlZCA9IHRydWU7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBubyB0cmFucy11bml0LCBlbXB0eSBmaWxlLCBzbyBhZGQgdG8gYnVuZGxlIGF0IGVuZFxyXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRpb25idW5kbGVFbGVtLmFwcGVuZENoaWxkKG5ld1R1LmFzWG1sRWxlbWVudCgpKTtcclxuICAgICAgICAgICAgICAgIGluc2VydGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHJlZlVuaXRFbGVtZW50ID0gRE9NVXRpbGl0aWVzLmdldEVsZW1lbnRCeVRhZ05hbWVBbmRJZCh0aGlzLl9wYXJzZWREb2N1bWVudCwgJ3RyYW5zbGF0aW9uJywgaW1wb3J0QWZ0ZXJFbGVtZW50LmlkKTtcclxuICAgICAgICAgICAgaWYgKHJlZlVuaXRFbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICBET01VdGlsaXRpZXMuaW5zZXJ0QWZ0ZXIobmV3VHUuYXNYbWxFbGVtZW50KCksIHJlZlVuaXRFbGVtZW50KTtcclxuICAgICAgICAgICAgICAgIGluc2VydGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoaW5zZXJ0ZWQpIHtcclxuICAgICAgICAgICAgdGhpcy5sYXp5SW5pdGlhbGl6ZVRyYW5zVW5pdHMoKTtcclxuICAgICAgICAgICAgdGhpcy50cmFuc1VuaXRzLnB1c2gobmV3VHUpO1xyXG4gICAgICAgICAgICB0aGlzLmNvdW50TnVtYmVycygpO1xyXG4gICAgICAgICAgICByZXR1cm4gbmV3VHU7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlIGEgbmV3IHRyYW5zbGF0aW9uIGZpbGUgZm9yIHRoaXMgZmlsZSBmb3IgYSBnaXZlbiBsYW5ndWFnZS5cclxuICAgICAqIE5vcm1hbGx5LCB0aGlzIGlzIGp1c3QgYSBjb3B5IG9mIHRoZSBvcmlnaW5hbCBvbmUuXHJcbiAgICAgKiBCdXQgZm9yIFhNQiB0aGUgdHJhbnNsYXRpb24gZmlsZSBoYXMgZm9ybWF0ICdYVEInLlxyXG4gICAgICogQHBhcmFtIGxhbmcgTGFuZ3VhZ2UgY29kZVxyXG4gICAgICogQHBhcmFtIGZpbGVuYW1lIGV4cGVjdGVkIGZpbGVuYW1lIHRvIHN0b3JlIGZpbGVcclxuICAgICAqIEBwYXJhbSBpc0RlZmF1bHRMYW5nIEZsYWcsIHdldGhlciBmaWxlIGNvbnRhaW5zIHRoZSBkZWZhdWx0IGxhbmd1YWdlLlxyXG4gICAgICogVGhlbiBzb3VyY2UgYW5kIHRhcmdldCBhcmUganVzdCBlcXVhbC5cclxuICAgICAqIFRoZSBjb250ZW50IHdpbGwgYmUgY29waWVkLlxyXG4gICAgICogU3RhdGUgd2lsbCBiZSBmaW5hbC5cclxuICAgICAqIEBwYXJhbSBjb3B5Q29udGVudCBGbGFnLCB3ZXRoZXIgdG8gY29weSBjb250ZW50IG9yIGxlYXZlIGl0IGVtcHR5LlxyXG4gICAgICogV2JlbiB0cnVlLCBjb250ZW50IHdpbGwgYmUgY29waWVkIGZyb20gc291cmNlLlxyXG4gICAgICogV2hlbiBmYWxzZSwgY29udGVudCB3aWxsIGJlIGxlZnQgZW1wdHkgKGlmIGl0IGlzIG5vdCB0aGUgZGVmYXVsdCBsYW5ndWFnZSkuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBjcmVhdGVUcmFuc2xhdGlvbkZpbGVGb3JMYW5nKGxhbmc6IHN0cmluZywgZmlsZW5hbWU6IHN0cmluZywgaXNEZWZhdWx0TGFuZzogYm9vbGVhbiwgY29weUNvbnRlbnQ6IGJvb2xlYW4pXHJcbiAgICAgICAgOiBJVHJhbnNsYXRpb25NZXNzYWdlc0ZpbGUge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihmb3JtYXQoJ0ZpbGUgXCIlc1wiLCB4dGIgZmlsZXMgYXJlIG5vdCB0cmFuc2xhdGFibGUsIHRoZXkgYXJlIGFscmVhZHkgdHJhbnNsYXRpb25zJywgZmlsZW5hbWUpKTtcclxuICAgIH1cclxufVxyXG4iXX0=