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.

339 lines 49 kB
import { Injectable } from '@angular/core'; import { matchAll } from './utils'; import * as i0 from "@angular/core"; /** * A service that provides various functions for en- and decoding data type strings in order to make them * meaningfully parseable by regex */ export class DataTypeEncoder { // Substrings // ----------------------------------------------------- /** * Finds all substrings in a piece of text and replaces all special characters within with @@@...@@@-placeholders. * * @param text - The text to parse for substrings */ encodeSubstrings(text) { // Get a list of all quotes (that are not preceded by an escaping backslash) const singleQuotes = matchAll(text, /'/gm).filter(match => match.index === 0 || text[match.index - 1] !== '\\'); const doubleQuotes = matchAll(text, /"/gm).filter(match => match.index === 0 || text[match.index - 1] !== '\\'); const graveQuotes = matchAll(text, /`/gm).filter(match => match.index === 0 || text[match.index - 1] !== '\\'); const allQuotes = [...singleQuotes, ...doubleQuotes, ...graveQuotes]; allQuotes.sort((a, b) => a['index'] - b['index']); // Create quotes text segments const quoteSegments = []; let outermostOpenedQuote = null; for (const quote of allQuotes) { if (!outermostOpenedQuote) { outermostOpenedQuote = quote; } else { if (outermostOpenedQuote[0] === quote[0]) { quoteSegments.push({ startIndex: outermostOpenedQuote.index + 1, endIndex: quote['index'] }); outermostOpenedQuote = null; } } } if (outermostOpenedQuote !== null) { throw Error('Input parse error. String was opened, but not closed.'); } // Encode quote segments const encodedBracketsText = this.encodeTextSegments(text, quoteSegments, this.encodeStringSpecialChars); return encodedBracketsText; } /** * Encodes all special characters that might be confused as code syntax in a piece of string * * @param text - The text to encode */ encodeStringSpecialChars(text) { text = text.replace(/'/g, '@@@singlequote@@@'); text = text.replace(/"/g, '@@@doublequote@@@'); text = text.replace(/`/g, '@@@gravequote@@@'); text = text.replace(/:/g, '@@@colon@@@'); text = text.replace(/;/g, '@@@semicolon@@@'); text = text.replace(/\./g, '@@@dot@@@'); text = text.replace(/,/g, '@@@comma@@@'); text = text.replace(/\\/g, '@@@backslash@@@'); text = text.replace(/\(/g, '@@@openRoundBracket@@@'); text = text.replace(/\)/g, '@@@closeRoundBracket@@@'); text = text.replace(/\[/g, '@@@openSquareBracket@@@'); text = text.replace(/\]/g, '@@@closeSquareBracket@@@'); text = text.replace(/\{/g, '@@@openCurlyBracket@@@'); text = text.replace(/\}/g, '@@@closeCurlyBracket@@@'); return text; } /** * Decodes the special characters again * * @param text - The text to decode */ decodeStringSpecialChars(text) { text = text.replace(/@@@singlequote@@@/g, '\''); text = text.replace(/@@@doublequote@@@/g, '"'); text = text.replace(/@@@gravequote@@@/g, '`'); text = text.replace(/@@@colon@@@/g, ':'); text = text.replace(/@@@semicolon@@@/g, ';'); text = text.replace(/@@@dot@@@/g, '.'); text = text.replace(/@@@comma@@@/g, ','); text = text.replace(/@@@backslash@@@/g, '\\'); text = text.replace(/@@@openRoundBracket@@@/g, '('); text = text.replace(/@@@closeRoundBracket@@@/g, ')'); text = text.replace(/@@@openSquareBracket@@@/g, '['); text = text.replace(/@@@closeSquareBracket@@@/g, ']'); text = text.replace(/@@@openCurlyBracket@@@/g, '{'); text = text.replace(/@@@closeCurlyBracket@@@/g, '}'); return text; } // Subfunctions // ----------------------------------------------------- /** * Finds all subfunctions in a piece of text and replaces their round brackets with @@@...@@@-placeholders. * * @param text - The text to parse for substrings */ encodeSubfunctions(text) { const openingBrackets = matchAll(text, /\(/gm); const closingBrackets = matchAll(text, /\)/gm); const allBrackets = [...openingBrackets, ...closingBrackets]; allBrackets.sort((a, b) => a['index'] - b['index']); // Create functions text segments const functionSegments = []; const openedBrackets = []; for (const bracket of allBrackets) { if (bracket[0] === '(') { openedBrackets.push(bracket); } else { if (openedBrackets.length === 0) { throw Error('Input parse error. Closed function bracket without opening it first.'); } // Only collect the outermost function brackets, not nested ones if (openedBrackets.length === 1) { functionSegments.push({ startIndex: openedBrackets[0].index + 1, endIndex: bracket['index'] }); } openedBrackets.pop(); } } if (openedBrackets.length !== 0) { throw Error('Input parse error. Opened function bracket without closing it.'); } // Encode quote segments const encodedFunctionsText = this.encodeTextSegments(text, functionSegments, this.encodeFunctionBrackets); return encodedFunctionsText; } /** * Encodes all round brackets with harmless placeholders * * @param text - The text to encode */ encodeFunctionBrackets(text) { text = text.replace(/\(/g, '@@@fnOpenBracket@@@'); text = text.replace(/\)/g, '@@@fnCloseBracket@@@'); return text; } /** * Decodes all round brackets again * * @param text - The text to decode */ decodeFunctionBrackets(text) { text = text.replace(/@@@fnOpenBracket@@@/g, '\('); text = text.replace(/@@@fnCloseBracket@@@/g, '\)'); return text; } // Subbrackets // ----------------------------------------------------- /** * Finds all subbrackets in a piece of text and replaces their brackets with @@@...@@@-placeholders. * * @param text - The text to parse for substrings */ encodeVariableSubbrackets(text) { // Property accessor opening brackets can be identified by what they are preceded by. // Must be a) text, b) closing square bracket or c) closing round bracket. Arrays can't be preceded by any of these. const variableOpeningBracketsWithLookbehinds = '(?<=[a-zA-Z_$\\]\)])\\['; // Too new for many older browsers const variableOpeningBrackets = '(?:[a-zA-Z_$\\]\)])(\\[)'; const openingBrackets = matchAll(text, new RegExp(variableOpeningBrackets, 'gm')); // Note: Can't simply find closing brackets as well (as is done in the other encoder functions), because the closing // bracket doesn't have a uniquely identifiable syntax. Might also be array endings. // Find the corresponding closing bracket for each opening bracket by parsing the following brackets const bracketSegments = []; for (const openingBracket of openingBrackets) { const followingText = text.substring(openingBracket.index + 2); // openingBracket.index + 2, b/c the regex starts at the character before the opening bracket and followingText is supposed to start after the opening bracket const followingOpeningBrackets = matchAll(followingText, /\[/gm); const followingClosingBrackets = matchAll(followingText, /\]/gm); const allFollowingBrackets = [...followingOpeningBrackets, ...followingClosingBrackets]; allFollowingBrackets.sort((a, b) => a['index'] - b['index']); let openedBrackets = 1; // Start with the first opening bracket already counted for (const followingBracket of allFollowingBrackets) { openedBrackets = followingBracket[0] === ']' ? openedBrackets - 1 : openedBrackets + 1; if (openedBrackets === 0) { bracketSegments.push({ startIndex: openingBracket.index + 2, endIndex: openingBracket.index + 2 + followingBracket['index'] }); break; } } if (openedBrackets !== 0) { throw Error('Input parse error. Opened bracket without closing it.'); } } // Throw out nested brackets const outerBracketSegments = []; for (const bracketSegment of bracketSegments) { if (outerBracketSegments.length === 0) { outerBracketSegments.push(bracketSegment); } else { if (outerBracketSegments[outerBracketSegments.length - 1].endIndex < bracketSegment.startIndex) { outerBracketSegments.push(bracketSegment); } } } // Encode bracket segments const encodedBracketsText = this.encodeTextSegments(text, outerBracketSegments, this.encodeVariableBrackets); return encodedBracketsText; } /** * Encodes all brackets with harmless placeholders * * @param text - The text to encode */ encodeVariableBrackets(text) { text = text.replace(/\[/g, '@@@variableOpeningBracket@@@'); text = text.replace(/\]/g, '@@@variableClosingBracket@@@'); return text; } /** * Decodes all brackets again * * @param text - The text to encode */ decodeVariableBrackets(text) { text = text.replace(/@@@variableOpeningBracket@@@/g, '\['); text = text.replace(/@@@variableClosingBracket@@@/g, '\]'); return text; } // Context var placeholder // ----------------------------------------------------- /** * Transforms a context var (that is already encoded for substrings, subfunctions and subbrackets) into a string placeholder * by encoding the context var syntax itself. This is so that can be safely parsed by JSON.parse() as a string and also so it * won't be misinterpreted by other regexes looking for JSON syntax (especially arrays b/c of context-var []-property-brackets) * * @param contextVar - The context var to transform */ transformContextVarIntoPlacerholder(contextVar) { // Replace context. with __CXT__ contextVar = '__CXT__' + contextVar.substring(7); // Encode variable syntax contextVar = contextVar.replace(/\"/g, '@@@cxtDoubleQuote@@@'); contextVar = contextVar.replace(/\./g, '@@@cxtDot@@@'); contextVar = contextVar.replace(/\[/g, '@@@cxtOpenSquareBracket@@@'); contextVar = contextVar.replace(/\]/g, '@@@cxtCloseSquareBracket@@@'); contextVar = contextVar.replace(/\(/g, '@@@cxtOpenRoundBracket@@@'); contextVar = contextVar.replace(/\)/g, '@@@cxtCloseRoundBracket@@@'); return contextVar; } /** * Transforms a context var placeholder back into the actual context var * * @param contextVar - The placeholder context var */ transformPlaceholderIntoContextVar(contextVar) { contextVar = 'context' + contextVar.substring(7); contextVar = contextVar.replace(/@@@cxtDoubleQuote@@@/g, '"'); contextVar = contextVar.replace(/@@@cxtDot@@@/g, '.'); contextVar = contextVar.replace(/@@@cxtOpenSquareBracket@@@/g, '['); contextVar = contextVar.replace(/@@@cxtCloseSquareBracket@@@/g, ']'); contextVar = contextVar.replace(/@@@cxtOpenRoundBracket@@@/g, '('); contextVar = contextVar.replace(/@@@cxtCloseRoundBracket@@@/g, ')'); return contextVar; } // Other // ----------------------------------------------------- /** * Takes a piece of text as well as array of TextSegments and encodes them with the help of an encodingFunction * The encoded text is then automatically assembled and returned. * * @param text - The text in question * @param specialTextSegments - The segments in the text to encode * @param encodingFunction - The encoding function to use */ encodeTextSegments(text, specialTextSegments, encodingFunction) { // 1. Divide whole text into two types of segments: Those to be encoded and those to be left as they are const allTextSegments = []; for (const specialTextSegment of specialTextSegments) { // Push normal text segment since last special segment const lastSegmentEndIndex = allTextSegments.length === 0 ? 0 : allTextSegments[allTextSegments.length - 1].endIndex; allTextSegments.push({ type: 'text', startIndex: lastSegmentEndIndex, endIndex: specialTextSegment.startIndex, string: text.substring(lastSegmentEndIndex, specialTextSegment.startIndex) }); // Push next special segment allTextSegments.push({ type: 'special', startIndex: specialTextSegment.startIndex, endIndex: specialTextSegment.endIndex, string: text.substring(specialTextSegment.startIndex, specialTextSegment.endIndex) }); } // Add text segment for trailing text after last special segment const lastBracketEndIndex = allTextSegments.length === 0 ? 0 : allTextSegments[allTextSegments.length - 1].endIndex; allTextSegments.push({ type: 'text', startIndex: lastBracketEndIndex, endIndex: text.length - 1, string: text.substring(lastBracketEndIndex) }); // 2. Encode all special segments for (const segment of allTextSegments) { if (segment.type === 'special') { segment.string = encodingFunction(segment.string); } } // 3. Concat everything together again let encodedString = ''; for (const segment of allTextSegments) { encodedString += segment.string; } return encodedString; } /** * Strips all escaping backslashes from a piece of text * * @param text - The text in question */ stripSlashes(text) { return text.replace(/\\(.)/g, '$1'); // return text.replace(new RegExp('\\\\(.)', 'g'), '$1'); } /** * Escapes all double quotes in a piece of text * * @param text - The text in question */ escapeDoubleQuotes(text) { const result = text.replace(/\\/g, '\\\\').replace(/\"/g, '\\"'); return result; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DataTypeEncoder, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DataTypeEncoder, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DataTypeEncoder, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YVR5cGVFbmNvZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWR5bmFtaWMtaG9va3Mvc3JjL2xpYi9zZXJ2aWNlcy91dGlscy9kYXRhVHlwZUVuY29kZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sU0FBUyxDQUFDOztBQU9uQzs7O0dBR0c7QUFJSCxNQUFNLE9BQU8sZUFBZTtJQUUxQixhQUFhO0lBQ2Isd0RBQXdEO0lBRXhEOzs7O09BSUc7SUFDSCxnQkFBZ0IsQ0FBQyxJQUFZO1FBQzNCLDRFQUE0RTtRQUM1RSxNQUFNLFlBQVksR0FBUSxRQUFRLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFDO1FBQ3JILE1BQU0sWUFBWSxHQUFRLFFBQVEsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEtBQUssS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUM7UUFDckgsTUFBTSxXQUFXLEdBQVEsUUFBUSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsS0FBSyxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQztRQUNw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UUFDdkIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNwQyx5REFBeUQ7SUFDM0QsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxrQkFBa0IsQ0FBQyxJQUFZO1FBQzdCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDakUsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQzsrR0FyV1UsZUFBZTttSEFBZixlQUFlLGNBRmQsTUFBTTs7NEZBRVAsZUFBZTtrQkFIM0IsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBtYXRjaEFsbCB9IGZyb20gJy4vdXRpbHMnO1xuXG5pbnRlcmZhY2UgVGV4dFNlZ21lbnQge1xuICBzdGFydEluZGV4OiBudW1iZXI7XG4gIGVuZEluZGV4OiBudW1iZXI7XG59XG5cbi8qKlxuICogQSBzZXJ2aWNlIHRoYXQgcHJvdmlkZXMgdmFyaW91cyBmdW5jdGlvbnMgZm9yIGVuLSBhbmQgZGVjb2RpbmcgZGF0YSB0eXBlIHN0cmluZ3MgaW4gb3JkZXIgdG8gbWFrZSB0aGVtXG4gKiBtZWFuaW5nZnVsbHkgcGFyc2VhYmxlIGJ5IHJlZ2V4XG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIERhdGFUeXBlRW5jb2RlciB7XG5cbiAgLy8gU3Vic3RyaW5nc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKlxuICAgKiBGaW5kcyBhbGwgc3Vic3RyaW5ncyBpbiBhIHBpZWNlIG9mIHRleHQgYW5kIHJlcGxhY2VzIGFsbCBzcGVjaWFsIGNoYXJhY3RlcnMgd2l0aGluIHdpdGggQEBALi4uQEBALXBsYWNlaG9sZGVycy5cbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCB0byBwYXJzZSBmb3Igc3Vic3RyaW5nc1xuICAgKi9cbiAgZW5jb2RlU3Vic3RyaW5ncyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIC8vIEdldCBhIGxpc3Qgb2YgYWxsIHF1b3RlcyAodGhhdCBhcmUgbm90IHByZWNlZGVkIGJ5IGFuIGVzY2FwaW5nIGJhY2tzbGFzaClcbiAgICBjb25zdCBzaW5nbGVRdW90ZXM6IGFueSA9IG1hdGNoQWxsKHRleHQsIC8nL2dtKS5maWx0ZXIobWF0Y2ggPT4gbWF0Y2guaW5kZXggPT09IDAgfHwgdGV4dFttYXRjaC5pbmRleCAtIDFdICE9PSAnXFxcXCcpO1xuICAgIGNvbnN0IGRvdWJsZVF1b3RlczogYW55ID0gbWF0Y2hBbGwodGV4dCwgL1wiL2dtKS5maWx0ZXIobWF0Y2ggPT4gbWF0Y2guaW5kZXggPT09IDAgfHwgdGV4dFttYXRjaC5pbmRleCAtIDFdICE9PSAnXFxcXCcpO1xuICAgIGNvbnN0IGdyYXZlUXVvdGVzOiBhbnkgPSBtYXRjaEFsbCh0ZXh0LCAvYC9nbSkuZmlsdGVyKG1hdGNoID0+IG1hdGNoLmluZGV4ID09PSAwIHx8IHRleHRbbWF0Y2guaW5kZXggLSAxXSAhPT0gJ1xcXFwnKTtcbiAgICBjb25zdCBhbGxRdW90ZXMgPSBbLi4uc2luZ2xlUXVvdGVzLCAuLi5kb3VibGVRdW90ZXMsIC4uLmdyYXZlUXVvdGVzXTtcbiAgICBhbGxRdW90ZXMuc29ydCgoYSwgYikgPT4gYVsnaW5kZXgnXSAtIGJbJ2luZGV4J10pO1xuXG4gICAgLy8gQ3JlYXRlIHF1b3RlcyB0ZXh0IHNlZ21lbnRzXG4gICAgY29uc3QgcXVvdGVTZWdtZW50czogVGV4dFNlZ21lbnRbXSA9IFtdO1xuICAgIGxldCBvdXRlcm1vc3RPcGVuZWRRdW90ZSA9IG51bGw7XG4gICAgZm9yIChjb25zdCBxdW90ZSBvZiBhbGxRdW90ZXMpIHtcbiAgICAgIGlmICghb3V0ZXJtb3N0T3BlbmVkUXVvdGUpIHtcbiAgICAgICAgb3V0ZXJtb3N0T3BlbmVkUXVvdGUgPSBxdW90ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChvdXRlcm1vc3RPcGVuZWRRdW90ZVswXSA9PT0gcXVvdGVbMF0pIHtcbiAgICAgICAgICBxdW90ZVNlZ21lbnRzLnB1c2goe1xuICAgICAgICAgICAgc3RhcnRJbmRleDogb3V0ZXJtb3N0T3BlbmVkUXVvdGUuaW5kZXggKyAxLFxuICAgICAgICAgICAgZW5kSW5kZXg6IHF1b3RlWydpbmRleCddXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgb3V0ZXJtb3N0T3BlbmVkUXVvdGUgPSBudWxsO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG91dGVybW9zdE9wZW5lZFF1b3RlICE9PSBudWxsKSB7XG4gICAgICB0aHJvdyBFcnJvcignSW5wdXQgcGFyc2UgZXJyb3IuIFN0cmluZyB3YXMgb3BlbmVkLCBidXQgbm90IGNsb3NlZC4nKTtcbiAgICB9XG5cbiAgICAvLyBFbmNvZGUgcXVvdGUgc2VnbWVudHNcbiAgICBjb25zdCBlbmNvZGVkQnJhY2tldHNUZXh0ID0gdGhpcy5lbmNvZGVUZXh0U2VnbWVudHModGV4dCwgcXVvdGVTZWdtZW50cywgdGhpcy5lbmNvZGVTdHJpbmdTcGVjaWFsQ2hhcnMpO1xuXG4gICAgcmV0dXJuIGVuY29kZWRCcmFja2V0c1RleHQ7XG4gIH1cblxuICAvKipcbiAgICogRW5jb2RlcyBhbGwgc3BlY2lhbCBjaGFyYWN0ZXJzIHRoYXQgbWlnaHQgYmUgY29uZnVzZWQgYXMgY29kZSBzeW50YXggaW4gYSBwaWVjZSBvZiBzdHJpbmdcbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCB0byBlbmNvZGVcbiAgICovXG4gIGVuY29kZVN0cmluZ1NwZWNpYWxDaGFycyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoLycvZywgJ0BAQHNpbmdsZXF1b3RlQEBAJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvXCIvZywgJ0BAQGRvdWJsZXF1b3RlQEBAJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvYC9nLCAnQEBAZ3JhdmVxdW90ZUBAQCcpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoLzovZywgJ0BAQGNvbG9uQEBAJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvOy9nLCAnQEBAc2VtaWNvbG9uQEBAJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvXFwuL2csICdAQEBkb3RAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC8sL2csICdAQEBjb21tYUBAQCcpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL1xcXFwvZywgJ0BAQGJhY2tzbGFzaEBAQCcpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL1xcKC9nLCAnQEBAb3BlblJvdW5kQnJhY2tldEBAQCcpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL1xcKS9nLCAnQEBAY2xvc2VSb3VuZEJyYWNrZXRAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXFsvZywgJ0BAQG9wZW5TcXVhcmVCcmFja2V0QEBAJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvXFxdL2csICdAQEBjbG9zZVNxdWFyZUJyYWNrZXRAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXHsvZywgJ0BAQG9wZW5DdXJseUJyYWNrZXRAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXH0vZywgJ0BAQGNsb3NlQ3VybHlCcmFja2V0QEBAJyk7XG4gICAgcmV0dXJuIHRleHQ7XG4gIH1cblxuICAvKipcbiAgICogRGVjb2RlcyB0aGUgc3BlY2lhbCBjaGFyYWN0ZXJzIGFnYWluXG4gICAqXG4gICAqIEBwYXJhbSB0ZXh0IC0gVGhlIHRleHQgdG8gZGVjb2RlXG4gICAqL1xuICBkZWNvZGVTdHJpbmdTcGVjaWFsQ2hhcnModGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBzaW5nbGVxdW90ZUBAQC9nLCAnXFwnJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAZG91YmxlcXVvdGVAQEAvZywgJ1wiJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAZ3JhdmVxdW90ZUBAQC9nLCAnYCcpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL0BAQGNvbG9uQEBAL2csICc6Jyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAc2VtaWNvbG9uQEBAL2csICc7Jyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAZG90QEBAL2csICcuJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAY29tbWFAQEAvZywgJywnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBiYWNrc2xhc2hAQEAvZywgJ1xcXFwnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBvcGVuUm91bmRCcmFja2V0QEBAL2csICcoJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAY2xvc2VSb3VuZEJyYWNrZXRAQEAvZywgJyknKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBvcGVuU3F1YXJlQnJhY2tldEBAQC9nLCAnWycpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL0BAQGNsb3NlU3F1YXJlQnJhY2tldEBAQC9nLCAnXScpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL0BAQG9wZW5DdXJseUJyYWNrZXRAQEAvZywgJ3snKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBjbG9zZUN1cmx5QnJhY2tldEBAQC9nLCAnfScpO1xuICAgIHJldHVybiB0ZXh0O1xuICB9XG5cbiAgLy8gU3ViZnVuY3Rpb25zXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLyoqXG4gICAqIEZpbmRzIGFsbCBzdWJmdW5jdGlvbnMgaW4gYSBwaWVjZSBvZiB0ZXh0IGFuZCByZXBsYWNlcyB0aGVpciByb3VuZCBicmFja2V0cyB3aXRoIEBAQC4uLkBAQC1wbGFjZWhvbGRlcnMuXG4gICAqXG4gICAqIEBwYXJhbSB0ZXh0IC0gVGhlIHRleHQgdG8gcGFyc2UgZm9yIHN1YnN0cmluZ3NcbiAgICovXG4gIGVuY29kZVN1YmZ1bmN0aW9ucyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IG9wZW5pbmdCcmFja2V0cyA9IG1hdGNoQWxsKHRleHQsIC9cXCgvZ20pO1xuICAgIGNvbnN0IGNsb3NpbmdCcmFja2V0cyA9IG1hdGNoQWxsKHRleHQsIC9cXCkvZ20pO1xuICAgIGNvbnN0IGFsbEJyYWNrZXRzID0gWy4uLm9wZW5pbmdCcmFja2V0cywgLi4uY2xvc2luZ0JyYWNrZXRzXTtcbiAgICBhbGxCcmFja2V0cy5zb3J0KChhLCBiKSA9PiBhWydpbmRleCddIC0gYlsnaW5kZXgnXSk7XG5cbiAgICAvLyBDcmVhdGUgZnVuY3Rpb25zIHRleHQgc2VnbWVudHNcbiAgICBjb25zdCBmdW5jdGlvblNlZ21lbnRzOiBUZXh0U2VnbWVudFtdID0gW107XG4gICAgY29uc3Qgb3BlbmVkQnJhY2tldHMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IGJyYWNrZXQgb2YgYWxsQnJhY2tldHMpIHtcbiAgICAgIGlmIChicmFja2V0WzBdID09PSAnKCcpIHtcbiAgICAgICAgb3BlbmVkQnJhY2tldHMucHVzaChicmFja2V0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChvcGVuZWRCcmFja2V0cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICB0aHJvdyBFcnJvcignSW5wdXQgcGFyc2UgZXJyb3IuIENsb3NlZCBmdW5jdGlvbiBicmFja2V0IHdpdGhvdXQgb3BlbmluZyBpdCBmaXJzdC4nKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBPbmx5IGNvbGxlY3QgdGhlIG91dGVybW9zdCBmdW5jdGlvbiBicmFja2V0cywgbm90IG5lc3RlZCBvbmVzXG4gICAgICAgIGlmIChvcGVuZWRCcmFja2V0cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBmdW5jdGlvblNlZ21lbnRzLnB1c2goe1xuICAgICAgICAgICAgc3RhcnRJbmRleDogb3BlbmVkQnJhY2tldHNbMF0uaW5kZXggKyAxLFxuICAgICAgICAgICAgZW5kSW5kZXg6IGJyYWNrZXRbJ2luZGV4J11cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBvcGVuZWRCcmFja2V0cy5wb3AoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAob3BlbmVkQnJhY2tldHMubGVuZ3RoICE9PSAwKSB7XG4gICAgICB0aHJvdyBFcnJvcignSW5wdXQgcGFyc2UgZXJyb3IuIE9wZW5lZCBmdW5jdGlvbiBicmFja2V0IHdpdGhvdXQgY2xvc2luZyBpdC4nKTtcbiAgICB9XG5cbiAgICAvLyBFbmNvZGUgcXVvdGUgc2VnbWVudHNcbiAgICBjb25zdCBlbmNvZGVkRnVuY3Rpb25zVGV4dCA9IHRoaXMuZW5jb2RlVGV4dFNlZ21lbnRzKHRleHQsIGZ1bmN0aW9uU2VnbWVudHMsIHRoaXMuZW5jb2RlRnVuY3Rpb25CcmFja2V0cyk7XG5cbiAgICByZXR1cm4gZW5jb2RlZEZ1bmN0aW9uc1RleHQ7XG4gIH1cblxuICAvKipcbiAgICogRW5jb2RlcyBhbGwgcm91bmQgYnJhY2tldHMgd2l0aCBoYXJtbGVzcyBwbGFjZWhvbGRlcnNcbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCB0byBlbmNvZGVcbiAgICovXG4gIGVuY29kZUZ1bmN0aW9uQnJhY2tldHModGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXCgvZywgJ0BAQGZuT3BlbkJyYWNrZXRAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXCkvZywgJ0BAQGZuQ2xvc2VCcmFja2V0QEBAJyk7XG4gICAgcmV0dXJuIHRleHQ7XG4gIH1cblxuICAvKipcbiAgICogRGVjb2RlcyBhbGwgcm91bmQgYnJhY2tldHMgYWdhaW5cbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCB0byBkZWNvZGVcbiAgICovXG4gIGRlY29kZUZ1bmN0aW9uQnJhY2tldHModGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBmbk9wZW5CcmFja2V0QEBAL2csICdcXCgnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBmbkNsb3NlQnJhY2tldEBAQC9nLCAnXFwpJyk7XG4gICAgcmV0dXJuIHRleHQ7XG4gIH1cblxuICAvLyBTdWJicmFja2V0c1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKlxuICAgKiBGaW5kcyBhbGwgc3ViYnJhY2tldHMgaW4gYSBwaWVjZSBvZiB0ZXh0IGFuZCByZXBsYWNlcyB0aGVpciBicmFja2V0cyB3aXRoIEBAQC4uLkBAQC1wbGFjZWhvbGRlcnMuXG4gICAqXG4gICAqIEBwYXJhbSB0ZXh0IC0gVGhlIHRleHQgdG8gcGFyc2UgZm9yIHN1YnN0cmluZ3NcbiAgICovXG4gIGVuY29kZVZhcmlhYmxlU3ViYnJhY2tldHModGV4dDogc3RyaW5nKTogc3RyaW5nIHtcblxuICAgIC8vIFByb3BlcnR5IGFjY2Vzc29yIG9wZW5pbmcgYnJhY2tldHMgY2FuIGJlIGlkZW50aWZpZWQgYnkgd2hhdCB0aGV5IGFyZSBwcmVjZWRlZCBieS5cbiAgICAvLyBNdXN0IGJlIGEpIHRleHQsIGIpIGNsb3Npbmcgc3F1YXJlIGJyYWNrZXQgb3IgYykgY2xvc2luZyByb3VuZCBicmFja2V0LiBBcnJheXMgY2FuJ3QgYmUgcHJlY2VkZWQgYnkgYW55IG9mIHRoZXNlLlxuICAgIGNvbnN0IHZhcmlhYmxlT3BlbmluZ0JyYWNrZXRzV2l0aExvb2tiZWhpbmRzID0gJyg/PD1bYS16QS1aXyRcXFxcXVxcKV0pXFxcXFsnOyAvLyBUb28gbmV3IGZvciBtYW55IG9sZGVyIGJyb3dzZXJzXG4gICAgY29uc3QgdmFyaWFibGVPcGVuaW5nQnJhY2tldHMgPSAnKD86W2EtekEtWl8kXFxcXF1cXCldKShcXFxcWyknO1xuXG4gICAgY29uc3Qgb3BlbmluZ0JyYWNrZXRzID0gbWF0Y2hBbGwodGV4dCwgbmV3IFJlZ0V4cCh2YXJpYWJsZU9wZW5pbmdCcmFja2V0cywgJ2dtJykpO1xuICAgIC8vIE5vdGU6IENhbid0IHNpbXBseSBmaW5kIGNsb3NpbmcgYnJhY2tldHMgYXMgd2VsbCAoYXMgaXMgZG9uZSBpbiB0aGUgb3RoZXIgZW5jb2RlciBmdW5jdGlvbnMpLCBiZWNhdXNlIHRoZSBjbG9zaW5nXG4gICAgLy8gYnJhY2tldCBkb2Vzbid0IGhhdmUgYSB1bmlxdWVseSBpZGVudGlmaWFibGUgc3ludGF4LiBNaWdodCBhbHNvIGJlIGFycmF5IGVuZGluZ3MuXG5cbiAgICAvLyBGaW5kIHRoZSBjb3JyZXNwb25kaW5nIGNsb3NpbmcgYnJhY2tldCBmb3IgZWFjaCBvcGVuaW5nIGJyYWNrZXQgYnkgcGFyc2luZyB0aGUgZm9sbG93aW5nIGJyYWNrZXRzXG4gICAgY29uc3QgYnJhY2tldFNlZ21lbnRzOiBUZXh0U2VnbWVudFtdID0gW107XG4gICAgZm9yIChjb25zdCBvcGVuaW5nQnJhY2tldCBvZiBvcGVuaW5nQnJhY2tldHMpIHtcbiAgICAgIGNvbnN0IGZvbGxvd2luZ1RleHQgPSB0ZXh0LnN1YnN0cmluZyhvcGVuaW5nQnJhY2tldC5pbmRleCArIDIpOyAvLyBvcGVuaW5nQnJhY2tldC5pbmRleCArIDIsIGIvYyB0aGUgcmVnZXggc3RhcnRzIGF0IHRoZSBjaGFyYWN0ZXIgYmVmb3JlIHRoZSBvcGVuaW5nIGJyYWNrZXQgYW5kIGZvbGxvd2luZ1RleHQgaXMgc3VwcG9zZWQgdG8gc3RhcnQgYWZ0ZXIgdGhlIG9wZW5pbmcgYnJhY2tldFxuICAgICAgY29uc3QgZm9sbG93aW5nT3BlbmluZ0JyYWNrZXRzID0gbWF0Y2hBbGwoZm9sbG93aW5nVGV4dCwgL1xcWy9nbSk7XG4gICAgICBjb25zdCBmb2xsb3dpbmdDbG9zaW5nQnJhY2tldHMgPSBtYXRjaEFsbChmb2xsb3dpbmdUZXh0LCAvXFxdL2dtKTtcbiAgICAgIGNvbnN0IGFsbEZvbGxvd2luZ0JyYWNrZXRzID0gWy4uLmZvbGxvd2luZ09wZW5pbmdCcmFja2V0cywgLi4uZm9sbG93aW5nQ2xvc2luZ0JyYWNrZXRzXTtcbiAgICAgIGFsbEZvbGxvd2luZ0JyYWNrZXRzLnNvcnQoKGEsIGIpID0+IGFbJ2luZGV4J10gLSBiWydpbmRleCddKTtcblxuICAgICAgbGV0IG9wZW5lZEJyYWNrZXRzID0gMTsgLy8gU3RhcnQgd2l0aCB0aGUgZmlyc3Qgb3BlbmluZyBicmFja2V0IGFscmVhZHkgY291bnRlZFxuICAgICAgZm9yIChjb25zdCBmb2xsb3dpbmdCcmFja2V0IG9mIGFsbEZvbGxvd2luZ0JyYWNrZXRzKSB7XG4gICAgICAgIG9wZW5lZEJyYWNrZXRzID0gZm9sbG93aW5nQnJhY2tldFswXSA9PT0gJ10nID8gb3BlbmVkQnJhY2tldHMgLSAxIDogb3BlbmVkQnJhY2tldHMgKyAxO1xuICAgICAgICBpZiAob3BlbmVkQnJhY2tldHMgPT09IDApIHtcbiAgICAgICAgICBicmFja2V0U2VnbWVudHMucHVzaCh7XG4gICAgICAgICAgICBzdGFydEluZGV4OiBvcGVuaW5nQnJhY2tldC5pbmRleCArIDIsXG4gICAgICAgICAgICBlbmRJbmRleDogb3BlbmluZ0JyYWNrZXQuaW5kZXggKyAyICsgZm9sbG93aW5nQnJhY2tldFsnaW5kZXgnXVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChvcGVuZWRCcmFja2V0cyAhPT0gMCkge1xuICAgICAgICB0aHJvdyBFcnJvcignSW5wdXQgcGFyc2UgZXJyb3IuIE9wZW5lZCBicmFja2V0IHdpdGhvdXQgY2xvc2luZyBpdC4nKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUaHJvdyBvdXQgbmVzdGVkIGJyYWNrZXRzXG4gICAgY29uc3Qgb3V0ZXJCcmFja2V0U2VnbWVudHMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IGJyYWNrZXRTZWdtZW50IG9mIGJyYWNrZXRTZWdtZW50cykge1xuICAgICAgaWYgKG91dGVyQnJhY2tldFNlZ21lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBvdXRlckJyYWNrZXRTZWdtZW50cy5wdXNoKGJyYWNrZXRTZWdtZW50KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChvdXRlckJyYWNrZXRTZWdtZW50c1tvdXRlckJyYWNrZXRTZWdtZW50cy5sZW5ndGggLSAxXS5lbmRJbmRleCA8IGJyYWNrZXRTZWdtZW50LnN0YXJ0SW5kZXgpIHtcbiAgICAgICAgICBvdXRlckJyYWNrZXRTZWdtZW50cy5wdXNoKGJyYWNrZXRTZWdtZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEVuY29kZSBicmFja2V0IHNlZ21lbnRzXG4gICAgY29uc3QgZW5jb2RlZEJyYWNrZXRzVGV4dCA9IHRoaXMuZW5jb2RlVGV4dFNlZ21lbnRzKHRleHQsIG91dGVyQnJhY2tldFNlZ21lbnRzLCB0aGlzLmVuY29kZVZhcmlhYmxlQnJhY2tldHMpO1xuXG4gICAgcmV0dXJuIGVuY29kZWRCcmFja2V0c1RleHQ7XG4gIH1cblxuICAvKipcbiAgICogRW5jb2RlcyBhbGwgYnJhY2tldHMgd2l0aCBoYXJtbGVzcyBwbGFjZWhvbGRlcnNcbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCB0byBlbmNvZGVcbiAgICovXG4gIGVuY29kZVZhcmlhYmxlQnJhY2tldHModGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXFsvZywgJ0BAQHZhcmlhYmxlT3BlbmluZ0JyYWNrZXRAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXF0vZywgJ0BAQHZhcmlhYmxlQ2xvc2luZ0JyYWNrZXRAQEAnKTtcbiAgICByZXR1cm4gdGV4dDtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWNvZGVzIGFsbCBicmFja2V0cyBhZ2FpblxuICAgKlxuICAgKiBAcGFyYW0gdGV4dCAtIFRoZSB0ZXh0IHRvIGVuY29kZVxuICAgKi9cbiAgZGVjb2RlVmFyaWFibGVCcmFja2V0cyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL0BAQHZhcmlhYmxlT3BlbmluZ0JyYWNrZXRAQEAvZywgJ1xcWycpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL0BAQHZhcmlhYmxlQ2xvc2luZ0JyYWNrZXRAQEAvZywgJ1xcXScpO1xuICAgIHJldHVybiB0ZXh0O1xuICB9XG5cbiAgLy8gQ29udGV4dCB2YXIgcGxhY2Vob2xkZXJcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAvKipcbiAgICogVHJhbnNmb3JtcyBhIGNvbnRleHQgdmFyICh0aGF0IGlzIGFscmVhZHkgZW5jb2RlZCBmb3Igc3Vic3RyaW5ncywgc3ViZnVuY3Rpb25zIGFuZCBzdWJicmFja2V0cykgaW50byBhIHN0cmluZyBwbGFjZWhvbGRlclxuICAgKiBieSBlbmNvZGluZyB0aGUgY29udGV4dCB2YXIgc3ludGF4IGl0c2VsZi4gVGhpcyBpcyBzbyB0aGF0IGNhbiBiZSBzYWZlbHkgcGFyc2VkIGJ5IEpTT04ucGFyc2UoKSBhcyBhIHN0cmluZyBhbmQgYWxzbyBzbyBpdFxuICAgKiB3b24ndCBiZSBtaXNpbnRlcnByZXRlZCBieSBvdGhlciByZWdleGVzIGxvb2tpbmcgZm9yIEpTT04gc3ludGF4IChlc3BlY2lhbGx5IGFycmF5cyBiL2Mgb2YgY29udGV4dC12YXIgW10tcHJvcGVydHktYnJhY2tldHMpXG4gICAqXG4gICAqIEBwYXJhbSBjb250ZXh0VmFyIC0gVGhlIGNvbnRleHQgdmFyIHRvIHRyYW5zZm9ybVxuICAgKi9cbiAgdHJhbnNmb3JtQ29udGV4dFZhckludG9QbGFjZXJob2xkZXIoY29udGV4dFZhcjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAvLyBSZXBsYWNlIGNvbnRleHQuIHdpdGggX19DWFRfX1xuICAgIGNvbnRleHRWYXIgPSAnX19DWFRfXycgKyBjb250ZXh0VmFyLnN1YnN0cmluZyg3KTtcbiAgICAvLyBFbmNvZGUgdmFyaWFibGUgc3ludGF4XG4gICAgY29udGV4dFZhciA9IGNvbnRleHRWYXIucmVwbGFjZSgvXFxcIi9nLCAnQEBAY3h0RG91YmxlUXVvdGVAQEAnKTtcbiAgICBjb250ZXh0VmFyID0gY29udGV4dFZhci5yZXBsYWNlKC9cXC4vZywgJ0BAQGN4dERvdEBAQCcpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL1xcWy9nLCAnQEBAY3h0T3BlblNxdWFyZUJyYWNrZXRAQEAnKTtcbiAgICBjb250ZXh0VmFyID0gY29udGV4dFZhci5yZXBsYWNlKC9cXF0vZywgJ0BAQGN4dENsb3NlU3F1YXJlQnJhY2tldEBAQCcpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL1xcKC9nLCAnQEBAY3h0T3BlblJvdW5kQnJhY2tldEBAQCcpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL1xcKS9nLCAnQEBAY3h0Q2xvc2VSb3VuZEJyYWNrZXRAQEAnKTtcbiAgICByZXR1cm4gY29udGV4dFZhcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFuc2Zvcm1zIGEgY29udGV4dCB2YXIgcGxhY2Vob2xkZXIgYmFjayBpbnRvIHRoZSBhY3R1YWwgY29udGV4dCB2YXJcbiAgICogXG4gICAqIEBwYXJhbSBjb250ZXh0VmFyIC0gVGhlIHBsYWNlaG9sZGVyIGNvbnRleHQgdmFyXG4gICAqL1xuICB0cmFuc2Zvcm1QbGFjZWhvbGRlckludG9Db250ZXh0VmFyKGNvbnRleHRWYXI6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29udGV4dFZhciA9ICdjb250ZXh0JyArIGNvbnRleHRWYXIuc3Vic3RyaW5nKDcpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL0BAQGN4dERvdWJsZVF1b3RlQEBAL2csICdcIicpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL0BAQGN4dERvdEBAQC9nLCAnLicpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL0BAQGN4dE9wZW5TcXVhcmVCcmFja2V0QEBAL2csICdbJyk7XG4gICAgY29udGV4dFZhciA9IGNvbnRleHRWYXIucmVwbGFjZSgvQEBAY3h0Q2xvc2VTcXVhcmVCcmFja2V0QEBAL2csICddJyk7XG4gICAgY29udGV4dFZhciA9IGNvbnRleHRWYXIucmVwbGFjZSgvQEBAY3h0T3BlblJvdW5kQnJhY2tldEBAQC9nLCAnKCcpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL0BAQGN4dENsb3NlUm91bmRCcmFja2V0QEBAL2csICcpJyk7XG4gICAgcmV0dXJuIGNvbnRleHRWYXI7XG4gIH1cblxuICAvLyBPdGhlclxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKlxuICAgKiBUYWtlcyBhIHBpZWNlIG9mIHRleHQgYXMgd2VsbCBhcyBhcnJheSBvZiBUZXh0U2VnbWVudHMgYW5kIGVuY29kZXMgdGhlbSB3aXRoIHRoZSBoZWxwIG9mIGFuIGVuY29kaW5nRnVuY3Rpb25cbiAgICogVGhlIGVuY29kZWQgdGV4dCBpcyB0aGVuIGF1dG9tYXRpY2FsbHkgYXNzZW1ibGVkIGFuZCByZXR1cm5lZC5cbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCBpbiBxdWVzdGlvblxuICAgKiBAcGFyYW0gc3BlY2lhbFRleHRTZWdtZW50cyAtIFRoZSBzZWdtZW50cyBpbiB0aGUgdGV4dCB0byBlbmNvZGVcbiAgICogQHBhcmFtIGVuY29kaW5nRnVuY3Rpb24gLSBUaGUgZW5jb2RpbmcgZnVuY3Rpb24gdG8gdXNlXG4gICAqL1xuICBwcml2YXRlIGVuY29kZVRleHRTZWdtZW50cyh0ZXh0OiBzdHJpbmcsIHNwZWNpYWxUZXh0U2VnbWVudHM6IFRleHRTZWdtZW50W10sIGVuY29kaW5nRnVuY3Rpb246IGFueSk6IHN0cmluZyB7XG4gICAgLy8gMS4gRGl2aWRlIHdob2xlIHRleHQgaW50byB0d28gdHlwZXMgb2Ygc2VnbWVudHM6IFRob3NlIHRvIGJlIGVuY29kZWQgYW5kIHRob3NlIHRvIGJlIGxlZnQgYXMgdGhleSBhcmVcbiAgICBjb25zdCBhbGxUZXh0U2VnbWVudHMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IHNwZWNpYWxUZXh0U2VnbWVudCBvZiBzcGVjaWFsVGV4dFNlZ21lbnRzKSB7XG4gICAgICAvLyBQdXNoIG5vcm1hbCB0ZXh0IHNlZ21lbnQgc2luY2UgbGFzdCBzcGVjaWFsIHNlZ21lbnRcbiAgICAgIGNvbnN0IGxhc3RTZWdtZW50RW5kSW5kZXg6IG51bWJlciA9IGFsbFRleHRTZWdtZW50cy5sZW5ndGggPT09IDAgPyAwIDogYWxsVGV4dFNlZ21lbnRzW2FsbFRleHRTZWdtZW50cy5sZW5ndGggLSAxXS5lbmRJbmRleDtcbiAgICAgIGFsbFRleHRTZWdtZW50cy5wdXNoKHtcbiAgICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgICBzdGFydEluZGV4OiBsYXN0U2VnbWVudEVuZEluZGV4LFxuICAgICAgICBlbmRJbmRleDogc3BlY2lhbFRleHRTZWdtZW50LnN0YXJ0SW5kZXgsXG4gICAgICAgIHN0cmluZzogdGV4dC5zdWJzdHJpbmcobGFzdFNlZ21lbnRFbmRJbmRleCwgc3BlY2lhbFRleHRTZWdtZW50LnN0YXJ0SW5kZXgpXG4gICAgICB9KTtcblxuICAgICAgLy8gUHVzaCBuZXh0IHNwZWNpYWwgc2VnbWVudFxuICAgICAgYWxsVGV4dFNlZ21lbnRzLnB1c2goe1xuICAgICAgICB0eXBlOiAnc3BlY2lhbCcsXG4gICAgICAgIHN0YXJ0SW5kZXg6IHNwZWNpYWxUZXh0U2VnbWVudC5zdGFydEluZGV4LFxuICAgICAgICBlbmRJbmRleDogc3BlY2lhbFRleHRTZWdtZW50LmVuZEluZGV4LFxuICAgICAgICBzdHJpbmc6IHRleHQuc3Vic3RyaW5nKHNwZWNpYWxUZXh0U2VnbWVudC5zdGFydEluZGV4LCBzcGVjaWFsVGV4dFNlZ21lbnQuZW5kSW5kZXgpXG4gICAgICB9KTtcbiAgICB9XG4gICAgLy8gQWRkIHRleHQgc2VnbWVudCBmb3IgdHJhaWxpbmcgdGV4dCBhZnRlciBsYXN0IHNwZWNpYWwgc2VnbWVudFxuICAgIGNvbnN0IGxhc3RCcmFja2V0RW5kSW5kZXggPSBhbGxUZXh0U2VnbWVudHMubGVuZ3RoID09PSAwID8gMCA6IGFsbFRleHRTZWdtZW50c1thbGxUZXh0U2VnbWVudHMubGVuZ3RoIC0gMV0uZW5kSW5kZXg7XG4gICAgYWxsVGV4dFNlZ21lbnRzLnB1c2goe1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgc3RhcnRJbmRleDogbGFzdEJyYWNrZXRFbmRJbmRleCxcbiAgICAgIGVuZEluZGV4OiB0ZXh0Lmxlbmd0aCAtIDEsXG4gICAgICBzdHJpbmc6IHRleHQuc3Vic3RyaW5nKGxhc3RCcmFja2V0RW5kSW5kZXgpXG4gICAgfSk7XG5cbiAgICAvLyAyLiBFbmNvZGUgYWxsIHNwZWNpYWwgc2VnbWVudHNcbiAgICBmb3IgKGNvbnN0IHNlZ21lbnQgb2YgYWxsVGV4dFNlZ21lbnRzKSB7XG4gICAgICBpZiAoc2VnbWVudC50eXBlID09PSAnc3BlY2lhbCcpIHtcbiAgICAgICAgc2VnbWVudC5zdHJpbmcgPSBlbmNvZGluZ0Z1bmN0aW9uKHNlZ21lbnQuc3RyaW5nKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyAzLiBDb25jYXQgZXZlcnl0aGluZyB0b2dldGhlciBhZ2FpblxuICAgIGxldCBlbmNvZGVkU3RyaW5nID0gJyc7XG4gICAgZm9yIChjb25zdCBzZWdtZW50IG9mIGFsbFRleHRTZWdtZW50cykge1xuICAgICAgZW5jb2RlZFN0cmluZyArPSBzZWdtZW50LnN0cmluZztcbiAgICB9XG5cbiAgICByZXR1cm4gZW5jb2RlZFN0cmluZztcbiAgfVxuXG4gIC8qKlxuICAgKiBTdHJpcHMgYWxsIGVzY2FwaW5nIGJhY2tzbGFzaGVzIGZyb20gYSBwaWVjZSBvZiB0ZXh0XG4gICAqXG4gICAqIEBwYXJhbSB0ZXh0IC0gVGhlIHRleHQgaW4gcXVlc3Rpb25cbiAgICovXG4gIHN0cmlwU2xhc2hlcyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0ZXh0LnJlcGxhY2UoL1xcXFwoLikvZywgJyQxJyk7XG4gICAgLy8gcmV0dXJuIHRleHQucmVwbGFjZShuZXcgUmVnRXhwKCdcXFxcXFxcXCguKScsICdnJyksICckMScpO1xuICB9XG5cbiAgLyoqXG4gICAqIEVzY2FwZXMgYWxsIGRvdWJsZSBxdW90ZXMgaW4gYSBwaWVjZSBvZiB0ZXh0XG4gICAqXG4gICAqIEBwYXJhbSB0ZXh0IC0gVGhlIHRleHQgaW4gcXVlc3Rpb25cbiAgICovXG4gIGVzY2FwZURvdWJsZVF1b3Rlcyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHJlc3VsdCA9IHRleHQucmVwbGFjZSgvXFxcXC9nLCAnXFxcXFxcXFwnKS5yZXBsYWNlKC9cXFwiL2csICdcXFxcXCInKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG59XG4iXX0=