UNPKG

@ngx-i18nsupport/ngx-i18nsupport-lib

Version:

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

850 lines 71.4 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import * as tslib_1 from "tslib"; import { STATE_NEW, STATE_TRANSLATED, STATE_FINAL } from '../api/constants'; import { DOMUtilities } from './dom-utilities'; import { AbstractTransUnit } from './abstract-trans-unit'; import { XliffMessageParser } from './xliff-message-parser'; import { isNullOrUndefined } from 'util'; /** * Created by martin on 01.05.2017. * A Translation Unit in an XLIFF 1.2 file. */ var /** * Created by martin on 01.05.2017. * A Translation Unit in an XLIFF 1.2 file. */ XliffTransUnit = /** @class */ (function (_super) { tslib_1.__extends(XliffTransUnit, _super); function XliffTransUnit(_element, _id, _translationMessagesFile) { return _super.call(this, _element, _id, _translationMessagesFile) || this; } /** * @return {?} */ XliffTransUnit.prototype.sourceContent = /** * @return {?} */ function () { /** @type {?} */ var sourceElement = DOMUtilities.getFirstElementByTagName(this._element, 'source'); return DOMUtilities.getXMLContent(sourceElement); }; /** * Set new source content in the transunit. * Normally, this is done by ng-extract. * Method only exists to allow xliffmerge to merge missing changed source content. * @param newContent the new content. */ /** * Set new source content in the transunit. * Normally, this is done by ng-extract. * Method only exists to allow xliffmerge to merge missing changed source content. * @param {?} newContent the new content. * @return {?} */ XliffTransUnit.prototype.setSourceContent = /** * Set new source content in the transunit. * Normally, this is done by ng-extract. * Method only exists to allow xliffmerge to merge missing changed source content. * @param {?} newContent the new content. * @return {?} */ function (newContent) { /** @type {?} */ var source = DOMUtilities.getFirstElementByTagName(this._element, 'source'); if (!source) { // should not happen, there always has to be a source, but who knows.. source = this._element.appendChild(this._element.ownerDocument.createElement('source')); } DOMUtilities.replaceContentWithXMLContent(source, newContent); }; /** * Return a parser used for normalized messages. */ /** * Return a parser used for normalized messages. * @protected * @return {?} */ XliffTransUnit.prototype.messageParser = /** * Return a parser used for normalized messages. * @protected * @return {?} */ function () { return new XliffMessageParser(); }; /** * The original text value, that is to be translated, as normalized message. */ /** * The original text value, that is to be translated, as normalized message. * @return {?} */ XliffTransUnit.prototype.createSourceContentNormalized = /** * The original text value, that is to be translated, as normalized message. * @return {?} */ function () { /** @type {?} */ var sourceElement = DOMUtilities.getFirstElementByTagName(this._element, 'source'); if (sourceElement) { return this.messageParser().createNormalizedMessageFromXML(sourceElement, null); } else { return null; } }; /** * the translated value (containing all markup, depends on the concrete format used). */ /** * the translated value (containing all markup, depends on the concrete format used). * @return {?} */ XliffTransUnit.prototype.targetContent = /** * the translated value (containing all markup, depends on the concrete format used). * @return {?} */ function () { /** @type {?} */ var targetElement = DOMUtilities.getFirstElementByTagName(this._element, 'target'); return DOMUtilities.getXMLContent(targetElement); }; /** * the translated value, but all placeholders are replaced with {{n}} (starting at 0) * and all embedded html is replaced by direct html markup. */ /** * the translated value, but all placeholders are replaced with {{n}} (starting at 0) * and all embedded html is replaced by direct html markup. * @return {?} */ XliffTransUnit.prototype.targetContentNormalized = /** * the translated value, but all placeholders are replaced with {{n}} (starting at 0) * and all embedded html is replaced by direct html markup. * @return {?} */ function () { /** @type {?} */ var targetElement = DOMUtilities.getFirstElementByTagName(this._element, 'target'); return new XliffMessageParser().createNormalizedMessageFromXML(targetElement, this.sourceContentNormalized()); }; /** * State of the translation as stored in the xml. */ /** * State of the translation as stored in the xml. * @return {?} */ XliffTransUnit.prototype.nativeTargetState = /** * State of the translation as stored in the xml. * @return {?} */ function () { /** @type {?} */ var targetElement = DOMUtilities.getFirstElementByTagName(this._element, 'target'); if (targetElement) { return targetElement.getAttribute('state'); } else { return null; } }; /** * set state in xml. * @param nativeState nativeState */ /** * set state in xml. * @protected * @param {?} nativeState nativeState * @return {?} */ XliffTransUnit.prototype.setNativeTargetState = /** * set state in xml. * @protected * @param {?} nativeState nativeState * @return {?} */ function (nativeState) { /** @type {?} */ var targetElement = DOMUtilities.getFirstElementByTagName(this._element, 'target'); if (targetElement) { targetElement.setAttribute('state', nativeState); } }; /** * Map an abstract state (new, translated, final) to a concrete state used in the xml. * Returns the state to be used in the xml. * @param state one of Constants.STATE... * @returns a native state (depends on concrete format) * @throws error, if state is invalid. */ /** * Map an abstract state (new, translated, final) to a concrete state used in the xml. * Returns the state to be used in the xml. * @throws error, if state is invalid. * @protected * @param {?} state one of Constants.STATE... * @return {?} a native state (depends on concrete format) */ XliffTransUnit.prototype.mapStateToNativeState = /** * Map an abstract state (new, translated, final) to a concrete state used in the xml. * Returns the state to be used in the xml. * @throws error, if state is invalid. * @protected * @param {?} state one of Constants.STATE... * @return {?} a native state (depends on concrete format) */ function (state) { switch (state) { case STATE_NEW: return 'new'; case STATE_TRANSLATED: return 'translated'; case STATE_FINAL: return 'final'; default: throw new Error('unknown state ' + state); } }; /** * Map a native state (found in the document) to an abstract state (new, translated, final). * Returns the abstract state. * @param nativeState nativeState */ /** * Map a native state (found in the document) to an abstract state (new, translated, final). * Returns the abstract state. * @protected * @param {?} nativeState nativeState * @return {?} */ XliffTransUnit.prototype.mapNativeStateToState = /** * Map a native state (found in the document) to an abstract state (new, translated, final). * Returns the abstract state. * @protected * @param {?} nativeState nativeState * @return {?} */ function (nativeState) { switch (nativeState) { case 'new': return STATE_NEW; case 'needs-translation': return STATE_NEW; case 'translated': return STATE_TRANSLATED; case 'needs-adaptation': return STATE_TRANSLATED; case 'needs-l10n': return STATE_TRANSLATED; case 'needs-review-adaptation': return STATE_TRANSLATED; case 'needs-review-l10n': return STATE_TRANSLATED; case 'needs-review-translation': return STATE_TRANSLATED; case 'final': return STATE_FINAL; case 'signed-off': return STATE_FINAL; default: return STATE_NEW; } }; /** * All the source elements in the trans unit. * The source element is a reference to the original template. * It contains the name of the template file and a line number with the position inside the template. * It is just a help for translators to find the context for the translation. * This is set when using Angular 4.0 or greater. * Otherwise it just returns an empty array. */ /** * All the source elements in the trans unit. * The source element is a reference to the original template. * It contains the name of the template file and a line number with the position inside the template. * It is just a help for translators to find the context for the translation. * This is set when using Angular 4.0 or greater. * Otherwise it just returns an empty array. * @return {?} */ XliffTransUnit.prototype.sourceReferences = /** * All the source elements in the trans unit. * The source element is a reference to the original template. * It contains the name of the template file and a line number with the position inside the template. * It is just a help for translators to find the context for the translation. * This is set when using Angular 4.0 or greater. * Otherwise it just returns an empty array. * @return {?} */ function () { /** @type {?} */ var sourceElements = this._element.getElementsByTagName('context-group'); /** @type {?} */ var sourceRefs = []; for (var i = 0; i < sourceElements.length; i++) { /** @type {?} */ var elem = sourceElements.item(i); if (elem.getAttribute('purpose') === 'location') { /** @type {?} */ var contextElements = elem.getElementsByTagName('context'); /** @type {?} */ var sourcefile = null; /** @type {?} */ var linenumber = 0; for (var j = 0; j < contextElements.length; j++) { /** @type {?} */ var contextElem = contextElements.item(j); if (contextElem.getAttribute('context-type') === 'sourcefile') { sourcefile = DOMUtilities.getPCDATA(contextElem); } if (contextElem.getAttribute('context-type') === 'linenumber') { linenumber = Number.parseInt(DOMUtilities.getPCDATA(contextElem), 10); } } sourceRefs.push({ sourcefile: sourcefile, linenumber: linenumber }); } } return sourceRefs; }; /** * Set source ref elements in the transunit. * Normally, this is done by ng-extract. * Method only exists to allow xliffmerge to merge missing source refs. * @param sourceRefs the sourcerefs to set. Old ones are removed. */ /** * Set source ref elements in the transunit. * Normally, this is done by ng-extract. * Method only exists to allow xliffmerge to merge missing source refs. * @param {?} sourceRefs the sourcerefs to set. Old ones are removed. * @return {?} */ XliffTransUnit.prototype.setSourceReferences = /** * Set source ref elements in the transunit. * Normally, this is done by ng-extract. * Method only exists to allow xliffmerge to merge missing source refs. * @param {?} sourceRefs the sourcerefs to set. Old ones are removed. * @return {?} */ function (sourceRefs) { var _this = this; this.removeAllSourceReferences(); sourceRefs.forEach((/** * @param {?} ref * @return {?} */ function (ref) { /** @type {?} */ var contextGroup = _this._element.ownerDocument.createElement('context-group'); contextGroup.setAttribute('purpose', 'location'); /** @type {?} */ var contextSource = _this._element.ownerDocument.createElement('context'); contextSource.setAttribute('context-type', 'sourcefile'); contextSource.appendChild(_this._element.ownerDocument.createTextNode(ref.sourcefile)); /** @type {?} */ var contextLine = _this._element.ownerDocument.createElement('context'); contextLine.setAttribute('context-type', 'linenumber'); contextLine.appendChild(_this._element.ownerDocument.createTextNode(ref.linenumber.toString(10))); contextGroup.appendChild(contextSource); contextGroup.appendChild(contextLine); _this._element.appendChild(contextGroup); })); }; /** * @private * @return {?} */ XliffTransUnit.prototype.removeAllSourceReferences = /** * @private * @return {?} */ function () { /** @type {?} */ var sourceElements = this._element.getElementsByTagName('context-group'); /** @type {?} */ var toBeRemoved = []; for (var i = 0; i < sourceElements.length; i++) { /** @type {?} */ var elem = sourceElements.item(i); if (elem.getAttribute('purpose') === 'location') { toBeRemoved.push(elem); } } toBeRemoved.forEach((/** * @param {?} elem * @return {?} */ function (elem) { elem.parentNode.removeChild(elem); })); }; /** * The description set in the template as value of the i18n-attribute. * e.g. i18n="mydescription". * In xliff this is stored as a note element with attribute from="description". */ /** * The description set in the template as value of the i18n-attribute. * e.g. i18n="mydescription". * In xliff this is stored as a note element with attribute from="description". * @return {?} */ XliffTransUnit.prototype.description = /** * The description set in the template as value of the i18n-attribute. * e.g. i18n="mydescription". * In xliff this is stored as a note element with attribute from="description". * @return {?} */ function () { /** @type {?} */ var noteElem = this.findNoteElementWithFromAttribute('description'); if (noteElem) { return DOMUtilities.getPCDATA(noteElem); } else { return null; } }; /** * Change description property of trans-unit. * @param description description */ /** * Change description property of trans-unit. * @param {?} description description * @return {?} */ XliffTransUnit.prototype.setDescription = /** * Change description property of trans-unit. * @param {?} description description * @return {?} */ function (description) { /** @type {?} */ var noteElem = this.findNoteElementWithFromAttribute('description'); if (description) { if (isNullOrUndefined(noteElem)) { // create it noteElem = this.createNoteElementWithFromAttribute('description', description); } else { DOMUtilities.replaceContentWithXMLContent(noteElem, description); } } else { if (!isNullOrUndefined(noteElem)) { // remove node this.removeNoteElementWithFromAttribute('description'); } } }; /** * Find a note element with attribute from='<attrValue>' * @param attrValue attrValue * @return element or null is absent */ /** * Find a note element with attribute from='<attrValue>' * @private * @param {?} attrValue attrValue * @return {?} element or null is absent */ XliffTransUnit.prototype.findNoteElementWithFromAttribute = /** * Find a note element with attribute from='<attrValue>' * @private * @param {?} attrValue attrValue * @return {?} element or null is absent */ function (attrValue) { /** @type {?} */ var noteElements = this._element.getElementsByTagName('note'); for (var i = 0; i < noteElements.length; i++) { /** @type {?} */ var noteElem = noteElements.item(i); if (noteElem.getAttribute('from') === attrValue) { return noteElem; } } return null; }; /** * Get all note elements where from attribute is not description or meaning * @return elements */ /** * Get all note elements where from attribute is not description or meaning * @private * @return {?} elements */ XliffTransUnit.prototype.findAllAdditionalNoteElements = /** * Get all note elements where from attribute is not description or meaning * @private * @return {?} elements */ function () { /** @type {?} */ var noteElements = this._element.getElementsByTagName('note'); /** @type {?} */ var result = []; for (var i = 0; i < noteElements.length; i++) { /** @type {?} */ var noteElem = noteElements.item(i); /** @type {?} */ var fromAttribute = noteElem.getAttribute('from'); if (fromAttribute !== 'description' && fromAttribute !== 'meaning') { result.push(noteElem); } } return result; }; /** * Create a new note element with attribute from='<attrValue>' * @param fromAttrValue value of "from" attribute * @param content text value of note element * @return the new created element */ /** * Create a new note element with attribute from='<attrValue>' * @private * @param {?} fromAttrValue value of "from" attribute * @param {?} content text value of note element * @return {?} the new created element */ XliffTransUnit.prototype.createNoteElementWithFromAttribute = /** * Create a new note element with attribute from='<attrValue>' * @private * @param {?} fromAttrValue value of "from" attribute * @param {?} content text value of note element * @return {?} the new created element */ function (fromAttrValue, content) { /** @type {?} */ var noteElement = this._element.ownerDocument.createElement('note'); if (fromAttrValue) { noteElement.setAttribute('from', fromAttrValue); } noteElement.setAttribute('priority', '1'); if (content) { DOMUtilities.replaceContentWithXMLContent(noteElement, content); } this._element.appendChild(noteElement); return noteElement; }; /** * Remove note element with attribute from='<attrValue>' * @param attrValue attrValue */ /** * Remove note element with attribute from='<attrValue>' * @private * @param {?} attrValue attrValue * @return {?} */ XliffTransUnit.prototype.removeNoteElementWithFromAttribute = /** * Remove note element with attribute from='<attrValue>' * @private * @param {?} attrValue attrValue * @return {?} */ function (attrValue) { /** @type {?} */ var noteElement = this.findNoteElementWithFromAttribute(attrValue); if (noteElement) { this._element.removeChild(noteElement); } }; /** * Remove all note elements where attribute "from" is not description or meaning. */ /** * Remove all note elements where attribute "from" is not description or meaning. * @private * @return {?} */ XliffTransUnit.prototype.removeAllAdditionalNoteElements = /** * Remove all note elements where attribute "from" is not description or meaning. * @private * @return {?} */ function () { var _this = this; /** @type {?} */ var noteElements = this.findAllAdditionalNoteElements(); noteElements.forEach((/** * @param {?} noteElement * @return {?} */ function (noteElement) { _this._element.removeChild(noteElement); })); }; /** * The meaning (intent) set in the template as value of the i18n-attribute. * This is the part in front of the | symbol. * e.g. i18n="meaning|mydescription". * In xliff this is stored as a note element with attribute from="meaning". */ /** * The meaning (intent) set in the template as value of the i18n-attribute. * This is the part in front of the | symbol. * e.g. i18n="meaning|mydescription". * In xliff this is stored as a note element with attribute from="meaning". * @return {?} */ XliffTransUnit.prototype.meaning = /** * The meaning (intent) set in the template as value of the i18n-attribute. * This is the part in front of the | symbol. * e.g. i18n="meaning|mydescription". * In xliff this is stored as a note element with attribute from="meaning". * @return {?} */ function () { /** @type {?} */ var noteElem = this.findNoteElementWithFromAttribute('meaning'); if (noteElem) { return DOMUtilities.getPCDATA(noteElem); } else { return null; } }; /** * Change meaning property of trans-unit. * @param meaning meaning */ /** * Change meaning property of trans-unit. * @param {?} meaning meaning * @return {?} */ XliffTransUnit.prototype.setMeaning = /** * Change meaning property of trans-unit. * @param {?} meaning meaning * @return {?} */ function (meaning) { /** @type {?} */ var noteElem = this.findNoteElementWithFromAttribute('meaning'); if (meaning) { if (isNullOrUndefined(noteElem)) { // create it noteElem = this.createNoteElementWithFromAttribute('meaning', meaning); } else { DOMUtilities.replaceContentWithXMLContent(noteElem, meaning); } } else { if (!isNullOrUndefined(noteElem)) { // remove node this.removeNoteElementWithFromAttribute('meaning'); } } }; /** * Get all notes of the trans-unit. * Notes are remarks made by a translator. * (description and meaning are not included here!) */ /** * Get all notes of the trans-unit. * Notes are remarks made by a translator. * (description and meaning are not included here!) * @return {?} */ XliffTransUnit.prototype.notes = /** * Get all notes of the trans-unit. * Notes are remarks made by a translator. * (description and meaning are not included here!) * @return {?} */ function () { /** @type {?} */ var noteElememts = this.findAllAdditionalNoteElements(); return noteElememts.map((/** * @param {?} elem * @return {?} */ function (elem) { return { from: elem.getAttribute('from'), text: DOMUtilities.getPCDATA(elem) }; })); }; /** * Test, wether setting of notes is supported. * If not, setNotes will do nothing. * xtb does not support this, all other formats do. */ /** * Test, wether setting of notes is supported. * If not, setNotes will do nothing. * xtb does not support this, all other formats do. * @return {?} */ XliffTransUnit.prototype.supportsSetNotes = /** * Test, wether setting of notes is supported. * If not, setNotes will do nothing. * xtb does not support this, all other formats do. * @return {?} */ function () { return true; }; /** * Add notes to trans unit. * @param newNotes the notes to add. * @throws an Error if any note contains description or meaning as from attribute. */ /** * Add notes to trans unit. * @throws an Error if any note contains description or meaning as from attribute. * @param {?} newNotes the notes to add. * @return {?} */ XliffTransUnit.prototype.setNotes = /** * Add notes to trans unit. * @throws an Error if any note contains description or meaning as from attribute. * @param {?} newNotes the notes to add. * @return {?} */ function (newNotes) { var _this = this; if (!isNullOrUndefined(newNotes)) { this.checkNotes(newNotes); } this.removeAllAdditionalNoteElements(); if (!isNullOrUndefined(newNotes)) { newNotes.forEach((/** * @param {?} note * @return {?} */ function (note) { /** @type {?} */ var noteElem = _this.createNoteElementWithFromAttribute(note.from, note.text); })); } }; /** * Set the translation to a given string (including markup). * @param translation translation */ /** * Set the translation to a given string (including markup). * @protected * @param {?} translation translation * @return {?} */ XliffTransUnit.prototype.translateNative = /** * Set the translation to a given string (including markup). * @protected * @param {?} translation translation * @return {?} */ function (translation) { /** @type {?} */ var target = DOMUtilities.getFirstElementByTagName(this._element, 'target'); if (!target) { /** @type {?} */ var source = DOMUtilities.getFirstElementByTagName(this._element, 'source'); target = DOMUtilities.createFollowingSibling('target', source); } DOMUtilities.replaceContentWithXMLContent(target, (/** @type {?} */ (translation))); this.setTargetState(STATE_TRANSLATED); }; /** * Copy source to target to use it as dummy translation. * Returns a changed copy of this trans unit. * receiver is not changed. * (internal usage only, a client should call importNewTransUnit on ITranslationMessageFile) */ /** * Copy source to target to use it as dummy translation. * Returns a changed copy of this trans unit. * receiver is not changed. * (internal usage only, a client should call importNewTransUnit on ITranslationMessageFile) * @param {?} isDefaultLang * @param {?} copyContent * @param {?} targetFile * @return {?} */ XliffTransUnit.prototype.cloneWithSourceAsTarget = /** * Copy source to target to use it as dummy translation. * Returns a changed copy of this trans unit. * receiver is not changed. * (internal usage only, a client should call importNewTransUnit on ITranslationMessageFile) * @param {?} isDefaultLang * @param {?} copyContent * @param {?} targetFile * @return {?} */ function (isDefaultLang, copyContent, targetFile) { /** @type {?} */ var element = (/** @type {?} */ (this._element.cloneNode(true))); /** @type {?} */ var clone = new XliffTransUnit(element, this._id, targetFile); clone.useSourceAsTarget(isDefaultLang, copyContent); return clone; }; /** * Copy source to target to use it as dummy translation. * (internal usage only, a client should call createTranslationFileForLang on ITranslationMessageFile) */ /** * Copy source to target to use it as dummy translation. * (internal usage only, a client should call createTranslationFileForLang on ITranslationMessageFile) * @param {?} isDefaultLang * @param {?} copyContent * @return {?} */ XliffTransUnit.prototype.useSourceAsTarget = /** * Copy source to target to use it as dummy translation. * (internal usage only, a client should call createTranslationFileForLang on ITranslationMessageFile) * @param {?} isDefaultLang * @param {?} copyContent * @return {?} */ function (isDefaultLang, copyContent) { /** @type {?} */ var source = DOMUtilities.getFirstElementByTagName(this._element, 'source'); /** @type {?} */ var target = DOMUtilities.getFirstElementByTagName(this._element, 'target'); if (!target) { target = DOMUtilities.createFollowingSibling('target', source); } if (isDefaultLang || copyContent) { /** @type {?} */ var sourceString = DOMUtilities.getXMLContent(source); /** @type {?} */ var newTargetString = sourceString; if (!this.isICUMessage(sourceString)) { newTargetString = this.translationMessagesFile().getNewTransUnitTargetPraefix() + sourceString + this.translationMessagesFile().getNewTransUnitTargetSuffix(); } DOMUtilities.replaceContentWithXMLContent(target, newTargetString); } else { DOMUtilities.replaceContentWithXMLContent(target, ''); } if (isDefaultLang) { target.setAttribute('state', this.mapStateToNativeState(STATE_FINAL)); } else { target.setAttribute('state', this.mapStateToNativeState(STATE_NEW)); } }; return XliffTransUnit; }(AbstractTransUnit)); /** * Created by martin on 01.05.2017. * A Translation Unit in an XLIFF 1.2 file. */ export { XliffTransUnit }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieGxpZmYtdHJhbnMtdW5pdC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BuZ3gtaTE4bnN1cHBvcnQvbmd4LWkxOG5zdXBwb3J0LWxpYi8iLCJzb3VyY2VzIjpbImltcGwveGxpZmYtdHJhbnMtdW5pdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLE9BQU8sRUFBQyxTQUFTLEVBQUUsZ0JBQWdCLEVBQUUsV0FBVyxFQUFDLE1BQU0sa0JBQWtCLENBQUM7QUFLMUUsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBQzdDLE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBQ3hELE9BQU8sRUFBQyxrQkFBa0IsRUFBQyxNQUFNLHdCQUF3QixDQUFDO0FBRzFELE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLE1BQU0sQ0FBQzs7Ozs7QUFNdkM7Ozs7O0lBQW9DLDBDQUFpQjtJQUVqRCx3QkFBWSxRQUFpQixFQUFFLEdBQVcsRUFBRSx3QkFBa0Q7ZUFDMUYsa0JBQU0sUUFBUSxFQUFFLEdBQUcsRUFBRSx3QkFBd0IsQ0FBQztJQUNsRCxDQUFDOzs7O0lBRU0sc0NBQWE7OztJQUFwQjs7WUFDVSxhQUFhLEdBQUcsWUFBWSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDO1FBQ3BGLE9BQU8sWUFBWSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRUQ7Ozs7O09BS0c7Ozs7Ozs7O0lBQ0kseUNBQWdCOzs7Ozs7O0lBQXZCLFVBQXdCLFVBQWtCOztZQUNsQyxNQUFNLEdBQUcsWUFBWSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDO1FBQzNFLElBQUksQ0FBQyxNQUFNLEVBQUU7WUFDVCxzRUFBc0U7WUFDdEUsTUFBTSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxRQUFR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WUFDbEMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUFDLEVBQUU7Z0JBQ2xDLGVBQWUsR0FBRyxJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQyw0QkFBNEIsRUFBRTtzQkFDekUsWUFBWTtzQkFDWixJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQywyQkFBMkIsRUFBRSxDQUFDO2FBQ3RFO1lBQ0QsWUFBWSxDQUFDLDRCQUE0QixDQUFDLE1BQU0sRUFBRSxlQUFlLENBQUMsQ0FBQztTQUN0RTthQUFNO1lBQ0gsWUFBWSxDQUFDLDRCQUE0QixDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztTQUN6RDtRQUNELElBQUksYUFBYSxFQUFFO1lBQ2YsTUFBTSxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7U0FDekU7YUFBTTtZQUNILE1BQU0sQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO1NBQ3ZFO0lBQ0wsQ0FBQztJQUNMLHFCQUFDO0FBQUQsQ0FBQyxBQTViRCxDQUFvQyxpQkFBaUIsR0E0YnBEIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtTVEFURV9ORVcsIFNUQVRFX1RSQU5TTEFURUQsIFNUQVRFX0ZJTkFMfSBmcm9tICcuLi9hcGkvY29uc3RhbnRzJztcclxuaW1wb3J0IHtJVHJhbnNsYXRpb25NZXNzYWdlc0ZpbGV9IGZyb20gJy4uL2FwaS9pLXRyYW5zbGF0aW9uLW1lc3NhZ2VzLWZpbGUnO1xyXG5pbXBvcnQge0lOb3JtYWxpemVkTWVzc2FnZX0gZnJvbSAnLi4vYXBpL2ktbm9ybWFsaXplZC1tZXNzYWdlJztcclxuaW1wb3J0IHtJVHJhbnNVbml0fSBmcm9tICcuLi9hcGkvaS10cmFucy11bml0JztcclxuaW1wb3J0IHtJTm90ZX0gZnJvbSAnLi4vYXBpL2ktbm90ZSc7XHJcbmltcG9ydCB7RE9NVXRpbGl0aWVzfSBmcm9tICcuL2RvbS11dGlsaXRpZXMnO1xyXG5pbXBvcnQge0Fic3RyYWN0VHJhbnNVbml0fSBmcm9tICcuL2Fic3RyYWN0LXRyYW5zLXVuaXQnO1xyXG5pbXBvcnQge1hsaWZmTWVzc2FnZVBhcnNlcn0gZnJvbSAnLi94bGlmZi1tZXNzYWdlLXBhcnNlcic7XHJcbmltcG9ydCB7UGFyc2VkTWVzc2FnZX0gZnJvbSAnLi9wYXJzZWQtbWVzc2FnZSc7XHJcbmltcG9ydCB7QWJzdHJhY3RNZXNzYWdlUGFyc2VyfSBmcm9tICcuL2Fic3RyYWN0LW1lc3NhZ2UtcGFyc2VyJztcclxuaW1wb3J0IHtpc051bGxPclVuZGVmaW5lZH0gZnJvbSAndXRpbCc7XHJcbi8qKlxyXG4gKiBDcmVhdGVkIGJ5IG1hcnRpbiBvbiAwMS4wNS4yMDE3LlxyXG4gKiBBIFRyYW5zbGF0aW9uIFVuaXQgaW4gYW4gWExJRkYgMS4yIGZpbGUuXHJcbiAqL1xyXG5cclxuZXhwb3J0IGNsYXNzIFhsaWZmVHJhbnNVbml0IGV4dGVuZHMgQWJzdHJhY3RUcmFuc1VuaXQgaW1wbGVtZW50cyBJVHJhbnNVbml0IHtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihfZWxlbWVudDogRWxlbWVudCwgX2lkOiBzdHJpbmcsIF90cmFuc2xhdGlvbk1lc3NhZ2VzRmlsZTogSVRyYW5zbGF0aW9uTWVzc2FnZXNGaWxlKSB7XHJcbiAgICAgICAgc3VwZXIoX2VsZW1lbnQsIF9pZCwgX3RyYW5zbGF0aW9uTWVzc2FnZXNGaWxlKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgc291cmNlQ29udGVudCgpOiBzdHJpbmcge1xyXG4gICAgICAgIGNvbnN0IHNvdXJjZUVsZW1lbnQgPSBET01VdGlsaXRpZXMuZ2V0Rmlyc3RFbGVtZW50QnlUYWdOYW1lKHRoaXMuX2VsZW1lbnQsICdzb3VyY2UnKTtcclxuICAgICAgICByZXR1cm4gRE9NVXRpbGl0aWVzLmdldFhNTENvbnRlbnQoc291cmNlRWxlbWVudCk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTZXQgbmV3IHNvdXJjZSBjb250ZW50IGluIHRoZSB0cmFuc3VuaXQuXHJcbiAgICAgKiBOb3JtYWxseSwgdGhpcyBpcyBkb25lIGJ5IG5nLWV4dHJhY3QuXHJcbiAgICAgKiBNZXRob2Qgb25seSBleGlzdHMgdG8gYWxsb3cgeGxpZmZtZXJnZSB0byBtZXJnZSBtaXNzaW5nIGNoYW5nZWQgc291cmNlIGNvbnRlbnQuXHJcbiAgICAgKiBAcGFyYW0gbmV3Q29udGVudCB0aGUgbmV3IGNvbnRlbnQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzZXRTb3VyY2VDb250ZW50KG5ld0NvbnRlbnQ6IHN0cmluZykge1xyXG4gICAgICAgIGxldCBzb3VyY2UgPSBET01VdGlsaXRpZXMuZ2V0Rmlyc3RFbGVtZW50QnlUYWdOYW1lKHRoaXMuX2VsZW1lbnQsICdzb3VyY2UnKTtcclxuICAgICAgICBpZiAoIXNvdXJjZSkge1xyXG4gICAgICAgICAgICAvLyBzaG91bGQgbm90IGhhcHBlbiwgdGhlcmUgYWx3YXlzIGhhcyB0byBiZSBhIHNvdXJjZSwgYnV0IHdobyBrbm93cy4uXHJcbiAgICAgICAgICAgIHNvdXJjZSA9IHRoaXMuX2VsZW1lbnQuYXBwZW5kQ2hpbGQodGhpcy5fZWxlbWVudC5vd25lckRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NvdXJjZScpKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgRE9NVXRpbGl0aWVzLnJlcGxhY2VDb250ZW50V2l0aFhNTENvbnRlbnQoc291cmNlLCBuZXdDb250ZW50KTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFJldHVybiBhIHBhcnNlciB1c2VkIGZvciBub3JtYWxpemVkIG1lc3NhZ2VzLlxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgbWVzc2FnZVBhcnNlcigpOiBBYnN0cmFjdE1lc3NhZ2VQYXJzZXIge1xyXG4gICAgICAgIHJldHVybiBuZXcgWGxpZmZNZXNzYWdlUGFyc2VyKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUaGUgb3JpZ2luYWwgdGV4dCB2YWx1ZSwgdGhhdCBpcyB0byBiZSB0cmFuc2xhdGVkLCBhcyBub3JtYWxpemVkIG1lc3NhZ2UuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBjcmVhdGVTb3VyY2VDb250ZW50Tm9ybWFsaXplZCgpOiBQYXJzZWRNZXNzYWdlIHtcclxuICAgICAgICBjb25zdCBzb3VyY2VFbGVtZW50ID0gRE9NVXRpbGl0aWVzLmdldEZpcnN0RWxlbWVudEJ5VGFnTmFtZSh0aGlzLl9lbGVtZW50LCAnc291cmNlJyk7XHJcbiAgICAgICAgaWYgKHNvdXJjZUVsZW1lbnQpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMubWVzc2FnZVBhcnNlcigpLmNyZWF0ZU5vcm1hbGl6ZWRNZXNzYWdlRnJvbVhNTChzb3VyY2VFbGVtZW50LCBudWxsKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiB0aGUgdHJhbnNsYXRlZCB2YWx1ZSAoY29udGFpbmluZyBhbGwgbWFya3VwLCBkZXBlbmRzIG9uIHRoZSBjb25jcmV0ZSBmb3JtYXQgdXNlZCkuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyB0YXJnZXRDb250ZW50KCk6IHN0cmluZyB7XHJcbiAgICAgICAgY29uc3QgdGFyZ2V0RWxlbWVudCA9IERPTVV0aWxpdGllcy5nZXRGaXJzdEVsZW1lbnRCeVRhZ05hbWUodGhpcy5fZWxlbWVudCwgJ3RhcmdldCcpO1xyXG4gICAgICAgIHJldHVybiBET01VdGlsaXRpZXMuZ2V0WE1MQ29udGVudCh0YXJnZXRFbGVtZW50KTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIHRoZSB0cmFuc2xhdGVkIHZhbHVlLCBidXQgYWxsIHBsYWNlaG9sZGVycyBhcmUgcmVwbGFjZWQgd2l0aCB7e259fSAoc3RhcnRpbmcgYXQgMClcclxuICAgICAqIGFuZCBhbGwgZW1iZWRkZWQgaHRtbCBpcyByZXBsYWNlZCBieSBkaXJlY3QgaHRtbCBtYXJrdXAuXHJcbiAgICAgKi9cclxuICAgIHRhcmdldENvbnRlbnROb3JtYWxpemVkKCk6IElOb3JtYWxpemVkTWVzc2FnZSB7XHJcbiAgICAgICAgY29uc3QgdGFyZ2V0RWxlbWVudCA9IERPTVV0aWxpdGllcy5nZXRGaXJzdEVsZW1lbnRCeVRhZ05hbWUodGhpcy5fZWxlbWVudCwgJ3RhcmdldCcpO1xyXG4gIC