UNPKG

ngx-dynamic-hooks

Version:

Automatically insert live Angular components into a dynamic string of content (based on their selector or any pattern of your choice) and render the result in the DOM.

163 lines 26.2 kB
import { Injectable } from '@angular/core'; import { anchorAttrHookId, anchorAttrParseToken } from '../../constants/core'; import { matchAll } from './utils'; import * as i0 from "@angular/core"; import * as i1 from "../platform/autoPlatformService"; const sanitizerPlaceholderTag = 'dynamic-hooks-sanitization-placeholder'; const sanitizerPlaceholderRegex = new RegExp(`<\/?${sanitizerPlaceholderTag}.*?>`, 'g'); /** * A utility service that sanitizes an Element and all of its children while exluding found hook elements */ export class ContentSanitizer { constructor(platformService) { this.platformService = platformService; this.attrWhitelist = [anchorAttrHookId, anchorAttrParseToken, 'class', 'href', 'src']; } /** * Sanitizes an element while preserving marked hook anchors * * @param contentElement - The element to sanitize * @param hookIndex - The current hookIndex * @param token - The current ParseToken */ sanitize(contentElement, hookIndex, token) { const originalHookAnchors = {}; // Replace all hook anchors with custom placeholder elements // This is so the browser has no predefined rules where they can and can't exist in the dom hierarchy and doesn't edit the html. for (const hook of Object.values(hookIndex)) { const anchorElement = this.platformService.querySelectorAll(contentElement, `[${anchorAttrHookId}="${hook.id}"][${anchorAttrParseToken}="${token}"]`)?.[0]; if (anchorElement) { originalHookAnchors[hook.id] = anchorElement; const parentElement = this.platformService.getParentNode(anchorElement); const childNodes = this.platformService.getChildNodes(anchorElement); const placeholderElement = this.platformService.createElement(sanitizerPlaceholderTag); this.platformService.setAttribute(placeholderElement, anchorAttrHookId, hook.id.toString()); this.platformService.setAttribute(placeholderElement, anchorAttrParseToken, token); this.platformService.insertBefore(parentElement, placeholderElement, anchorElement); this.platformService.removeChild(parentElement, anchorElement); for (const node of childNodes) { this.platformService.appendChild(placeholderElement, node); } } } // Encode sanitization placeholders (so they survive sanitization) let innerHTML = this.platformService.getInnerContent(contentElement); innerHTML = this.findAndEncodeTags(innerHTML, sanitizerPlaceholderRegex); // Sanitize (without warnings) const consoleWarnFn = console.warn; console.warn = () => { }; let sanitizedInnerHtml = this.platformService.sanitize(innerHTML); console.warn = consoleWarnFn; // Decode sanitization placeholders sanitizedInnerHtml = this.decodeTagString(sanitizedInnerHtml); contentElement.innerHTML = sanitizedInnerHtml || ''; // Restore original hook anchors for (const [hookId, anchorElement] of Object.entries(originalHookAnchors)) { const placeholderElement = this.platformService.querySelectorAll(contentElement, `${sanitizerPlaceholderTag}[${anchorAttrHookId}="${hookId}"]`)?.[0]; if (placeholderElement) { const parentElement = this.platformService.getParentNode(placeholderElement); const childNodes = this.platformService.getChildNodes(placeholderElement); this.platformService.insertBefore(parentElement, anchorElement, placeholderElement); this.platformService.removeChild(parentElement, placeholderElement); for (const node of childNodes) { this.platformService.appendChild(anchorElement, node); } // As a last step, sanitize the hook anchor attrs as well this.sanitizeElementAttrs(anchorElement); } } return contentElement; } /** * Sanitizes a single element's attributes * * @param element - The element in question */ sanitizeElementAttrs(element) { // Collect all existing attributes, put them on span-element, sanitize it, then copy surviving attrs back onto hook anchor element const attrs = this.platformService.getAttributeNames(element); const tmpWrapperElement = this.platformService.createElement('div'); const tmpElement = this.platformService.createElement('span'); this.platformService.appendChild(tmpWrapperElement, tmpElement); // Move attr to tmp for (const attr of attrs) { try { this.platformService.setAttribute(tmpElement, attr, this.platformService.getAttribute(element, attr)); } catch (e) { } // Keep in separate try-catch, so the first doesn't stop the second try { // Always keep those two if (attr !== anchorAttrHookId && attr !== anchorAttrParseToken) { this.platformService.removeAttribute(element, attr); } } catch (e) { } } // Sanitize tmp tmpWrapperElement.innerHTML = this.platformService.sanitize(this.platformService.getInnerContent(tmpWrapperElement)); // Move surviving attrs back to element const sanitizedTmpElement = this.platformService.querySelectorAll(tmpWrapperElement, 'span')[0]; const survivingAttrs = this.platformService.getAttributeNames(sanitizedTmpElement); for (const survivingAttr of survivingAttrs) { try { this.platformService.setAttribute(element, survivingAttr, this.platformService.getAttribute(sanitizedTmpElement, survivingAttr)); } catch (e) { } } return element; } // En/decoding placeholders // ------------------------ /** * Finds and encodes all tags that match the specified regex so that they survive sanitization * * @param content - The stringified html content to search * @param substrRegex - The regex that matches the element tags */ findAndEncodeTags(content, substrRegex) { let encodedContent = content; const matches = matchAll(content, substrRegex); matches.sort((a, b) => b.index - a.index); for (const match of matches) { const startIndex = match.index; const endIndex = match.index + match[0].length; const textBeforeSelector = encodedContent.substring(0, startIndex); const encodedPlaceholder = this.encodeTagString(encodedContent.substring(startIndex, endIndex)); const textAfterSelector = encodedContent.substring(endIndex); encodedContent = textBeforeSelector + encodedPlaceholder + textAfterSelector; } return encodedContent; } /** * Encodes the special html chars in a html tag so that is is considered a harmless string * * @param element - The element as a string */ encodeTagString(element) { element = element.replace(/</g, '@@@hook-lt@@@'); element = element.replace(/>/g, '@@@hook-gt@@@'); element = element.replace(/"/g, '@@@hook-dq@@@'); return element; } /** * Decodes the encoded html chars in a html tag again * * @param element - The element as a string */ decodeTagString(element) { element = element.replace(/@@@hook-lt@@@/g, '<'); element = element.replace(/@@@hook-gt@@@/g, '>'); element = element.replace(/@@@hook-dq@@@/g, '"'); return element; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentSanitizer, deps: [{ token: i1.AutoPlatformService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentSanitizer, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentSanitizer, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.AutoPlatformService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGVudFNhbml0aXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1keW5hbWljLWhvb2tzL3NyYy9saWIvc2VydmljZXMvdXRpbHMvY29udGVudFNhbml0aXplci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRzNDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzlFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxTQUFTLENBQUM7OztBQUVuQyxNQUFNLHVCQUF1QixHQUFHLHdDQUF3QyxDQUFDO0FBQ3pFLE1BQU0seUJBQXlCLEdBQUcsSUFBSSxNQUFNLENBQUMsT0FBTyx1QkFBdUIsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBRXhGOztHQUVHO0FBSUgsTUFBTSxPQUFPLGdCQUFnQjtJQUkzQixZQUFvQixlQUFvQztRQUFwQyxvQkFBZSxHQUFmLGVBQWUsQ0FBcUI7UUFGeEQsa0JBQWEsR0FBRyxDQUFDLGdCQUFnQixFQUFFLG9CQUFvQixFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUE7SUFFckIsQ0FBQztJQUU1RDs7Ozs7O09BTUc7SUFDSCxRQUFRLENBQUMsY0FBbUIsRUFBRSxTQUFvQixFQUFFLEtBQWE7UUFDL0QsTUFBTSxtQkFBbUIsR0FBeUIsRUFBRSxDQUFDO1FBRXJELDREQUE0RDtRQUM1RCxnSUFBZ0k7UUFDaEksS0FBSyxNQUFNLElBQUksSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDNUMsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxjQUFjLEVBQUUsSUFBSSxnQkFBZ0IsS0FBSyxJQUFJLENBQUMsRUFBRSxNQUFNLG9CQUFvQixLQUFL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QU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLGdCQUFnQixFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ2pELE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7K0dBbEtVLGdCQUFnQjttSEFBaEIsZ0JBQWdCLGNBRmYsTUFBTTs7NEZBRVAsZ0JBQWdCO2tCQUg1QixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEhvb2tJbmRleCB9IGZyb20gJy4uLy4uL2ludGVyZmFjZXNQdWJsaWMnO1xuaW1wb3J0IHsgQXV0b1BsYXRmb3JtU2VydmljZSB9IGZyb20gJy4uL3BsYXRmb3JtL2F1dG9QbGF0Zm9ybVNlcnZpY2UnO1xuaW1wb3J0IHsgYW5jaG9yQXR0ckhvb2tJZCwgYW5jaG9yQXR0clBhcnNlVG9rZW4gfSBmcm9tICcuLi8uLi9jb25zdGFudHMvY29yZSc7XG5pbXBvcnQgeyBtYXRjaEFsbCB9IGZyb20gJy4vdXRpbHMnO1xuXG5jb25zdCBzYW5pdGl6ZXJQbGFjZWhvbGRlclRhZyA9ICdkeW5hbWljLWhvb2tzLXNhbml0aXphdGlvbi1wbGFjZWhvbGRlcic7XG5jb25zdCBzYW5pdGl6ZXJQbGFjZWhvbGRlclJlZ2V4ID0gbmV3IFJlZ0V4cChgPFxcLz8ke3Nhbml0aXplclBsYWNlaG9sZGVyVGFnfS4qPz5gLCAnZycpO1xuXG4vKipcbiAqIEEgdXRpbGl0eSBzZXJ2aWNlIHRoYXQgc2FuaXRpemVzIGFuIEVsZW1lbnQgYW5kIGFsbCBvZiBpdHMgY2hpbGRyZW4gd2hpbGUgZXhsdWRpbmcgZm91bmQgaG9vayBlbGVtZW50c1xuICovXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBDb250ZW50U2FuaXRpemVyIHtcbiAgXG4gIGF0dHJXaGl0ZWxpc3QgPSBbYW5jaG9yQXR0ckhvb2tJZCwgYW5jaG9yQXR0clBhcnNlVG9rZW4sICdjbGFzcycsICdocmVmJywgJ3NyYyddXG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBwbGF0Zm9ybVNlcnZpY2U6IEF1dG9QbGF0Zm9ybVNlcnZpY2UpIHt9XG5cbiAgLyoqXG4gICAqIFNhbml0aXplcyBhbiBlbGVtZW50IHdoaWxlIHByZXNlcnZpbmcgbWFya2VkIGhvb2sgYW5jaG9yc1xuICAgKiBcbiAgICogQHBhcmFtIGNvbnRlbnRFbGVtZW50IC0gVGhlIGVsZW1lbnQgdG8gc2FuaXRpemVcbiAgICogQHBhcmFtIGhvb2tJbmRleCAtIFRoZSBjdXJyZW50IGhvb2tJbmRleFxuICAgKiBAcGFyYW0gdG9rZW4gLSBUaGUgY3VycmVudCBQYXJzZVRva2VuXG4gICAqL1xuICBzYW5pdGl6ZShjb250ZW50RWxlbWVudDogYW55LCBob29rSW5kZXg6IEhvb2tJbmRleCwgdG9rZW46IHN0cmluZyk6IGFueSB7XG4gICAgY29uc3Qgb3JpZ2luYWxIb29rQW5jaG9yczoge1trZXk6IHN0cmluZ106IGFueX0gPSB7fTtcblxuICAgIC8vIFJlcGxhY2UgYWxsIGhvb2sgYW5jaG9ycyB3aXRoIGN1c3RvbSBwbGFjZWhvbGRlciBlbGVtZW50c1xuICAgIC8vIFRoaXMgaXMgc28gdGhlIGJyb3dzZXIgaGFzIG5vIHByZWRlZmluZWQgcnVsZXMgd2hlcmUgdGhleSBjYW4gYW5kIGNhbid0IGV4aXN0IGluIHRoZSBkb20gaGllcmFyY2h5IGFuZCBkb2Vzbid0IGVkaXQgdGhlIGh0bWwuXG4gICAgZm9yIChjb25zdCBob29rIG9mIE9iamVjdC52YWx1ZXMoaG9va0luZGV4KSkge1xuICAgICAgY29uc3QgYW5jaG9yRWxlbWVudCA9IHRoaXMucGxhdGZvcm1TZXJ2aWNlLnF1ZXJ5U2VsZWN0b3JBbGwoY29udGVudEVsZW1lbnQsIGBbJHthbmNob3JBdHRySG9va0lkfT1cIiR7aG9vay5pZH1cIl1bJHthbmNob3JBdHRyUGFyc2VUb2tlbn09XCIke3Rva2VufVwiXWApPy5bMF07XG4gICAgICBpZiAoYW5jaG9yRWxlbWVudCkge1xuICAgICAgICBvcmlnaW5hbEhvb2tBbmNob3JzW2hvb2suaWRdID0gYW5jaG9yRWxlbWVudDtcblxuICAgICAgICBjb25zdCBwYXJlbnRFbGVtZW50ID0gdGhpcy5wbGF0Zm9ybVNlcnZpY2UuZ2V0UGFyZW50Tm9kZShhbmNob3JFbGVtZW50KTtcbiAgICAgICAgY29uc3QgY2hpbGROb2RlcyA9IHRoaXMucGxhdGZvcm1TZXJ2aWNlLmdldENoaWxkTm9kZXMoYW5jaG9yRWxlbWVudCk7XG5cbiAgICAgICAgY29uc3QgcGxhY2Vob2xkZXJFbGVtZW50ID0gdGhpcy5wbGF0Zm9ybVNlcnZpY2UuY3JlYXRlRWxlbWVudChzYW5pdGl6ZXJQbGFjZWhvbGRlclRhZyk7XG4gICAgICAgIHRoaXMucGxhdGZvcm1TZXJ2aWNlLnNldEF0dHJpYnV0ZShwbGFjZWhvbGRlckVsZW1lbnQsIGFuY2hvckF0dHJIb29rSWQsIGhvb2suaWQudG9TdHJpbmcoKSk7XG4gICAgICAgIHRoaXMucGxhdGZvcm1TZXJ2aWNlLnNldEF0dHJpYnV0ZShwbGFjZWhvbGRlckVsZW1lbnQsIGFuY2hvckF0dHJQYXJzZVRva2VuLCB0b2tlbik7XG4gICAgICAgIHRoaXMucGxhdGZvcm1TZXJ2aWNlLmluc2VydEJlZm9yZShwYXJlbnRFbGVtZW50LCBwbGFjZWhvbGRlckVsZW1lbnQsIGFuY2hvckVsZW1lbnQpO1xuICAgICAgICB0aGlzLnBsYXRmb3JtU2VydmljZS5yZW1vdmVDaGlsZChwYXJlbnRFbGVtZW50LCBhbmNob3JFbGVtZW50KTtcbiAgICAgICAgZm9yIChjb25zdCBub2RlIG9mIGNoaWxkTm9kZXMpIHtcbiAgICAgICAgICB0aGlzLnBsYXRmb3JtU2VydmljZS5hcHBlbmRDaGlsZChwbGFjZWhvbGRlckVsZW1lbnQsIG5vZGUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gRW5jb2RlIHNhbml0aXphdGlvbiBwbGFjZWhvbGRlcnMgKHNvIHRoZXkgc3Vydml2ZSBzYW5pdGl6YXRpb24pXG4gICAgbGV0IGlubmVySFRNTCA9IHRoaXMucGxhdGZvcm1TZXJ2aWNlLmdldElubmVyQ29udGVudChjb250ZW50RWxlbWVudCk7XG4gICAgaW5uZXJIVE1MID0gdGhpcy5maW5kQW5kRW5jb2RlVGFncyhpbm5lckhUTUwsIHNhbml0aXplclBsYWNlaG9sZGVyUmVnZXgpO1xuXG4gICAgLy8gU2FuaXRpemUgKHdpdGhvdXQgd2FybmluZ3MpXG4gICAgY29uc3QgY29uc29sZVdhcm5GbiA9IGNvbnNvbGUud2FybjtcbiAgICBjb25zb2xlLndhcm4gPSAoKSA9PiB7fTtcbiAgICBsZXQgc2FuaXRpemVkSW5uZXJIdG1sID0gdGhpcy5wbGF0Zm9ybVNlcnZpY2Uuc2FuaXRpemUoaW5uZXJIVE1MKTtcbiAgICBjb25zb2xlLndhcm4gPSBjb25zb2xlV2FybkZuO1xuXG4gICAgLy8gRGVjb2RlIHNhbml0aXphdGlvbiBwbGFjZWhvbGRlcnNcbiAgICBzYW5pdGl6ZWRJbm5lckh0bWwgPSB0aGlzLmRlY29kZVRhZ1N0cmluZyhzYW5pdGl6ZWRJbm5lckh0bWwpO1xuICAgIGNvbnRlbnRFbGVtZW50LmlubmVySFRNTCA9IHNhbml0aXplZElubmVySHRtbCB8fCAnJztcblxuICAgIC8vIFJlc3RvcmUgb3JpZ2luYWwgaG9vayBhbmNob3JzXG4gICAgZm9yIChjb25zdCBbaG9va0lkLCBhbmNob3JFbGVtZW50XSBvZiBPYmplY3QuZW50cmllcyhvcmlnaW5hbEhvb2tBbmNob3JzKSkge1xuICAgICAgY29uc3QgcGxhY2Vob2xkZXJFbGVtZW50ID0gdGhpcy5wbGF0Zm9ybVNlcnZpY2UucXVlcnlTZWxlY3RvckFsbChjb250ZW50RWxlbWVudCwgYCR7c2FuaXRpemVyUGxhY2Vob2xkZXJUYWd9WyR7YW5jaG9yQXR0ckhvb2tJZH09XCIke2hvb2tJZH1cIl1gKT8uWzBdO1xuICAgICAgaWYgKHBsYWNlaG9sZGVyRWxlbWVudCkge1xuICAgICAgICBjb25zdCBwYXJlbnRFbGVtZW50ID0gdGhpcy5wbGF0Zm9ybVNlcnZpY2UuZ2V0UGFyZW50Tm9kZShwbGFjZWhvbGRlckVsZW1lbnQpO1xuICAgICAgICBjb25zdCBjaGlsZE5vZGVzID0gdGhpcy5wbGF0Zm9ybVNlcnZpY2UuZ2V0Q2hpbGROb2RlcyhwbGFjZWhvbGRlckVsZW1lbnQpO1xuICAgICAgICB0aGlzLnBsYXRmb3JtU2VydmljZS5pbnNlcnRCZWZvcmUocGFyZW50RWxlbWVudCwgYW5jaG9yRWxlbWVudCwgcGxhY2Vob2xkZXJFbGVtZW50KTtcbiAgICAgICAgdGhpcy5wbGF0Zm9ybVNlcnZpY2UucmVtb3ZlQ2hpbGQocGFyZW50RWxlbWVudCwgcGxhY2Vob2xkZXJFbGVtZW50KTtcbiAgICAgICAgZm9yIChjb25zdCBub2RlIG9mIGNoaWxkTm9kZXMpIHtcbiAgICAgICAgICB0aGlzLnBsYXRmb3JtU2VydmljZS5hcHBlbmRDaGlsZChhbmNob3JFbGVtZW50LCBub2RlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFzIGEgbGFzdCBzdGVwLCBzYW5pdGl6ZSB0aGUgaG9vayBhbmNob3IgYXR0cnMgYXMgd2VsbFxuICAgICAgICB0aGlzLnNhbml0aXplRWxlbWVudEF0dHJzKGFuY2hvckVsZW1lbnQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBjb250ZW50RWxlbWVudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTYW5pdGl6ZXMgYSBzaW5nbGUgZWxlbWVudCdzIGF0dHJpYnV0ZXNcbiAgICpcbiAgICogQHBhcmFtIGVsZW1lbnQgLSBUaGUgZWxlbWVudCBpbiBxdWVzdGlvblxuICAgKi9cbiAgcHJpdmF0ZSBzYW5pdGl6ZUVsZW1lbnRBdHRycyhlbGVtZW50OiBhbnkpOiBhbnkge1xuICAgICAgLy8gQ29sbGVjdCBhbGwgZXhpc3RpbmcgYXR0cmlidXRlcywgcHV0IHRoZW0gb24gc3Bhbi1lbGVtZW50LCBzYW5pdGl6ZSBpdCwgdGhlbiBjb3B5IHN1cnZpdmluZyBhdHRycyBiYWNrIG9udG8gaG9vayBhbmNob3IgZWxlbWVudFxuICAgICAgY29uc3QgYXR0cnMgPSB0aGlzLnBsYXRmb3JtU2VydmljZS5nZXRBdHRyaWJ1dGVOYW1lcyhlbGVtZW50KTtcbiAgICAgIGNvbnN0IHRtcFdyYXBwZXJFbGVtZW50ID0gdGhpcy5wbGF0Zm9ybVNlcnZpY2UuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgICBjb25zdCB0bXBFbGVtZW50ID0gdGhpcy5wbGF0Zm9ybVNlcnZpY2UuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgICAgdGhpcy5wbGF0Zm9ybVNlcnZpY2UuYXBwZW5kQ2hpbGQodG1wV3JhcHBlckVsZW1lbnQsIHRtcEVsZW1lbnQpO1xuICAgICAgXG4gICAgICAvLyBNb3ZlIGF0dHIgdG8gdG1wXG4gICAgICBmb3IgKGNvbnN0IGF0dHIgb2YgYXR0cnMpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0aGlzLnBsYXRmb3JtU2VydmljZS5zZXRBdHRyaWJ1dGUodG1wRWxlbWVudCwgYXR0ciwgdGhpcy5wbGF0Zm9ybVNlcnZpY2UuZ2V0QXR0cmlidXRlKGVsZW1lbnQsIGF0dHIpISk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHt9XG4gICAgICAgIC8vIEtlZXAgaW4gc2VwYXJhdGUgdHJ5LWNhdGNoLCBzbyB0aGUgZmlyc3QgZG9lc24ndCBzdG9wIHRoZSBzZWNvbmRcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBBbHdheXMga2VlcCB0aG9zZSB0d29cbiAgICAgICAgICBpZiAoYXR0ciAhPT0gYW5jaG9yQXR0ckhvb2tJZCAmJiBhdHRyICE9PSBhbmNob3JBdHRyUGFyc2VUb2tlbikge1xuICAgICAgICAgICAgdGhpcy5wbGF0Zm9ybVNlcnZpY2UucmVtb3ZlQXR0cmlidXRlKGVsZW1lbnQsIGF0dHIpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge30gICAgICAgICAgXG4gICAgICB9XG5cbiAgICAgIC8vIFNhbml0aXplIHRtcFxuICAgICAgdG1wV3JhcHBlckVsZW1lbnQuaW5uZXJIVE1MID0gdGhpcy5wbGF0Zm9ybVNlcnZpY2Uuc2FuaXRpemUodGhpcy5wbGF0Zm9ybVNlcnZpY2UuZ2V0SW5uZXJDb250ZW50KHRtcFdyYXBwZXJFbGVtZW50KSk7XG5cbiAgICAgIC8vIE1vdmUgc3Vydml2aW5nIGF0dHJzIGJhY2sgdG8gZWxlbWVudFxuICAgICAgY29uc3Qgc2FuaXRpemVkVG1wRWxlbWVudCA9IHRoaXMucGxhdGZvcm1TZXJ2aWNlLnF1ZXJ5U2VsZWN0b3JBbGwodG1wV3JhcHBlckVsZW1lbnQsICdzcGFuJylbMF07XG4gICAgICBjb25zdCBzdXJ2aXZpbmdBdHRycyA9IHRoaXMucGxhdGZvcm1TZXJ2aWNlLmdldEF0dHJpYnV0ZU5hbWVzKHNhbml0aXplZFRtcEVsZW1lbnQpO1xuICAgICAgZm9yIChjb25zdCBzdXJ2aXZpbmdBdHRyIG9mIHN1cnZpdmluZ0F0dHJzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdGhpcy5wbGF0Zm9ybVNlcnZpY2Uuc2V0QXR0cmlidXRlKGVsZW1lbnQsIHN1cnZpdmluZ0F0dHIsIHRoaXMucGxhdGZvcm1TZXJ2aWNlLmdldEF0dHJpYnV0ZShzYW5pdGl6ZWRUbXBFbGVtZW50LCBzdXJ2aXZpbmdBdHRyKSEpO1xuICAgICAgICB9IGNhdGNoIChlKSB7fVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gZWxlbWVudDtcbiAgfVxuXG4gIC8vIEVuL2RlY29kaW5nIHBsYWNlaG9sZGVyc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAvKipcbiAgICogRmluZHMgYW5kIGVuY29kZXMgYWxsIHRhZ3MgdGhhdCBtYXRjaCB0aGUgc3BlY2lmaWVkIHJlZ2V4IHNvIHRoYXQgdGhleSBzdXJ2aXZlIHNhbml0aXphdGlvblxuICAgKiBcbiAgICogQHBhcmFtIGNvbnRlbnQgLSBUaGUgc3RyaW5naWZpZWQgaHRtbCBjb250ZW50IHRvIHNlYXJjaFxuICAgKiBAcGFyYW0gc3Vic3RyUmVnZXggLSBUaGUgcmVnZXggdGhhdCBtYXRjaGVzIHRoZSBlbGVtZW50IHRhZ3NcbiAgICovXG4gIHByaXZhdGUgZmluZEFuZEVuY29kZVRhZ3MoY29udGVudDogc3RyaW5nLCBzdWJzdHJSZWdleDogUmVnRXhwKTogc3RyaW5nIHtcbiAgICBsZXQgZW5jb2RlZENvbnRlbnQgPSBjb250ZW50O1xuXG4gICAgY29uc3QgbWF0Y2hlcyA9IG1hdGNoQWxsKGNvbnRlbnQsIHN1YnN0clJlZ2V4KTtcbiAgICBtYXRjaGVzLnNvcnQoKGEsIGIpID0+IGIuaW5kZXggLSBhLmluZGV4KTtcblxuICAgIGZvciAoY29uc3QgbWF0Y2ggb2YgbWF0Y2hlcykge1xuICAgICAgY29uc3Qgc3RhcnRJbmRleCA9IG1hdGNoLmluZGV4O1xuICAgICAgY29uc3QgZW5kSW5kZXggPSBtYXRjaC5pbmRleCArIG1hdGNoWzBdLmxlbmd0aDtcblxuICAgICAgY29uc3QgdGV4dEJlZm9yZVNlbGVjdG9yID0gZW5jb2RlZENvbnRlbnQuc3Vic3RyaW5nKDAsIHN0YXJ0SW5kZXgpO1xuICAgICAgY29uc3QgZW5jb2RlZFBsYWNlaG9sZGVyID0gdGhpcy5lbmNvZGVUYWdTdHJpbmcoZW5jb2RlZENvbnRlbnQuc3Vic3RyaW5nKHN0YXJ0SW5kZXgsIGVuZEluZGV4KSk7XG4gICAgICBjb25zdCB0ZXh0QWZ0ZXJTZWxlY3RvciA9IGVuY29kZWRDb250ZW50LnN1YnN0cmluZyhlbmRJbmRleCk7XG4gICAgICBlbmNvZGVkQ29udGVudCA9IHRleHRCZWZvcmVTZWxlY3RvciArIGVuY29kZWRQbGFjZWhvbGRlciArIHRleHRBZnRlclNlbGVjdG9yO1xuICAgIH1cblxuICAgIHJldHVybiBlbmNvZGVkQ29udGVudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmNvZGVzIHRoZSBzcGVjaWFsIGh0bWwgY2hhcnMgaW4gYSBodG1sIHRhZyBzbyB0aGF0IGlzIGlzIGNvbnNpZGVyZWQgYSBoYXJtbGVzcyBzdHJpbmdcbiAgICpcbiAgICogQHBhcmFtIGVsZW1lbnQgLSBUaGUgZWxlbWVudCBhcyBhIHN0cmluZ1xuICAgKi9cbiAgcHJpdmF0ZSBlbmNvZGVUYWdTdHJpbmcoZWxlbWVudDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBlbGVtZW50ID0gZWxlbWVudC5yZXBsYWNlKC88L2csICdAQEBob29rLWx0QEBAJyk7XG4gICAgZWxlbWVudCA9IGVsZW1lbnQucmVwbGFjZSgvPi9nLCAnQEBAaG9vay1ndEBAQCcpO1xuICAgIGVsZW1lbnQgPSBlbGVtZW50LnJlcGxhY2UoL1wiL2csICdAQEBob29rLWRxQEBAJyk7XG4gICAgcmV0dXJuIGVsZW1lbnQ7XG4gIH1cblxuICAvKipcbiAgICogRGVjb2RlcyB0aGUgZW5jb2RlZCBodG1sIGNoYXJzIGluIGEgaHRtbCB0YWcgYWdhaW5cbiAgICpcbiAgICogQHBhcmFtIGVsZW1lbnQgLSBUaGUgZWxlbWVudCBhcyBhIHN0cmluZ1xuICAgKi9cbiAgcHJpdmF0ZSBkZWNvZGVUYWdTdHJpbmcoZWxlbWVudDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBlbGVtZW50ID0gZWxlbWVudC5yZXBsYWNlKC9AQEBob29rLWx0QEBAL2csICc8Jyk7XG4gICAgZWxlbWVudCA9IGVsZW1lbnQucmVwbGFjZSgvQEBAaG9vay1ndEBAQC9nLCAnPicpO1xuICAgIGVsZW1lbnQgPSBlbGVtZW50LnJlcGxhY2UoL0BAQGhvb2stZHFAQEAvZywgJ1wiJyk7XG4gICAgcmV0dXJuIGVsZW1lbnQ7XG4gIH1cblxufVxuIl19