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
JavaScript
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