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
JavaScript
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YVR5cGVFbmNvZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWR5bmFtaWMtaG9va3Mvc3JjL2xpYi9zZXJ2aWNlcy91dGlscy9kYXRhVHlwZUVuY29kZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sU0FBUyxDQUFDOztBQU9uQzs7O0dBR0c7QUFJSCxNQUFNLE9BQU8sZUFBZTtJQUUxQixhQUFhO0lBQ2Isd0RBQXdEO0lBRXhEOzs7O09BSUc7SUFDSCxnQkFBZ0IsQ0FBQyxJQUFZO1FBQzNCLDRFQUE0RTtRQUM1RSxNQUFNLFlBQVksR0FBUSxRQUFRLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQyxDQUFDO1FBQ3JILE1BQU0sWUFBWSxHQUFRLFFBQVEsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEtBQUssS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUM7UUFDckgsTUFBTSxXQUFXLEdBQVEsUUFBUSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsS0FBSyxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQztRQUNwSCxNQUFNLFNBQVMsR0FBRyxDQUFDLEdBQUcsWUFBWSxFQUFFLEdBQUcsWUFBWSxFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7UUFDckUsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUVsRCw4QkFBOEI7UUFDOUIsTUFBTSxhQUFhLEdBQWtCLEVBQUUsQ0FBQztRQUN4QyxJQUFJLG9CQUFvQixHQUFHLElBQUksQ0FBQztRQUNoQyxLQUFLLE1BQU0sS0FBSyxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQzlCLElBQUksQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO2dCQUMxQixvQkFBb0IsR0FBRyxLQUFLLENBQUM7WUFDL0IsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLElBQUksb0JBQW9CLENBQUMsQ0FBQyxDQUFDLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7b0JBQ3pDLGFBQWEsQ0FBQyxJQUFJLENBQUM7d0JBQ2pCLFVBQVUsRUFBRSxvQkFBb0IsQ0FBQyxLQUFLLEdBQUcsQ0FBQzt3QkFDMUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUM7cUJBQ3pCLENBQUMsQ0FBQztvQkFDSCxvQkFBb0IsR0FBRyxJQUFJLENBQUM7Z0JBQzlCLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksb0JBQW9CLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDbEMsTUFBTSxLQUFLLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUN2RSxDQUFDO1FBRUQsd0JBQXdCO1FBQ3hCLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxhQUFhLEVBQUUsSUFBSSxDQUFDLHdCQUF3QixDQUFDLENBQUM7UUFFeEcsT0FBTyxtQkFBbUIsQ0FBQztJQUM3QixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILHdCQUF3QixDQUFDLElBQVk7UUFDbkMsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLG1CQUFtQixDQUFDLENBQUM7UUFDL0MsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLG1CQUFtQixDQUFDLENBQUM7UUFDL0MsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLGtCQUFrQixDQUFDLENBQUM7UUFDOUMsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBQ3pDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO1FBQzdDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsQ0FBQztRQUN4QyxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFDekMsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLGlCQUFpQixDQUFDLENBQUM7UUFDOUMsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLHdCQUF3QixDQUFDLENBQUM7UUFDckQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLHlCQUF5QixDQUFDLENBQUM7UUFDdEQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLHlCQUF5QixDQUFDLENBQUM7UUFDdEQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLDBCQUEwQixDQUFDLENBQUM7UUFDdkQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLHdCQUF3QixDQUFDLENBQUM7UUFDckQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLHlCQUF5QixDQUFDLENBQUM7UUFDdEQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILHdCQUF3QixDQUFDLElBQVk7UUFDbkMsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsb0JBQW9CLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDaEQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsb0JBQW9CLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDL0MsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsbUJBQW1CLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDOUMsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3pDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLGtCQUFrQixFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzdDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFlBQVksRUFBRSxHQUFHLENBQUMsQ0FBQztRQUN2QyxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxjQUFjLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDekMsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsa0JBQWtCLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDOUMsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMseUJBQXlCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDcEQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsMEJBQTBCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDckQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsMEJBQTBCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDckQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsMkJBQTJCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDdEQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMseUJBQXlCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDcEQsSUFBSSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsMEJBQTBCLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDckQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsZUFBZTtJQUNmLHdEQUF3RDtJQUV4RDs7OztPQUlHO0lBQ0gsa0JBQWtCLENBQUMsSUFBWTtRQUM3QixNQUFNLGVBQWUsR0FBRyxRQUFRLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQy9DLE1BQU0sZUFBZSxHQUFHLFFBQVEsQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDL0MsTUFBTSxXQUFXLEdBQUcsQ0FBQyxHQUFHLGVBQWUsRUFBRSxHQUFHLGVBQWUsQ0FBQyxDQUFDO1FBQzdELFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFFcEQsaUNBQWlDO1FBQ2pDLE1BQU0sZ0JBQWdCLEdBQWtCLEVBQUUsQ0FBQztRQUMzQyxNQUFNLGNBQWMsR0FBRyxFQUFFLENBQUM7UUFDMUIsS0FBSyxNQUFNLE9BQU8sSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUNsQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLEVBQUUsQ0FBQztnQkFDdkIsY0FBYyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUMvQixDQUFDO2lCQUFNLENBQUM7Z0JBQ04sSUFBSSxjQUFjLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO29CQUNoQyxNQUFNLEtBQUssQ0FBQyxzRUFBc0UsQ0FBQyxDQUFDO2dCQUN0RixDQUFDO2dCQUNELGdFQUFnRTtnQkFDaEUsSUFBSSxjQUFjLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO29CQUNoQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUM7d0JBQ3BCLFVBQVUsRUFBRSxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLENBQUM7d0JBQ3ZDLFFBQVEsRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDO3FCQUMzQixDQUFDLENBQUM7Z0JBQ0wsQ0FBQztnQkFDRCxjQUFjLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDdkIsQ0FBQztRQUNILENBQUM7UUFFRCxJQUFJLGNBQWMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDaEMsTUFBTSxLQUFLLENBQUMsZ0VBQWdFLENBQUMsQ0FBQztRQUNoRixDQUFDO1FBRUQsd0JBQXdCO1FBQ3hCLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsc0JBQXNCLENBQUMsQ0FBQztRQUUxRyxPQUFPLG9CQUFvQixDQUFDO0lBQzlCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsc0JBQXNCLENBQUMsSUFBWTtRQUNqQyxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUscUJBQXFCLENBQUMsQ0FBQztRQUNsRCxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztRQUNuRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsc0JBQXNCLENBQUMsSUFBWTtRQUNqQyxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNsRCxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyx1QkFBdUIsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNuRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxjQUFjO0lBQ2Qsd0RBQXdEO0lBRXhEOzs7O09BSUc7SUFDSCx5QkFBeUIsQ0FBQyxJQUFZO1FBRXBDLHFGQUFxRjtRQUNyRixvSEFBb0g7UUFDcEgsTUFBTSxzQ0FBc0MsR0FBRyx5QkFBeUIsQ0FBQyxDQUFDLGtDQUFrQztRQUM1RyxNQUFNLHVCQUF1QixHQUFHLDBCQUEwQixDQUFDO1FBRTNELE1BQU0sZUFBZSxHQUFHLFFBQVEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxNQUFNLENBQUMsdUJBQXVCLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNsRixvSEFBb0g7UUFDcEgsb0ZBQW9GO1FBRXBGLG9HQUFvRztRQUNwRyxNQUFNLGVBQWUsR0FBa0IsRUFBRSxDQUFDO1FBQzFDLEtBQUssTUFBTSxjQUFjLElBQUksZUFBZSxFQUFFLENBQUM7WUFDN0MsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsOEpBQThKO1lBQzlOLE1BQU0sd0JBQXdCLEdBQUcsUUFBUSxDQUFDLGFBQWEsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUNqRSxNQUFNLHdCQUF3QixHQUFHLFFBQVEsQ0FBQyxhQUFhLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDakUsTUFBTSxvQkFBb0IsR0FBRyxDQUFDLEdBQUcsd0JBQXdCLEVBQUUsR0FBRyx3QkFBd0IsQ0FBQyxDQUFDO1lBQ3hGLG9CQUFvQixDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztZQUU3RCxJQUFJLGNBQWMsR0FBRyxDQUFDLENBQUMsQ0FBQyx1REFBdUQ7WUFDL0UsS0FBSyxNQUFNLGdCQUFnQixJQUFJLG9CQUFvQixFQUFFLENBQUM7Z0JBQ3BELGNBQWMsR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLGNBQWMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLGNBQWMsR0FBRyxDQUFDLENBQUM7Z0JBQ3ZGLElBQUksY0FBYyxLQUFLLENBQUMsRUFBRSxDQUFDO29CQUN6QixlQUFlLENBQUMsSUFBSSxDQUFDO3dCQUNuQixVQUFVLEVBQUUsY0FBYyxDQUFDLEtBQUssR0FBRyxDQUFDO3dCQUNwQyxRQUFRLEVBQUUsY0FBYyxDQUFDLEtBQUssR0FBRyxDQUFDLEdBQUcsZ0JBQWdCLENBQUMsT0FBTyxDQUFDO3FCQUMvRCxDQUFDLENBQUM7b0JBQ0gsTUFBTTtnQkFDUixDQUFDO1lBQ0gsQ0FBQztZQUVELElBQUksY0FBYyxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUN6QixNQUFNLEtBQUssQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO1lBQ3ZFLENBQUM7UUFDSCxDQUFDO1FBRUQsNEJBQTRCO1FBQzVCLE1BQU0sb0JBQW9CLEdBQUcsRUFBRSxDQUFDO1FBQ2hDLEtBQUssTUFBTSxjQUFjLElBQUksZUFBZSxFQUFFLENBQUM7WUFDN0MsSUFBSSxvQkFBb0IsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3RDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUM1QyxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sSUFBSSxvQkFBb0IsQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsUUFBUSxHQUFHLGNBQWMsQ0FBQyxVQUFVLEVBQUUsQ0FBQztvQkFDL0Ysb0JBQW9CLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO2dCQUM1QyxDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFFRCwwQkFBMEI7UUFDMUIsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxFQUFFLG9CQUFvQixFQUFFLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1FBRTdHLE9BQU8sbUJBQW1CLENBQUM7SUFDN0IsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxzQkFBc0IsQ0FBQyxJQUFZO1FBQ2pDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSw4QkFBOEIsQ0FBQyxDQUFDO1FBQzNELElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSw4QkFBOEIsQ0FBQyxDQUFDO1FBQzNELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxzQkFBc0IsQ0FBQyxJQUFZO1FBQ2pDLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLCtCQUErQixFQUFFLElBQUksQ0FBQyxDQUFDO1FBQzNELElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLCtCQUErQixFQUFFLElBQUksQ0FBQyxDQUFDO1FBQzNELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELDBCQUEwQjtJQUMxQix3REFBd0Q7SUFFeEQ7Ozs7OztPQU1HO0lBQ0gsbUNBQW1DLENBQUMsVUFBa0I7UUFDcEQsZ0NBQWdDO1FBQ2hDLFVBQVUsR0FBRyxTQUFTLEdBQUcsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNqRCx5QkFBeUI7UUFDekIsVUFBVSxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLHNCQUFzQixDQUFDLENBQUM7UUFDL0QsVUFBVSxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQ3ZELFVBQVUsR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSw0QkFBNEIsQ0FBQyxDQUFDO1FBQ3JFLFVBQVUsR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSw2QkFBNkIsQ0FBQyxDQUFDO1FBQ3RFLFVBQVUsR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSwyQkFBMkIsQ0FBQyxDQUFDO1FBQ3BFLFVBQVUsR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSw0QkFBNEIsQ0FBQyxDQUFDO1FBQ3JFLE9BQU8sVUFBVSxDQUFDO0lBQ3BCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsa0NBQWtDLENBQUMsVUFBa0I7UUFDbkQsVUFBVSxHQUFHLFNBQVMsR0FBRyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2pELFVBQVUsR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLHVCQUF1QixFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzlELFVBQVUsR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLGVBQWUsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUN0RCxVQUFVLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyw2QkFBNkIsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNwRSxVQUFVLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyw4QkFBOEIsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNyRSxVQUFVLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyw0QkFBNEIsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNuRSxVQUFVLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyw2QkFBNkIsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUNwRSxPQUFPLFVBQVUsQ0FBQztJQUNwQixDQUFDO0lBRUQsUUFBUTtJQUNSLHdEQUF3RDtJQUV4RDs7Ozs7OztPQU9HO0lBQ0ssa0JBQWtCLENBQUMsSUFBWSxFQUFFLG1CQUFrQyxFQUFFLGdCQUFxQjtRQUNoRyx3R0FBd0c7UUFDeEcsTUFBTSxlQUFlLEdBQUcsRUFBRSxDQUFDO1FBQzNCLEtBQUssTUFBTSxrQkFBa0IsSUFBSSxtQkFBbUIsRUFBRSxDQUFDO1lBQ3JELHNEQUFzRDtZQUN0RCxNQUFNLG1CQUFtQixHQUFXLGVBQWUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxlQUFlLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztZQUM1SCxlQUFlLENBQUMsSUFBSSxDQUFDO2dCQUNuQixJQUFJLEVBQUUsTUFBTTtnQkFDWixVQUFVLEVBQUUsbUJBQW1CO2dCQUMvQixRQUFRLEVBQUUsa0JBQWtCLENBQUMsVUFBVTtnQkFDdkMsTUFBTSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsbUJBQW1CLEVBQUUsa0JBQWtCLENBQUMsVUFBVSxDQUFDO2FBQzNFLENBQUMsQ0FBQztZQUVILDRCQUE0QjtZQUM1QixlQUFlLENBQUMsSUFBSSxDQUFDO2dCQUNuQixJQUFJLEVBQUUsU0FBUztnQkFDZixVQUFVLEVBQUUsa0JBQWtCLENBQUMsVUFBVTtnQkFDekMsUUFBUSxFQUFFLGtCQUFrQixDQUFDLFFBQVE7Z0JBQ3JDLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLGtCQUFrQixDQUFDLFVBQVUsRUFBRSxrQkFBa0IsQ0FBQyxRQUFRLENBQUM7YUFDbkYsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUNELGdFQUFnRTtRQUNoRSxNQUFNLG1CQUFtQixHQUFHLGVBQWUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxlQUFlLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztRQUNwSCxlQUFlLENBQUMsSUFBSSxDQUFDO1lBQ25CLElBQUksRUFBRSxNQUFNO1lBQ1osVUFBVSxFQUFFLG1CQUFtQjtZQUMvQixRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDO1lBQ3pCLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLG1CQUFtQixDQUFDO1NBQzVDLENBQUMsQ0FBQztRQUVILGlDQUFpQztRQUNqQyxLQUFLLE1BQU0sT0FBTyxJQUFJLGVBQWUsRUFBRSxDQUFDO1lBQ3RDLElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDL0IsT0FBTyxDQUFDLE1BQU0sR0FBRyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDcEQsQ0FBQztRQUNILENBQUM7UUFFRCxzQ0FBc0M7UUFDdEMsSUFBSSxhQUFhLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLEtBQUssTUFBTSxPQUFPLElBQUksZUFBZSxFQUFFLENBQUM7WUFDdEMsYUFBYSxJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUM7UUFDbEMsQ0FBQztRQUVELE9BQU8sYUFBYSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsWUFBWSxDQUFDLElBQVk7UUFDdkIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNwQyx5REFBeUQ7SUFDM0QsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxrQkFBa0IsQ0FBQyxJQUFZO1FBQzdCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDakUsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQzsrR0FyV1UsZUFBZTttSEFBZixlQUFlLGNBRmQsTUFBTTs7NEZBRVAsZUFBZTtrQkFIM0IsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBtYXRjaEFsbCB9IGZyb20gJy4vdXRpbHMnO1xuXG5pbnRlcmZhY2UgVGV4dFNlZ21lbnQge1xuICBzdGFydEluZGV4OiBudW1iZXI7XG4gIGVuZEluZGV4OiBudW1iZXI7XG59XG5cbi8qKlxuICogQSBzZXJ2aWNlIHRoYXQgcHJvdmlkZXMgdmFyaW91cyBmdW5jdGlvbnMgZm9yIGVuLSBhbmQgZGVjb2RpbmcgZGF0YSB0eXBlIHN0cmluZ3MgaW4gb3JkZXIgdG8gbWFrZSB0aGVtXG4gKiBtZWFuaW5nZnVsbHkgcGFyc2VhYmxlIGJ5IHJlZ2V4XG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIERhdGFUeXBlRW5jb2RlciB7XG5cbiAgLy8gU3Vic3RyaW5nc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKlxuICAgKiBGaW5kcyBhbGwgc3Vic3RyaW5ncyBpbiBhIHBpZWNlIG9mIHRleHQgYW5kIHJlcGxhY2VzIGFsbCBzcGVjaWFsIGNoYXJhY3RlcnMgd2l0aGluIHdpdGggQEBALi4uQEBALXBsYWNlaG9sZGVycy5cbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCB0byBwYXJzZSBmb3Igc3Vic3RyaW5nc1xuICAgKi9cbiAgZW5jb2RlU3Vic3RyaW5ncyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIC8vIEdldCBhIGxpc3Qgb2YgYWxsIHF1b3RlcyAodGhhdCBhcmUgbm90IHByZWNlZGVkIGJ5IGFuIGVzY2FwaW5nIGJhY2tzbGFzaClcbiAgICBjb25zdCBzaW5nbGVRdW90ZXM6IGFueSA9IG1hdGNoQWxsKHRleHQsIC8nL2dtKS5maWx0ZXIobWF0Y2ggPT4gbWF0Y2guaW5kZXggPT09IDAgfHwgdGV4dFttYXRjaC5pbmRleCAtIDFdICE9PSAnXFxcXCcpO1xuICAgIGNvbnN0IGRvdWJsZVF1b3RlczogYW55ID0gbWF0Y2hBbGwodGV4dCwgL1wiL2dtKS5maWx0ZXIobWF0Y2ggPT4gbWF0Y2guaW5kZXggPT09IDAgfHwgdGV4dFttYXRjaC5pbmRleCAtIDFdICE9PSAnXFxcXCcpO1xuICAgIGNvbnN0IGdyYXZlUXVvdGVzOiBhbnkgPSBtYXRjaEFsbCh0ZXh0LCAvYC9nbSkuZmlsdGVyKG1hdGNoID0+IG1hdGNoLmluZGV4ID09PSAwIHx8IHRleHRbbWF0Y2guaW5kZXggLSAxXSAhPT0gJ1xcXFwnKTtcbiAgICBjb25zdCBhbGxRdW90ZXMgPSBbLi4uc2luZ2xlUXVvdGVzLCAuLi5kb3VibGVRdW90ZXMsIC4uLmdyYXZlUXVvdGVzXTtcbiAgICBhbGxRdW90ZXMuc29ydCgoYSwgYikgPT4gYVsnaW5kZXgnXSAtIGJbJ2luZGV4J10pO1xuXG4gICAgLy8gQ3JlYXRlIHF1b3RlcyB0ZXh0IHNlZ21lbnRzXG4gICAgY29uc3QgcXVvdGVTZWdtZW50czogVGV4dFNlZ21lbnRbXSA9IFtdO1xuICAgIGxldCBvdXRlcm1vc3RPcGVuZWRRdW90ZSA9IG51bGw7XG4gICAgZm9yIChjb25zdCBxdW90ZSBvZiBhbGxRdW90ZXMpIHtcbiAgICAgIGlmICghb3V0ZXJtb3N0T3BlbmVkUXVvdGUpIHtcbiAgICAgICAgb3V0ZXJtb3N0T3BlbmVkUXVvdGUgPSBxdW90ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChvdXRlcm1vc3RPcGVuZWRRdW90ZVswXSA9PT0gcXVvdGVbMF0pIHtcbiAgICAgICAgICBxdW90ZVNlZ21lbnRzLnB1c2goe1xuICAgICAgICAgICAgc3RhcnRJbmRleDogb3V0ZXJtb3N0T3BlbmVkUXVvdGUuaW5kZXggKyAxLFxuICAgICAgICAgICAgZW5kSW5kZXg6IHF1b3RlWydpbmRleCddXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgb3V0ZXJtb3N0T3BlbmVkUXVvdGUgPSBudWxsO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG91dGVybW9zdE9wZW5lZFF1b3RlICE9PSBudWxsKSB7XG4gICAgICB0aHJvdyBFcnJvcignSW5wdXQgcGFyc2UgZXJyb3IuIFN0cmluZyB3YXMgb3BlbmVkLCBidXQgbm90IGNsb3NlZC4nKTtcbiAgICB9XG5cbiAgICAvLyBFbmNvZGUgcXVvdGUgc2VnbWVudHNcbiAgICBjb25zdCBlbmNvZGVkQnJhY2tldHNUZXh0ID0gdGhpcy5lbmNvZGVUZXh0U2VnbWVudHModGV4dCwgcXVvdGVTZWdtZW50cywgdGhpcy5lbmNvZGVTdHJpbmdTcGVjaWFsQ2hhcnMpO1xuXG4gICAgcmV0dXJuIGVuY29kZWRCcmFja2V0c1RleHQ7XG4gIH1cblxuICAvKipcbiAgICogRW5jb2RlcyBhbGwgc3BlY2lhbCBjaGFyYWN0ZXJzIHRoYXQgbWlnaHQgYmUgY29uZnVzZWQgYXMgY29kZSBzeW50YXggaW4gYSBwaWVjZSBvZiBzdHJpbmdcbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCB0byBlbmNvZGVcbiAgICovXG4gIGVuY29kZVN0cmluZ1NwZWNpYWxDaGFycyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoLycvZywgJ0BAQHNpbmdsZXF1b3RlQEBAJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvXCIvZywgJ0BAQGRvdWJsZXF1b3RlQEBAJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvYC9nLCAnQEBAZ3JhdmVxdW90ZUBAQCcpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoLzovZywgJ0BAQGNvbG9uQEBAJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvOy9nLCAnQEBAc2VtaWNvbG9uQEBAJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvXFwuL2csICdAQEBkb3RAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC8sL2csICdAQEBjb21tYUBAQCcpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL1xcXFwvZywgJ0BAQGJhY2tzbGFzaEBAQCcpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL1xcKC9nLCAnQEBAb3BlblJvdW5kQnJhY2tldEBAQCcpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL1xcKS9nLCAnQEBAY2xvc2VSb3VuZEJyYWNrZXRAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXFsvZywgJ0BAQG9wZW5TcXVhcmVCcmFja2V0QEBAJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvXFxdL2csICdAQEBjbG9zZVNxdWFyZUJyYWNrZXRAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXHsvZywgJ0BAQG9wZW5DdXJseUJyYWNrZXRAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXH0vZywgJ0BAQGNsb3NlQ3VybHlCcmFja2V0QEBAJyk7XG4gICAgcmV0dXJuIHRleHQ7XG4gIH1cblxuICAvKipcbiAgICogRGVjb2RlcyB0aGUgc3BlY2lhbCBjaGFyYWN0ZXJzIGFnYWluXG4gICAqXG4gICAqIEBwYXJhbSB0ZXh0IC0gVGhlIHRleHQgdG8gZGVjb2RlXG4gICAqL1xuICBkZWNvZGVTdHJpbmdTcGVjaWFsQ2hhcnModGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBzaW5nbGVxdW90ZUBAQC9nLCAnXFwnJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAZG91YmxlcXVvdGVAQEAvZywgJ1wiJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAZ3JhdmVxdW90ZUBAQC9nLCAnYCcpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL0BAQGNvbG9uQEBAL2csICc6Jyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAc2VtaWNvbG9uQEBAL2csICc7Jyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAZG90QEBAL2csICcuJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAY29tbWFAQEAvZywgJywnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBiYWNrc2xhc2hAQEAvZywgJ1xcXFwnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBvcGVuUm91bmRCcmFja2V0QEBAL2csICcoJyk7XG4gICAgdGV4dCA9IHRleHQucmVwbGFjZSgvQEBAY2xvc2VSb3VuZEJyYWNrZXRAQEAvZywgJyknKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBvcGVuU3F1YXJlQnJhY2tldEBAQC9nLCAnWycpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL0BAQGNsb3NlU3F1YXJlQnJhY2tldEBAQC9nLCAnXScpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL0BAQG9wZW5DdXJseUJyYWNrZXRAQEAvZywgJ3snKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBjbG9zZUN1cmx5QnJhY2tldEBAQC9nLCAnfScpO1xuICAgIHJldHVybiB0ZXh0O1xuICB9XG5cbiAgLy8gU3ViZnVuY3Rpb25zXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLyoqXG4gICAqIEZpbmRzIGFsbCBzdWJmdW5jdGlvbnMgaW4gYSBwaWVjZSBvZiB0ZXh0IGFuZCByZXBsYWNlcyB0aGVpciByb3VuZCBicmFja2V0cyB3aXRoIEBAQC4uLkBAQC1wbGFjZWhvbGRlcnMuXG4gICAqXG4gICAqIEBwYXJhbSB0ZXh0IC0gVGhlIHRleHQgdG8gcGFyc2UgZm9yIHN1YnN0cmluZ3NcbiAgICovXG4gIGVuY29kZVN1YmZ1bmN0aW9ucyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IG9wZW5pbmdCcmFja2V0cyA9IG1hdGNoQWxsKHRleHQsIC9cXCgvZ20pO1xuICAgIGNvbnN0IGNsb3NpbmdCcmFja2V0cyA9IG1hdGNoQWxsKHRleHQsIC9cXCkvZ20pO1xuICAgIGNvbnN0IGFsbEJyYWNrZXRzID0gWy4uLm9wZW5pbmdCcmFja2V0cywgLi4uY2xvc2luZ0JyYWNrZXRzXTtcbiAgICBhbGxCcmFja2V0cy5zb3J0KChhLCBiKSA9PiBhWydpbmRleCddIC0gYlsnaW5kZXgnXSk7XG5cbiAgICAvLyBDcmVhdGUgZnVuY3Rpb25zIHRleHQgc2VnbWVudHNcbiAgICBjb25zdCBmdW5jdGlvblNlZ21lbnRzOiBUZXh0U2VnbWVudFtdID0gW107XG4gICAgY29uc3Qgb3BlbmVkQnJhY2tldHMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IGJyYWNrZXQgb2YgYWxsQnJhY2tldHMpIHtcbiAgICAgIGlmIChicmFja2V0WzBdID09PSAnKCcpIHtcbiAgICAgICAgb3BlbmVkQnJhY2tldHMucHVzaChicmFja2V0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChvcGVuZWRCcmFja2V0cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICB0aHJvdyBFcnJvcignSW5wdXQgcGFyc2UgZXJyb3IuIENsb3NlZCBmdW5jdGlvbiBicmFja2V0IHdpdGhvdXQgb3BlbmluZyBpdCBmaXJzdC4nKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBPbmx5IGNvbGxlY3QgdGhlIG91dGVybW9zdCBmdW5jdGlvbiBicmFja2V0cywgbm90IG5lc3RlZCBvbmVzXG4gICAgICAgIGlmIChvcGVuZWRCcmFja2V0cy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBmdW5jdGlvblNlZ21lbnRzLnB1c2goe1xuICAgICAgICAgICAgc3RhcnRJbmRleDogb3BlbmVkQnJhY2tldHNbMF0uaW5kZXggKyAxLFxuICAgICAgICAgICAgZW5kSW5kZXg6IGJyYWNrZXRbJ2luZGV4J11cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBvcGVuZWRCcmFja2V0cy5wb3AoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAob3BlbmVkQnJhY2tldHMubGVuZ3RoICE9PSAwKSB7XG4gICAgICB0aHJvdyBFcnJvcignSW5wdXQgcGFyc2UgZXJyb3IuIE9wZW5lZCBmdW5jdGlvbiBicmFja2V0IHdpdGhvdXQgY2xvc2luZyBpdC4nKTtcbiAgICB9XG5cbiAgICAvLyBFbmNvZGUgcXVvdGUgc2VnbWVudHNcbiAgICBjb25zdCBlbmNvZGVkRnVuY3Rpb25zVGV4dCA9IHRoaXMuZW5jb2RlVGV4dFNlZ21lbnRzKHRleHQsIGZ1bmN0aW9uU2VnbWVudHMsIHRoaXMuZW5jb2RlRnVuY3Rpb25CcmFja2V0cyk7XG5cbiAgICByZXR1cm4gZW5jb2RlZEZ1bmN0aW9uc1RleHQ7XG4gIH1cblxuICAvKipcbiAgICogRW5jb2RlcyBhbGwgcm91bmQgYnJhY2tldHMgd2l0aCBoYXJtbGVzcyBwbGFjZWhvbGRlcnNcbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCB0byBlbmNvZGVcbiAgICovXG4gIGVuY29kZUZ1bmN0aW9uQnJhY2tldHModGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXCgvZywgJ0BAQGZuT3BlbkJyYWNrZXRAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXCkvZywgJ0BAQGZuQ2xvc2VCcmFja2V0QEBAJyk7XG4gICAgcmV0dXJuIHRleHQ7XG4gIH1cblxuICAvKipcbiAgICogRGVjb2RlcyBhbGwgcm91bmQgYnJhY2tldHMgYWdhaW5cbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCB0byBkZWNvZGVcbiAgICovXG4gIGRlY29kZUZ1bmN0aW9uQnJhY2tldHModGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBmbk9wZW5CcmFja2V0QEBAL2csICdcXCgnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9AQEBmbkNsb3NlQnJhY2tldEBAQC9nLCAnXFwpJyk7XG4gICAgcmV0dXJuIHRleHQ7XG4gIH1cblxuICAvLyBTdWJicmFja2V0c1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKlxuICAgKiBGaW5kcyBhbGwgc3ViYnJhY2tldHMgaW4gYSBwaWVjZSBvZiB0ZXh0IGFuZCByZXBsYWNlcyB0aGVpciBicmFja2V0cyB3aXRoIEBAQC4uLkBAQC1wbGFjZWhvbGRlcnMuXG4gICAqXG4gICAqIEBwYXJhbSB0ZXh0IC0gVGhlIHRleHQgdG8gcGFyc2UgZm9yIHN1YnN0cmluZ3NcbiAgICovXG4gIGVuY29kZVZhcmlhYmxlU3ViYnJhY2tldHModGV4dDogc3RyaW5nKTogc3RyaW5nIHtcblxuICAgIC8vIFByb3BlcnR5IGFjY2Vzc29yIG9wZW5pbmcgYnJhY2tldHMgY2FuIGJlIGlkZW50aWZpZWQgYnkgd2hhdCB0aGV5IGFyZSBwcmVjZWRlZCBieS5cbiAgICAvLyBNdXN0IGJlIGEpIHRleHQsIGIpIGNsb3Npbmcgc3F1YXJlIGJyYWNrZXQgb3IgYykgY2xvc2luZyByb3VuZCBicmFja2V0LiBBcnJheXMgY2FuJ3QgYmUgcHJlY2VkZWQgYnkgYW55IG9mIHRoZXNlLlxuICAgIGNvbnN0IHZhcmlhYmxlT3BlbmluZ0JyYWNrZXRzV2l0aExvb2tiZWhpbmRzID0gJyg/PD1bYS16QS1aXyRcXFxcXVxcKV0pXFxcXFsnOyAvLyBUb28gbmV3IGZvciBtYW55IG9sZGVyIGJyb3dzZXJzXG4gICAgY29uc3QgdmFyaWFibGVPcGVuaW5nQnJhY2tldHMgPSAnKD86W2EtekEtWl8kXFxcXF1cXCldKShcXFxcWyknO1xuXG4gICAgY29uc3Qgb3BlbmluZ0JyYWNrZXRzID0gbWF0Y2hBbGwodGV4dCwgbmV3IFJlZ0V4cCh2YXJpYWJsZU9wZW5pbmdCcmFja2V0cywgJ2dtJykpO1xuICAgIC8vIE5vdGU6IENhbid0IHNpbXBseSBmaW5kIGNsb3NpbmcgYnJhY2tldHMgYXMgd2VsbCAoYXMgaXMgZG9uZSBpbiB0aGUgb3RoZXIgZW5jb2RlciBmdW5jdGlvbnMpLCBiZWNhdXNlIHRoZSBjbG9zaW5nXG4gICAgLy8gYnJhY2tldCBkb2Vzbid0IGhhdmUgYSB1bmlxdWVseSBpZGVudGlmaWFibGUgc3ludGF4LiBNaWdodCBhbHNvIGJlIGFycmF5IGVuZGluZ3MuXG5cbiAgICAvLyBGaW5kIHRoZSBjb3JyZXNwb25kaW5nIGNsb3NpbmcgYnJhY2tldCBmb3IgZWFjaCBvcGVuaW5nIGJyYWNrZXQgYnkgcGFyc2luZyB0aGUgZm9sbG93aW5nIGJyYWNrZXRzXG4gICAgY29uc3QgYnJhY2tldFNlZ21lbnRzOiBUZXh0U2VnbWVudFtdID0gW107XG4gICAgZm9yIChjb25zdCBvcGVuaW5nQnJhY2tldCBvZiBvcGVuaW5nQnJhY2tldHMpIHtcbiAgICAgIGNvbnN0IGZvbGxvd2luZ1RleHQgPSB0ZXh0LnN1YnN0cmluZyhvcGVuaW5nQnJhY2tldC5pbmRleCArIDIpOyAvLyBvcGVuaW5nQnJhY2tldC5pbmRleCArIDIsIGIvYyB0aGUgcmVnZXggc3RhcnRzIGF0IHRoZSBjaGFyYWN0ZXIgYmVmb3JlIHRoZSBvcGVuaW5nIGJyYWNrZXQgYW5kIGZvbGxvd2luZ1RleHQgaXMgc3VwcG9zZWQgdG8gc3RhcnQgYWZ0ZXIgdGhlIG9wZW5pbmcgYnJhY2tldFxuICAgICAgY29uc3QgZm9sbG93aW5nT3BlbmluZ0JyYWNrZXRzID0gbWF0Y2hBbGwoZm9sbG93aW5nVGV4dCwgL1xcWy9nbSk7XG4gICAgICBjb25zdCBmb2xsb3dpbmdDbG9zaW5nQnJhY2tldHMgPSBtYXRjaEFsbChmb2xsb3dpbmdUZXh0LCAvXFxdL2dtKTtcbiAgICAgIGNvbnN0IGFsbEZvbGxvd2luZ0JyYWNrZXRzID0gWy4uLmZvbGxvd2luZ09wZW5pbmdCcmFja2V0cywgLi4uZm9sbG93aW5nQ2xvc2luZ0JyYWNrZXRzXTtcbiAgICAgIGFsbEZvbGxvd2luZ0JyYWNrZXRzLnNvcnQoKGEsIGIpID0+IGFbJ2luZGV4J10gLSBiWydpbmRleCddKTtcblxuICAgICAgbGV0IG9wZW5lZEJyYWNrZXRzID0gMTsgLy8gU3RhcnQgd2l0aCB0aGUgZmlyc3Qgb3BlbmluZyBicmFja2V0IGFscmVhZHkgY291bnRlZFxuICAgICAgZm9yIChjb25zdCBmb2xsb3dpbmdCcmFja2V0IG9mIGFsbEZvbGxvd2luZ0JyYWNrZXRzKSB7XG4gICAgICAgIG9wZW5lZEJyYWNrZXRzID0gZm9sbG93aW5nQnJhY2tldFswXSA9PT0gJ10nID8gb3BlbmVkQnJhY2tldHMgLSAxIDogb3BlbmVkQnJhY2tldHMgKyAxO1xuICAgICAgICBpZiAob3BlbmVkQnJhY2tldHMgPT09IDApIHtcbiAgICAgICAgICBicmFja2V0U2VnbWVudHMucHVzaCh7XG4gICAgICAgICAgICBzdGFydEluZGV4OiBvcGVuaW5nQnJhY2tldC5pbmRleCArIDIsXG4gICAgICAgICAgICBlbmRJbmRleDogb3BlbmluZ0JyYWNrZXQuaW5kZXggKyAyICsgZm9sbG93aW5nQnJhY2tldFsnaW5kZXgnXVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChvcGVuZWRCcmFja2V0cyAhPT0gMCkge1xuICAgICAgICB0aHJvdyBFcnJvcignSW5wdXQgcGFyc2UgZXJyb3IuIE9wZW5lZCBicmFja2V0IHdpdGhvdXQgY2xvc2luZyBpdC4nKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUaHJvdyBvdXQgbmVzdGVkIGJyYWNrZXRzXG4gICAgY29uc3Qgb3V0ZXJCcmFja2V0U2VnbWVudHMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IGJyYWNrZXRTZWdtZW50IG9mIGJyYWNrZXRTZWdtZW50cykge1xuICAgICAgaWYgKG91dGVyQnJhY2tldFNlZ21lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICBvdXRlckJyYWNrZXRTZWdtZW50cy5wdXNoKGJyYWNrZXRTZWdtZW50KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChvdXRlckJyYWNrZXRTZWdtZW50c1tvdXRlckJyYWNrZXRTZWdtZW50cy5sZW5ndGggLSAxXS5lbmRJbmRleCA8IGJyYWNrZXRTZWdtZW50LnN0YXJ0SW5kZXgpIHtcbiAgICAgICAgICBvdXRlckJyYWNrZXRTZWdtZW50cy5wdXNoKGJyYWNrZXRTZWdtZW50KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEVuY29kZSBicmFja2V0IHNlZ21lbnRzXG4gICAgY29uc3QgZW5jb2RlZEJyYWNrZXRzVGV4dCA9IHRoaXMuZW5jb2RlVGV4dFNlZ21lbnRzKHRleHQsIG91dGVyQnJhY2tldFNlZ21lbnRzLCB0aGlzLmVuY29kZVZhcmlhYmxlQnJhY2tldHMpO1xuXG4gICAgcmV0dXJuIGVuY29kZWRCcmFja2V0c1RleHQ7XG4gIH1cblxuICAvKipcbiAgICogRW5jb2RlcyBhbGwgYnJhY2tldHMgd2l0aCBoYXJtbGVzcyBwbGFjZWhvbGRlcnNcbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCB0byBlbmNvZGVcbiAgICovXG4gIGVuY29kZVZhcmlhYmxlQnJhY2tldHModGV4dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXFsvZywgJ0BAQHZhcmlhYmxlT3BlbmluZ0JyYWNrZXRAQEAnKTtcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXF0vZywgJ0BAQHZhcmlhYmxlQ2xvc2luZ0JyYWNrZXRAQEAnKTtcbiAgICByZXR1cm4gdGV4dDtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWNvZGVzIGFsbCBicmFja2V0cyBhZ2FpblxuICAgKlxuICAgKiBAcGFyYW0gdGV4dCAtIFRoZSB0ZXh0IHRvIGVuY29kZVxuICAgKi9cbiAgZGVjb2RlVmFyaWFibGVCcmFja2V0cyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL0BAQHZhcmlhYmxlT3BlbmluZ0JyYWNrZXRAQEAvZywgJ1xcWycpO1xuICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL0BAQHZhcmlhYmxlQ2xvc2luZ0JyYWNrZXRAQEAvZywgJ1xcXScpO1xuICAgIHJldHVybiB0ZXh0O1xuICB9XG5cbiAgLy8gQ29udGV4dCB2YXIgcGxhY2Vob2xkZXJcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAvKipcbiAgICogVHJhbnNmb3JtcyBhIGNvbnRleHQgdmFyICh0aGF0IGlzIGFscmVhZHkgZW5jb2RlZCBmb3Igc3Vic3RyaW5ncywgc3ViZnVuY3Rpb25zIGFuZCBzdWJicmFja2V0cykgaW50byBhIHN0cmluZyBwbGFjZWhvbGRlclxuICAgKiBieSBlbmNvZGluZyB0aGUgY29udGV4dCB2YXIgc3ludGF4IGl0c2VsZi4gVGhpcyBpcyBzbyB0aGF0IGNhbiBiZSBzYWZlbHkgcGFyc2VkIGJ5IEpTT04ucGFyc2UoKSBhcyBhIHN0cmluZyBhbmQgYWxzbyBzbyBpdFxuICAgKiB3b24ndCBiZSBtaXNpbnRlcnByZXRlZCBieSBvdGhlciByZWdleGVzIGxvb2tpbmcgZm9yIEpTT04gc3ludGF4IChlc3BlY2lhbGx5IGFycmF5cyBiL2Mgb2YgY29udGV4dC12YXIgW10tcHJvcGVydHktYnJhY2tldHMpXG4gICAqXG4gICAqIEBwYXJhbSBjb250ZXh0VmFyIC0gVGhlIGNvbnRleHQgdmFyIHRvIHRyYW5zZm9ybVxuICAgKi9cbiAgdHJhbnNmb3JtQ29udGV4dFZhckludG9QbGFjZXJob2xkZXIoY29udGV4dFZhcjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAvLyBSZXBsYWNlIGNvbnRleHQuIHdpdGggX19DWFRfX1xuICAgIGNvbnRleHRWYXIgPSAnX19DWFRfXycgKyBjb250ZXh0VmFyLnN1YnN0cmluZyg3KTtcbiAgICAvLyBFbmNvZGUgdmFyaWFibGUgc3ludGF4XG4gICAgY29udGV4dFZhciA9IGNvbnRleHRWYXIucmVwbGFjZSgvXFxcIi9nLCAnQEBAY3h0RG91YmxlUXVvdGVAQEAnKTtcbiAgICBjb250ZXh0VmFyID0gY29udGV4dFZhci5yZXBsYWNlKC9cXC4vZywgJ0BAQGN4dERvdEBAQCcpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL1xcWy9nLCAnQEBAY3h0T3BlblNxdWFyZUJyYWNrZXRAQEAnKTtcbiAgICBjb250ZXh0VmFyID0gY29udGV4dFZhci5yZXBsYWNlKC9cXF0vZywgJ0BAQGN4dENsb3NlU3F1YXJlQnJhY2tldEBAQCcpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL1xcKC9nLCAnQEBAY3h0T3BlblJvdW5kQnJhY2tldEBAQCcpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL1xcKS9nLCAnQEBAY3h0Q2xvc2VSb3VuZEJyYWNrZXRAQEAnKTtcbiAgICByZXR1cm4gY29udGV4dFZhcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmFuc2Zvcm1zIGEgY29udGV4dCB2YXIgcGxhY2Vob2xkZXIgYmFjayBpbnRvIHRoZSBhY3R1YWwgY29udGV4dCB2YXJcbiAgICogXG4gICAqIEBwYXJhbSBjb250ZXh0VmFyIC0gVGhlIHBsYWNlaG9sZGVyIGNvbnRleHQgdmFyXG4gICAqL1xuICB0cmFuc2Zvcm1QbGFjZWhvbGRlckludG9Db250ZXh0VmFyKGNvbnRleHRWYXI6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29udGV4dFZhciA9ICdjb250ZXh0JyArIGNvbnRleHRWYXIuc3Vic3RyaW5nKDcpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL0BAQGN4dERvdWJsZVF1b3RlQEBAL2csICdcIicpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL0BAQGN4dERvdEBAQC9nLCAnLicpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL0BAQGN4dE9wZW5TcXVhcmVCcmFja2V0QEBAL2csICdbJyk7XG4gICAgY29udGV4dFZhciA9IGNvbnRleHRWYXIucmVwbGFjZSgvQEBAY3h0Q2xvc2VTcXVhcmVCcmFja2V0QEBAL2csICddJyk7XG4gICAgY29udGV4dFZhciA9IGNvbnRleHRWYXIucmVwbGFjZSgvQEBAY3h0T3BlblJvdW5kQnJhY2tldEBAQC9nLCAnKCcpO1xuICAgIGNvbnRleHRWYXIgPSBjb250ZXh0VmFyLnJlcGxhY2UoL0BAQGN4dENsb3NlUm91bmRCcmFja2V0QEBAL2csICcpJyk7XG4gICAgcmV0dXJuIGNvbnRleHRWYXI7XG4gIH1cblxuICAvLyBPdGhlclxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKlxuICAgKiBUYWtlcyBhIHBpZWNlIG9mIHRleHQgYXMgd2VsbCBhcyBhcnJheSBvZiBUZXh0U2VnbWVudHMgYW5kIGVuY29kZXMgdGhlbSB3aXRoIHRoZSBoZWxwIG9mIGFuIGVuY29kaW5nRnVuY3Rpb25cbiAgICogVGhlIGVuY29kZWQgdGV4dCBpcyB0aGVuIGF1dG9tYXRpY2FsbHkgYXNzZW1ibGVkIGFuZCByZXR1cm5lZC5cbiAgICpcbiAgICogQHBhcmFtIHRleHQgLSBUaGUgdGV4dCBpbiBxdWVzdGlvblxuICAgKiBAcGFyYW0gc3BlY2lhbFRleHRTZWdtZW50cyAtIFRoZSBzZWdtZW50cyBpbiB0aGUgdGV4dCB0byBlbmNvZGVcbiAgICogQHBhcmFtIGVuY29kaW5nRnVuY3Rpb24gLSBUaGUgZW5jb2RpbmcgZnVuY3Rpb24gdG8gdXNlXG4gICAqL1xuICBwcml2YXRlIGVuY29kZVRleHRTZWdtZW50cyh0ZXh0OiBzdHJpbmcsIHNwZWNpYWxUZXh0U2VnbWVudHM6IFRleHRTZWdtZW50W10sIGVuY29kaW5nRnVuY3Rpb246IGFueSk6IHN0cmluZyB7XG4gICAgLy8gMS4gRGl2aWRlIHdob2xlIHRleHQgaW50byB0d28gdHlwZXMgb2Ygc2VnbWVudHM6IFRob3NlIHRvIGJlIGVuY29kZWQgYW5kIHRob3NlIHRvIGJlIGxlZnQgYXMgdGhleSBhcmVcbiAgICBjb25zdCBhbGxUZXh0U2VnbWVudHMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IHNwZWNpYWxUZXh0U2VnbWVudCBvZiBzcGVjaWFsVGV4dFNlZ21lbnRzKSB7XG4gICAgICAvLyBQdXNoIG5vcm1hbCB0ZXh0IHNlZ21lbnQgc2luY2UgbGFzdCBzcGVjaWFsIHNlZ21lbnRcbiAgICAgIGNvbnN0IGxhc3RTZWdtZW50RW5kSW5kZXg6IG51bWJlciA9IGFsbFRleHRTZWdtZW50cy5sZW5ndGggPT09IDAgPyAwIDogYWxsVGV4dFNlZ21lbnRzW2FsbFRleHRTZWdtZW50cy5sZW5ndGggLSAxXS5lbmRJbmRleDtcbiAgICAgIGFsbFRleHRTZWdtZW50cy5wdXNoKHtcbiAgICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgICBzdGFydEluZGV4OiBsYXN0U2VnbWVudEVuZEluZGV4LFxuICAgICAgICBlbmRJbmRleDogc3BlY2lhbFRleHRTZWdtZW50LnN0YXJ0SW5kZXgsXG4gICAgICAgIHN0cmluZzogdGV4dC5zdWJzdHJpbmcobGFzdFNlZ21lbnRFbmRJbmRleCwgc3BlY2lhbFRleHRTZWdtZW50LnN0YXJ0SW5kZXgpXG4gICAgICB9KTtcblxuICAgICAgLy8gUHVzaCBuZXh0IHNwZWNpYWwgc2VnbWVudFxuICAgICAgYWxsVGV4dFNlZ21lbnRzLnB1c2goe1xuICAgICAgICB0eXBlOiAnc3BlY2lhbCcsXG4gICAgICAgIHN0YXJ0SW5kZXg6IHNwZWNpYWxUZXh0U2VnbWVudC5zdGFydEluZGV4LFxuICAgICAgICBlbmRJbmRleDogc3BlY2lhbFRleHRTZWdtZW50LmVuZEluZGV4LFxuICAgICAgICBzdHJpbmc6IHRleHQuc3Vic3RyaW5nKHNwZWNpYWxUZXh0U2VnbWVudC5zdGFydEluZGV4LCBzcGVjaWFsVGV4dFNlZ21lbnQuZW5kSW5kZXgpXG4gICAgICB9KTtcbiAgICB9XG4gICAgLy8gQWRkIHRleHQgc2VnbWVudCBmb3IgdHJhaWxpbmcgdGV4dCBhZnRlciBsYXN0IHNwZWNpYWwgc2VnbWVudFxuICAgIGNvbnN0IGxhc3RCcmFja2V0RW5kSW5kZXggPSBhbGxUZXh0U2VnbWVudHMubGVuZ3RoID09PSAwID8gMCA6IGFsbFRleHRTZWdtZW50c1thbGxUZXh0U2VnbWVudHMubGVuZ3RoIC0gMV0uZW5kSW5kZXg7XG4gICAgYWxsVGV4dFNlZ21lbnRzLnB1c2goe1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgc3RhcnRJbmRleDogbGFzdEJyYWNrZXRFbmRJbmRleCxcbiAgICAgIGVuZEluZGV4OiB0ZXh0Lmxlbmd0aCAtIDEsXG4gICAgICBzdHJpbmc6IHRleHQuc3Vic3RyaW5nKGxhc3RCcmFja2V0RW5kSW5kZXgpXG4gICAgfSk7XG5cbiAgICAvLyAyLiBFbmNvZGUgYWxsIHNwZWNpYWwgc2VnbWVudHNcbiAgICBmb3IgKGNvbnN0IHNlZ21lbnQgb2YgYWxsVGV4dFNlZ21lbnRzKSB7XG4gICAgICBpZiAoc2VnbWVudC50eXBlID09PSAnc3BlY2lhbCcpIHtcbiAgICAgICAgc2VnbWVudC5zdHJpbmcgPSBlbmNvZGluZ0Z1bmN0aW9uKHNlZ21lbnQuc3RyaW5nKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyAzLiBDb25jYXQgZXZlcnl0aGluZyB0b2dldGhlciBhZ2FpblxuICAgIGxldCBlbmNvZGVkU3RyaW5nID0gJyc7XG4gICAgZm9yIChjb25zdCBzZWdtZW50IG9mIGFsbFRleHRTZWdtZW50cykge1xuICAgICAgZW5jb2RlZFN0cmluZyArPSBzZWdtZW50LnN0cmluZztcbiAgICB9XG5cbiAgICByZXR1cm4gZW5jb2RlZFN0cmluZztcbiAgfVxuXG4gIC8qKlxuICAgKiBTdHJpcHMgYWxsIGVzY2FwaW5nIGJhY2tzbGFzaGVzIGZyb20gYSBwaWVjZSBvZiB0ZXh0XG4gICAqXG4gICAqIEBwYXJhbSB0ZXh0IC0gVGhlIHRleHQgaW4gcXVlc3Rpb25cbiAgICovXG4gIHN0cmlwU2xhc2hlcyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0ZXh0LnJlcGxhY2UoL1xcXFwoLikvZywgJyQxJyk7XG4gICAgLy8gcmV0dXJuIHRleHQucmVwbGFjZShuZXcgUmVnRXhwKCdcXFxcXFxcXCguKScsICdnJyksICckMScpO1xuICB9XG5cbiAgLyoqXG4gICAqIEVzY2FwZXMgYWxsIGRvdWJsZSBxdW90ZXMgaW4gYSBwaWVjZSBvZiB0ZXh0XG4gICAqXG4gICAqIEBwYXJhbSB0ZXh0IC0gVGhlIHRleHQgaW4gcXVlc3Rpb25cbiAgICovXG4gIGVzY2FwZURvdWJsZVF1b3Rlcyh0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHJlc3VsdCA9IHRleHQucmVwbGFjZSgvXFxcXC9nLCAnXFxcXFxcXFwnKS5yZXBsYWNlKC9cXFwiL2csICdcXFxcXCInKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG59XG4iXX0=