2023-06-29 11:55:02 +08:00

13517 lines
2.1 MiB
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
if you want to view the source visit the plugins github repository
'Shell commands' plugin for Obsidian.
Copyright (C) 2021 - 2023 Jarkko Linnanvirta
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
'use strict';
var obsidian = require('obsidian');
var child_process = require('child_process');
var os = require('os');
var path = require('path');
var electron = require('electron');
var fs = require('fs');
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var path__namespace = /*#__PURE__*/_interopNamespace(path);
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Modal extends obsidian.Modal {
constructor(plugin) {
super(plugin.app);
this.plugin = plugin;
this._isOpen = false;
}
onOpen() {
this._isOpen = true;
// Make the modal scrollable if it has more content than what fits in the screen.
this.modalEl.addClass("SC-modal", "SC-scrollable");
// Approve the modal by pressing the enter key (if enabled).
if (this.plugin.settings.approve_modals_by_pressing_enter_key) {
this.scope.register([], "enter", (event) => {
// Check that no textarea is focused and no autocomplete menu is open.
if (0 === document.querySelectorAll("textarea:focus").length &&
0 === document.querySelectorAll("div.SC-autocomplete").length) {
// No textareas with focus and no open autocomplete menus were found.
this.approve();
event.preventDefault();
event.stopPropagation();
}
});
}
}
isOpen() {
return this._isOpen;
}
setTitle(title) {
this.titleEl.innerText = title;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class ConfirmationModal extends SC_Modal {
constructor(plugin, title, question, yes_button_text) {
super(plugin);
this.question = question;
this.yes_button_text = yes_button_text;
this.approved = false;
this.setTitle(title);
this.promise = new Promise((resolve) => {
this.resolve_promise = resolve;
});
}
onOpen() {
super.onOpen();
// Display the question
this.modalEl.createEl("p", { text: this.question });
// Display the yes button
new obsidian.Setting(this.modalEl)
.addButton(button => button
.setButtonText(this.yes_button_text)
.onClick(() => this.approve()));
}
approve() {
// Got a confirmation from a user
this.resolve_promise(true);
this.approved = true;
this.close();
}
onClose() {
super.onClose();
if (!this.approved) { // TODO: Find out if there is a way to not use this kind of flag property. Can the status be checked from the promise itself?
this.resolve_promise(false);
}
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* If true, logging stuff to console.log() will be enabled.
* Might also enable some testing {{variables}} in the future, perhaps.
*/
let DEBUG_ON = false;
function setDEBUG_ON(value) {
DEBUG_ON = value;
}
/**
* Calls console.log(), but only if debugging is enabled.
* @param message
*/
function debugLog(message) {
if (DEBUG_ON) {
console.log(message);
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class IDGenerator {
constructor(reserved_ids = [], min_length = 10, characters = "abcdefghijklmnopqrstuvwxyz0123456789") {
this.reserved_ids = reserved_ids;
this.min_length = min_length;
this.characters = characters;
}
addReservedID(id) {
debugLog(IDGenerator.name + ": Adding id " + id + " to the list of reserved ids.");
this.reserved_ids.push(id);
}
generateID() {
let generated_id = "";
while (generated_id.length < this.min_length || this.isIDReserved(generated_id)) {
generated_id += this.generateCharacter();
}
this.reserved_ids.push(generated_id);
debugLog(IDGenerator.name + ": Generated id " + generated_id);
return generated_id;
}
getReservedIDs() {
return this.reserved_ids;
}
generateCharacter() {
return this.characters.charAt(Math.floor(Math.random() * this.characters.length));
}
isIDReserved(id) {
return this.reserved_ids.contains(id);
}
}
const id_generator = new IDGenerator();
function getIDGenerator() {
return id_generator;
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function getVaultAbsolutePath(app) {
// Original code was copied 2021-08-22 from https://github.com/phibr0/obsidian-open-with/blob/84f0e25ba8e8355ff83b22f4050adde4cc6763ea/main.ts#L66-L67
// But the code has been rewritten 2021-08-27 as per https://github.com/obsidianmd/obsidian-releases/pull/433#issuecomment-906087095
const adapter = app.vault.adapter;
if (adapter instanceof obsidian.FileSystemAdapter) {
return adapter.getBasePath();
}
throw new Error("Could not retrieve vault path. No DataAdapter was found from app.vault.adapter.");
}
function getPluginAbsolutePath(plugin) {
return normalizePath2(path__namespace.join(getVaultAbsolutePath(plugin.app), plugin.app.vault.configDir, "plugins", plugin.getPluginId()));
}
/**
* For some reason there is no Platform.isWindows .
*/
function isWindows() {
return process.platform === "win32";
}
/**
* This is just a wrapper around platform() in order to cast the type to PlatformId.
* TODO: Consider renaming this to getPlatformId().
*/
function getOperatingSystem() {
// @ts-ignore In theory, platform() can return an OS name not included in OperatingSystemName. But as Obsidian
// currently does not support anything else than Windows, Mac and Linux (except mobile platforms, but they are
// ruled out by the manifest of this plugin), it should be safe to assume that the current OS is one of those
// three.
return os.platform();
}
function getView(app) {
const view = app.workspace.getActiveViewOfType(obsidian.MarkdownView);
if (!view) {
debugLog("getView(): Could not get a view. Will return null.");
return null;
}
return view;
}
function getEditor(app) {
const view = getView(app);
if (null === view) {
// Could not get a view.
return null;
}
// Ensure that view.editor exists! It exists at least if this is a MarkDownView.
if ("editor" in view) {
// Good, it exists.
// @ts-ignore We already know that view.editor exists.
return view.editor;
}
// Did not find an editor.
debugLog("getEditor(): 'view' does not have a property named 'editor'. Will return null.");
return null;
}
// eslint-disable-next-line @typescript-eslint/ban-types
function cloneObject(object) {
return Object.assign({}, object);
}
/**
* Merges two or more objects together. If they have same property names, former objects' properties get overwritten by later objects' properties.
*
* @param objects
*/
// eslint-disable-next-line @typescript-eslint/ban-types
function combineObjects(...objects) {
return Object.assign({}, ...objects);
}
function mergeSets(set1, set2) {
return new Set([...set1, ...set2]);
}
/**
* Returns a new Set cloned from 'from_set', with all items presented in 'remove' removed from it.
*
* @param from_set
* @param remove Can be either a Set of removable items, or a single item.
*/
function removeFromSet(from_set, remove) {
const reduced_set = new Set(from_set);
if (remove instanceof Set) {
for (const removable of remove) {
reduced_set.delete(removable);
}
}
else {
reduced_set.delete(remove);
}
return reduced_set;
}
/**
* Same as normalizePath(), but fixes these glitches:
* - Leading forward slashes / backward slashes should not be removed.
* - \ should not be converted to / if platform is Windows. In other words, / should be converted to \ if platform is Windows.
*
* TODO: I've opened a discussion about this on Obsidian's forums. If anything new comes up in the discussion, make changes accordingly. https://forum.obsidian.md/t/normalizepath-removes-a-leading/24713
*/
function normalizePath2(path) {
// 1. Preparations
path = path.trim();
const leading_slashes_regexp = /^[/\\]*/gu; // Get as many / or \ slashes as there are in the very beginning of path. Can also be "" (an empty string).
const leading_slashes_array = leading_slashes_regexp.exec(path); // An array with only one item.
if (null === leading_slashes_array) {
// It should always match. This exception should never happen, but have it just in case.
throw new Error("normalizePath2(): leading_slashes_regexp did not match.");
}
let leading_slashes = leading_slashes_array[0];
// 2. Run the original normalizePath()
path = obsidian.normalizePath(path);
// 3. Fixes
// Check that correct slashes are used.
if (isWindows()) {
// The platform is Windows.
// Convert / to \
path = path.replace(/\//gu, "\\"); // Need to use a regexp instead of a normal "/" -> "\\" replace because the normal replace would only replace first occurrence of /.
leading_slashes = leading_slashes.replace(/\//gu, "\\"); // Same here.
}
// Now ensure that path still contains leading slashes (if there were any before calling normalizePath()).
// Check that the path should have a similar set of leading slashes at the beginning. It can be at least "/" (on linux/Mac), or "\\" (on Windows when it's a network path), in theory even "///" or "\\\\\" whatever.
// normalizePath() seems to remove leading slashes (and they are needed to be re-added), but it's needed to check first, otherwise the path would have double leading slashes if normalizePath() gets fixed in the future.
if (leading_slashes.length && path.slice(0, leading_slashes.length) !== leading_slashes) {
// The path does not contain the required set of leading slashes, so add them.
path = leading_slashes + path;
}
// 4. Done
return path;
}
function extractFileName(file_path, with_extension = true) {
if (with_extension) {
return path__namespace.parse(file_path).base;
}
else {
return path__namespace.parse(file_path).name;
}
}
function extractFileParentPath(file_path) {
return path__namespace.parse(file_path).dir;
}
// eslint-disable-next-line @typescript-eslint/ban-types
function joinObjectProperties(object, glue) {
let result = "";
for (const property_name in object) {
if (result.length) {
result += glue;
}
// @ts-ignore
result += object[property_name];
}
return result;
}
/**
* Removes all duplicates from an array.
*
* Idea is copied 2021-10-06 from https://stackoverflow.com/a/33121880/2754026
*/
function uniqueArray(array) {
return [...new Set(array)];
}
/**
* Opens a web browser in the specified URL.
* @param url
*/
function gotoURL(url) {
electron.shell.openExternal(url); // This returns a promise, but it can be ignored as there's nothing to do after opening the browser.
}
function generateObsidianCommandName(plugin, shell_command, alias) {
const prefix = plugin.settings.obsidian_command_palette_prefix;
if (alias) {
// If an alias is set for the command, Obsidian's command palette should display the alias text instead of the actual command.
return prefix + alias;
}
return prefix + shell_command;
}
function isInteger(value, allow_minus) {
if (allow_minus) {
return !!value.match(/^-?\d+$/u);
}
else {
return !!value.match(/^\d+$/u);
}
}
/**
* Translates 1-indexed caret line and column to a 0-indexed EditorPosition object. Also translates a possibly negative line
* to a positive line from the end of the file, and a possibly negative column to a positive column from the end of the line.
* @param editor
* @param caret_line
* @param caret_column
*/
function prepareEditorPosition(editor, caret_line, caret_column) {
// Determine line
if (caret_line < 0) {
// Negative line means to calculate it from the end of the file.
caret_line = Math.max(0, editor.lastLine() + caret_line + 1);
}
else {
// Positive line needs just a small adjustment.
// Editor line is zero-indexed, line numbers are 1-indexed.
caret_line -= 1;
}
// Determine column
if (caret_column < 0) {
// Negative column means to calculate it from the end of the line.
caret_column = Math.max(0, editor.getLine(caret_line).length + caret_column + 1);
}
else {
// Positive column needs just a small adjustment.
// Editor column is zero-indexed, column numbers are 1-indexed.
caret_column -= 1;
}
return {
line: caret_line,
ch: caret_column,
};
}
function getSelectionFromTextarea(textarea_element, return_null_if_empty) {
const selected_text = textarea_element.value.substring(textarea_element.selectionStart, textarea_element.selectionEnd);
return "" === selected_text && return_null_if_empty ? null : selected_text;
}
/**
* Creates an HTMLElement (with freely decidable tag) and adds the given content into it as normal text. No HTML formatting
* is supported, i.e. possible HTML special characters are shown as-is. Newline characters are converted to <br> elements.
*
* @param tag
* @param content
* @param parent_element
*/
function createMultilineTextElement(tag, content, parent_element) {
const content_element = parent_element.createEl(tag);
// Insert content line-by-line
const content_lines = content.split(/\r\n|\r|\n/g); // Don't use ( ) with | because .split() would then include the newline characters in the resulting array.
content_lines.forEach((content_line, content_line_index) => {
// Insert the line.
content_element.insertAdjacentText("beforeend", content_line);
// Insert a linebreak <br> if needed.
if (content_line_index < content_lines.length - 1) {
content_element.insertAdjacentHTML("beforeend", "<br>");
}
});
return content_element;
}
function randomInteger(min, max) {
const range = max - min + 1;
return min + Math.floor(Math.random() * range);
}
/**
* Does the following prefixings:
* \ will become \\
* [ will become \[
* ] will become \]
* ( will become \(
* ) will become \)
*
* @param content
*/
function escapeMarkdownLinkCharacters(content) {
// TODO: \[ can be replaced with [ as eslint suggests and ten remove the ignore line below. I'm not doing it now because it would be outside of the scope of this commit/issue #70.
// eslint-disable-next-line no-useless-escape
return content.replace(/[\\()\[\]]/gu, "\\$&");
}
function copyToClipboard(text) {
return electron.clipboard.writeText(text);
}
async function getFileContentWithoutYAML(app, file) {
return new Promise((resolve) => {
// The logic is borrowed 2022-09-01 from https://forum.obsidian.md/t/how-to-get-current-file-content-without-yaml-frontmatter/26197/2
// Thank you, endorama! <3
const file_content = app.vault.read(file);
file_content.then((file_content) => {
const frontmatter_cache = app.metadataCache.getFileCache(file)?.frontmatter;
if (frontmatter_cache) {
// A YAML frontmatter is present in the file.
const frontmatter_end_line_number = frontmatter_cache.position.end.line + 1; // + 1: Take the last --- line into account, too.
const file_content_without_frontmatter = file_content.split("\n").slice(frontmatter_end_line_number).join("\n");
return resolve(file_content_without_frontmatter);
}
else {
// No YAML frontmatter is present in the file.
// Return the whole file content, because there's nothing to remove.
return resolve(file_content);
}
});
});
}
async function getFileYAML(app, file, withDashes) {
return new Promise((resolve) => {
// The logic is borrowed 2022-09-01 from https://forum.obsidian.md/t/how-to-get-current-file-content-without-yaml-frontmatter/26197/2
// Thank you, endorama! <3
const fileContent = app.vault.read(file);
fileContent.then((file_content) => {
const frontmatterCache = app.metadataCache.getFileCache(file)?.frontmatter;
if (frontmatterCache) {
// A YAML frontmatter is present in the file.
const frontmatterEndLineNumber = frontmatterCache.position.end.line + 1; // + 1: Take the last --- line into account, too.
let firstLine;
let lastLine;
if (withDashes) {
// Take full YAML content, including --- lines at the top and bottom.
firstLine = 0;
lastLine = frontmatterEndLineNumber;
}
else {
// Exclude --- lines.
firstLine = 1;
lastLine = frontmatterEndLineNumber - 1;
}
const frontmatterContent = file_content.split("\n").slice(firstLine, lastLine).join("\n");
return resolve(frontmatterContent);
}
else {
// No YAML frontmatter is present in the file.
return resolve(null);
}
});
});
}
/**
* Escapes a string that will be used as a pattern in a regular expression.
*
* Note that this does not escape minus: - . It's probably ok as long as you won't wrap the result of this function in square brackets [ ] . For more information, read a comment by coolaj86 on Nov 29, 2019 at 2:44 in this Stack Overflow answer: https://stackoverflow.com/a/6969486/2754026
*
* Copied 2022-03-10 from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
* Modifications:
* - Added TypeScript data type hints for the parameter and return value.
* - Added 'export' keyword.
* - Added this JSDoc.
* - No other changes.
*
* @param string
* @return string
*/
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
const DocumentationMainLink = "https://publish.obsidian.md/shellcommands";
const DocumentationBuiltInVariablesBaseLink = "https://publish.obsidian.md/shellcommands/Variables/"; // When used, a variable's name will be appended to the end. Keep the trailing slash!
const DocumentationBuiltInVariablesIndexLink = "https://publish.obsidian.md/shellcommands/Variables/Variables+-+general+principles#All+variables";
const DocumentationCustomVariablesLink = "https://publish.obsidian.md/shellcommands/Variables/Custom+variables";
const DocumentationAutocompleteLink = "https://publish.obsidian.md/shellcommands/Variables/Autocomplete/Autocomplete";
const DocumentationEventsFolderLink = "https://publish.obsidian.md/shellcommands/Events/";
const DocumentationPATHAugmentationsLink = "https://publish.obsidian.md/shellcommands/Environments/Additions+to+the+PATH+environment+variable";
const DocumentationOutputWrappersLink = "https://publish.obsidian.md/shellcommands/Output+handling/Output+wrappers";
const DocumentationOutputHandlingModeLink = "https://publish.obsidian.md/shellcommands/Output+handling/Realtime+output+handling";
const DocumentationStdinContentLink = "https://publish.obsidian.md/shellcommands/Variables/Pass+variables+to+stdin";
const GitHubLink = "https://github.com/Taitava/obsidian-shellcommands";
const ChangelogLink = "https://github.com/Taitava/obsidian-shellcommands/blob/main/CHANGELOG.md";
const LicenseLink = "https://github.com/Taitava/obsidian-shellcommands/blob/main/LICENSE";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* Variables that can be used to inject values to shell commands using {{variable:argument}} syntax.
*/
class Variable {
constructor(plugin) {
this.plugin = plugin;
/**
* If this is false, the variable can be assigned a default value that can be used in situations where the variable is unavailable.
* TODO: Set to false, as most Variables are not always available. Then remove all 'always_available = false' lines from subclasses, and add 'always_available = true' to those subclasses that need it.
* @protected
*/
this.always_available = true;
this.app = plugin.app;
}
getValue(t_shell_command = null, sc_event = null, variableArguments = {},
/**
* Will parse variables in a default value (only used if this variable is not available this time). The callback
* is only used, if t_shell_command is given. Set to null, if no variable parsing is needed for default values.
* */
default_value_parser = null) {
return new Promise((resolve) => {
// Cast arguments (if any) to their correct data types
const castedArguments = this.castArguments(variableArguments);
// Generate a value, or catch an exception if one occurs.
this.generateValue(castedArguments, sc_event).then((value) => {
// Value generation succeeded.
return resolve({
value: value,
error_messages: [],
succeeded: true,
});
}).catch((error) => {
// Caught a VariableError or an Error.
if (error instanceof VariableError) {
// The variable is not available in this situation.
debugLog(this.constructor.name + ".getValue(): Caught a VariableError and will determine how to handle it: " + error.message);
// Check what should be done.
const default_value_configuration = t_shell_command?.getDefaultValueConfigurationForVariable(this); // The method can return undefined, and t_shell_command can be null.
const default_value_type = default_value_configuration ? default_value_configuration.type : "show-errors";
const debug_message_base = "Variable " + this.getFullName() + " is not available. ";
switch (default_value_type) {
case "show-errors":
// Generate error messages by calling generateValue().
debugLog(debug_message_base + "Will prevent shell command execution and show visible error messages.");
return resolve({
value: null,
error_messages: [error.message],
succeeded: false,
});
case "cancel-silently":
// Prevent execution, but do not show any errors
debugLog(debug_message_base + "Will prevent shell command execution silently without visible error messages.");
return resolve({
value: null,
error_messages: [],
succeeded: false,
});
case "value":
// Return a default value.
if (!default_value_configuration) {
// This should not happen, because default_value_type is never "value" when default_value_configuration is undefined or null.
// This check is just for TypeScript compiler to understand that default_value_configuration is defined when it's accessed below.
throw new Error("Default value configuration is undefined.");
}
debugLog(debug_message_base + "Will use a default value: " + default_value_configuration.value);
if (default_value_parser) {
// Parse possible variables in the default value.
default_value_parser(default_value_configuration.value).then((default_value_parsing_result) => {
return resolve({
value: default_value_parsing_result.succeeded
? default_value_parsing_result.parsed_content
: default_value_parsing_result.original_content,
error_messages: default_value_parsing_result.error_messages,
succeeded: default_value_parsing_result.succeeded,
});
});
}
else {
// No variable parsing is wanted.
return resolve({
value: default_value_configuration.value,
error_messages: [],
succeeded: true,
});
}
break;
default:
throw new Error("Unrecognised default value type: " + default_value_type);
}
}
else {
// A program logic error has happened.
debugLog(this.constructor.name + ".getValue(): Caught an unrecognised error of class: " + error.constructor.name + ". Will rethrow it.");
throw error;
}
});
});
}
getParameters() {
const child_class = this.constructor;
return child_class.parameters;
}
getParameterSeparator() {
const child_class = this.constructor;
return child_class.parameter_separator;
}
getPattern() {
const error_prefix = this.variable_name + ".getPattern(): ";
let pattern = '\\{\\{!?' + escapeRegExp(this.variable_name);
for (const parameter_name in this.getParameters()) {
const parameter = this.getParameters()[parameter_name];
let parameter_type_pattern = this.getParameterSeparator(); // Here this.parameter_separator (= : ) is included in the parameter value just so that it's not needed to do nested parenthesis to accomplish possible optionality: (:())?. parseShellCommandVariables() will remove the leading : .
// Check should we use parameter.options or parameter.type.
if (undefined === parameter.options &&
undefined === parameter.type) {
// Neither is defined :(
throw Error(error_prefix + "Parameter '" + parameter_name + "' should define either 'type' or 'options', neither is defined!");
}
else if (undefined !== parameter.options &&
undefined !== parameter.type) {
// Both are defined :(
throw Error(error_prefix + "Parameter '" + parameter_name + "' should define either 'type' or 'options', not both!");
}
else if (undefined !== parameter.options) {
// Use parameter.options
parameter_type_pattern += parameter.options.join("|" + this.getParameterSeparator()); // E.g. "absolute|:relative" for {{file_path:mode}} variable's 'mode' parameter.
}
else {
// Use parameter.type
switch (parameter.type) {
case "string":
parameter_type_pattern += ".*?";
break;
case "integer":
parameter_type_pattern += "\\d+";
break;
default:
throw Error(error_prefix + "Parameter '" + parameter_name + "' has an unrecognised type: " + parameter.type);
}
}
// Add the subpattern to 'pattern'.
pattern += "(" + parameter_type_pattern + ")";
if (!parameter.required) {
// Make the parameter optional.
pattern += "?";
}
}
pattern += '\\}\\}';
return pattern;
}
getParameterNames() {
return Object.getOwnPropertyNames(this.getParameters());
}
/**
* @param variableArguments String typed arguments. Arguments that should be typed otherly, will be cast to other types. Then all arguments are returned.
*/
castArguments(variableArguments) {
const castedArguments = {};
for (const parameterName of Object.getOwnPropertyNames(variableArguments)) {
const parameter_type = this.getParameters()[parameterName].type ?? "string"; // If the variable uses "options" instead of "type", then the type is always "string".
const argument = variableArguments[parameterName];
switch (parameter_type) {
case "string":
castedArguments[parameterName] = argument;
break;
case "integer":
castedArguments[parameterName] = parseInt(argument);
break;
}
}
return castedArguments;
}
/**
* Creates a VariableError and passes it to a rejector function, which will pass the VariableError to Variable.getValue().
* Then it will be handled there according to user preferences.
*
* @param message
* @param rejector
* @protected
*/
reject(message, rejector) {
rejector(this.newVariableError(message));
}
/**
* Similar to Variable.reject(), but uses a traditional throw. Can be used in async methods. For methods that create
* Promises manually, Variable.reject() should be used, because errors thrown in manually created Promises are not caught
* by Variable.getValue()'s Promise.catch() callback.
*
* @param message
* @protected
*/
throw(message) {
throw this.newVariableError(message);
}
newVariableError(message) {
const prefix = this.getFullName() + ": ";
return new VariableError(prefix + message);
}
getAutocompleteItems() {
// Check if the variable has at least one _mandatory_ parameter.
let parameter_indicator = "";
const parameter_names = Object.getOwnPropertyNames(this.getParameters())
.filter(parameter_name => this.getParameters()[parameter_name].required === true) // Only include mandatory parameters
;
if (parameter_names.length > 0) {
parameter_indicator = Variable.parameter_separator; // When the variable name ends with a parameter separator character, it indicates to a user that an argument should be supplied.
}
return [
// Normal variable
{
value: "{{" + this.variable_name + parameter_indicator + "}}",
help_text: (this.help_text + " " + this.getAvailabilityText()).trim(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped version of the variable
{
value: "{{!" + this.variable_name + parameter_indicator + "}}",
help_text: (this.help_text + " " + this.getAvailabilityText()).trim(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>" + this.getFullName() + "</strong>";
}
/**
* Returns the Variable's name wrapped in {{ and }}.
*
* TODO: Change hardcoded {{ }} entries to use this method all around the code.
*/
getFullName() {
return "{{" + this.variable_name + "}}";
}
/**
* TODO: Create a class BuiltinVariable and move this method there. This should not be present for CustomVariables.
*/
getDocumentationLink() {
return DocumentationBuiltInVariablesBaseLink + encodeURI(this.getFullName());
}
/**
* TODO: Create a class BuiltinVariable and move this method there. This should not be present for CustomVariables.
*/
createDocumentationLinkElement(container) {
const description = this.getFullName() + ": " + this.help_text
+ os.EOL + os.EOL +
"Click for external documentation.";
container.createEl("a", {
text: this.getFullName(),
href: this.getDocumentationLink(),
attr: { "aria-label": description },
});
}
/**
* Returns a unique string that can be used in default value configurations.
* @return Normal variable name, if this is a built-in variable; or an ID string if this is a CustomVariable.
*/
getIdentifier() {
return this.getFullName();
}
/**
* This can be used to determine if the variable can sometimes be unavailable. Used in settings to allow a user to define
* default values for variables that are not always available, filtering out always available variables for which default
* values would not make sense.
*/
isAlwaysAvailable() {
return this.always_available;
}
/**
* For variables that are always available, returns an empty string.
*/
getAvailabilityText() {
return "";
}
/**
* Same as getAvailabilityText(), but removes HTML from the result.
*/
getAvailabilityTextPlain() {
return this.getAvailabilityText().replace(/<\/?strong>/ig, ""); // Remove <strong> and </strong> markings from the help text
}
/**
* Returns a default value configuration object that should be used if a shell command does not define its own
* default value configuration object.
*/
getGlobalDefaultValueConfiguration() {
// Works for built-in variables only. CustomVariable class needs to override this method and not call the parent!
return this.plugin.settings.builtin_variables[this.getIdentifier()]?.default_value; // Can return null
}
}
Variable.parameter_separator = ":";
/**
* A definition for what parameters this variables takes.
* @protected
*/
Variable.parameters = {};
/**
* Thrown when Variables encounter errors that users should solve. Variable.getValue() will catch these and show to user
* (unless errors are ignored).
*/
class VariableError extends Error {
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_Output extends Variable {
constructor(plugin, output_content) {
super(plugin);
this.output_content = output_content;
this.variable_name = "output";
this.help_text = "Gives text outputted by a shell command after it's executed.";
}
async generateValue() {
return this.output_content;
}
getAvailabilityText() {
return "<strong>Only available</strong> in <em>output wrappers</em>, cannot be used as input for shell commands.";
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Escaper {
constructor(raw_value) {
this.raw_value = raw_value;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* Prefixes all characters that are not letters, numbers or underscores with a prefix character that can be defined by child classes.
*/
class AllSpecialCharactersEscaper extends Escaper {
escape() {
return this.raw_value.replace(/[^\w\d]/gu, (special_character) => {
// Do the replacing in a function in order to avoid a possible $ character to be interpreted by JavaScript to interact with the regex.
// More information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_a_parameter (referenced 2021-11-02.
return this.prefix + special_character;
});
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class ShEscaper extends AllSpecialCharactersEscaper {
constructor() {
super(...arguments);
this.prefix = "\\"; // In *sh, escaping should use a backslash, e.g. "Hello, world!" becomes \"Hello\,\ world\!\"
}
escape() {
return this.replace_newlines(super.escape());
}
/**
* Converts escaped newline characters to a form that the Bourne family shells will interpret as literal newlines,
* not as ignorable characters.
*
* @param escaped_value
* @private
*/
replace_newlines(escaped_value) {
return escaped_value
.replaceAll(this.prefix + "\r", this.prefix + this.prefix + "r") // Replace a real linefeed with a literal "\\r".
.replaceAll(this.prefix + "\n", this.prefix + this.prefix + "n") // Replace a real newline with a literal "\\n".
;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class PowerShellEscaper extends AllSpecialCharactersEscaper {
constructor() {
super(...arguments);
this.prefix = "`"; // In PowerShell, escaping should use a ` character, e.g. "Hello, world!" becomes `"Hello`,` world`!`"
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function escapeValue(shell, raw_value) {
shell = extractFileName(shell.toLowerCase());
let escaper;
switch (shell) {
case "bash":
case "dash":
case "zsh":
case "sh": // May sometimes appear when using the "Use system default (sh)" option as a default shell.
escaper = new ShEscaper(raw_value);
break;
case "powershell.exe": // PowerShell 5 is only available for Windows.
case "pwsh.exe": // In Windows.
case "pwsh": // In Linux and Mac. (SC does not actually support using PowerShell on Linux/Mac just yet, but support can be added).
escaper = new PowerShellEscaper(raw_value);
break;
case "cmd.exe":
// Exception: There is no escaping support for CMD, so all values will be left unescaped when CMD is used. :(
return raw_value;
default:
// Shell was not recognised.
new obsidian.Notice("EscapeValue(): Unrecognised shell: " + shell);
throw new Error("EscapeValue(): Unrecognised shell: " + shell);
}
return escaper.escape();
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_Clipboard extends Variable {
constructor() {
super(...arguments);
this.variable_name = "clipboard";
this.help_text = "Gives the content you last copied to your clipboard.";
}
async generateValue() {
return electron.clipboard.readText();
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class EditorVariable extends Variable {
constructor() {
super(...arguments);
this.always_available = false;
}
getEditorOrThrow() {
const editor = getEditor(this.app);
if (null === editor) {
// No editor.
this.throw("Could not get an editor instance! Please create a discussion in GitHub.");
}
return editor;
}
/**
* Can be made protected if needed to be accessed by subclasses.
* @private
*/
getViewOrThrow() {
const view = getView(this.app);
if (null === view) {
// No view.
this.throw("Could not get a view instance! Please create a discussion in GitHub.");
}
return view;
}
requireViewModeSource() {
const view = this.getViewOrThrow();
const view_mode = view.getMode(); // "preview" or "source" ("live" was removed from Obsidian API in 0.13.8 on 2021-12-10).
switch (view_mode) {
case "preview":
// The leaf is in preview mode, which makes things difficult.
// FIXME: Make it possible to use this feature also in preview mode.
debugLog("EditorVariable: 'view' is in preview mode, and the poor guy who wrote this code, does not know how to return an editor instance that could be used for getting text selection.");
this.throw("You need to turn editing mode on, unfortunately this variable does not work in preview mode.");
break;
case "source":
// Good, the editor is in "source" mode, so it's possible to get a selection, caret position or other editing related information.
return;
default:
this.throw("Unrecognised view mode: " + view_mode);
break;
}
}
getAvailabilityText() {
return "<strong>Only available</strong> when a note pane is open, not in graph view, nor when viewing non-text files.";
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact:
* - Vinay Rajur: https://github.com/vrajur
* - Jarkko Linnanvirta: https://github.com/Taitava/
*/
class Variable_CaretPosition extends EditorVariable {
constructor() {
super(...arguments);
this.variable_name = "caret_position";
this.help_text = "Gives the line number and column position of the current caret position as 'line:column'. Get only the line number using {{caret_position:line}}, and only the column with {{caret_position:column}}. Line and column numbers are 1-indexed.";
}
async generateValue(castedArguments) {
// Check that we are able to get an editor
const editor = this.getEditorOrThrow();
const position = editor.getCursor('to');
const line = position.line + 1; // editor position is zero-indexed, line numbers are 1-indexed
const column = position.ch + 1; // editor position is zero-indexed, column positions are 1-indexed
if (undefined !== castedArguments.mode) {
switch (castedArguments.mode.toLowerCase()) {
case "line":
return `${line}`;
case "column":
return `${column}`;
default:
this.throw("Unrecognised argument: " + castedArguments.mode);
}
}
else {
// default case when no args provided
return `${line}:${column}`;
}
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + "}}",
help_text: "Gives the line number and column position of the current caret position as 'line:column'. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":line}}",
help_text: "Gives the line number of the current caret position. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":column}}",
help_text: "Gives the column number of the current caret position. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + "}}",
help_text: "Gives the line number and column position of the current caret position as 'line:column'. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":line}}",
help_text: "Gives the line number of the current caret position. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":column}}",
help_text: "Gives the column number of the current caret position. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{caret_position}}</strong>, <strong>{{caret_position:line}}</strong> or <strong>{{caret_position:column}}</strong>";
}
getAvailabilityText() {
return super.getAvailabilityText() + " Not available in preview mode.";
}
}
Variable_CaretPosition.parameters = {
mode: {
options: ["line", "column"],
required: false,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_Date extends Variable {
constructor() {
super(...arguments);
this.variable_name = "date";
this.help_text = "Gives a date/time stamp as per your liking. The \"format\" part can be customized and is mandatory. Formatting options: https://momentjs.com/docs/#/displaying/format/";
}
async generateValue(castedArguments) {
return obsidian.moment().format(castedArguments.format);
}
}
Variable_Date.parameters = {
format: {
type: "string",
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* TODO: Consider creating a decorator class for TFolder and moving this function to be a method in it.
*
* @param app
* @param folder
* @param mode
*/
function getFolderPath(app, folder, mode) {
switch (mode.toLowerCase()) {
case "absolute":
return normalizePath2(getVaultAbsolutePath(app) + "/" + folder.path);
case "relative":
if (folder.isRoot()) {
// Obsidian API does not give a correct folder.path value for the vault's root folder.
// TODO: See this discussion and apply possible changes if something will come up: https://forum.obsidian.md/t/vault-root-folders-relative-path-gives/24857
return ".";
}
else {
// This is a normal subfolder
return normalizePath2(folder.path); // Normalize to get a correct slash between directories depending on platform. On Windows it should be \ .
}
}
}
/**
* TODO: Consider creating a decorator class for TFile and moving this function to be a method in it.
*
* @param app
* @param file
* @param mode
*/
function getFilePath(app, file, mode) {
switch (mode.toLowerCase()) {
case "absolute":
return normalizePath2(getVaultAbsolutePath(app) + "/" + file.path);
case "relative":
return normalizePath2(file.path); // Normalize to get a correct slash depending on platform. On Windows it should be \ .
}
}
/**
* TODO: Consider creating a decorator class for TFile and moving this function to be a method in it.
* @param file
* @param with_dot
*/
function getFileExtension(file, with_dot) {
const file_extension = file.extension;
// Should the extension be given with or without a dot?
if (with_dot) {
// A preceding dot must be included.
if (file_extension.length > 0) {
// But only if the extension is not empty.
return "." + file_extension;
}
}
// No dot should be included, or the extension is empty
return file_extension;
}
function getFileTags(app, file) {
const cache = app.metadataCache.getFileCache(file);
if (!cache) {
throw new Error("Could not get metadata cache.");
}
// Get tags. May include duplicates, if a tag is defined multiple times in the same file.
const tagsIncludingDuplicates = obsidian.getAllTags(cache) ?? []; // ?? [] = in case null is returned, convert it to an empty array. I have no clue in which situation this might happen. Maybe if the file does not contain any tags?
// Iron out possible duplicates.
const tagsWithoutDuplicates = uniqueArray(tagsIncludingDuplicates);
// Remove preceding hash characters. E.g. #tag becomes tag
tagsWithoutDuplicates.forEach((tag, index) => {
tagsWithoutDuplicates[index] = tag.replace("#", "");
});
return tagsWithoutDuplicates;
}
/**
* @param app
* @param file
* @param property_path
* @return string|string[] Either a result string, or an array of error messages.
*/
function getFileYAMLValue(app, file, property_path) {
const error_messages = [];
const property_parts = property_path.split(".");
// Validate all property names along the path
property_parts.forEach((property_name) => {
if (0 === property_name.length) {
error_messages.push("YAML property '" + property_path + "' has an empty property name. Remove possible double dots or a preceding/trailing dot.");
}
});
if (error_messages.length > 0) {
// Failure in property name(s).
return error_messages;
}
const frontmatter = app.metadataCache.getFileCache(file)?.frontmatter;
// Check that a YAML section is available in the file
if (undefined === frontmatter) {
// No it ain't.
error_messages.push("No YAML frontmatter section is defined for the current file.");
return error_messages;
}
else {
// A YAML section is available.
// Read the property's value.
return nested_read(property_parts, property_path, frontmatter);
}
/**
* @param property_parts Property path split into parts (= property names). The deeper the nesting goes, the fewer values will be left in this array. This should always contain at least one part! If not, an Error is thrown.
* @param property_path The original, whole property path string.
* @param yaml_object
* @return string|string[] Either a result string, or an array of error messages.
*/
function nested_read(property_parts, property_path, yaml_object) {
// Check that property_parts contains at least one part.
if (property_parts.length === 0) {
throw new Error("No more property parts to read!");
}
let property_name = property_parts.shift(); // as string: Tell TypeScript that the result is not undefined, because the array is not empty.
// Check if the property name is a negative numeric index.
if (property_name.match(/^-\d+$/u)) {
// The property name is a negative number.
// Check that yaml_object contains at least one element.
const yaml_object_keys = Object.getOwnPropertyNames(yaml_object).filter(key => key !== "length"); // All _really custom_ yaml keys, not .length
if (yaml_object_keys.length > 0) {
// Check if yaml_object happens to be an indexed list.
let is_indexed_list = true;
yaml_object_keys.forEach((key) => {
if (!key.match(/^\d+$/u)) {
// At least one non-numeric key was found, so consider the object not to be an indexed list.
is_indexed_list = false;
}
});
if (is_indexed_list) {
// The object is an indexed list and property_name is a negative index number.
// Translate property_name to a positive index from the end of the list.
property_name = Math.max(0, // If a greatly negative index is used (e.g. -999), don't allow the new index to be negative again.
yaml_object_keys.length
+ parseInt(property_name) // Although + is used, this will be a subtraction, because property_name is prefixed with a minus.
).toString();
}
}
}
// Get a value
const property_value = yaml_object[property_name];
// Check if the value is either: not found, object, or literal.
if (undefined === property_value) {
// Property was not found.
error_messages.push("YAML property '" + property_name + "' is not found.");
return error_messages;
}
else if (null === property_value) {
// Property is found, but has an empty value. Example:
// ---
// itemA: valueA
// itemB:
// itemC: valueC
// ---
// Here `itemB` would have a null value.
error_messages.push("YAML property '" + property_name + "' has a null value. Make sure the property is not accidentally left empty.");
return error_messages;
}
else if ("object" === typeof property_value) {
// The value is an object.
// Check if we have still dot notation parts left in the property path.
if (0 === property_parts.length) {
// No dot notation parts are left.
// Freak out.
const nested_elements_keys = Object.getOwnPropertyNames(property_value);
if (nested_elements_keys.length > 0) {
error_messages.push("YAML property '" + property_name + "' contains a nested element with keys: " + nested_elements_keys.join(", ") + ". Use e.g. '" + property_path + "." + nested_elements_keys[0] + "' to get its value.");
}
else {
error_messages.push("YAML property '" + property_name + "' contains a nested element. Use a property name that points to a literal value instead.");
}
return error_messages;
}
else {
// Dot notation path still has another property name left, so continue the hunt.
return nested_read(property_parts, property_path, property_value);
}
}
else {
// The value is literal, i.e. a string or number.
if (property_parts.length > 0) {
error_messages.push("YAML property '" + property_name + "' gives already a literal value '" + property_value.toString() + "', but the argument '" + property_path + "' assumes the property would contain a nested element with the key '" + property_parts[0] + "'.");
return error_messages;
}
else {
return property_value.toString();
}
}
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class FileVariable extends Variable {
constructor() {
super(...arguments);
this.always_available = false;
}
getFileOrThrow() {
const currentFile = this.app.workspace.getActiveFile();
if (!currentFile) {
this.throw("No file is active at the moment. Open a file or click a pane that has a file open.");
}
return currentFile;
}
getAvailabilityText() {
return "<strong>Only available</strong> when the active pane contains a file, not in graph view or other non-file view.";
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_FileExtension extends FileVariable {
constructor() {
super(...arguments);
this.variable_name = "file_extension";
this.help_text = "Gives the current file name's ending. Use {{file_extension:with-dot}} to include a preceding dot. If the extension is empty, no dot is added. {{file_extension:no-dot}} never includes a dot.";
}
async generateValue(castedArguments) {
return getFileExtension(this.getFileOrThrow(), castedArguments.dot === "with-dot");
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":no-dot}}",
help_text: "Gives the current file name's ending without a preceding dot. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":with-dot}}",
help_text: "Gives the current file name's ending with a preceding dot. If the extension is empty, no dot is included. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":no-dot}}",
help_text: "Gives the current file name's ending without a preceding dot. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":with-dot}}",
help_text: "Gives the current file name's ending with a preceding dot. If the extension is empty, no dot is included. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{file_extension:with-dot}}</strong> or <strong>{{file_extension:no-dot}}</strong>";
}
}
Variable_FileExtension.parameters = {
"dot": {
options: ["with-dot", "no-dot"],
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_FileName extends FileVariable {
constructor() {
super(...arguments);
this.variable_name = "file_name";
this.help_text = "Gives the current file name with a file extension. If you need it without the extension, use {{title}} instead.";
}
async generateValue() {
return this.getFileOrThrow().name;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_FilePath extends FileVariable {
constructor() {
super(...arguments);
this.variable_name = "file_path";
this.help_text = "Gives path to the current file, either as absolute from the root of the file system, or as relative from the root of the Obsidian vault.";
}
async generateValue(castedArguments) {
return getFilePath(this.app, this.getFileOrThrow(), castedArguments.mode);
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":absolute}}",
help_text: "Gives path to the current file, absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":relative}}",
help_text: "Gives path to the current file, relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":absolute}}",
help_text: "Gives path to the current file, absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":relative}}",
help_text: "Gives path to the current file, relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{file_path:relative}}</strong> or <strong>{{file_path:absolute}}</strong>";
}
}
Variable_FilePath.parameters = {
mode: {
options: ["absolute", "relative"],
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class FolderVariable extends FileVariable {
getFolderOrThrow() {
// Get current file's parent folder.
const file = this.getFileOrThrow();
const currentFolder = file.parent;
if (!currentFolder) {
// No parent folder.
this.throw("The current file does not have a parent for some strange reason.");
}
return currentFolder;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_FolderName extends FolderVariable {
constructor() {
super(...arguments);
this.variable_name = "folder_name";
this.help_text = "Gives the current file's parent folder name, or a dot if the folder is the vault's root. No ancestor folders are included.";
}
async generateValue() {
const folder = this.getFolderOrThrow();
return folder.isRoot()
? "." // Return a dot instead of an empty string.
: folder.name;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_FolderPath extends FolderVariable {
constructor() {
super(...arguments);
this.variable_name = "folder_path";
this.help_text = "Gives path to the current file's parent folder, either as absolute from the root of the file system, or as relative from the root of the Obsidian vault.";
}
async generateValue(castedArguments) {
return getFolderPath(this.app, this.getFolderOrThrow(), castedArguments.mode);
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":absolute}}",
help_text: "Gives path to the current file's parent folder, absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":relative}}",
help_text: "Gives path to the current file's parent folder, relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":absolute}}",
help_text: "Gives path to the current file's parent folder, absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":relative}}",
help_text: "Gives path to the current file's parent folder, relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{folder_path:relative}}</strong> or <strong>{{folder_path:absolute}}</strong>";
}
}
Variable_FolderPath.parameters = {
mode: {
options: ["absolute", "relative"],
required: true,
}
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_Selection extends EditorVariable {
constructor() {
super(...arguments);
this.variable_name = "selection";
this.help_text = "Gives the currently selected text.";
}
async generateValue() {
// Check that we are able to get an editor
const editor = this.getEditorOrThrow();
// Check the view mode
this.requireViewModeSource();
// Good, the editor is in "source" mode, so it's possible to get a selection.
if (editor.somethingSelected()) {
return editor.getSelection();
}
this.throw("Nothing is selected. " + os.EOL + os.EOL + "(This error message was added in SC 0.18.0. Earlier the variable gave an empty text in this situation. If you want to restore the old behavior, go to SC settings, then to Variables tab, and define a default value for {{selection}}.)");
}
getAvailabilityText() {
return "<strong>Only available</strong> when something is selected in <em>Editing</em>/<em>Live preview</em> mode, <strong>not</strong> in <em>Reading</em> mode.";
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_Tags extends FileVariable {
constructor() {
super(...arguments);
this.variable_name = "tags";
this.help_text = "Gives all tags defined in the current note. Replace the \"separator\" part with a comma, space or whatever characters you want to use as a separator between tags. A separator is always needed to be defined.";
}
async generateValue(castedArguments) {
return getFileTags(this.app, this.getFileOrThrow()).join(castedArguments.separator);
}
}
Variable_Tags.parameters = {
separator: {
type: "string",
required: true,
}
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_Title extends FileVariable {
constructor() {
super(...arguments);
this.variable_name = "title";
this.help_text = "Gives the current file name without a file extension. If you need it with the extension, use {{file_name}} instead.";
}
async generateValue() {
return this.getFileOrThrow().basename;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_VaultPath extends Variable {
constructor() {
super(...arguments);
this.variable_name = "vault_path";
this.help_text = "Gives the Obsidian vault's absolute path from the root of the filesystem. This is the same that is used as a default working directory if you do not define one manually. If you define a working directory manually, this variable won't give you your manually defined directory, it always gives the vault's root directory.";
}
async generateValue() {
return getVaultAbsolutePath(this.app);
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_Workspace extends Variable {
constructor() {
super(...arguments);
this.variable_name = "workspace";
this.help_text = "Gives the current workspace's name.";
this.always_available = false;
}
async generateValue() {
// Idea how to access the workspaces plugin is copied 2021-09-15 from https://github.com/Vinzent03/obsidian-advanced-uri/blob/f7ef80d5252481242e69496208e925874209f4aa/main.ts#L168-L179
// @ts-ignore internalPlugins exists, although it's not in obsidian.d.ts.
const workspaces_plugin = this.app.internalPlugins?.plugins?.workspaces;
if (!workspaces_plugin) {
this.throw("Workspaces core plugin is not found for some reason. Please create a discussion in GitHub.");
}
else if (!workspaces_plugin.enabled) {
this.throw("Workspaces core plugin is not enabled.");
}
const workspace_name = workspaces_plugin.instance?.activeWorkspace;
if (!workspace_name) {
this.throw("Could not figure out the current workspace's name. Probably you have not loaded a workspace. You can do it e.g. via \"Manage workspaces\" from the left side panel.");
}
// All ok
return workspace_name;
}
getAvailabilityText() {
return "<strong>Only available</strong> when the Workspaces core plugin is enabled.";
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_Passthrough extends Variable {
constructor() {
super(...arguments);
this.variable_name = "passthrough";
this.help_text = "Gives the same value that is passed as an argument. Used for testing special characters' escaping.";
}
async generateValue(castedArguments) {
// Simply return the argument that was received.
return castedArguments.value;
}
getAvailabilityText() {
return "<strong>Only available</strong> in debug mode.";
}
}
Variable_Passthrough.parameters = {
value: {
type: "string",
required: true,
}
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_YAMLValue extends FileVariable {
constructor() {
super(...arguments);
this.variable_name = "yaml_value";
this.help_text = "Reads a single value from the current file's frontmatter. Takes a property name as an argument. You can access nested properties with dot notation: property1.property2";
}
async generateValue(castedArguments) {
// We do have an active file
const result = getFileYAMLValue(this.app, this.getFileOrThrow(), castedArguments.property_name);
if (Array.isArray(result)) {
// The result contains error message(s).
this.throw(result.join(" "));
}
else {
// The result is ok, it's a string.
return result;
}
}
getAvailabilityText() {
return super.getAvailabilityText() + " Also, the given YAML property must exist in the file's frontmatter.";
}
getHelpName() {
return "<strong>{{yaml_value:property}}</strong>";
}
}
Variable_YAMLValue.parameters = {
property_name: {
type: "string",
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class EventVariable extends Variable {
constructor() {
super(...arguments);
this.always_available = false;
}
/**
* Every subclass should call this method in their generateValue() before generating a value. This method will throw
* a VariableError if an incompatible SC_Event is tried to be used with this {{variable}}.
*
* @protected
*/
requireCorrectEvent(sc_event) {
// 1. Check generally that an event is happening.
// (Maybe this check is not so important anymore, as sc_event is now received as a parameter instead of from a property, but check just in case.)
if (!sc_event) {
this.throw("This variable can only be used during events: " + this.getSummaryOfSupportedEvents());
}
// 2. Check particularly which event it is.
if (!this.supportsSC_Event(sc_event.getClass())) {
this.throw("This variable does not support event '" + sc_event.static().getTitle() + "'. Supported events: " + this.getSummaryOfSupportedEvents());
}
}
supportsSC_Event(sc_event_class) {
return this.supported_sc_events.contains(sc_event_class);
}
getSummaryOfSupportedEvents() {
const sc_event_titles = [];
this.supported_sc_events.forEach((sc_event_class) => {
sc_event_titles.push(sc_event_class.getTitle());
});
return sc_event_titles.join(", ");
}
getAvailabilityText() {
return "<strong>Only available</strong> in events: " + this.getSummaryOfSupportedEvents() + ".";
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* Named SC_Event instead of just Event, because Event is a class in JavaScript.
*/
class SC_Event {
constructor(plugin) {
/**
* If true, changing the enabled/disabled status of the event permits registering the event immediately, so it can activate
* anytime. Usually true, but can be set to false if immediate registering tends to trigger the event unnecessarily.
*
* Events are always registered when loading the plugin, regardless of this property.
* @protected
*/
this.register_after_changing_settings = true;
this.event_registrations = {};
this.default_configuration = {
enabled: false,
};
this.plugin = plugin;
this.app = plugin.app;
this.subclass_instance = this; // Stores a subclass reference, not a base class reference.
}
getClass() {
return this.subclass_instance.constructor;
}
canRegisterAfterChangingSettings() {
return this.register_after_changing_settings;
}
register(t_shell_command) {
const event_reference = this._register(t_shell_command);
if (event_reference) {
this.plugin.registerEvent(event_reference);
this.event_registrations[t_shell_command.getId()] = event_reference;
}
}
unregister(t_shell_command) {
// Check if an EventRef is available.
if (undefined === this.event_registrations[t_shell_command.getId()]) {
// The event was registered without an EventRef object.
// Provide a TShellCommand to _unregister() so it can do a custom unregistering.
this._unregister(t_shell_command);
}
else {
// The event registration had created an EventRef object.
// Provide the EventRef to _unregister() and forget it afterwards.
this._unregister(this.event_registrations[t_shell_command.getId()]);
delete this.event_registrations[t_shell_command.getId()];
}
}
/**
* Executes a shell command.
* @param t_shell_command
* @param parsing_process SC_MenuEvent can use this to pass an already started ParsingProcess instance. If omitted, a new ParsingProcess will be created.
*/
async trigger(t_shell_command, parsing_process) {
// Execute the shell command.
const executor = new ShellCommandExecutor(this.plugin, t_shell_command, this);
await executor.doPreactionsAndExecuteShellCommand(parsing_process);
}
static getCode() {
return this.event_code;
}
static getTitle() {
return this.event_title;
}
/**
* Creates a list of variables to the given container element. Each variable is a link to its documentation.
*
* @param container
* @return A boolean indicating whether anything was created or not. Not all SC_Events utilise event variables.
*/
createSummaryOfEventVariables(container) {
let hasCreatedElements = false;
this.getEventVariables().forEach((variable) => {
if (hasCreatedElements) {
container.insertAdjacentText("beforeend", ", ");
}
hasCreatedElements = true;
variable.createDocumentationLinkElement(container);
});
return hasCreatedElements;
}
getEventVariables() {
const event_variables = [];
this.plugin.getVariables().forEach((variable) => {
// Check if the variable is an EventVariable
if (variable instanceof EventVariable) {
// Yes it is.
// Check if the variable supports this particular event.
if (variable.supportsSC_Event(this.getClass())) {
// Yes it supports.
event_variables.push(variable);
}
}
});
return event_variables;
}
/**
* Can be overridden in child classes that need custom settings fields.
*
* @param enabled
*/
getDefaultConfiguration(enabled) {
const configuration = cloneObject(this.default_configuration);
configuration.enabled = enabled;
return configuration;
}
getConfiguration(t_shell_command) {
return t_shell_command.getEventConfiguration(this);
}
/**
* Can be overridden in child classes to provide custom configuration fields for ShellCommandsExtraOptionsModal.
*
* @param extra_settings_container
*/
createExtraSettingsFields(extra_settings_container, t_shell_command) {
// Most classes do not define custom settings, so for those classes this method does not need to do anything.
}
/**
* Returns all the TShellCommand instances that have enabled this event.
*/
getTShellCommands() {
const enabled_t_shell_commands = [];
Object.values(this.plugin.getTShellCommands()).forEach((t_shell_command) => {
// Check if this event has been enabled for the shell command.
if (t_shell_command.isSC_EventEnabled(this.static().event_code)) {
// Yes, it's enabled.
enabled_t_shell_commands.push(t_shell_command);
}
});
return enabled_t_shell_commands;
}
static() {
return this.constructor;
}
/**
* Child classes can override this to hook into a situation where a user has enabled an event in settings.
*
* @param t_shell_command The TShellCommand instance for which this SC_Event was enabled for.
*/
onAfterEnabling(t_shell_command) {
// If an SC_Event does not override this hook method, do nothing.
}
static getDocumentationLink() {
return DocumentationEventsFolderLink + encodeURIComponent(this.event_title);
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_WorkspaceEvent extends SC_Event {
_register(t_shell_command) {
// @ts-ignore TODO: Find a way to get a dynamic type for this.workspace_event .
return this.app.workspace.on(this.workspace_event, this.getTrigger(t_shell_command));
}
_unregister(event_reference) {
this.app.workspace.offref(event_reference);
}
getTrigger(t_shell_command) {
return async (...parameters /* Need to have this ugly parameter thing so that subclasses can define their own parameters. */) => await this.trigger(t_shell_command);
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_MenuEvent extends SC_WorkspaceEvent {
async addTShellCommandToMenu(t_shell_command, menu) {
// Create the menu item as soon as possible. (If it's created after 'await parsing_process.process()' below, it won't be shown in the menu for some reason, at least in Obsidian 0.16.1).
menu.addItem(async (menuItem) => {
// Parse shell command variables to get a title
let title = t_shell_command.getAliasOrShellCommand(); // May contain unparsed variables.
let parsing_process;
if (this.plugin.settings.preview_variables_in_command_palette) {
// Start a parsing process
parsing_process = t_shell_command.createParsingProcess(this);
if (await parsing_process.process()) {
// Parsing succeeded.
const parsing_results = parsing_process.getParsingResults();
const aliasParsingResult = parsing_results["alias"]; // as ParsingResult: Tells TypeScript that the object exists.
const shellCommandParsingResult = parsing_results["shell_command"]; // as ParsingResult: Tells TypeScript that the object exists.
title = aliasParsingResult.parsed_content || shellCommandParsingResult.parsed_content; // Try to use a parsed alias, but if no alias is available, use a parsed shell command instead. as string = parsed shell command always exist when the parsing itself has succeeded.
}
// If parsing process fails, the failed process can be passed to this.trigger(). The execution will eventually be cancelled and error messages displayed (if displaying is allowed).
}
// Set menu item title - be it parsed or not.
menuItem.setTitle(title);
// Icon and onClick handler.
menuItem
.setIcon(t_shell_command.getIconId()) // Icon id can be null.
.onClick(async () => {
await this.trigger(t_shell_command, parsing_process);
});
});
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_AbstractFileMenuEvent extends SC_MenuEvent {
constructor() {
super(...arguments);
this.workspace_event = "file-menu";
}
getTrigger(t_shell_command) {
return async (menu, file, source, leaf) => {
// Check that it's the correct menu: if the SC_Event requires a file menu, 'file' needs to be a TFile, otherwise it needs to be a TFolder.
if ((this.file_or_folder === "folder" && file instanceof obsidian.TFolder) || (this.file_or_folder === "file" && file instanceof obsidian.TFile)) {
// The menu is correct.
// File/folder for declareExtraVariables()
switch (this.file_or_folder) {
case "file":
this.file = file;
break;
case "folder":
this.folder = file;
break;
}
await this.addTShellCommandToMenu(t_shell_command, menu);
}
};
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FileMenu extends SC_AbstractFileMenuEvent {
constructor() {
super(...arguments);
this.file_or_folder = "file";
}
getFile() {
return this.file;
}
getFolder() {
return this.file.parent;
}
}
SC_Event_FileMenu.event_code = "file-menu";
SC_Event_FileMenu.event_title = "File menu";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_VaultEvent extends SC_Event {
_register(t_shell_command) {
// @ts-ignore TODO: Find a way to get a dynamic type for this.vault_event .
return this.app.vault.on(this.vault_event, this.getTrigger(t_shell_command));
}
_unregister(event_reference) {
this.app.vault.offref(event_reference);
}
getTrigger(t_shell_command) {
return async (file, ...extra_arguments /* Needed for SC_Event_FileRenamed and SC_Event_FolderRenamed to be able to define an additional parameter.*/) => {
// Check that it's the correct type of file: if the SC_Event requires a file, 'file' needs to be a TFile, otherwise it needs to be a TFolder.
if ((this.file_or_folder === "folder" && file instanceof obsidian.TFolder) || (this.file_or_folder === "file" && file instanceof obsidian.TFile)) {
// The file type is correct.
// File/folder for declareExtraVariables()
switch (this.file_or_folder) {
case "file":
this.file = file;
break;
case "folder":
this.folder = file;
break;
}
await this.trigger(t_shell_command);
}
};
}
/**
* This should only be called if file_or_folder is "file"!
*/
getFile() {
return this.file;
}
/**
* This can be called whether file_or_folder is "file" or "folder".
*/
getFolder() {
switch (this.file_or_folder) {
case "file":
return this.file.parent;
case "folder":
return this.folder;
}
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FileCreated extends SC_VaultEvent {
constructor() {
super(...arguments);
this.vault_event = "create";
this.file_or_folder = "file";
}
}
SC_Event_FileCreated.event_code = "file-created";
SC_Event_FileCreated.event_title = "File created";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FileContentModified extends SC_VaultEvent {
constructor() {
super(...arguments);
this.vault_event = "modify";
this.file_or_folder = "file";
}
}
SC_Event_FileContentModified.event_code = "file-content-modified";
SC_Event_FileContentModified.event_title = "File content modified";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FileDeleted extends SC_VaultEvent {
constructor() {
super(...arguments);
this.vault_event = "delete";
this.file_or_folder = "file";
}
}
SC_Event_FileDeleted.event_code = "file-deleted";
SC_Event_FileDeleted.event_title = "File deleted";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_VaultMoveOrRenameEvent extends SC_VaultEvent {
constructor() {
super(...arguments);
this.vault_event = "rename";
}
getTrigger(t_shell_command) {
// Get a trigger from the parent class (SC_VaultEvent).
const trigger = super.getTrigger(t_shell_command);
return async (abstract_file, old_relative_path) => {
// Detect if the file/folder was moved or renamed.
// If the file/folder name has stayed the same, conclude that the file has been MOVED, not renamed. Otherwise, conclude the opposite.
const old_file_name = extractFileName(old_relative_path);
const new_file_name = abstract_file.name;
const event_type = (old_file_name === new_file_name) ? "move" : "rename"; // Tells what really happened. this.move_or_rename tells what is the condition for the event to trigger.
// Only proceed the triggering, if the determined type equals the one defined by the event class.
if (event_type === this.move_or_rename) {
// The event type is correct.
// File and folder for declareExtraVariables()
switch (this.file_or_folder) {
case "file":
this.file_old_relative_path = old_relative_path;
this.folder_old_relative_path = extractFileParentPath(old_relative_path);
break;
case "folder":
this.folder_old_relative_path = old_relative_path;
break;
}
// Call the normal trigger function.
await trigger(abstract_file);
}
};
}
getFolderOldRelativePath() {
return this.folder_old_relative_path;
}
getFileOldRelativePath() {
return this.file_old_relative_path;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FileRenamed extends SC_VaultMoveOrRenameEvent {
constructor() {
super(...arguments);
this.move_or_rename = "rename";
this.file_or_folder = "file";
}
}
SC_Event_FileRenamed.event_code = "file-renamed";
SC_Event_FileRenamed.event_title = "File renamed";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FileMoved extends SC_VaultMoveOrRenameEvent {
constructor() {
super(...arguments);
this.move_or_rename = "move";
this.file_or_folder = "file";
}
}
SC_Event_FileMoved.event_code = "file-moved";
SC_Event_FileMoved.event_title = "File moved";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventFileName extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_file_name";
this.help_text = "Gives the event related file name with a file extension. If you need it without the extension, use {{event_title}} instead.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
async generateValue(argumentsAreNotUsed, sc_event) {
this.requireCorrectEvent(sc_event);
return sc_event.getFile().name;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventFilePath extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_file_path";
this.help_text = "Gives path to the event related file, either as absolute from the root of the file system, or as relative from the root of the Obsidian vault.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
async generateValue(castedArguments, sc_event) {
this.requireCorrectEvent(sc_event);
return getFilePath(this.app, sc_event.getFile(), castedArguments.mode);
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":absolute}}",
help_text: "Gives path to the event related file, absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":relative}}",
help_text: "Gives path to the event related file, relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":absolute}}",
help_text: "Gives path to the event related file, absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":relative}}",
help_text: "Gives path to the event related file, relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{event_file_path:relative}}</strong> or <strong>{{event_file_path:absolute}}</strong>";
}
}
Variable_EventFilePath.parameters = {
mode: {
options: ["absolute", "relative"],
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FolderMenu extends SC_AbstractFileMenuEvent {
constructor() {
super(...arguments);
this.file_or_folder = "folder";
}
getFolder() {
return this.folder;
}
}
SC_Event_FolderMenu.event_code = "folder-menu";
SC_Event_FolderMenu.event_title = "Folder menu";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FolderCreated extends SC_VaultEvent {
constructor() {
super(...arguments);
this.vault_event = "create";
this.file_or_folder = "folder";
}
}
SC_Event_FolderCreated.event_code = "folder-created";
SC_Event_FolderCreated.event_title = "Folder created";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FolderDeleted extends SC_VaultEvent {
constructor() {
super(...arguments);
this.vault_event = "delete";
this.file_or_folder = "folder";
}
}
SC_Event_FolderDeleted.event_code = "folder-deleted";
SC_Event_FolderDeleted.event_title = "Folder deleted";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FolderRenamed extends SC_VaultMoveOrRenameEvent {
constructor() {
super(...arguments);
this.move_or_rename = "rename";
this.file_or_folder = "folder";
}
}
SC_Event_FolderRenamed.event_code = "folder-renamed";
SC_Event_FolderRenamed.event_title = "Folder renamed";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_FolderMoved extends SC_VaultMoveOrRenameEvent {
constructor() {
super(...arguments);
this.move_or_rename = "move";
this.file_or_folder = "folder";
}
}
SC_Event_FolderMoved.event_code = "folder-moved";
SC_Event_FolderMoved.event_title = "Folder moved";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventFolderName extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_folder_name";
this.help_text = "File events: Gives the event related file's parent folder name. Folder events: Gives the selected folder's name. Gives a dot if the folder is the vault's root. No ancestor folders are included.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FolderMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
SC_Event_FolderCreated,
SC_Event_FolderDeleted,
SC_Event_FolderMoved,
SC_Event_FolderRenamed,
];
}
async generateValue(argumentsAreNotUsed, sc_event) {
this.requireCorrectEvent(sc_event);
const folder = sc_event.getFolder();
return folder.isRoot()
? "." // Return a dot instead of an empty string.
: folder.name;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventFolderPath extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_folder_path";
this.help_text = "File events: Gives path to the event related file's parent folder. Folder events: Gives path to the event related folder. The path is either absolute from the root of the file system, or relative from the root of the Obsidian vault.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FolderMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
SC_Event_FolderCreated,
SC_Event_FolderDeleted,
SC_Event_FolderMoved,
SC_Event_FolderRenamed,
];
}
async generateValue(castedArguments, sc_event) {
this.requireCorrectEvent(sc_event);
return getFolderPath(this.app, sc_event.getFolder(), castedArguments.mode);
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":absolute}}",
help_text: "File events: Gives path to the event related file's parent folder. Folder events: Gives path to the event related folder. The path is absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":relative}}",
help_text: "File events: Gives path to the event related file's parent folder. Folder events: Gives path to the event related folder. The path is relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":absolute}}",
help_text: "File events: Gives path to the event related file's parent folder. Folder events: Gives path to the event related folder. The path is absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":relative}}",
help_text: "File events: Gives path to the event related file's parent folder. Folder events: Gives path to the event related folder. The path is relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{event_folder_path:relative}}</strong> or <strong>{{event_folder_path:absolute}}</strong>";
}
}
Variable_EventFolderPath.parameters = {
mode: {
options: ["absolute", "relative"],
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventTitle extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_title";
this.help_text = "Gives the event related file name without a file extension. If you need it with the extension, use {{event_file_name}} instead.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
async generateValue(argumentsAreNotUsed, sc_event) {
this.requireCorrectEvent(sc_event);
return sc_event.getFile().basename;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventFileExtension extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_file_extension";
this.help_text = "Gives the event related file name's ending. Use {{event_file_extension:with-dot}} to include a preceding dot. If the extension is empty, no dot is added. {{event_file_extension:no-dot}} never includes a dot.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
async generateValue(castedArguments, sc_event) {
this.requireCorrectEvent(sc_event);
return getFileExtension(sc_event.getFile(), castedArguments.dot === "with-dot");
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":no-dot}}",
help_text: "Gives the event related file name's ending without a preceding dot. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":with-dot}}",
help_text: "Gives the event related file name's ending with a preceding dot. If the extension is empty, no dot is included. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":no-dot}}",
help_text: "Gives the event related file name's ending without a preceding dot. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":with-dot}}",
help_text: "Gives the event related file name's ending with a preceding dot. If the extension is empty, no dot is included. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{event_file_extension:with-dot}}</strong> or <strong>{{event_file_extension:no-dot}}</strong>";
}
}
Variable_EventFileExtension.parameters = {
"dot": {
options: ["with-dot", "no-dot"],
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventTags extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_tags";
this.help_text = "Gives all tags defined in the event related note. Replace the \"separator\" part with a comma, space or whatever characters you want to use as a separator between tags. A separator is always needed to be defined.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
async generateValue(castedArguments, sc_event) {
this.requireCorrectEvent(sc_event);
const file = sc_event.getFile();
return getFileTags(this.app, file).join(castedArguments.separator);
}
}
Variable_EventTags.parameters = {
separator: {
type: "string",
required: true,
}
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventYAMLValue extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_yaml_value";
this.help_text = "Reads a single value from the event related file's frontmatter. Takes a property name as an argument. You can access nested properties with dot notation: property1.property2";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
async generateValue(castedArguments, sc_event) {
this.requireCorrectEvent(sc_event);
const result = getFileYAMLValue(this.app, sc_event.getFile(), castedArguments.property_name);
if (Array.isArray(result)) {
// The result contains error message(s).
this.throw(result.join(" "));
}
else {
// The result is ok, it's a string.
return result;
}
}
getAvailabilityText() {
return super.getAvailabilityText() + " Also, the given YAML property must exist in the file's frontmatter.";
}
getHelpName() {
return "<strong>{{event_yaml_value:property}}</strong>";
}
}
Variable_EventYAMLValue.parameters = {
property_name: {
type: "string",
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_Environment extends Variable {
constructor() {
super(...arguments);
this.variable_name = "environment";
this.help_text = "Gives an environment variable's value. It's an original value received when Obsidian was started.";
this.always_available = false;
}
async generateValue(castedArguments) {
// Check that the requested environment variable exists.
if (undefined !== process.env[castedArguments.variable]) {
// Yes, it exists.
return process.env[castedArguments.variable]; // as string: tells TypeScript compiler that the item exists, is not undefined.
}
else {
// It does not exist.
// Freak out.
this.throw(`Environment variable named '${castedArguments.variable}' does not exist.`);
}
}
getHelpName() {
return "<strong>{{environment:variable}}</strong>";
}
getAvailabilityText() {
return "<strong>Only available</strong> if the passed environment variable name exists.";
}
}
Variable_Environment.parameters = {
variable: {
type: "string",
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventOldFileName extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_old_file_name";
this.help_text = "Gives the renamed file's old name with a file extension. If you need it without the extension, use {{event_old_title}} instead.";
this.supported_sc_events = [
SC_Event_FileRenamed,
];
}
async generateValue(argumentsAreNotUsed, sc_event) {
this.requireCorrectEvent(sc_event);
return extractFileName(sc_event.getFileOldRelativePath(), true);
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventOldFilePath extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_old_file_path";
this.help_text = "Gives the renamed/moved file's old path, either as absolute from the root of the file system, or as relative from the root of the Obsidian vault.";
this.supported_sc_events = [
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
async generateValue(castedArguments, sc_event) {
this.requireCorrectEvent(sc_event);
const file_old_relative_path = sc_event.getFileOldRelativePath();
switch (castedArguments.mode.toLowerCase()) {
case "relative":
return normalizePath2(file_old_relative_path);
case "absolute":
return normalizePath2(getVaultAbsolutePath(this.app) + "/" + file_old_relative_path);
}
this.throw("Unrecognized mode parameter: " + castedArguments.mode);
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":absolute}}",
help_text: "Gives the renamed/moved file's old path, absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":relative}}",
help_text: "Gives the renamed/moved file's old path, relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":absolute}}",
help_text: "Gives the renamed/moved file's old path, absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":relative}}",
help_text: "Gives the renamed/moved file's old path, relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{event_file_path:relative}}</strong> or <strong>{{event_file_path:absolute}}</strong>";
}
}
Variable_EventOldFilePath.parameters = {
mode: {
options: ["absolute", "relative"],
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventOldFolderName extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_old_folder_name";
this.help_text = "File events: Gives the moved file's old parent folder's name. Folder events: Gives the renamed folder's old name.";
this.supported_sc_events = [
SC_Event_FileMoved,
SC_Event_FolderRenamed,
];
}
async generateValue(argumentsAreNotUsed, sc_event) {
this.requireCorrectEvent(sc_event);
return extractFileName(sc_event.getFolderOldRelativePath());
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventOldFolderPath extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_old_folder_path";
this.help_text = "File events: Gives the moved file's old parent folder's path. Folder events: Gives the renamed/moved folder's old path. The path is either as absolute from the root of the file system, or as relative from the root of the Obsidian vault.";
this.supported_sc_events = [
SC_Event_FileMoved,
SC_Event_FolderMoved,
SC_Event_FolderRenamed,
];
}
async generateValue(castedArguments, sc_event) {
this.requireCorrectEvent(sc_event);
const folder_old_relative_path = sc_event.getFolderOldRelativePath();
switch (castedArguments.mode.toLowerCase()) {
case "relative":
return normalizePath2(folder_old_relative_path);
case "absolute":
return normalizePath2(getVaultAbsolutePath(this.app) + "/" + folder_old_relative_path);
}
this.throw("Unrecognized mode parameter: " + castedArguments.mode);
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":absolute}}",
help_text: "File events: Gives the moved file's old parent folder's path. Folder events: Gives the renamed/moved folder's old path. The path is absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":relative}}",
help_text: "File events: Gives the moved file's old parent folder's path. Folder events: Gives the renamed/moved folder's old path. The path is relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":absolute}}",
help_text: "File events: Gives the moved file's old parent folder's path. Folder events: Gives the renamed/moved folder's old path. The path is absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":relative}}",
help_text: "File events: Gives the moved file's old parent folder's path. Folder events: Gives the renamed/moved folder's old path. The path is relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{event_file_path:relative}}</strong> or <strong>{{event_file_path:absolute}}</strong>";
}
}
Variable_EventOldFolderPath.parameters = {
mode: {
options: ["absolute", "relative"],
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventOldTitle extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_old_title";
this.help_text = "Gives the renamed file's old name without a file extension. If you need it with the extension, use {{event_old_file_name}} instead.";
this.supported_sc_events = [
SC_Event_FileRenamed,
];
}
async generateValue(argumentsAreNotUsed, sc_event) {
this.requireCorrectEvent(sc_event);
return extractFileName(sc_event.getFileOldRelativePath(), false);
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_NewNoteFolderName extends Variable {
constructor() {
super(...arguments);
this.variable_name = "new_note_folder_name";
this.help_text = "Gives the folder name for \"Default location for new notes\" (a setting in Obsidian). No ancestor folders are included.";
}
async generateValue() {
const current_file = this.app.workspace.getActiveFile(); // Needed just in case new notes should be created in the same folder as the currently open file.
const folder = this.app.fileManager.getNewFileParent(current_file ? current_file.path : ""); // If no file is open, use an empty string as instructed in .getNewFileParent()'s documentation.
if (!folder) {
this.throw("Cannot determine a folder name for new notes. Please create a discussion in GitHub."); // I guess this never happens.
}
// If the folder is the vault's root folder, return "." instead of " " (a space character). I don't know why the name is " " when the folder is root.
return folder.isRoot()
? "."
: folder.name;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_NewNoteFolderPath extends Variable {
constructor() {
super(...arguments);
this.variable_name = "new_note_folder_path";
this.help_text = "Gives path to the \"Default location for new notes\" folder (a setting in Obsidian), either as absolute from the root of the file system, or as relative from the root of the Obsidian vault.";
}
async generateValue(castedArguments) {
const current_file = this.app.workspace.getActiveFile(); // Needed just in case new notes should be created in the same folder as the currently open file.
const folder = this.app.fileManager.getNewFileParent(current_file ? current_file.path : ""); // If no file is open, use an empty string as instructed in .getNewFileParent()'s documentation.
if (folder) {
return getFolderPath(this.app, folder, castedArguments.mode);
}
else {
this.throw("Cannot determine a folder path for new notes. Please create a discussion in GitHub."); // I guess this never happens.
}
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":absolute}}",
help_text: "Gives path to the \"Default location for new notes\" folder (a setting in Obsidian), absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":relative}}",
help_text: "Gives path to the \"Default location for new notes\" folder (a setting in Obsidian), relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":absolute}}",
help_text: "Gives path to the \"Default location for new notes\" folder (a setting in Obsidian), absolute from the root of the file system. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":relative}}",
help_text: "Gives path to the \"Default location for new notes\" folder (a setting in Obsidian), relative from the root of the Obsidian vault. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{folder_path:relative}}</strong> or <strong>{{folder_path:absolute}}</strong>";
}
}
Variable_NewNoteFolderPath.parameters = {
mode: {
options: ["absolute", "relative"],
required: true,
}
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_FileURI extends FileVariable {
constructor() {
super(...arguments);
this.variable_name = "file_uri";
this.help_text = "Gives an Obsidian URI that opens the current file.";
}
async generateValue() {
return this.plugin.getObsidianURI("open", {
file: obsidian.normalizePath(this.getFileOrThrow().path), // Use normalizePath() instead of normalizePath2() because / should not be converted to \ on Windows because this is used as a URI, not as a file system path.
});
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventFileURI extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_file_uri";
this.help_text = "Gives an Obsidian URI that opens the event related file.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
async generateValue(argumentsAreNotUsed, sc_event) {
this.requireCorrectEvent(sc_event);
const file = sc_event.getFile();
return this.plugin.getObsidianURI("open", {
file: obsidian.normalizePath(file.path), // Use normalizePath() instead of normalizePath2() because / should not be converted to \ on Windows because this is used as a URI, not as a file system path.
});
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_NoteContent extends FileVariable {
constructor() {
super(...arguments);
this.variable_name = "note_content";
this.help_text = "Gives the current note's content without YAML frontmatter. If you need YAML included, use {{file_content}} instead.";
}
async generateValue() {
return await getFileContentWithoutYAML(this.app, this.getFileOrThrow());
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventNoteContent extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_note_content";
this.help_text = "Gives the event related file's content without YAML frontmatter. If you need YAML included, use {{event_file_content}} instead.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
async generateValue(argumentsAreNotUsed, sc_event) {
this.requireCorrectEvent(sc_event);
return await getFileContentWithoutYAML(this.app, sc_event.getFile());
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_FileContent extends FileVariable {
constructor() {
super(...arguments);
this.variable_name = "file_content";
this.help_text = "Gives the current file's content, including YAML frontmatter. If you need YAML excluded, use {{note_content}} instead.";
}
async generateValue() {
// Retrieve file content.
return await app.vault.read(this.getFileOrThrow());
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventFileContent extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_file_content";
this.help_text = "Gives the event related file's content, including YAML frontmatter. If you need YAML excluded, use {{event_note_content}} instead.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
async generateValue(argumentsAreNotUsed, sc_event) {
this.requireCorrectEvent(sc_event);
// Retrieve file content.
return await app.vault.read(sc_event.getFile());
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_CaretParagraph extends EditorVariable {
constructor() {
super(...arguments);
this.variable_name = "caret_paragraph";
this.help_text = "Gives a text line at the current caret position.";
}
async generateValue() {
const editor = this.getEditorOrThrow();
this.requireViewModeSource();
const caretPosition = editor.getCursor('to');
return editor.getLine(caretPosition.line);
}
getAvailabilityText() {
return super.getAvailabilityText() + " Not available in preview mode.";
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_Newline extends Variable {
constructor() {
super(...arguments);
this.variable_name = "newline";
this.help_text = "Gives a \\n character. Used for testing line break escaping. An optional argument can be used to tell how many newlines are needed.";
}
async generateValue(castedArguments) {
// Return \n, possibly repeating it
return "\n".repeat(castedArguments.count ?? 1);
}
getAvailabilityText() {
return "<strong>Only available</strong> in debug mode.";
}
}
Variable_Newline.parameters = {
count: {
type: "integer",
required: false,
}
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_YAMLContent extends FileVariable {
constructor() {
super(...arguments);
this.variable_name = "yaml_content";
this.help_text = "Gives the current note's YAML frontmatter. Dashes --- can be included or excluded.";
}
generateValue(castedArguments) {
return new Promise((resolve, reject) => {
let file;
try {
file = this.getFileOrThrow();
}
catch (error) {
// Need to catch here, because Variable.getValue()'s .catch() block won't be able to catch thrown errors,
// it can only catch errors that were passed to reject().
reject(error);
return;
}
getFileYAML(this.app, file, "with-dashes" === castedArguments.withDashes).then((yamlContent) => {
if (null === yamlContent) {
// No YAML frontmatter.
this.reject("The current file does not contain a YAML frontmatter.", reject);
}
else {
// Got a YAML frontmatter.
resolve(yamlContent);
}
});
});
}
getAvailabilityText() {
return super.getAvailabilityText() + " Also, a YAML frontmatter section needs to be present.";
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":with-dashes}}",
help_text: "Gives the current note's YAML frontmatter, wrapped between --- lines. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":no-dashes}}",
help_text: "Gives the current note's YAML frontmatter, excluding top and bottom --- lines. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":with-dashes}}",
help_text: "Gives the current note's YAML frontmatter, wrapped between --- lines." + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":no-dashes}}",
help_text: "Gives the current note's YAML frontmatter, excluding top and bottom --- lines. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{yaml_content:with-dashes}}</strong> or <strong>{{yaml_content:no-dashes}}</strong>";
}
}
Variable_YAMLContent.parameters = {
withDashes: {
options: ["with-dashes", "no-dashes"],
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Variable_EventYAMLContent extends EventVariable {
constructor() {
super(...arguments);
this.variable_name = "event_yaml_content";
this.help_text = "Gives the event related note's YAML frontmatter. Dashes --- can be included or excluded.";
this.supported_sc_events = [
SC_Event_FileMenu,
SC_Event_FileCreated,
SC_Event_FileContentModified,
SC_Event_FileDeleted,
SC_Event_FileMoved,
SC_Event_FileRenamed,
];
}
generateValue(castedArguments, sc_event) {
return new Promise((resolve, reject) => {
try {
this.requireCorrectEvent(sc_event);
}
catch (error) {
// Need to catch here, because Variable.getValue()'s .catch() block won't be able to catch thrown errors,
// it can only catch errors that were passed to reject().
reject(error);
return;
}
getFileYAML(this.app, sc_event.getFile(), castedArguments.withDashes === "with-dashes").then((yamlContent) => {
if (null === yamlContent) {
// No YAML frontmatter.
this.reject("The event related file does not contain a YAML frontmatter.", reject);
}
else {
// Got a YAML frontmatter.
resolve(yamlContent);
}
});
});
}
getAvailabilityText() {
return super.getAvailabilityText() + " Also, a YAML frontmatter section needs to be present.";
}
getAutocompleteItems() {
return [
// Normal variables
{
value: "{{" + this.variable_name + ":with-dashes}}",
help_text: "Gives the event related note's YAML frontmatter, wrapped between --- lines. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{" + this.variable_name + ":no-dashes}}",
help_text: "Gives the event related note's YAML frontmatter, excluding top and bottom --- lines. " + this.getAvailabilityText(),
group: "Variables",
type: "normal-variable",
documentationLink: this.getDocumentationLink(),
},
// Unescaped variables
{
value: "{{!" + this.variable_name + ":with-dashes}}",
help_text: "Gives the event related note's YAML frontmatter, wrapped between --- lines." + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
{
value: "{{!" + this.variable_name + ":no-dashes}}",
help_text: "Gives the event related note's YAML frontmatter, excluding top and bottom --- lines. " + this.getAvailabilityText(),
group: "Variables",
type: "unescaped-variable",
documentationLink: this.getDocumentationLink(),
},
];
}
getHelpName() {
return "<strong>{{event_yaml_content:with-dashes}}</strong> or <strong>{{event_yaml_content:no-dashes}}</strong>";
}
}
Variable_EventYAMLContent.parameters = {
withDashes: {
options: ["with-dashes", "no-dashes"],
required: true,
},
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function loadVariables(plugin) {
const variables = new VariableSet([]);
// Load CustomVariables
// Do this before loading built-in variables so that these user-defined variables will appear first in all lists containing variables.
plugin.getCustomVariableInstances().forEach((custom_variable_instance) => {
variables.add(custom_variable_instance.createCustomVariable());
});
// Load built-in variables.
const built_in_variables = [
// Normal variables
new Variable_CaretParagraph(plugin),
new Variable_CaretPosition(plugin),
new Variable_Clipboard(plugin),
new Variable_Date(plugin),
new Variable_Environment(plugin),
new Variable_FileContent(plugin),
new Variable_FileExtension(plugin),
new Variable_FileName(plugin),
new Variable_FilePath(plugin),
new Variable_FileURI(plugin),
new Variable_FolderName(plugin),
new Variable_FolderPath(plugin),
new Variable_NewNoteFolderName(plugin),
new Variable_NewNoteFolderPath(plugin),
new Variable_NoteContent(plugin),
// Variable_Output is not loaded here, because it's only used in OutputWrappers.
new Variable_Selection(plugin),
new Variable_Tags(plugin),
new Variable_Title(plugin),
new Variable_VaultPath(plugin),
new Variable_Workspace(plugin),
new Variable_YAMLContent(plugin),
new Variable_YAMLValue(plugin),
// Event variables
new Variable_EventFileContent(plugin),
new Variable_EventFileExtension(plugin),
new Variable_EventFileName(plugin),
new Variable_EventFilePath(plugin),
new Variable_EventFileURI(plugin),
new Variable_EventFolderName(plugin),
new Variable_EventFolderPath(plugin),
new Variable_EventNoteContent(plugin),
new Variable_EventOldFileName(plugin),
new Variable_EventOldFilePath(plugin),
new Variable_EventOldFolderName(plugin),
new Variable_EventOldFolderPath(plugin),
new Variable_EventOldTitle(plugin),
new Variable_EventTags(plugin),
new Variable_EventTitle(plugin),
new Variable_EventYAMLContent(plugin),
new Variable_EventYAMLValue(plugin),
];
if (DEBUG_ON) {
// Variables that are only designed for 'Shell commands test suite'.
built_in_variables.push(new Variable_Newline(plugin), new Variable_Passthrough(plugin));
}
for (const built_in_variable of built_in_variables) {
// JavaScript's Set does not have a method to add multiple items at once, so need to iterate them and add one-by-one.
variables.add(built_in_variable);
}
return variables;
}
class VariableSet extends Set {
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* @param plugin
* @param content
* @param shell Used to determine how to escape special characters in variable values. Can be null, if no escaping is wanted.
* @param t_shell_command Will only be used to read default value configurations. Can be null if no TShellCommand is available, but then no default values can be accessed.
* @param sc_event Use undefined, if parsing is not happening during an event.
* @param variables If you want to parse only a certain set of variables, define them in this parameter. If this is omitted, all variables will be parsed.
* @param raw_value_augmenter A callback that will be called before every substitution. Allows modifying or completely changing the resulted variable values.
* @param escaped_value_augmenter Same as raw_value_augmenter, but called after escaping the value. Can be used to for example wrap values in html elements for displaying purposes.
* @return ParsingResult
*/
async function parseVariables(plugin, content, shell, t_shell_command, sc_event, variables = plugin.getVariables(), raw_value_augmenter = null, escaped_value_augmenter = null) {
debugLog("parseVariables(): Starting to parse " + content + " with " + variables.size + " variables.");
// Initialize a parsing result object
const parsing_result = {
original_content: content,
parsed_content: content,
succeeded: false,
error_messages: [],
count_parsed_variables: 0,
};
for (const variable of variables) {
const pattern = new RegExp(variable.getPattern(), "igu"); // i: case-insensitive; g: match all occurrences instead of just the first one. u: support 4-byte unicode characters too.
const parameter_names = variable.getParameterNames();
let argument_matches;
while ((argument_matches = pattern.exec(content)) !== null) {
// Count how many times any variables have appeared.
parsing_result.count_parsed_variables++;
// Remove stuff that should not be iterated in a later loop.
/** Need to prefix with _ because JavaScript reserves the variable name 'arguments'. */
const _arguments = argument_matches.filter((value /* Won't be used */, key) => {
return "number" === typeof key;
// This leaves out for example the following non-numeric keys (and their values):
// - "groups"
// - "index"
// - "input"
// In the future, there can also come more elements that will be skipped. E.g. "indices". See: https://github.com/nothingislost/obsidian-dynamic-highlights/issues/25#issuecomment-1038563990 (referenced 2022-02-22).
});
// Get the {{variable}} string that will be substituted (= replaced with the actual value of the variable).
const substitute = _arguments.shift(); // '_arguments[0]' contains the whole match, not just an argument. Get it and remove it from '_arguments'. 'as string' is used to tell TypeScript that _arguments[0] is always defined.
// Iterate all arguments
const presentArguments = {};
for (const i in _arguments) {
// Check that the argument is not omitted. It can be omitted (= undefined), if the parameter is optional.
if (undefined !== _arguments[i]) {
// The argument is present.
const argument = _arguments[i].slice(1); // .slice(1): Remove a preceding :
const parameter_name = parameter_names[i];
presentArguments[parameter_name] = argument;
}
}
// Should the variable's value be escaped? (Usually yes).
let escape = true;
if ("{{!" === substitute.slice(0, 3)) { // .slice(0, 3) = get characters 0...2, so stop before 3. The 'end' parameter is confusing.
// The variable usage begins with {{! instead of {{
// This means the variable's value should NOT be escaped.
escape = false;
}
if (!shell) {
// Escaping is forced OFF.
escape = false;
}
// Render the variable
const variable_value_result = await variable.getValue(t_shell_command, sc_event, presentArguments,
// Define a recursive callback that can be used to parse possible variables in a default value of the current variable.
(raw_default_value) => {
// Avoid circular references by removing the current variable from the set of parseable variables.
// This will cumulate in deep nested parsing: Possible deeper parsing rounds will always have narrower
// and narrower sets of variables to parse.
const reduced_variables = removeFromSet(variables, variable);
return parseVariables(plugin, raw_default_value, null, // Disable escaping special characters at this phase to avoid double escaping, as escaping will be done later.
t_shell_command, sc_event, reduced_variables, raw_value_augmenter, escaped_value_augmenter);
});
// Allow custom modification of the raw value.
if (raw_value_augmenter) {
// The augmenter can modify the content of the variable_value_result object.
raw_value_augmenter(variable, variable_value_result);
}
const raw_variable_value = variable_value_result.value;
// Check possible error messages that might have come from rendering.
if (variable_value_result.succeeded) {
// Parsing was ok.
// Escape the value if needed.
let use_variable_value;
if (escape) {
// Use an escaped value.
use_variable_value = escapeValue(shell, // shell is always a string when escape is true.
raw_variable_value);
}
else {
// No escaping is wanted, so use the raw value.
use_variable_value = raw_variable_value; // raw_variable_value is always a string when variable_value_result.succeeded is true.
}
// Augment the escaped value, if wanted.
if (escaped_value_augmenter) {
use_variable_value = escaped_value_augmenter(variable, use_variable_value);
}
// Replace the variable name with the variable value.
parsing_result.parsed_content = parsing_result.parsed_content /* not null */.replace(substitute, () => {
// Do the replacing in a function in order to avoid a possible $ character to be interpreted by JavaScript to interact with the regex.
// More information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_a_parameter (referenced 2021-11-02.)
return use_variable_value;
});
}
else {
// There has been problem(s) with this variable.
debugLog("parseVariables(): Parsing content " + content + " failed.");
parsing_result.succeeded = false;
parsing_result.parsed_content = null;
parsing_result.error_messages = variable_value_result.error_messages; // Returning now prevents parsing rest of the variables.
return parsing_result;
}
}
}
debugLog("parseVariables(): Parsing content " + content + " succeeded.");
parsing_result.succeeded = true;
return parsing_result;
}
/**
* Reads all variables from the content string, and returns a VariableSet containing all the found variables.
*
* This is needed in situations where variables will not be parsed (= variable values are not needed), but where it's just
* needed to know what variables e.g. a shell command relies on.
*
* @param plugin
* @param content
*/
function getUsedVariables(plugin, content) {
const search_for_variables = plugin.getVariables();
const found_variables = new VariableSet();
for (const variable of search_for_variables) {
const pattern = new RegExp(variable.getPattern(), "igu"); // i: case-insensitive; g: match all occurrences instead of just the first one. u: support 4-byte unicode characters too.
if (pattern.exec(content) !== null) {
// This variable was found.
found_variables.add(variable);
}
}
return found_variables;
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputChannel {
/**
* @param plugin
* @param t_shell_command
* @param shell_command_parsing_result
* @param outputHandlingMode
* @param processTerminator Will be called if user decides to end the process. Set to null if the process has already ended.
*/
constructor(plugin, t_shell_command, shell_command_parsing_result, outputHandlingMode, processTerminator) {
this.plugin = plugin;
this.t_shell_command = t_shell_command;
this.shell_command_parsing_result = shell_command_parsing_result;
this.outputHandlingMode = outputHandlingMode;
this.processTerminator = processTerminator;
this.app = plugin.app;
this.initialize();
}
/**
* Can be overridden in child classes in order to vary the title depending on output_stream.
* @param output_stream
*/
static getTitle(output_stream) {
return this.title;
}
/**
* Sub classes can do here initializations that are common to both handleBuffered() and handleRealtime().
*
* Inits could be done in contructor(), too, but this is cleaner - no need to deal with parameters and no need for a super()
* call.
*
* @protected
*/
initialize() {
// Do nothing by default.
}
async handleBuffered(output, error_code, enableOutputWrapping = true) {
this.requireHandlingMode("buffered");
// Qualify output
if (OutputChannel.isOutputEmpty(output)) {
// The output is empty
if (!this.static().accepts_empty_output) {
// This OutputChannel does not accept empty output, i.e. empty output should be just ignored.
debugLog(this.constructor.name + ".handleBuffered(): Ignoring empty output.");
return;
}
}
debugLog(this.constructor.name + ".handleBuffered(): Handling output...");
// Output is ok.
// Handle it.
await this._handleBuffered(await this.prepare_output(output, enableOutputWrapping), error_code);
debugLog("Output handling is done.");
}
/**
* @param outputStreamName
* @param outputContent
* @param enableOutputWrapping No caller actually sets this to false at the moment, unlike the handleBuffered() method's counterpart. But have this just in case.
*/
async handleRealtime(outputStreamName, outputContent, enableOutputWrapping = true) {
this.requireHandlingMode("realtime");
// Qualify output
if ("" === outputContent) {
// The output is empty
if (!this.static().accepts_empty_output) {
// This OutputChannel does not accept empty output, i.e. empty output should be just ignored.
debugLog(this.constructor.name + ".handleRealtime(): Ignoring empty output.");
return;
}
}
debugLog(this.constructor.name + ".handleRealtime(): Handling output...");
// Output is ok.
// If allowed, wrap the output with output wrapper text.
if (enableOutputWrapping) {
// Wrap output (but only if a wrapper is defined)
outputContent = await this.wrapOutput(outputStreamName, outputContent);
}
// Handle it.
await this._handleRealtime(outputContent, outputStreamName);
debugLog("Output handling is done.");
}
_endRealtime(exitCode) {
// Do nothing by default.
}
/**
* When a shell command is executed in "realtime" mode, a separate ending call should be made in order to pass an
* exit code to the OutputChannel. Some OutputChannels display the code to user, but most do not.
*
* @param exitCode
*/
endRealtime(exitCode) {
this.requireHandlingMode("realtime");
this._endRealtime(exitCode);
}
requireHandlingMode(requiredMode) {
if (this.outputHandlingMode !== requiredMode) {
throw new Error("this.outputHandlingMode must be '" + requiredMode + "'.");
}
}
static acceptsOutputStream(output_stream) {
return this.accepted_output_streams.contains(output_stream);
}
/**
* Does the following preparations:
* - Combines output streams (if wanted by the OutputChannel).
* - Wraps output (if defined in shell command configuration).
* @param output_streams
* @param enableOutputWrapping
* @private
*/
async prepare_output(output_streams, enableOutputWrapping) {
const wrapOutputIfEnabled = async (outputStreamName, outputContent) => {
if (enableOutputWrapping) {
// Wrap output content.
return await this.wrapOutput(outputStreamName, outputContent);
}
else {
// Wrapping is disabled, return unmodified output content.
return outputContent;
}
};
const wrap_outputs_separately = async () => {
const wrapped_output_streams = {};
let output_stream_name;
for (output_stream_name in output_streams) {
wrapped_output_streams[output_stream_name] = await wrapOutputIfEnabled(output_stream_name, output_streams[output_stream_name]);
}
return wrapped_output_streams;
};
// Check if outputs should be combined.
const combineOutputStreams = this.static().combine_output_streams;
if (combineOutputStreams) {
// Combine output strings into a single string.
// Can output wrapping be combined?
if (this.t_shell_command.isOutputWrapperStdoutSameAsStderr()) {
// Output wrapping can be combined.
return await wrapOutputIfEnabled("stdout", joinObjectProperties(output_streams, combineOutputStreams));
}
else {
// Output wrapping needs to be done separately.
const wrapped_output_streams = await wrap_outputs_separately();
return joinObjectProperties(wrapped_output_streams, combineOutputStreams); // Use combineOutputStreams as a glue string.
}
}
else {
// Do not combine, handle each stream separately
return await wrap_outputs_separately();
}
}
/**
* Surrounds the given output text with an output wrapper. If no output wrapper is defined, returns the original
* output text without any modifications.
*/
async wrapOutput(output_stream, output_content) {
// Get preparsed output wrapper content. It has all other variables parsed, except {{output}}.
const parsing_result_key = "output_wrapper_" + output_stream;
const output_wrapper_content = this.shell_command_parsing_result[parsing_result_key];
// Check if output wrapper content exists.
if (undefined === output_wrapper_content) {
// No OutputWrapper is defined for this shell command.
// Return the output text without modifications.
debugLog("Output wrapping: No wrapper is defined for '" + output_stream + "'.");
return output_content;
}
// Parse the {{output}} variable
const output_variable = new Variable_Output(this.plugin, output_content);
const parsing_result = await parseVariables(this.plugin, output_wrapper_content, null, // No shell anymore, so no need for escaping.
this.t_shell_command, null, // No support for {{event_*}} variables is needed, because they are already parsed in output_wrapper_content. This phase only parses {{output}} variable, nothing else.
new VariableSet([output_variable]));
// Inspect the parsing result. It should always succeed, as the {{output}} variable should not give any errors.
if (parsing_result.succeeded) {
// Succeeded.
debugLog("Output wrapping: Wrapping " + output_stream + " succeeded.");
return parsing_result.parsed_content;
}
else {
// Failed for some reason.
this.plugin.newError("Output wrapping failed, see error(s) below.");
this.plugin.newErrors(parsing_result.error_messages);
throw new Error("Output wrapping failed: Parsing {{output}} resulted in error(s): " + parsing_result.error_messages.join(" "));
}
}
/**
* Can be moved to a global function isOutputStreamEmpty() if needed.
* @param output
* @private
*/
static isOutputEmpty(output) {
if (undefined !== output.stderr) {
return false;
}
return undefined === output.stdout || "" === output.stdout;
}
static() {
return this.constructor;
}
}
OutputChannel.accepted_output_streams = ["stdout", "stderr"];
OutputChannel.accepts_empty_output = false;
/**
* Determines if the output channel wants to handle a unified output or not. If yes, this property should define a
* delimiter string that will be used as a glue between different output streams.
*
* @protected
*/
OutputChannel.combine_output_streams = false;
/**
* Used in OutputModal to redirect output based on hotkeys. If this is undefined, then the output channel is completely
* excluded from OutputModal.
*/
OutputChannel.hotkey_letter = undefined;
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputChannel_Notification extends OutputChannel {
constructor() {
super(...arguments);
/**
* All received output cumulatively. Subsequent handlings will then use the whole output, not just new parts.
* Only used in "realtime" mode.
*
* @private
*/
this.realtimeContentBuffer = "";
/**
* A flag for indicating that if any stderr output has happened, all subsequent handlings should format the output
* Notice message with error formatting (i.e. show [...] at the beginning of the message).
* @private
*/
this.realtimeHasStderrOccurred = false;
}
static getTitle(output_stream) {
switch (output_stream) {
case "stdout":
return "Notification balloon";
case "stderr":
return "Error balloon";
}
}
async _handleBuffered(output, error_code) {
// Iterate output streams.
// There can be both "stdout" and "stderr" present at the same time, or just one of them. If both are present, two
// notifications will be created.
let output_stream_name;
for (output_stream_name in output) {
const output_message = output[output_stream_name]; // as string = output message is not undefined because of the for loop.
this.notify(output_stream_name, output_message, error_code);
}
}
async _handleRealtime(outputContent, outputStreamName) {
// Append new content
this.realtimeContentBuffer += outputContent;
// Raise a flag if seeing 'stderr' output.
if ("stderr" === outputStreamName) {
this.realtimeHasStderrOccurred = true;
}
// Does a Notice exist already?
if (this.realtimeNotice) {
// Reuse an existing Notice.
// Should output be formatted as an error message?
let updatedMessage;
if (this.realtimeHasStderrOccurred) {
// Apply error formatting to output
updatedMessage = OutputChannel_Notification.formatErrorMessage(this.realtimeContentBuffer, null);
}
else {
// Use output as-is
updatedMessage = this.realtimeContentBuffer;
}
// Use the updated output
this.realtimeNotice.setMessage(updatedMessage);
// Update notice hiding timeout
window.clearTimeout(this.realtimeNoticeTimeout); // Remove old timeout
this.handleNotificationHiding(outputStreamName); // Add new timeout
}
else {
// Create a new Notice.
this.realtimeNotice = this.notify(this.realtimeHasStderrOccurred ? "stderr" : "stdout", this.realtimeContentBuffer, null, 0);
// Create a timeout for hiding the Notice
this.handleNotificationHiding(outputStreamName);
}
// Terminating button
// @ts-ignore Notice.noticeEl belongs to Obsidian's PRIVATE API, and it may change without a prior notice. Only
// create the button if noticeEl exists and is an HTMLElement.
const noticeEl = this.realtimeNotice.noticeEl;
if (null === this.processTerminator) {
throw new Error("Process terminator is not set, although it should be set when handling output in realtime mode.");
}
if (undefined !== noticeEl && noticeEl instanceof HTMLElement) {
this.plugin.createRequestTerminatingButton(noticeEl, this.processTerminator);
}
}
_endRealtime(exitCode) {
if (exitCode !== 0 || this.realtimeHasStderrOccurred) {
// If a Notice exists, update it with the exitCode
this.realtimeNotice?.setMessage(OutputChannel_Notification.formatErrorMessage(this.realtimeContentBuffer, exitCode));
}
// Remove terminating button
// @ts-ignore Notice.noticeEl belongs to Obsidian's PRIVATE API, and it may change without a prior notice. Only
// create the button if noticeEl exists and is an HTMLElement.
const noticeEl = this.realtimeNotice?.noticeEl;
if (undefined !== noticeEl && noticeEl instanceof HTMLElement) {
noticeEl.find(".SC-icon-terminate-process")?.remove(); // ? = Only try to remove if the button exists. It does not exist if .setMessage() was called above as it overwrites all content in the Notice.
}
}
/**
*
* @param outputStreamName
* @param outputContent
* @param exitCode
* @param noticeTimeout Allows overriding the notice/error timeout setting.
* @private
*/
notify(outputStreamName, outputContent, exitCode, noticeTimeout) {
switch (outputStreamName) {
case "stdout":
// Normal output
return this.plugin.newNotification(outputContent, noticeTimeout ?? undefined);
case "stderr":
// Error output
return this.plugin.newError(OutputChannel_Notification.formatErrorMessage(outputContent, exitCode), noticeTimeout ?? undefined);
}
}
static formatErrorMessage(outputContent, exitCode) {
if (null === exitCode) {
// If a "realtime" process is not finished, there is no exit code yet.
// @ts-ignore Yea I know "..." is not a number nor null. :)
exitCode = "...";
}
return "[" + exitCode + "]: " + outputContent;
}
handleNotificationHiding(outputStreamName) {
// Hide by timeout
let normalTimeout;
switch (outputStreamName) {
case "stdout":
normalTimeout = this.plugin.getNotificationMessageDurationMs();
break;
case "stderr":
normalTimeout = this.plugin.getErrorMessageDurationMs();
break;
}
this.realtimeNoticeTimeout = window.setTimeout(() => {
// Hide the Notice
this.realtimeNotice?.hide(); // ? = Don't try to hide if a user has closed the notification by clicking. See the 'this.realtimeNotice = undefined;' line in the below click handler.
this.realtimeNotice = undefined;
this.realtimeNoticeTimeout = undefined;
}, normalTimeout);
// Subscribe to Notice's click event.
// @ts-ignore Notice.noticeEl belongs to Obsidian's PRIVATE API, and it may change without a prior notice. Only
// define the click listener if noticeEl exists and is an HTMLElement.
const noticeEl = this.realtimeNotice.noticeEl;
if (undefined !== noticeEl && noticeEl instanceof HTMLElement) {
noticeEl.onClickEvent(() => {
window.clearTimeout(this.realtimeNoticeTimeout); // Make sure timeout will not accidentally try to later hide an already hidden Notification.
this.realtimeNoticeTimeout = undefined;
this.realtimeNotice = undefined; // Give a signal to _handleRealtime() that if new output comes, a new Notice should be created.
});
}
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputChannel_CurrentFile extends OutputChannel {
async _handleBuffered(outputContent) {
this.handle(outputContent);
}
async _handleRealtime(outputContent) {
this.handle(outputContent);
}
handle(output_message) {
const editor = getEditor(this.app);
const view = getView(this.app);
if (null === editor) {
// For some reason it's not possible to get an editor.
this.plugin.newError("Could not get an editor instance! Please create a discussion in GitHub. The command output is in the next error box:");
this.plugin.newError(output_message); // Good to output it at least some way.
debugLog("OutputChannel_CurrentFile: Could not get an editor instance.");
return;
}
// Check if the view is in source mode
if (null === view) {
// For some reason it's not possible to get an editor, but it's not a big problem.
debugLog("OutputChannel_CurrentFile: Could not get a view instance.");
}
else {
// We do have a view
if ("source" !== view.getMode()) {
// Warn that the output might go to an unexpected place in the note file.
this.plugin.newNotification("Note that your active note is not in 'Edit' mode! The output comes visible when you switch to 'Edit' mode again!");
}
}
// Insert into the current file
this.insertIntoEditor(editor, output_message);
}
}
/**
* There can be both "stdout" and "stderr" present at the same time, or just one of them. If both are present, they
* will be joined together with " " as a separator.
* @protected
*/
OutputChannel_CurrentFile.combine_output_streams = " ";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputChannel_CurrentFileCaret extends OutputChannel_CurrentFile {
/**
* Inserts text into the given editor, at caret position.
*
* @param editor
* @param output_message
* @protected
*/
insertIntoEditor(editor, output_message) {
editor.replaceSelection(output_message);
}
}
OutputChannel_CurrentFileCaret.title = "Current file: caret position";
OutputChannel_CurrentFileCaret.hotkey_letter = "R";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputChannel_CurrentFileTop extends OutputChannel_CurrentFile {
/**
* Inserts text into the given editor, at top.
*
* @param editor
* @param output_message
* @protected
*/
insertIntoEditor(editor, output_message) {
const top_position = editor.offsetToPos(0);
editor.replaceRange(output_message, top_position);
}
}
OutputChannel_CurrentFileTop.title = "Current file: top";
OutputChannel_CurrentFileTop.hotkey_letter = "T";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputChannel_StatusBar extends OutputChannel {
constructor() {
super(...arguments);
/**
* All received output cumulatively. Subsequent handlings will then use the whole output, not just new parts.
* Only used in "realtime" mode.
*
* @private
*/
this.realtimeContentBuffer = "";
}
async _handleBuffered(outputContent) {
this.setStatusBarContent(outputContent);
}
async _handleRealtime(outputContent) {
this.realtimeContentBuffer += outputContent;
this.setStatusBarContent(this.realtimeContentBuffer);
}
setStatusBarContent(outputContent) {
const status_bar_element = this.plugin.getOutputStatusBarElement();
outputContent = outputContent.trim();
// Full output (shown when hovering with mouse)
status_bar_element.setAttr("aria-label", outputContent);
// Show last line permanently.
const output_message_lines = outputContent.split(/(\r\n|\r|\n)/u);
const last_output_line = output_message_lines[output_message_lines.length - 1];
status_bar_element.setText(last_output_line);
}
}
OutputChannel_StatusBar.title = "Status bar";
OutputChannel_StatusBar.accepts_empty_output = true;
OutputChannel_StatusBar.hotkey_letter = "S";
/**
* Combine stdout and stderr (in case both of them happen to be present).
* @protected
*/
OutputChannel_StatusBar.combine_output_streams = os.EOL + os.EOL;
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputChannel_CurrentFileBottom extends OutputChannel_CurrentFile {
/**
* Inserts text into the given editor, at bottom.
*
* @param editor
* @param output_message
* @protected
*/
insertIntoEditor(editor, output_message) {
const bottom_position = {
ch: editor.getLine(editor.lastLine()).length,
line: editor.lastLine(), // ... the last line.
}; // *) But do not subtract 1, because ch is zero-based, so when .length is used without -1, we are pointing AFTER the last character.
editor.replaceRange(output_message, bottom_position);
}
}
OutputChannel_CurrentFileBottom.title = "Current file: bottom";
OutputChannel_CurrentFileBottom.hotkey_letter = "B";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputChannel_Clipboard extends OutputChannel {
constructor() {
super(...arguments);
/**
* All received output cumulatively. Subsequent handlings will then use the whole output, not just new parts.
* Only used in "realtime" mode.
*
* @private
*/
this.realtimeContentBuffer = "";
}
async _handleBuffered(outputContent) {
await copyToClipboard(outputContent);
this.notify(outputContent);
}
async _handleRealtime(outputContent) {
this.realtimeContentBuffer += outputContent;
await copyToClipboard(this.realtimeContentBuffer);
this.notify(this.realtimeContentBuffer);
}
notify(output_message) {
if (this.plugin.settings.output_channel_clipboard_also_outputs_to_notification) {
// Notify the user so they know a) what was copied to clipboard, and b) that their command has finished execution.
this.plugin.newNotification("Copied to clipboard: " + os.EOL + output_message + os.EOL + os.EOL + "(Notification can be turned off in settings.)");
}
}
}
OutputChannel_Clipboard.title = "Clipboard";
OutputChannel_Clipboard.hotkey_letter = "L";
/**
* There can be both "stdout" and "stderr" present at the same time, or just one of them. If both are present, they
* will be joined together with " " as a separator.
* @protected
*/
OutputChannel_Clipboard.combine_output_streams = " "; // TODO: Change to "" as there should be no extra space between stdout and stderr. Compare it to the terminal: AFAIK there is no separation between stdout and stderr outputs, just that typically each output ends with a newline.
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* TODO: Move this to TShellCommand.
*/
function getHotkeysForShellCommand(plugin, shell_command_id) {
// Retrieve all hotkeys set by user.
// @ts-ignore
const app_custom_hotkeys = plugin.app.hotkeyManager?.customKeys;
if (!app_custom_hotkeys) {
debugLog("getHotkeysForShellCommand() failed, will return an empty array.");
return [];
}
// Get only our hotkeys.
const hotkey_index = plugin.getPluginId() + ":" + plugin.generateObsidianCommandId(shell_command_id); // E.g. "obsidian-shellcommands:shell-command-0"
debugLog("getHotkeysForShellCommand() succeeded.");
return app_custom_hotkeys[hotkey_index] ?? []; // If no hotkey array is set for this command, return an empty array. Although I do believe that all commands do have an array anyway, but have this check just in case.
}
/**
* TODO: Is there a way to make Obsidian do this conversion for us? Check this: https://github.com/pjeby/hotkey-helper/blob/c8a032e4c52bd9ce08cb909cec15d1ed9d0a3439/src/plugin.js#L4-L6
*
* @param hotkey
* @constructor
*/
function HotkeyToString(hotkey) {
const keys = [];
hotkey.modifiers.forEach((modifier) => {
let modifier_key = modifier.toString(); // This is one of 'Mod' | 'Ctrl' | 'Meta' | 'Shift' | 'Alt'
if ("Mod" === modifier_key) {
// Change "Mod" to something more meaningful.
modifier_key = CmdOrCtrl(); // isMacOS should also be true if the device is iPhone/iPad. Can be handy if this plugin gets mobile support some day.
}
keys.push(modifier_key);
});
keys.push(hotkey.key); // This is something like a letter ('A', 'B' etc) or space/enter/whatever.
return keys.join(" + ");
}
function CmdOrCtrl() {
return obsidian.Platform.isMacOS ? "Cmd" : "Ctrl";
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputChannel_Modal extends OutputChannel {
initialize() {
// Initialize a modal (but don't open yet)
this.modal = new OutputModal(this.plugin, this.t_shell_command, this.shell_command_parsing_result, this.processTerminator);
}
async _handleBuffered(outputs, error_code) {
// Pass outputs to modal
this.modal.setOutputContents(outputs);
// Define a possible error code to be shown on the modal.
if (error_code !== null) {
this.modal.setExitCode(error_code);
}
// Done
this.modal.open();
}
async _handleRealtime(outputContent, outputStreamName) {
this.modal.addOutputContent(outputStreamName, outputContent);
if (!this.modal.isOpen()) {
this.modal.open();
}
}
/**
* @param exitCode Can be null if user terminated the process by clicking a button. In other places exitCode can be null if process is still running, but here that cannot be the case.
*
* @protected
*/
_endRealtime(exitCode) {
// Delete terminator button as the process is already ended.
this.modal.removeProcessTerminatorButton();
// Pass exitCode to the modal
this.modal.setExitCode(exitCode);
}
}
OutputChannel_Modal.title = "Ask after execution";
class OutputModal extends SC_Modal {
constructor(plugin, t_shell_command, shell_command_parsing_result, processTerminator) {
super(plugin);
this.processTerminator = processTerminator;
this.exit_code = null; // TODO: Think about changing the logic: exit code could be undefined when it's not received, and null when a user has terminated the execution. The change needs to be done in the whole plugin, although I only wrote about it in this OutputModal class.
this.outputFields = {};
this.t_shell_command = t_shell_command;
this.shell_command_parsing_result = shell_command_parsing_result;
this.createOutputFields();
}
/**
* Called when doing "buffered" output handling.
*
* @param outputs
*/
setOutputContents(outputs) {
Object.getOwnPropertyNames(outputs).forEach((outputStreamName) => {
const outputField = this.outputFields[outputStreamName];
// Set field value
const textareaComponent = outputField.components.first();
const outputContent = outputs[outputStreamName];
textareaComponent.setValue(outputContent); // as string = outputContent is not undefined because of the .forEach() loop.
// Make field visible (if it's not already)
outputField.settingEl.matchParent(".SC-hide")?.removeClass("SC-hide");
});
}
/**
* Called when doing "realtime" output handling.
*
* @param outputStreamName
* @param outputContent
*/
addOutputContent(outputStreamName, outputContent) {
const outputField = this.outputFields[outputStreamName];
// Update field value
const textareaComponent = outputField.components.first();
textareaComponent.setValue(textareaComponent.getValue() + outputContent);
// Make field visible (if it's not already)
outputField.settingEl.matchParent(".SC-hide")?.removeClass("SC-hide");
}
onOpen() {
super.onOpen();
this.modalEl.addClass("SC-modal-output");
// Heading
const heading = this.shell_command_parsing_result.alias;
this.titleEl.innerText = heading ? heading : "Shell command output"; // TODO: Use this.setTitle() instead.
// Shell command preview
this.modalEl.createEl("pre", { text: this.shell_command_parsing_result.shell_command, attr: { class: "SC-no-margin SC-wrappable" } }); // no margin so that exit code will be close.
// Container for terminating button and exit code
const processResultContainer = this.modalEl.createDiv();
// 'Request to terminate the process' icon button
if (this.processTerminator) {
this.processTerminatorButtonContainer = processResultContainer.createEl('span');
this.plugin.createRequestTerminatingButton(this.processTerminatorButtonContainer, this.processTerminator);
}
// Exit code (put on same line with process terminator button, if exists)
this.exitCodeElement = processResultContainer.createEl("small", { text: "Executing...", attr: { style: "font-weight: bold;" } }); // Show "Executing..." before an actual exit code is received.
if (this.exit_code !== null) {
this.displayExitCode();
}
// Output fields
this.modalEl.insertAdjacentElement("beforeend", this.outputFieldsContainer);
// Focus on the first output field
this.focusFirstField();
// A tip about selecting text.
this.modalEl.createDiv({
text: "Tip! If you select something, only the selected text will be used.",
attr: { class: "setting-item-description" /* A CSS class defined by Obsidian. */ },
});
}
createOutputFields() {
// Create a parent-less container. onOpen() will place it in the correct place.
this.outputFieldsContainer = document.createElement('div');
// Create field containers in correct order
let stdoutFieldContainer;
let stderrFieldContainer;
switch (this.t_shell_command.getOutputChannelOrder()) {
case "stdout-first": {
stdoutFieldContainer = this.outputFieldsContainer.createDiv();
stderrFieldContainer = this.outputFieldsContainer.createDiv();
break;
}
case "stderr-first": {
stderrFieldContainer = this.outputFieldsContainer.createDiv();
stdoutFieldContainer = this.outputFieldsContainer.createDiv();
break;
}
}
// Create fields
this.outputFields.stdout = this.createOutputField("stdout", stdoutFieldContainer);
this.outputFields.stderr = this.createOutputField("stderr", stderrFieldContainer);
// Hide the fields' containers at the beginning. They will be shown when content is added.
stdoutFieldContainer.addClass("SC-hide");
stderrFieldContainer.addClass("SC-hide");
}
createOutputField(output_stream, containerElement) {
let output_textarea;
containerElement.createEl("hr", { attr: { class: "SC-no-margin" } });
// Output stream name
new obsidian.Setting(containerElement)
.setName(output_stream)
.setHeading()
.setClass("SC-no-bottom-border");
// Textarea
const textarea_setting = new obsidian.Setting(containerElement)
.addTextArea(textarea => output_textarea = textarea);
textarea_setting.infoEl.addClass("SC-hide"); // Make room for the textarea by hiding the left column.
textarea_setting.settingEl.addClass("SC-output-channel-modal-textarea-container", "SC-no-top-border");
// Add controls for redirecting the output to another channel.
const redirect_setting = new obsidian.Setting(containerElement)
.setDesc("Redirect:")
.setClass("SC-no-top-border")
.setClass("SC-output-channel-modal-redirection-buttons-container") // I think this calls actually HTMLDivElement.addClass(), so it should not override the previous .setClass().
;
const outputChannels = getOutputChannelClasses();
Object.getOwnPropertyNames(outputChannels).forEach((output_channel_name) => {
const outputChannelClass = outputChannels[output_channel_name];
// Ensure this channel is not excluded by checking that is has a hotkey defined.
if (outputChannelClass.hotkey_letter) {
// Ensure the output channel accepts this output stream. E.g. OutputChannel_OpenFiles does not accept "stderr".
if (outputChannelClass.acceptsOutputStream(output_stream)) {
const textarea_element = textarea_setting.settingEl.find("textarea");
// Define an output handler
const handle_output = async () => {
// Redirect output to the selected channel
const output_streams = {};
output_streams[output_stream] =
getSelectionFromTextarea(textarea_element, true) // Use the selection, or...
?? output_textarea.getValue() // ...use the whole text, if nothing is selected.
;
const outputChannel = initializeOutputChannel(output_channel_name, this.plugin, this.t_shell_command, this.shell_command_parsing_result, "buffered", // Use "buffered" mode even if this modal was opened in "realtime" mode, because at this point the output redirection is a single-time job, not recurring.
this.processTerminator);
await outputChannel.handleBuffered(output_streams, this.exit_code, false); // false: Disable output wrapping as it's already wrapped before the output content was passed to this modal.
};
// Create the button
redirect_setting.addButton((button) => {
button.onClick(async (event) => {
// Handle output
await handle_output();
// Finish
if (event.ctrlKey) {
// Special click, control/command key is pressed.
// Close the modal.
this.close();
}
else {
// Normal click, control key is not pressed.
// Do not close the modal.
textarea_element.focus(); // Bring the focus back to the textarea in order to show a possible highlight (=selection) again.
}
});
// Define button texts and assign hotkeys
const output_channel_title = outputChannelClass.getTitle(output_stream);
// Button text
button.setButtonText(output_channel_title);
// Tips about hotkeys
button.setTooltip(`Redirect: Normal click OR ${CmdOrCtrl()} + ${outputChannelClass.hotkey_letter}.`
+ os.EOL + os.EOL +
`Redirect and close the modal: ${CmdOrCtrl()} + click OR ${CmdOrCtrl()} + Shift + ${outputChannelClass.hotkey_letter}.`);
});
// 1. hotkey: Ctrl/Cmd + number: handle output
this.scope.register(["Ctrl"], outputChannelClass.hotkey_letter, handle_output);
// 2. hotkey: Ctrl/Cmd + Shift + number: handle output and close the modal.
this.scope.register(["Ctrl", "Shift"], outputChannelClass.hotkey_letter, () => {
handle_output().then(); // then(): No need to wait for output handling to finish before closing the modal.
this.close();
});
}
}
});
return textarea_setting;
}
removeProcessTerminatorButton() {
if (this.processTerminatorButtonContainer) {
this.processTerminatorButtonContainer.remove();
}
}
/**
* Should be called only if an exit code was received.
*
* @param exit_code Can be null if user terminated the process by clicking a button.
*/
setExitCode(exit_code) {
this.exit_code = exit_code;
// Try to show the exit code.
if (this.isOpen()) {
if (null === this.exit_code) {
// User has terminated the process, so there's no exit code even though the process has ended.
this.exitCodeElement.innerText = "User terminated";
}
else {
// displayExistCode() can only be called if onOpen() has been called before.
// If onOpen() will be called later, it will call displayExitCode() itself when it sees that this.exit_code is defined.
this.displayExitCode();
}
}
}
displayExitCode() {
if (null === this.exit_code) {
// Currently there are two callers for this method, and both of them does a null check on the exit code before'
// the call, so we'll never get here in practise.
// TODO: Remove this checking/throwing and make this method able to display three texts: a) an exit code, b) Executing..., or c) User terminated.
throw new Error("Cannot display exit code because it's null");
}
this.exitCodeElement.innerText = "Exit code: " + this.exit_code.toString();
}
focusFirstField() {
switch (this.t_shell_command.getOutputChannelOrder()) {
case "stdout-first": {
this.outputFields.stdout.controlEl.find("textarea").focus();
break;
}
case "stderr-first": {
this.outputFields.stderr.controlEl.find("textarea").focus();
break;
}
}
}
approve() {
// No need to perform any action, just close the modal.
this.close();
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputChannel_OpenFiles extends OutputChannel {
_handleBuffered(output, error_code) {
let handlingPipeline = Promise.resolve();
let output_stream_name;
for (output_stream_name in output) {
handlingPipeline = handlingPipeline.finally(() => {
return this.handle(output[output_stream_name]);
});
}
return handlingPipeline;
}
_handleRealtime(outputContent) {
return this.handle(outputContent);
}
handle(outputContent) {
return new Promise((resolve) => {
// Read file definitions. Usually there's just one, but there can be many. Definitions are separated by newline
// characters. Each file definition defines one file to be opened.
const file_definitions_string = outputContent.trim(); // Contains at least file name(s), and MAYBE: a caret position, new pane option, and view state
const file_definitions = file_definitions_string.split(/[\r\n]+/u);
// Iterate all file definitions that should be opened.
let opening_pipeline = Promise.resolve();
for (const file_definition of file_definitions) {
// Chain each file opening to happen one after another. If one file opening fails for whatever reason, it
// is ok to continue to open the next file. This is why .finally() is used instead of .then().
opening_pipeline = opening_pipeline.finally(() => {
return this.interpretFileOpeningDefinition(file_definition);
});
}
opening_pipeline.finally(() => resolve() /* Tell that all openings have been processed. */);
});
}
interpretFileOpeningDefinition(file_definition) {
return new Promise((resolve, reject) => {
debugLog("OutputChannel_OpenFiles: Interpreting file opening definition: " + file_definition);
// Get parts that define different details about how the file should be opened
const file_definition_parts = file_definition.split(":"); // If file_definition is "", i.e. an empty string, the result will be [""], i.e. an array with an empty string as its only item.
// The first part is always the file path
let open_file_path = file_definition_parts.shift(); // If file_definition is "", this will be "", too. 'as string' is used because file_definition_parts is never empty (it always contains at least one item), so .shift() will never return undefined here.
// On Windows: Check if an absolute path was split incorrectly. (E.g. a path starting with "C:\...").
if (isWindows() && file_definition_parts.length > 0) {
const combined_path = open_file_path + ":" + file_definition_parts[0];
if (path__namespace.isAbsolute(combined_path)) {
// Yes, the first two parts do form an absolute path together, so they should not be split.
open_file_path = combined_path;
file_definition_parts.shift(); // Remove the second part so that it won't be accidentally processed in the 'Special features' part.
}
}
// Trim the file path, for being able to use cleaner separation between file name and other parts, e.g: MyFile.md : new-pane
open_file_path = open_file_path.trim();
// Special features
const caret_parts = []; // If caret position is present in file_definition_parts, the first item in this array will be the caret line, the second will be the column. If more parts are present, they will be used for making selections.
let newLeaf = false;
let can_create_file = false;
let file_definition_interpreting_failed = false;
file_definition_parts.forEach((file_definition_part) => {
file_definition_part = file_definition_part.toLocaleLowerCase().trim(); // .trim() is for being able to use cleaner separation between e.g. different selections: MyFile.md:1:1:1:-1 : 5:1:5:-1
// Determine the part type
if (isInteger(file_definition_part, true)) {
// This is a number, so consider it as a caret position part.
caret_parts.push(parseInt(file_definition_part));
}
else {
const multipleNewPartsErrorMessage = "Cannot open file: Only one of the following can be defined: new-pane, new-tab, or new-window.";
switch (file_definition_part) {
case "new-pane":
// Ensure no new-* definition is used before.
if (newLeaf === false) {
newLeaf = "split";
}
else {
this.plugin.newError(multipleNewPartsErrorMessage);
file_definition_interpreting_failed = true;
}
break;
case "new-tab":
// Ensure no new-* definition is used before.
if (newLeaf === false) {
newLeaf = "tab";
}
else {
this.plugin.newError(multipleNewPartsErrorMessage);
file_definition_interpreting_failed = true;
}
break;
case "new-window":
// Ensure no new-* definition is used before.
if (newLeaf === false) {
newLeaf = "window";
}
else {
this.plugin.newError(multipleNewPartsErrorMessage);
file_definition_interpreting_failed = true;
}
break;
case "can-create-file":
can_create_file = true;
break;
default:
this.plugin.newError("Cannot open file: Unrecognised definition part: " + file_definition_part + " in " + file_definition);
file_definition_interpreting_failed = true;
}
}
});
if (file_definition_interpreting_failed) {
reject();
return;
}
// Ensure the path is relative
if (path__namespace.isAbsolute(open_file_path)) {
// The path is absolute.
// Check if it can be converted to relative.
const vault_absolute_path = getVaultAbsolutePath(this.app);
if (open_file_path.toLocaleLowerCase().startsWith(vault_absolute_path.toLocaleLowerCase())) {
// Converting to relative is possible
open_file_path = open_file_path.substr(vault_absolute_path.length); // Get everything after the point where the vault path ends.
}
else {
// Cannot convert to relative, because the file does not reside in the vault
this.plugin.newError("Cannot open file '" + open_file_path + "' as the path is outside this vault.");
reject();
return;
}
}
// Clean up the file path
open_file_path = obsidian.normalizePath(open_file_path); // normalizePath() is used on purpose, instead of normalizePath2(), because backslashes \ should be converted to forward slashes /
this.openFileInTab(open_file_path, newLeaf, can_create_file).then(() => {
// The file is now open
// Check, did we have a caret position available. If not, do nothing.
const count_caret_parts = caret_parts.length;
if (count_caret_parts > 0) {
// Yes, a caret position was defined in the output.
// Ensure the correct amount of caret position parts.
// 0 parts: no caret positioning needs to be done (but in this part of code the amount of parts is always greater than 0).
// 1 part: caret line is defined, no column.
// 2 parts: caret line and column are defined.
// 3 parts: NOT ALLOWED.
// 4 parts: selection starting position (line, column) and selection end position (line, column) are defined.
// 5 parts or more: NOT ALLOWED. Exception: any number of sets of four parts is allowed, i.e. 8 parts, 12 parts, 16 parts etc. are allowed as they can define multiple selections.
const error_message_base = "File opened, but caret cannot be positioned due to an incorrect amount (" + count_caret_parts + ") of numeric values in the output: " + file_definition + os.EOL + os.EOL;
if (count_caret_parts == 3) {
// Incorrect amount of caret parts
this.plugin.newError(error_message_base + "Three numeric parts is an incorrect amount, correct would be 1,2 or 4 parts.");
reject();
return;
}
else if (count_caret_parts > 4 && count_caret_parts % 4 !== 0) {
// Incorrect amount of caret parts
this.plugin.newError(error_message_base + "Perhaps too many numeric parts are defined? If more than four parts are defined, make sure to define complete sets of four parts. The amount of numeric parts needs to be dividable by 4.");
reject();
return;
}
// Even though the file is already loaded, rendering it may take some time, thus the height of the content may increase.
// For this reason, there needs to be a tiny delay before setting the caret position. If the caret position is set immediately,
// the caret will be placed in a correct position, but it might be that the editor does not scroll into correct position, so the
// caret might be out of the view, even when it's in a correct place. (Obsidian version 0.13.23).
window.setTimeout(() => {
const editor = getEditor(this.app);
if (editor) {
if (count_caret_parts >= 4) {
// Selection mode
// There can be multiple selections defined
const selections = [];
while (caret_parts.length) {
const fromLine = caret_parts.shift();
const fromColumn = caret_parts.shift();
const toLine = caret_parts.shift();
const toColumn = caret_parts.shift();
if (undefined === fromLine || undefined === fromColumn || undefined === toLine || undefined === toColumn) {
// This should never happen.
throw new Error("Encountered undefined values in fromLine, fromColumn, toLine, and/or toColumn. Strange, because the correct amount of parts in caret_parts was checked beforehand.");
}
selections.push({
anchor: prepareEditorPosition(editor, fromLine, fromColumn),
head: prepareEditorPosition(editor, toLine, toColumn),
});
}
editor.setSelections(selections);
}
else {
// Simple caret mode
const caret_line = caret_parts[0];
const caret_column = caret_parts[1] ?? 1;
editor.setCursor(prepareEditorPosition(editor, caret_line, caret_column));
}
// After placing carets / selecting text, have a small delay after allowing to open another file (in case multiple files are opened in a row). This allows the selection to be remembered in the pane's history.
window.setTimeout(resolve, 300); // If you change this ADDITIONAL delay, remember to change it in the documentation, too.
}
else {
// No editor
this.plugin.newError("File opened, but caret cannot be positioned because no editor was found.");
reject();
}
}, 500); // 500ms is probably long enough even if a new tab is opened (takes more time than opening a file into an existing tab). This can be made into a setting sometime. If you change this, remember to change it in the documentation, too.
}
else {
// No caret parts exist. All is done now.
resolve();
}
}, (error_message) => {
if (typeof error_message === "string") {
// Opening the file has failed.
this.plugin.newError(error_message);
}
else {
// Some other runtime error has occurred.
throw error_message;
}
reject();
});
});
}
openFileInTab(file_path, newLeaf, can_create_file) {
// Ensure that the file exists (or can be created)
const source_path = ""; // TODO: When adding an option for creating new files, read this documentation from Obsidian API's getNewFileParent(): "sourcePath The path to the current open/focused file, used when the user wants new files to be created “in the same folder”. Use an empty string if there is no active file."
const file_exists_or_can_be_created = can_create_file || null !== this.app.metadataCache.getFirstLinkpathDest(file_path, source_path);
if (file_exists_or_can_be_created) {
// Yes, the file exists (or can be created)
return this.app.workspace.openLinkText(file_path, source_path, newLeaf);
}
else {
// No, the file does not exist, and it may not be created.
return Promise.reject("Cannot open file '" + file_path + "', as it does not exist. (If you want to allow file creation, add :can-create-file to the shell command output.)");
}
}
}
OutputChannel_OpenFiles.title = "Open files";
OutputChannel_OpenFiles.hotkey_letter = "O";
/**
* This output channel is not suitable for stderr, as stderr can contain unexpected messages.
* @protected
*/
OutputChannel_OpenFiles.accepted_output_streams = ["stdout"];
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
const outputChannelClasses = {};
// Register output channels
registerOutputChannel("notification", OutputChannel_Notification);
registerOutputChannel("current-file-caret", OutputChannel_CurrentFileCaret);
registerOutputChannel("current-file-top", OutputChannel_CurrentFileTop);
registerOutputChannel("current-file-bottom", OutputChannel_CurrentFileBottom);
registerOutputChannel("open-files", OutputChannel_OpenFiles);
registerOutputChannel("status-bar", OutputChannel_StatusBar);
registerOutputChannel("clipboard", OutputChannel_Clipboard);
registerOutputChannel("modal", OutputChannel_Modal);
/**
* This function is designed to be called after a 'Wait until finished' type of shell command finishes its execution.
*
* @param plugin
* @param t_shell_command
* @param shell_command_parsing_result
* @param stdout
* @param stderr
* @param error_code TODO: Rename to exitCode everywhere in the codebase.
* @param output_channels
*/
function handleBufferedOutput(plugin, t_shell_command, shell_command_parsing_result, stdout, stderr, error_code, output_channels) {
// Terminology: Stream = outputs stream from a command, can be "stdout" or "stderr". Channel = a method for this application to present the output ot user, e.g. "notification".
const shell_command_configuration = t_shell_command.getConfiguration(); // TODO: Refactor OutputChannels to use TShellCommand instead of the configuration objects directly.
// Insert stdout and stderr to an object in a correct order
let output = {};
if (stdout.length && stderr.length) {
// Both stdout and stderr have content
// Decide the output order == Find out which data stream should be processed first, stdout or stderr.
switch (shell_command_configuration.output_channel_order) {
case "stdout-first":
output = {
stdout: stdout,
stderr: stderr,
};
break;
case "stderr-first":
output = {
stderr: stderr,
stdout: stdout,
};
break;
}
}
else if (stdout.length) {
// Only stdout has content
output = {
stdout: stdout,
};
}
else if (stderr.length) {
// Only stderr has content
output = {
stderr: stderr,
};
}
else {
// Neither stdout nor stderr have content
// Provide empty output, some output channels will process it, while other will just ignore it.
output = {
"stdout": "",
};
}
// Should stderr be processed same time with stdout?
if (output_channels.stdout === output_channels.stderr) {
// Stdout and stderr use the same channel.
// Make one handling call.
handle_stream(plugin, t_shell_command, shell_command_parsing_result, output_channels.stdout, output, error_code);
}
else {
// Stdout and stderr use different channels.
// Make two handling calls.
let output_stream_name;
for (output_stream_name in output) {
const output_channel_name = output_channels[output_stream_name];
const output_message = output[output_stream_name];
const separated_output = {};
separated_output[output_stream_name] = output_message;
handle_stream(plugin, t_shell_command, shell_command_parsing_result, output_channel_name, separated_output, error_code);
}
}
}
async function handle_stream(plugin, t_shell_command, shell_command_parsing_result, output_channel_name, output, error_code) {
// Check if the output should be ignored
if ("ignore" !== output_channel_name) {
// The output should not be ignored.
// Check that an output channel class exists
if (undefined === outputChannelClasses[output_channel_name]) {
throw new Error("No output channel class found for channel '" + output_channel_name + "'.");
}
// Instantiate the channel
const outputChannel = initializeOutputChannel(output_channel_name, plugin, t_shell_command, shell_command_parsing_result, "buffered", null);
// Perform handling the output
await outputChannel.handleBuffered(output, error_code);
}
}
function startRealtimeOutputHandling(plugin, tShellCommand, shellCommandParsingResult, outputChannelCodes, processTerminator) {
const outputChannels = {};
// stdout
if ("ignore" !== outputChannelCodes.stdout) {
outputChannels.stdout = initializeOutputChannel(outputChannelCodes.stdout, plugin, tShellCommand, shellCommandParsingResult, "realtime", processTerminator);
}
// stderr
if ("ignore" !== outputChannelCodes.stderr) {
if (outputChannelCodes.stderr === outputChannelCodes.stdout) {
// stderr should use the same channel instance as stdout.
outputChannels.stderr = outputChannels.stdout;
}
else {
// stderr uses a different channel than stdout.
outputChannels.stderr = initializeOutputChannel(outputChannelCodes.stderr, plugin, tShellCommand, shellCommandParsingResult, "realtime", processTerminator);
}
}
return outputChannels;
}
function getOutputChannelsOptionList(output_stream) {
const list = { ignore: "Ignore" };
for (const name in outputChannelClasses) {
const channelClass = outputChannelClasses[name];
// Check that the stream is suitable for the channel
if (channelClass.acceptsOutputStream(output_stream)) {
list[name] = channelClass.getTitle(output_stream);
}
}
return list;
}
function getOutputChannelClasses() {
return outputChannelClasses;
}
function initializeOutputChannel(channelCode, plugin, tShellCommand, shellCommandParsingResult, outputHandlingMode, processTerminator) {
// @ts-ignore TODO: Find out how to tell TypeScript that a subclass is being instatiated instead of the abstract base class:
return new outputChannelClasses[channelCode](plugin, tShellCommand, shellCommandParsingResult, outputHandlingMode, processTerminator);
}
function registerOutputChannel(channelCode, channelClass) {
if (undefined !== outputChannelClasses[channelCode]) {
throw new Error("OutputChannel named '" + channelCode + "' is already registered!");
}
outputChannelClasses[channelCode] = channelClass;
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
const PlatformShells = {
darwin: {
"/bin/bash": "Bash",
"/bin/dash": "Dash",
"/bin/zsh": "Zsh (Z shell)",
},
linux: {
"/bin/bash": "Bash",
"/bin/dash": "Dash",
"/bin/zsh": "Zsh (Z shell)",
},
win32: {
"pwsh.exe": "PowerShell Core",
"PowerShell.exe": "PowerShell 5",
"CMD.EXE": "cmd.exe",
},
};
function getUsersDefaultShell() {
if (isWindows()) {
if (undefined === process.env.ComSpec) {
throw new Error("process.env.ComSpec is not a string.");
}
return process.env.ComSpec;
}
else {
if (undefined === process.env.SHELL) {
throw new Error("process.env.SHELL is not a string.");
}
return process.env.SHELL;
}
}
function isShellSupported(shell) {
const shell_file_name = extractFileName(shell);
const supported_shells = Object.getOwnPropertyNames(PlatformShells[getOperatingSystem()]);
// Linux and macOS: Add the ambiguous 'sh' as a supported shell. It's not present in PlatformShells, because it's
// not desired to be an explicitly selectable shell as it's uncertain, which shell it actually points to. But have
// it supported when it comes from the "Use system default (sh)" option.
if (!isWindows()) {
// The platform is either Linux or macOS.
// Add 'sh' support.
supported_shells.push("sh");
}
for (const supported_shell_path of supported_shells) {
// Check that the shell file names match. It doesn't matter in which directory the shell is located in.
if (extractFileName(supported_shell_path).toLowerCase() === shell_file_name.toLowerCase()) {
// The shell can be considered to be supported.
return true;
}
}
return false;
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function getDefaultSettings(is_new_installation) {
return {
// Common:
settings_version: is_new_installation
? SC_Plugin.SettingsVersion // For new installations, a specific settings version number can be used, as migrations do not need to be taken into account.
: "prior-to-0.7.0" // This will be substituted by ShellCommandsPlugin.saveSettings() when the settings are saved.
,
// Hidden settings (no UI controls in the settings panel)
debug: false,
obsidian_command_palette_prefix: "Execute: ",
// Variables:
preview_variables_in_command_palette: true,
show_autocomplete_menu: true,
// Environments:
working_directory: "",
default_shells: {},
environment_variable_path_augmentations: {},
// Output:
error_message_duration: 20,
notification_message_duration: 10,
execution_notification_mode: "disabled",
output_channel_clipboard_also_outputs_to_notification: true,
// Events:
enable_events: true,
// Modals:
approve_modals_by_pressing_enter_key: true,
// Shell commands:
max_visible_lines_in_shell_command_fields: false,
shell_commands: [],
// Prompts:
prompts: [],
// Additional configuration for built-in variables:
builtin_variables: {},
// Custom variables
custom_variables: [],
// Output wrappers
output_wrappers: [],
};
}
const PlatformNames = {
darwin: "Macintosh",
linux: "Linux",
win32: "Windows",
};
const CommandPaletteOptions = {
enabled: "Command palette & hotkeys",
unlisted: "Hotkeys only",
disabled: "Excluded",
};
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class ShellCommandExecutor {
constructor(plugin, t_shell_command,
/** Needed for Preactions to be able to access all variables, in case any variables are used by a Preaction. Use null, if the shell command execution happens outside of any event context. */
sc_event) {
this.plugin = plugin;
this.t_shell_command = t_shell_command;
this.sc_event = sc_event;
}
/**
* Performs preactions, and if they all give resolved Promises, executes the shell command.
*/
async doPreactionsAndExecuteShellCommand(parsing_process, overriding_output_channel) {
const preactions = this.t_shell_command.getPreactions();
// Does an already started ParsingProcess exist?
if (!parsing_process) {
// No ParsingProcess yet.
// Create one and parse all variables that are safe to parse before preactions.
debugLog("Going to prepare possible Preactions, but will first start a variable parsing process. Depending on possible Preactions, this might not yet parse all variables.");
parsing_process = this.t_shell_command.createParsingProcess(this.sc_event);
// Parse the first set of variables, not all sets.
if (!await parsing_process.process()) {
// Some errors happened.
debugLog("Will not prepare possible Preactions, because the parsing process failed. Will cancel shell command execution.");
parsing_process.displayErrorMessages();
return;
}
}
else {
debugLog("Going to prepare possible Preactions with an already started variable parsing process.");
}
// Create a pipeline for preactions.
let preaction_pipeline = Promise.resolve(true); // Will contain a series of preaction performs.
// Confirm execution from a user, if needed.
// I haven't decided yet if I want to move this to be its own Preaction subclass. Might make sense, but requires configuration migration.
if (this.t_shell_command.getConfiguration().confirm_execution) {
preaction_pipeline = preaction_pipeline.then(() => {
debugLog("Asking a confirmation from a user to execute shell command #" + this.t_shell_command.getId());
return new Promise((resolve, reject) => {
const confirmation_modal = new ConfirmationModal(this.plugin, this.t_shell_command.getAliasOrShellCommand(), "Execute this shell command?", "Yes, execute");
confirmation_modal.open();
confirmation_modal.promise.then((execution_confirmed) => {
if (execution_confirmed) {
// The PromptModal has been closed.
// Check if user wanted to execute the shell command or cancel.
if (execution_confirmed) {
// User wants to execute.
debugLog("User confirmed to execute shell command #" + this.t_shell_command.getId());
resolve(true);
}
else {
// User wants to cancel.
debugLog("User cancelled execution of shell command #" + this.t_shell_command.getId());
resolve(false);
}
}
});
});
});
}
// Perform preactions
preactions.forEach((preaction) => {
debugLog(`Adding Preaction of type '${preaction.configuration.type}' to pipeline.`);
preaction_pipeline = preaction_pipeline.then(() => {
debugLog(`Calling Preaction of type '${preaction.configuration.type}'.`);
if (!parsing_process) {
// Should have a ParsingProcess at this point.
throw new Error("No parsing process. Cannot do preaction.");
}
return preaction.perform(parsing_process, this.sc_event);
});
});
if (0 === preactions.length) {
debugLog("No Preactions to perform. This is ok.");
}
preaction_pipeline.then(async (can_execute) => {
if (can_execute) {
// Parse either all variables, or if some variables are already parsed, then just the rest. Might also be that
// all variables are already parsed.
debugLog("Parsing all the rest of the variables (if there are any left).");
if (!parsing_process) {
// Should have a ParsingProcess at this point.
throw new Error("No parsing process. Cannot execute shell command.");
}
if (await parsing_process.processRest()) {
// Parsing the rest of the variables succeeded
// Execute the shell command.
const parsing_results = parsing_process.getParsingResults();
const shell_command_parsing_result = {
shell_command: parsing_results["shell_command"].parsed_content,
alias: parsing_results["alias"].parsed_content,
environment_variable_path_augmentation: parsing_results.environment_variable_path_augmentation.parsed_content,
stdinContent: parsing_results.stdinContent?.parsed_content,
output_wrapper_stdout: parsing_results.output_wrapper_stdout?.parsed_content,
output_wrapper_stderr: parsing_results.output_wrapper_stderr?.parsed_content,
succeeded: true,
error_messages: [],
};
debugLog("Will call ShellCommandExecutor.executeShellCommand().");
this.executeShellCommand(shell_command_parsing_result, overriding_output_channel);
}
else {
// Parsing has failed.
debugLog("Parsing the rest of the variables failed.");
parsing_process.displayErrorMessages();
}
}
else {
// Cancel execution
debugLog("Shell command execution cancelled.");
}
});
}
/**
* Does not ask for confirmation before execution. This should only be called if: a) a confirmation is already asked from a user, or b) this command is defined not to need a confirmation.
* Use confirmAndExecuteShellCommand() instead to have a confirmation asked before the execution.
*
* @param shell_command_parsing_result The actual shell command that will be executed is taken from this object's '.shell_command' property.
* @param overriding_output_channel Optional. If specified, all output streams will be directed to this output channel. Otherwise, output channels are determined from this.t_shell_command.
*/
executeShellCommand(shell_command_parsing_result, overriding_output_channel) {
const working_directory = this.getWorkingDirectory();
// Define output channels
let outputChannels = this.t_shell_command.getOutputChannels();
if (overriding_output_channel) {
// Ignore the shell command's normal channels and use temporarily something else.
outputChannels = {
'stdout': overriding_output_channel,
'stderr': overriding_output_channel,
};
}
// Check that the shell command is not empty
const shell_command = shell_command_parsing_result.shell_command.trim();
if (!shell_command.length) {
// It is empty
const error_message = this.getErrorMessageForEmptyShellCommand();
debugLog(error_message);
this.plugin.newError(error_message);
return;
}
// Check that the currently defined shell is supported by this plugin. If using system default shell, it's possible
// that the shell is something that is not supported. Also, the settings file can be edited manually, and incorrect
// shell can be written there.
const shell = this.t_shell_command.getShell();
if (!isShellSupported(shell)) {
debugLog("Shell is not supported: " + shell);
this.plugin.newError("This plugin does not support the following shell: " + shell);
return;
}
// Define an object for environment variables.
const environment_variables = cloneObject(process.env); // Need to clone process.env, otherwise the modifications below will be stored permanently until Obsidian is hard-restarted (= closed and launched again).
// Augment the PATH environment variable (if wanted)
const augmented_path = this.augmentPATHEnvironmentVariable(shell_command_parsing_result.environment_variable_path_augmentation);
if (augmented_path.length > 0) {
environment_variables[getPATHEnvironmentVariableName()] = augmented_path;
}
// Check that the working directory exists and is a folder
if (!fs__namespace.existsSync(working_directory)) {
// Working directory does not exist
// Prevent execution
debugLog("Working directory does not exist: " + working_directory);
this.plugin.newError("Working directory does not exist: " + working_directory);
}
else if (!fs__namespace.lstatSync(working_directory).isDirectory()) {
// Working directory is not a directory.
// Prevent execution
debugLog("Working directory exists but is not a folder: " + working_directory);
this.plugin.newError("Working directory exists but is not a folder: " + working_directory);
}
else {
// Working directory is OK
// Prepare execution options
const options = {
"cwd": working_directory,
"shell": shell,
"env": environment_variables,
};
// Execute the shell command
debugLog("Executing command " + shell_command + " in " + working_directory + "...");
try {
const child_process$1 = child_process.spawn(shell_command, options);
// Pass stdin content (if defined)
if (undefined !== shell_command_parsing_result.stdinContent) {
// Stdin content is defined
debugLog("Stdin content is present in parsing result. Will write it to the process.");
if (null === child_process$1.stdin) {
// noinspection ExceptionCaughtLocallyJS: The exception is caught locally below, but it's ok because it's then rethrown as the error message does not match '/spawn\s+ENAMETOOLONG/i'.
throw new Error("Shell command execution process does not have a standard input stream (stdin).");
}
child_process$1.stdin.write(shell_command_parsing_result.stdinContent);
child_process$1.stdin.end();
}
else {
debugLog("No stdin content is present in parsing result.");
}
// Common error handling regardless of output handling mode
child_process$1.on("error", (error) => {
// Probably most errors will NOT end up here, I guess this event occurs for some rare errors.
//
// A quote from https://nodejs.org/api/child_process.html#event-error (read 2022-10-29):
// > The 'error' event is emitted whenever:
// > - The process could not be spawned, or
// > - The process could not be killed, or
// > - Sending a message to the child process failed.
debugLog("Shell command failed to execute: Received a non-stderr error message: " + error.message);
this.plugin.newError("Shell command failed to execute. Error: " + error.message);
});
// Define output encoding
if (null === child_process$1.stdout || null == child_process$1.stderr) {
// The exception is caught locally below, but it's ok because it's then rethrown as the error message does not match '/spawn\s+ENAMETOOLONG/i'.
throw new Error("Child process's stdout and/or stderr stream is null.");
}
child_process$1.stdout.setEncoding("utf8"); // Receive stdout and ...
child_process$1.stderr.setEncoding("utf8"); // ... stderr as strings, not as Buffer objects.
// Define a terminator
const processTerminator = () => {
child_process$1.kill("SIGTERM");
};
// Hook into child_process for output handling
switch (this.t_shell_command.getOutputHandlingMode()) {
case "buffered": {
// Output will be buffered and handled as a single batch.
this.handleBufferedOutput(child_process$1, shell_command_parsing_result, outputChannels);
break;
}
case "realtime": {
// Output will be handled on-the-go.
this.handleRealtimeOutput(child_process$1, shell_command_parsing_result, outputChannels, processTerminator);
}
}
// Display a notification of the execution (if wanted).
if ("disabled" !== this.plugin.settings.execution_notification_mode) {
this.showExecutionNotification(child_process$1, shell_command, this.plugin.settings.execution_notification_mode, processTerminator);
}
}
catch (exception) {
// An exception has happened.
// Check if the shell command was too long.
if (exception.message.match(/spawn\s+ENAMETOOLONG/i)) {
// It was too long. Show an error message.
this.plugin.newError("Shell command execution failed because it's too long: " + shell_command.length + " characters. (Unfortunately the max limit is unknown).");
}
else {
// The shell command was not too long, this exception is about something else.
// Rethrow the exception.
throw exception;
}
}
}
}
handleBufferedOutput(child_process, shell_command_parsing_result, outputChannels) {
child_process.on("exit", (exitCode) => {
// exitCode is null if user terminated the process. Reference: https://nodejs.org/api/child_process.html#event-exit (read on 2022-11-27).
// Get outputs
if (null === child_process.stdout || null == child_process.stderr) {
// The exception is caught locally below, but it's ok because it's then rethrown as the error message does not match '/spawn\s+ENAMETOOLONG/i'.
throw new Error("Child process's stdout and/or stderr stream is null.");
}
const stdout = child_process.stdout.read() ?? "";
let stderr = child_process.stderr.read() ?? ""; // let instead of const: stderr can be emptied later due to ignoring.
// Did the shell command execute successfully?
if (exitCode === null || exitCode > 0) {
// Some error occurred
debugLog("Command executed and failed. Error number: " + exitCode + ". Stderr: " + stderr);
// Check if this error should be displayed to the user or not
if (null !== exitCode && this.t_shell_command.getIgnoreErrorCodes().contains(exitCode)) {
// The user has ignored this error.
debugLog("User has ignored this error, so won't display it.");
// Handle only stdout output stream
stderr = "";
exitCode = null; // TODO: consider if exitCode should just be left untouched. It could be informative to 'Ask after execution' output channel that shows exit code to user.
}
else {
// The error can be shown.
debugLog("Will display the error to user.");
}
// Handle at least stdout (and maybe stderr) output stream
handleBufferedOutput(this.plugin, this.t_shell_command, shell_command_parsing_result, stdout, stderr, exitCode, outputChannels);
}
else {
// Probably no errors, but do one more check.
// Even when 'error' is null and everything should be ok, there may still be error messages outputted in stderr.
if (stderr.length > 0) {
// Check a special case: should error code 0 be ignored?
if (this.t_shell_command.getIgnoreErrorCodes().contains(0)) {
// Exit code 0 is on the ignore list, so suppress stderr output.
stderr = "";
debugLog("Shell command executed: Encountered error code 0, but stderr is ignored.");
}
else {
debugLog("Shell command executed: Encountered error code 0, and stderr will be relayed to an output handler.");
}
}
else {
debugLog("Shell command executed: No errors.");
}
// Handle output
handleBufferedOutput(this.plugin, this.t_shell_command, shell_command_parsing_result, stdout, stderr, 0, outputChannels); // Use zero as an error code instead of null (0 means no error). If stderr happens to contain something, exit code 0 gets displayed in an error balloon (if that is selected as a channel for stderr).
}
});
}
handleRealtimeOutput(childProcess, shell_command_parsing_result, outputChannelCodes, processTerminator) {
// Prepare output channels
const outputChannels = startRealtimeOutputHandling(this.plugin, this.t_shell_command, shell_command_parsing_result, outputChannelCodes, processTerminator);
// Define an output handler
const handleNewOutputContent = async (outputStreamName, readableStream) => {
if (null === childProcess.stdout || null == childProcess.stderr) {
throw new Error("Child process's stdout and/or stderr stream is null.");
}
// Don't emit new events while the current handling is in progress. (I think) it might cause a race condition where a simultaneous handling could overwrite another handling's data. Pause both streams, not just the current one, to maintain correct handling order also between the two streams.
childProcess.stdout.pause();
childProcess.stderr.pause();
const outputContent = readableStream.read() ?? "";
const outputChannel = outputChannels[outputStreamName];
if (undefined === outputChannel) {
throw new Error("Output channel is undefined.");
}
await outputChannel.handleRealtime(outputStreamName, outputContent);
// Can emit new events again.
childProcess.stdout.resume();
childProcess.stderr.resume();
};
// Hook into output streams' (such as stdout and stderr) output retrieving events.
// Note that there might be just one stream, e.g. only stderr, if stdout is ignored. In the future, there might also be more than two streams, when custom streams are implemented.
for (const outputStreamName of Object.getOwnPropertyNames(outputChannels)) {
const readableStream = childProcess[outputStreamName];
if (null === readableStream) {
throw new Error("Child process's readable stream '" + outputStreamName + "' is null.");
}
readableStream.on("readable", () => handleNewOutputContent(outputStreamName, readableStream));
}
// Hook into exit events
childProcess.on("exit", (exitCode, signal /* TODO: Pass signal to channels so it can be shown to users in the future */) => {
// Call all OutputChannels' endRealtime().
const alreadyCalledChannelCodes = [];
for (const outputStreamName of Object.getOwnPropertyNames(outputChannels)) {
const outputChannel = outputChannels[outputStreamName];
if (undefined === outputChannel) {
throw new Error("Output channel is undefined.");
}
const outputChannelCode = outputChannelCodes[outputStreamName];
// Ensure this OutputChannel has not yet been called.
if (!alreadyCalledChannelCodes.includes(outputChannelCode)) {
// Not yet called, so do the call.
outputChannel.endRealtime(exitCode);
// Mark that this channel's endRealtime() has already been called. Solves a situation where stderr and stdout uses the same channel, in which case endRealtime() should not be accidentally called twice.
alreadyCalledChannelCodes.push(outputChannelCode);
}
}
});
}
getWorkingDirectory() {
// Returns either a user defined working directory, or an automatically detected one.
const working_directory = this.plugin.settings.working_directory;
if (working_directory.length == 0) {
// No working directory specified, so use the vault directory.
return getVaultAbsolutePath(this.plugin.app);
}
else if (!path__namespace.isAbsolute(working_directory)) {
// The working directory is relative.
// Help to make it refer to the vault's directory. Without this, the relative path would refer to Obsidian's installation directory (at least on Windows).
return path__namespace.join(getVaultAbsolutePath(this.plugin.app), working_directory);
}
return working_directory;
}
augmentPATHEnvironmentVariable(path_augmentation) {
path_augmentation = convertNewlinesToPATHSeparators(path_augmentation, getOperatingSystem());
// Check if there's anything to augment.
if (path_augmentation.length > 0) {
// Augment.
const original_path = process.env[getPATHEnvironmentVariableName()];
if (undefined === original_path) {
throw new Error("process.env does not contain '" + getPATHEnvironmentVariableName() + "'.");
}
let augmented_path;
if (path_augmentation.contains(original_path)) {
// The augmentation contains the original PATH.
// Simply replace the whole original PATH with the augmented one, as there's no need to care about including
// the original content.
debugLog("Augmenting environment variable PATH so it will become " + path_augmentation);
augmented_path = path_augmentation;
}
else {
// The augmentation does not contain the original PATH.
// Instead of simply replacing the original PATH, append the augmentation after it.
const separator = getPATHSeparator(getOperatingSystem());
debugLog("Augmenting environment variable PATH by adding " + separator + path_augmentation + " after it.");
augmented_path = original_path + separator + path_augmentation;
}
debugLog("PATH augmentation result: " + augmented_path);
return augmented_path;
}
else {
// No augmenting is needed.
debugLog("No augmentation is defined for environment variable PATH. This is completely ok.");
return "";
}
}
/**
* This method should only be called if it's first checked that neither shell command version for the current platform nor a 'default' version exists.
*
* @private
*/
getErrorMessageForEmptyShellCommand() {
if (this.t_shell_command.getNonEmptyPlatformIds().length > 0) {
// The shell command contains versions for other platforms, but not for the current one.
const current_platform_name = PlatformNames[getOperatingSystem()];
const version_word = this.t_shell_command.getNonEmptyPlatformIds().length > 1 ? "versions" : "a version";
const other_platform_names = this.t_shell_command.getNonEmptyPlatformIds().map(platform_id => PlatformNames[platform_id]).join(" and ");
return `The shell command does not have a version for ${current_platform_name}, it only has ${version_word} for ${other_platform_names}.`;
}
else {
// The shell command doesn't contain a version for any platforms, it's completely empty.
return "The shell command is empty. :(";
}
}
/**
* Displays a notification balloon indicating a user that a shell command is being executed.
*
* @param child_process
* @param shell_command
* @param execution_notification_mode
* @param processTerminator Will be called if user clicks 'Request to terminate the process' icon.
* @private
*/
showExecutionNotification(child_process, shell_command, execution_notification_mode, processTerminator) {
const createRequestTerminatingButton = (notice) => {
// @ts-ignore Notice.noticeEl belongs to Obsidian's PRIVATE API, and it may change without a prior notice. Only
// create the button if noticeEl exists and is an HTMLElement.
const noticeEl = notice.noticeEl;
if (undefined !== noticeEl && noticeEl instanceof HTMLElement) {
this.plugin.createRequestTerminatingButton(noticeEl, processTerminator);
}
};
const execution_notification_message = "Executing: " + (this.t_shell_command.getAlias() || shell_command);
switch (execution_notification_mode) {
case "quick": {
// Retrieve the timeout from settings defined by a user.
const processNotification = this.plugin.newNotification(execution_notification_message, undefined);
createRequestTerminatingButton(processNotification);
break;
}
case "permanent": {
// Show the notification until the process ends.
const processNotification = this.plugin.newNotification(execution_notification_message, 0);
createRequestTerminatingButton(processNotification);
// Hide the notification when the process finishes.
child_process.on("exit", () => processNotification.hide());
break;
}
case "if-long": {
// Only show the notification if the process runs for an extended period of time (defined below).
window.setTimeout(() => {
// Check if the process is still running.
if (null === child_process.exitCode && !child_process.killed) {
// The process is still running.
// Display notification.
const processNotification = this.plugin.newNotification(execution_notification_message, 0);
createRequestTerminatingButton(processNotification);
// Hide the notification when the process finishes.
child_process.on("exit", () => processNotification.hide());
}
}, 2000); // If you change the timeout, change documentation, too!
break;
}
}
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Instance {
constructor(model, configuration, parent_instance_or_configuration) {
this.model = model;
this.configuration = configuration;
debugLog(this.constructor.name + ": Creating a new instance.");
// Determine parent type
if (parent_instance_or_configuration instanceof Instance) {
// It's an instance object
this.parent_instance = parent_instance_or_configuration;
this.parent_configuration = this.parent_instance.configuration;
}
else {
// It's a configuration object.
// No parent instance is available, so probably this is about SC_MainSettings object, as it does not have Model/Instance classes (at least yet).
this.parent_instance = null; // It's null already, but do this just to make a statement.
this.parent_configuration = parent_instance_or_configuration;
}
}
setIfValid(field, value) {
return this.model.validateValue(this, field, value).then(() => {
this.configuration[field] = value;
});
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Model {
constructor(plugin) {
this.plugin = plugin;
}
createSettingFields(instance, parent_element, with_deletion = true) {
debugLog(this.constructor.name + ": Creating setting fields.");
// Create a container
const setting_fields_container = parent_element.createDiv(); // Create a nested container that can be easily deleted if the instance is deleted.
const main_setting_field = this._createSettingFields(instance, setting_fields_container);
if (with_deletion) {
main_setting_field.addExtraButton(button => button
.setIcon("trash")
.setTooltip("Delete this " + this.getSingularName().toLocaleLowerCase())
.onClick(() => {
// The trash icon has been clicked
// Open up a modal asking for confirmation if the instance can be deleted from this.parent_configuration.
const confirmation_modal = new ConfirmationModal(this.plugin, "Delete " + this.getSingularName().toLocaleLowerCase() + ": " + instance.getTitle(), "Are you sure you want to delete this " + this.getSingularName().toLocaleLowerCase() + "?", "Yes, delete");
confirmation_modal.open();
confirmation_modal.promise.then(async (deletion_confirmed) => {
if (deletion_confirmed) {
// User has confirmed the deletion.
// Delete the configuration and remove the instance from custom collections.
this.deleteInstance(instance);
// Delete setting fields.
setting_fields_container.remove();
// Save settings
await this.plugin.saveSettings();
}
});
}));
}
return main_setting_field;
}
/**
* Deletes the instance from configuration, and calls _deleteChild() which will delete the instance from custom collections.
*
* Can be made public if needed.
*/
deleteInstance(instance) {
debugLog(this.constructor.name + ": Deleting an instance.");
this._deleteInstance(instance);
const relation = this.defineParentConfigurationRelation(instance);
switch (relation.type) {
// case "one-to-one": // TODO: Uncomment when first model that needs this is implemented.
// This is a relation where 'key' points directly to the instance's configuration.
// delete this.parent_configuration[this.relation.key];
// break;
case "one-to-many-index": {
// This is a relation where 'key' points to an indexed array of instance configurations. Use 'index' to pick the correct instance configuration.
instance.parent_configuration[relation.key].splice(relation.index, 1); // Do not use delete, as it would place null in the list.
break;
}
case "one-to-many-id": {
// This is a relation where 'key' points to an indexed array of instance configurations. Use 'id' to determine the correct index.
const index = this.idToIndex(instance.parent_configuration[relation.key], relation.id);
if (null === index) {
// Something went wrong
throw new Error(`${this.constructor.name}.deleteInstance(): Could not find an index for id ${relation.id}.`);
}
instance.parent_configuration[relation.key].splice(index, 1); // Do not use delete, as it would place null in the list.
break;
}
}
}
idToIndex(configurations, id) {
let result_index = null;
configurations.forEach((instance_configuration, index) => {
if (instance_configuration.id === id) {
// This is the correct configuration.
result_index = index;
}
});
return result_index;
}
/**
* This should delete the instance from custom collections. It should be overridden by all Instance classes that have deletable children.
*/
_deleteInstance(instance) {
throw new Error(this.constructor.name + ".deleteInstance(): This class does not override _deleteInstance() method. Maybe the class is not supposed to have children?");
}
}
// Model class collection
const model_classes = new Map();
function introduceModelClass(model_class) {
model_classes.set(model_class.constructor.name, model_class);
}
function getModel(model_class_name) {
return model_classes.get(model_class_name);
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputWrapper extends Instance {
constructor(model, plugin, configuration, parent_configuration) {
super(model, configuration, parent_configuration);
this.model = model;
this.plugin = plugin;
this.configuration = configuration;
this.parent_configuration = parent_configuration;
// Introduce the ID to an ID generator so that it won't accidentally generate the same ID again when creating new OutputWrappers.
getIDGenerator().addReservedID(configuration.id);
}
getID() {
return this.configuration.id;
}
getTitle() {
return this.configuration.title;
}
getContent() {
return this.configuration.content;
}
getConfiguration() {
return this.configuration;
}
}
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn) {
var module = { exports: {} };
return fn(module, module.exports), module.exports;
}
var autocomplete = createCommonjsModule(function (module, exports) {
(function (global, factory) {
module.exports = factory() ;
}(commonjsGlobal, (function () {
/*
* https://github.com/kraaden/autocomplete
* Copyright (c) 2016 Denys Krasnoshchok
* MIT License
*/
function autocomplete(settings) {
// just an alias to minimize JS file size
var doc = document;
var container = settings.container || doc.createElement("div");
var containerStyle = container.style;
var userAgent = navigator.userAgent;
var mobileFirefox = ~userAgent.indexOf("Firefox") && ~userAgent.indexOf("Mobile");
var debounceWaitMs = settings.debounceWaitMs || 0;
var preventSubmit = settings.preventSubmit || false;
var disableAutoSelect = settings.disableAutoSelect || false;
// 'keyup' event will not be fired on Mobile Firefox, so we have to use 'input' event instead
var keyUpEventName = mobileFirefox ? "input" : "keyup";
var items = [];
var inputValue = "";
var minLen = 2;
var showOnFocus = settings.showOnFocus;
var selected;
var keypressCounter = 0;
var debounceTimer;
if (settings.minLength !== undefined) {
minLen = settings.minLength;
}
if (!settings.input) {
throw new Error("input undefined");
}
var input = settings.input;
container.className = "autocomplete " + (settings.className || "");
// IOS implementation for fixed positioning has many bugs, so we will use absolute positioning
containerStyle.position = "absolute";
/**
* Detach the container from DOM
*/
function detach() {
var parent = container.parentNode;
if (parent) {
parent.removeChild(container);
}
}
/**
* Clear debouncing timer if assigned
*/
function clearDebounceTimer() {
if (debounceTimer) {
window.clearTimeout(debounceTimer);
}
}
/**
* Attach the container to DOM
*/
function attach() {
if (!container.parentNode) {
doc.body.appendChild(container);
}
}
/**
* Check if container for autocomplete is displayed
*/
function containerDisplayed() {
return !!container.parentNode;
}
/**
* Clear autocomplete state and hide container
*/
function clear() {
// prevent the update call if there are pending AJAX requests
keypressCounter++;
items = [];
inputValue = "";
selected = undefined;
detach();
}
/**
* Update autocomplete position
*/
function updatePosition() {
if (!containerDisplayed()) {
return;
}
containerStyle.height = "auto";
containerStyle.width = input.offsetWidth + "px";
var maxHeight = 0;
var inputRect;
function calc() {
var docEl = doc.documentElement;
var clientTop = docEl.clientTop || doc.body.clientTop || 0;
var clientLeft = docEl.clientLeft || doc.body.clientLeft || 0;
var scrollTop = window.pageYOffset || docEl.scrollTop;
var scrollLeft = window.pageXOffset || docEl.scrollLeft;
inputRect = input.getBoundingClientRect();
var top = inputRect.top + input.offsetHeight + scrollTop - clientTop;
var left = inputRect.left + scrollLeft - clientLeft;
containerStyle.top = top + "px";
containerStyle.left = left + "px";
maxHeight = window.innerHeight - (inputRect.top + input.offsetHeight);
if (maxHeight < 0) {
maxHeight = 0;
}
containerStyle.top = top + "px";
containerStyle.bottom = "";
containerStyle.left = left + "px";
containerStyle.maxHeight = maxHeight + "px";
}
// the calc method must be called twice, otherwise the calculation may be wrong on resize event (chrome browser)
calc();
calc();
if (settings.customize && inputRect) {
settings.customize(input, inputRect, container, maxHeight);
}
}
/**
* Redraw the autocomplete div element with suggestions
*/
function update() {
// delete all children from autocomplete DOM container
while (container.firstChild) {
container.removeChild(container.firstChild);
}
// function for rendering autocomplete suggestions
var render = function (item, currentValue) {
var itemElement = doc.createElement("div");
itemElement.textContent = item.label || "";
return itemElement;
};
if (settings.render) {
render = settings.render;
}
// function to render autocomplete groups
var renderGroup = function (groupName, currentValue) {
var groupDiv = doc.createElement("div");
groupDiv.textContent = groupName;
return groupDiv;
};
if (settings.renderGroup) {
renderGroup = settings.renderGroup;
}
var fragment = doc.createDocumentFragment();
var prevGroup = "#9?$";
items.forEach(function (item) {
if (item.group && item.group !== prevGroup) {
prevGroup = item.group;
var groupDiv = renderGroup(item.group, inputValue);
if (groupDiv) {
groupDiv.className += " group";
fragment.appendChild(groupDiv);
}
}
var div = render(item, inputValue);
if (div) {
div.addEventListener("click", function (ev) {
settings.onSelect(item, input);
clear();
ev.preventDefault();
ev.stopPropagation();
});
if (item === selected) {
div.className += " selected";
}
fragment.appendChild(div);
}
});
container.appendChild(fragment);
if (items.length < 1) {
if (settings.emptyMsg) {
var empty = doc.createElement("div");
empty.className = "empty";
empty.textContent = settings.emptyMsg;
container.appendChild(empty);
}
else {
clear();
return;
}
}
attach();
updatePosition();
updateScroll();
}
function updateIfDisplayed() {
if (containerDisplayed()) {
update();
}
}
function resizeEventHandler() {
updateIfDisplayed();
}
function scrollEventHandler(e) {
if (e.target !== container) {
updateIfDisplayed();
}
else {
e.preventDefault();
}
}
function keyupEventHandler(ev) {
var keyCode = ev.which || ev.keyCode || 0;
var ignore = settings.keysToIgnore || [38 /* Up */, 13 /* Enter */, 27 /* Esc */, 39 /* Right */, 37 /* Left */, 16 /* Shift */, 17 /* Ctrl */, 18 /* Alt */, 20 /* CapsLock */, 91 /* WindowsKey */, 9 /* Tab */];
for (var _i = 0, ignore_1 = ignore; _i < ignore_1.length; _i++) {
var key = ignore_1[_i];
if (keyCode === key) {
return;
}
}
if (keyCode >= 112 /* F1 */ && keyCode <= 123 /* F12 */ && !settings.keysToIgnore) {
return;
}
// the down key is used to open autocomplete
if (keyCode === 40 /* Down */ && containerDisplayed()) {
return;
}
startFetch(0 /* Keyboard */);
}
/**
* Automatically move scroll bar if selected item is not visible
*/
function updateScroll() {
var elements = container.getElementsByClassName("selected");
if (elements.length > 0) {
var element = elements[0];
// make group visible
var previous = element.previousElementSibling;
if (previous && previous.className.indexOf("group") !== -1 && !previous.previousElementSibling) {
element = previous;
}
if (element.offsetTop < container.scrollTop) {
container.scrollTop = element.offsetTop;
}
else {
var selectBottom = element.offsetTop + element.offsetHeight;
var containerBottom = container.scrollTop + container.offsetHeight;
if (selectBottom > containerBottom) {
container.scrollTop += selectBottom - containerBottom;
}
}
}
}
/**
* Select the previous item in suggestions
*/
function selectPrev() {
if (items.length < 1) {
selected = undefined;
}
else {
if (selected === items[0]) {
selected = items[items.length - 1];
}
else {
for (var i = items.length - 1; i > 0; i--) {
if (selected === items[i] || i === 1) {
selected = items[i - 1];
break;
}
}
}
}
}
/**
* Select the next item in suggestions
*/
function selectNext() {
if (items.length < 1) {
selected = undefined;
}
if (!selected || selected === items[items.length - 1]) {
selected = items[0];
return;
}
for (var i = 0; i < (items.length - 1); i++) {
if (selected === items[i]) {
selected = items[i + 1];
break;
}
}
}
function keydownEventHandler(ev) {
var keyCode = ev.which || ev.keyCode || 0;
if (keyCode === 38 /* Up */ || keyCode === 40 /* Down */ || keyCode === 27 /* Esc */) {
var containerIsDisplayed = containerDisplayed();
if (keyCode === 27 /* Esc */) {
clear();
}
else {
if (!containerIsDisplayed || items.length < 1) {
return;
}
keyCode === 38 /* Up */
? selectPrev()
: selectNext();
update();
}
ev.preventDefault();
if (containerIsDisplayed) {
ev.stopPropagation();
}
return;
}
if (keyCode === 13 /* Enter */) {
if (selected) {
if (preventSubmit) {
ev.preventDefault();
}
settings.onSelect(selected, input);
clear();
}
}
}
function focusEventHandler() {
if (showOnFocus) {
startFetch(1 /* Focus */);
}
}
function startFetch(trigger) {
// If multiple keys were pressed, before we get an update from server,
// this may cause redrawing autocomplete multiple times after the last key was pressed.
// To avoid this, the number of times keyboard was pressed will be saved and checked before redraw.
var savedKeypressCounter = ++keypressCounter;
var inputText = input.value;
var cursorPos = input.selectionStart || 0;
if (inputText.length >= minLen || trigger === 1 /* Focus */) {
clearDebounceTimer();
debounceTimer = window.setTimeout(function () {
settings.fetch(inputText, function (elements) {
if (keypressCounter === savedKeypressCounter && elements) {
items = elements;
inputValue = inputText;
selected = (items.length < 1 || disableAutoSelect) ? undefined : items[0];
update();
}
}, trigger, cursorPos);
}, trigger === 0 /* Keyboard */ ? debounceWaitMs : 0);
}
else {
clear();
}
}
function blurEventHandler() {
// we need to delay clear, because when we click on an item, blur will be called before click and remove items from DOM
setTimeout(function () {
if (doc.activeElement !== input) {
clear();
}
}, 200);
}
/**
* Fixes #26: on long clicks focus will be lost and onSelect method will not be called
*/
container.addEventListener("mousedown", function (evt) {
evt.stopPropagation();
evt.preventDefault();
});
/**
* Fixes #30: autocomplete closes when scrollbar is clicked in IE
* See: https://stackoverflow.com/a/9210267/13172349
*/
container.addEventListener("focus", function () { return input.focus(); });
/**
* This function will remove DOM elements and clear event handlers
*/
function destroy() {
input.removeEventListener("focus", focusEventHandler);
input.removeEventListener("keydown", keydownEventHandler);
input.removeEventListener(keyUpEventName, keyupEventHandler);
input.removeEventListener("blur", blurEventHandler);
window.removeEventListener("resize", resizeEventHandler);
doc.removeEventListener("scroll", scrollEventHandler, true);
clearDebounceTimer();
clear();
}
// setup event handlers
input.addEventListener("keydown", keydownEventHandler);
input.addEventListener(keyUpEventName, keyupEventHandler);
input.addEventListener("blur", blurEventHandler);
input.addEventListener("focus", focusEventHandler);
window.addEventListener("resize", resizeEventHandler);
doc.addEventListener("scroll", scrollEventHandler, true);
return {
destroy: destroy
};
}
return autocomplete;
})));
});
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function getVariableAutocompleteItems(plugin) {
if (0 === autocomplete_items.length) {
plugin.getVariables().forEach((variable) => {
autocomplete_items.push(...variable.getAutocompleteItems());
});
}
return autocomplete_items;
}
function resetVariableAutocompleteItems() {
while (autocomplete_items.length) {
autocomplete_items.pop();
}
}
const autocomplete_items = [];
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
*
* @param plugin Used for getting a list of Variable autocomplete items.
* @param input_element
* @param call_on_completion A function that will be called when a user has selected a suggestion and performed the autocomplete action. onChange event will not be called, because it would trigger opening the autocomplete menu again, so that's why a separate callback is used.
* @param extra_autocomplete_items
*/
function createAutocomplete(plugin, input_element, call_on_completion, extra_autocomplete_items = []) {
const autocompleteMenu = autocomplete({
input: input_element,
fetch: (input_value_but_not_used, update) => {
const autocomplete_items = merge_and_sort_autocomplete_items(getVariableAutocompleteItems(plugin), CustomAutocompleteItems, extra_autocomplete_items);
const max_suggestions = 30;
// Get the so far typed text - exclude everything that is on the right side of the caret.
const caret_position = input_element.selectionStart;
if (null === caret_position) {
throw new Error("createAutocomplete(): fetch(): caret_position is null.");
}
const typed_text = input_element.value.slice(0, caret_position);
const search_query = get_search_query(typed_text);
if ("" === search_query.search_text) {
// No suggestions for empty word.
update([]);
}
else {
// The word is not empty, so can suggest something.
let matched_items = autocomplete_items.filter(item => item_match(item, search_query));
sort_autocomplete_items(matched_items, search_query);
matched_items = matched_items.slice(0, max_suggestions); // Limit to a reasonable amount of suggestions.
update(matched_items);
}
},
onSelect: (item) => {
// A user has selected an item to be autocompleted
// Get the item text and already typed text
let supplement = item.value;
let caret_position = input_element.selectionStart;
if (null === caret_position) {
throw new Error("createAutocomplete(): fetch(): caret_position is null.");
}
const typed_text = input_element.value.slice(0, caret_position);
const search_query = get_search_query(typed_text);
const search_text = search_query.search_text;
// Special case: Check if }} happens to appear after the caret
const after_caret = input_element.value.slice(caret_position, caret_position + 2);
if ("}}" === after_caret) {
// The replacing will happen in a {{variable}}.
// Do not accidentally insert another }} pair.
supplement = supplement.replace(/\}\}$/u, ""); // Only removes a trailing }} if there is one.
}
// Try to save part of the beginning, in case it seems like not being part of the search query.
let replace_start = find_starting_position(search_text, supplement); // The length difference of typed_text and search_text will be added here below.
if (false === replace_start) {
// This should never happen, but if it does, do not replace anything, just insert.
replace_start = caret_position;
}
else {
// Adjust the position
replace_start += typed_text.length - search_text.length;
}
// Choose a method for doing the inserting
if (undefined !== document.execCommand) {
// execCommand() is deprecated, but available.
// Use it to do the insertion, because this way an undo history can be preserved.
input_element.setSelectionRange(replace_start, caret_position); // First select the part that will be replaced, because execCommand() does not support defining positions. This adds a cumbersome selection step to the undo history, but at least undoing works.
document.execCommand("insertText", false, supplement);
}
else {
// execCommand() is not available anymore.
// Use setRangeText() to do the insertion. It will clear undo history, but at least the insertion works.
input_element.setRangeText(supplement, replace_start, caret_position);
}
// Move the caret to a logical continuation point
caret_position = replace_start + supplement.length;
if (supplement.match(/:\}\}$/u)) {
// Place the caret after the colon, instead of after }}.
caret_position -= 2;
}
input_element.setSelectionRange(caret_position, caret_position);
// Call a hook
call_on_completion(input_element.value);
},
render: (item) => {
const div_element = document.createElement("div");
div_element.createSpan({ text: item.value, attr: { class: "SC-autocomplete-value" } });
if (item.help_text) {
div_element.createSpan({ text: ": ", attr: { class: "SC-autocomplete-separator" } });
div_element.createSpan({ attr: { class: "SC-autocomplete-help-text" } }).insertAdjacentHTML("beforeend", item.help_text);
}
// Documentation link
const documentationLink = item.documentationLink;
if (undefined !== documentationLink) {
const documentationLinkElement = div_element.createEl("a", { attr: { "title": "Documentation: " + item.value } }); // Use "title" instead of "aria-label", because I don't know how to make "aria-label" show a tooltip box on a custom element.
obsidian.setIcon(documentationLinkElement, "help");
documentationLinkElement.addClass("SC-autocomplete-link-icon");
documentationLinkElement.onClickEvent((event) => {
gotoURL(documentationLink);
// event.preventDefault(); Not needed, I guess.
event.stopImmediatePropagation(); // Do not close the autocomplete menu.
});
}
return div_element;
},
minLength: 2,
className: "SC-autocomplete",
keysToIgnore: [38 /* Up */, 13 /* Enter */, 27 /* Esc */, 16 /* Shift */, 17 /* Ctrl */, 18 /* Alt */, 20 /* CapsLock */, 91 /* WindowsKey */, 9 /* Tab */],
preventSubmit: true, // Prevents creating newlines in textareas when enter is pressed in the autocomplete menu.
});
// Make the plugin able to close the menu if the plugin is disabled (or restarted).
plugin.registerAutocompleteMenu(autocompleteMenu);
}
function item_match(item, search_query) {
const item_value = item.value.toLocaleLowerCase();
const search_text = search_query.search_text.toLocaleLowerCase();
// Match query type
if (item.type !== search_query.search_type) {
// If the query type is different, do not include this item.
// This can happen e.g. if {{ is typed, and the item is not a variable, or {{! is typed, and the item is not an unescaped variable.
return false;
}
// Match text
let search_character;
let search_position = 0;
for (let search_character_index = 0; search_character_index < search_text.length; search_character_index++) {
search_character = search_text[search_character_index];
if (item_value.includes(search_character, search_position)) {
// This character was found in item_value.
search_position = item_value.indexOf(search_character, search_position) + 1;
}
else {
// This character was not found.
return false;
}
}
return true;
}
function find_starting_position(typed_text, supplement) {
typed_text = typed_text.toLocaleLowerCase();
supplement = supplement.toLocaleLowerCase();
for (let supplement_index = supplement.length; supplement_index >= 0; supplement_index--) {
const partial_supplement = supplement.slice(0, supplement_index);
if (typed_text.contains(partial_supplement)) {
return typed_text.indexOf(partial_supplement);
}
}
return false;
}
/**
* Sorts in place, does not make a copy.
* @param autocomplete_items
* @param search_query
*/
function sort_autocomplete_items(autocomplete_items, search_query) {
const search_text_excluding_curly_brackets = search_query.search_text.replace(/^{{!?/, "");
function get_common_beginning_length(autocomplete_item, search_query) {
const search_text = search_query.search_text.toLocaleLowerCase();
const item_value = autocomplete_item.value.toLocaleLowerCase();
const shortest_length = Math.min(search_text.length, item_value.length);
for (let character_index = 0; character_index < shortest_length; character_index++) {
const search_character = search_text[character_index];
const item_character = item_value[character_index];
if (search_character !== item_character) {
// The common beginning has ended.
return character_index;
}
}
return shortest_length;
}
autocomplete_items.sort((a, b) => {
const boost_a = Math.max(get_common_beginning_length(a, search_query), 1); // Boosts are used as multipliers,
const boost_b = Math.max(get_common_beginning_length(b, search_query), 1); // so they cannot be zero.
const a_length = a.value.length * boost_b; // boost_b worsens A (= makes it artificially "longer")
const b_length = b.value.length * boost_a; // boost_a worsens B
// Determine sorting method. If the search query is just a couple of characters, the matches would be quite vague, sorting by the matched items' length would not tell much, and the list would just look strangely ordered.
if (search_text_excluding_curly_brackets.length < 2 || a_length === b_length) {
// Sort alphabetically.
return a.value > b.value ? 1 : -1;
}
else {
// Sort by lengths. The shortest item is preferred. If an item has a long common beginning with the search query, boost the item up.
return a_length - b_length;
}
});
}
const CustomAutocompleteItems = [];
function addCustomAutocompleteItems(custom_autocomplete_yaml) {
// Ensure the content is not empty
if (0 === custom_autocomplete_yaml.trim().length) {
return "The content is empty.";
}
// Try to parse YAML syntax
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let yaml; // 'any' is defined in obsidian.d.ts for the return type of parseYaml(), so I made ESLint ignore it.
try {
yaml = obsidian.parseYaml(custom_autocomplete_yaml);
}
catch (error) {
// A syntax error has appeared.
return error.message;
}
if (null === yaml || typeof yaml !== "object") {
return "Unable to parse the content due to unknown reason.";
}
// Iterate autocomplete item groups
const group_names = Object.getOwnPropertyNames(yaml);
const error_messages = [];
group_names.forEach((group_name) => {
const group_items = yaml[group_name];
const group_item_values = Object.getOwnPropertyNames(group_items);
// Iterate all autocomplete items in the group
group_item_values.forEach((autocomplete_item_value) => {
const autocomplete_item_label = group_items[autocomplete_item_value];
if (typeof autocomplete_item_label !== "string") {
error_messages.push("Autocomplete item '" + autocomplete_item_value + "' has an incorrect help text type: " + autocomplete_item_label + " is a " + typeof autocomplete_item_label + ", but it should be a string.");
return;
}
// Determine a correct type for the item
let type = "other";
if (autocomplete_item_value.startsWith("{{")) {
// This is a variable
type = "normal-variable";
}
// The item is ok, add it to the list
CustomAutocompleteItems.push({
value: autocomplete_item_value,
help_text: autocomplete_item_label,
group: group_name,
type: type,
});
if (type === "normal-variable") {
// Add an unescaped version of the variable, too
CustomAutocompleteItems.push({
value: autocomplete_item_value.replace(/^\{\{/u, "{{!"),
help_text: autocomplete_item_label,
group: group_name,
type: "unescaped-variable",
});
}
});
});
if (error_messages.length > 0) {
// Something failed
return error_messages.join("; ");
}
// All ok
return true;
}
/**
* TODO: Can the sorting be removed from here? Now autocomplete items are sorted again every time when filtering, based on the keyword (https://github.com/Taitava/obsidian-shellcommands/issues/249).
* @param autocomplete_item_sets
*/
function merge_and_sort_autocomplete_items(...autocomplete_item_sets) {
const merged_autocomplete_items = (new Array()).concat(...autocomplete_item_sets);
return merged_autocomplete_items.sort((a, b) => {
// First compare groups
if (a.group < b.group) {
// a's group should come before b's group.
return -1;
}
else if (a.group > b.group) {
// a's group should come after b's group.
return 1;
}
else {
// The groups are the same.
// Compare values.
if (a.value < b.value) {
// a should come before b.
return -1;
}
else if (a.value > b.value) {
// a should come after b.
return 1;
}
else {
// The values are the same.
// The order does not matter.
return 0;
}
}
});
}
/**
* Reduces an input string to the nearest logical word.
* @param typed_text
*/
function get_search_query(typed_text) {
const searchTextMatchArray = typed_text.match(/\S*?$/u); // An array, but only one match is expected.
if (null === searchTextMatchArray) {
throw new Error("get_search_query(): Regex match failed.");
}
let search_text = searchTextMatchArray[0]; // Reduce the text - limit to a single word (= exclude spaces and everything before them).
let search_type = "other"; // May be overwritten.
if (search_text.contains("}}")) {
// The query happens right after a {{variable}}.
// Make the query string to start after the }} pair, i.e. remove }} and everything before it. This improves the search.
search_text = search_text.replace(/.+\}\}/u, "");
}
if (search_text.contains("{{")) {
// A {{variable}} is being queried.
// Make the query string to start from the {{ pair, i.e. remove everything before {{ . This improves the search.
search_text = search_text.replace(/.+\{\{/u, "{{");
if (search_text.contains("{{!")) {
// An _unescaped_ variable is searched for.
search_type = "unescaped-variable";
}
else {
// A normal variable is searched for.
search_type = "normal-variable";
}
}
return {
search_text: search_text,
search_type: search_type,
};
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputWrapperSettingsModal extends SC_Modal {
constructor(plugin, output_wrapper,
/** Can be undefined if the output wrapper is created from a place where there is no name element. */
output_wrapper_name_setting,
/** If defined, a button will be added and on_after_approval() / on_after_cancelling() will be called depending on whether the button was clicked or not. */
ok_button_text, on_after_approval, on_after_cancelling) {
super(plugin);
this.output_wrapper = output_wrapper;
this.output_wrapper_name_setting = output_wrapper_name_setting;
this.ok_button_text = ok_button_text;
this.on_after_approval = on_after_approval;
this.on_after_cancelling = on_after_cancelling;
this.approved = false;
}
onOpen() {
super.onOpen();
const container_element = this.modalEl.createDiv();
container_element.addClass("SC-setting-group"); // Make setting fields wider in this container.
// Title
const title_setting = new obsidian.Setting(container_element)
.setName("Output wrapper title")
.setDesc("Only used in settings, will not appear in output.")
.addText(text => text
.setValue(this.output_wrapper.getTitle())
.onChange(async (new_title) => {
this.output_wrapper.getConfiguration().title = new_title;
await this.plugin.saveSettings();
// Update the title in a name setting. (Only if the modal was created from a place where an OutputWrapper name element exists).
this.output_wrapper_name_setting?.setName(new_title);
}));
const title_input_element = title_setting.controlEl.find("input");
// Content
const output_variable = new Variable_Output(this.plugin, ""); // For getting an autocomplete item.
new obsidian.Setting(container_element)
.setName("Content")
.setDesc("Use {{output}} as a placeholder for text that will be received from a shell command. Other variables are available, too.")
.addTextArea(textarea_component => textarea_component
.setValue(this.output_wrapper.configuration.content)
.onChange(async (new_content) => {
this.output_wrapper.configuration.content = new_content;
await this.plugin.saveSettings();
})
.then((textarea_component) => {
// Autocomplete for Content.
if (this.plugin.settings.show_autocomplete_menu) {
createAutocomplete(this.plugin, textarea_component.inputEl, () => textarea_component.onChanged(), output_variable.getAutocompleteItems());
}
}));
// Focus on the title field.
title_input_element.focus();
// Ok button
const okButtonText = this.ok_button_text;
if (okButtonText) {
new obsidian.Setting(container_element)
.addButton(button => button
.setButtonText(okButtonText)
.onClick(() => this.approve()));
}
}
approve() {
if (this.on_after_approval) {
this.approved = true;
this.on_after_approval();
}
this.close();
}
onClose() {
super.onClose();
// Call a cancelling hook if one is defined (and if the closing happens due to cancelling, i.e. the ok button is NOT clicked).
if (!this.approved && this.on_after_cancelling) {
this.on_after_cancelling();
}
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class OutputWrapperModel extends Model {
constructor() {
super(...arguments);
this.output_wrappers = new OutputWrapperMap();
}
_createSettingFields(output_wrapper, container_element) {
debugLog("Creating setting fields for an OutputWrapper instance.");
const output_wrapper_name_setting = new obsidian.Setting(container_element)
// Configuration button
.setName(output_wrapper.getTitle())
.addExtraButton(button => button
.setTooltip("Define output wrapper content")
.setIcon("gear")
.onClick(() => {
this.openSettingsModal(output_wrapper, output_wrapper_name_setting);
}));
return output_wrapper_name_setting;
}
defineParentConfigurationRelation(output_wrapper) {
return {
type: "one-to-many-id",
key: "output_wrappers",
id: output_wrapper.getID(),
};
}
getSingularName() {
return "Output wrapper";
}
loadInstances(parent_configuration) {
debugLog("Loading OutputWrapper instances.");
this.output_wrappers = new OutputWrapperMap();
parent_configuration.output_wrappers.forEach((output_wrapper_configuration) => {
const output_wrapper = new OutputWrapper(this, this.plugin, output_wrapper_configuration, parent_configuration);
this.output_wrappers.set(output_wrapper_configuration.id, output_wrapper);
});
return this.output_wrappers;
}
newInstance(parent_configuration) {
debugLog("Creating a new OutputWrapper instance.");
// TODO: Move this logic to the base Model class.
// Setup a default configuration and generate an ID
const output_wrapper_configuration = this.getDefaultConfiguration();
// Instantiate an OutputWrapper
const output_wrapper = new OutputWrapper(this, this.plugin, output_wrapper_configuration, this.plugin.settings);
this.output_wrappers.set(output_wrapper.getID(), output_wrapper);
// Store the configuration into plugin's settings
parent_configuration.output_wrappers.push(output_wrapper_configuration);
// Return the OutputWrapper
return output_wrapper;
}
validateValue(output_wrapper, field, value) {
// No validation is needed, I guess. 'Title' and 'content' can both be empty, although an empty title does not make sense.
return Promise.resolve(undefined);
}
openSettingsModal(output_wrapper, output_wrapper_name_setting) {
debugLog("Opening settings modal for an OutputWrapper instance.");
const modal = new OutputWrapperSettingsModal(this.plugin, output_wrapper, output_wrapper_name_setting);
modal.open();
}
getDefaultConfiguration() {
return {
id: getIDGenerator().generateID(),
title: "",
content: "",
};
}
_deleteInstance(deletable_output_wrapper) {
debugLog("Deleting an OutputWrapper instance.");
// Remove the OutputWrapper from all TShellCommands that use it.
const shell_commands = this.plugin.getTShellCommands();
for (const shell_command_id in shell_commands) {
const t_shell_command = shell_commands[shell_command_id];
const output_wrappers = t_shell_command.getConfiguration().output_wrappers;
Object.each(output_wrappers, (output_wrapper_id, output_stream) => {
if (output_wrapper_id === deletable_output_wrapper.getID()) {
// A shell command uses the output wrapper that is about to be deleted.
// Configure the shell command not to use any output wrapper.
output_wrappers[output_stream] = null;
}
});
}
// Remove the OutputWrapper from this class's internal list.
this.output_wrappers.delete(deletable_output_wrapper.getID());
}
}
class OutputWrapperMap extends Map {
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function introduceModels(plugin) {
debugLog("Introducing models.");
// Keep in alphabetical order, if possible.
introduceModelClass(new CustomVariableModel(plugin));
introduceModelClass(new PromptFieldModel(plugin));
introduceModelClass(new PromptModel(plugin));
introduceModelClass(new OutputWrapperModel(plugin));
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* This class serves as the actual operational variable class for custom variables. It's paired with the CustomVariableInstance class, which acts
* as a configuration class to handle settings together with CustomVariableModel class.
*/
class CustomVariable extends Variable {
constructor(plugin, custom_variable_instance) {
super(plugin);
this.custom_variable_instance = custom_variable_instance;
this.value = null; // TODO: When implementing variable types, make this class abstract and let subclasses define the type of this property.
this.always_available = false;
this.on_change_callbacks = new Set();
this.updateProperties();
debugLog(`Loaded CustomVariable ${this.variable_name}.`);
}
async generateValue() {
if (null === this.value) {
debugLog(`Custom variable ${this.variable_name} does not have a value yet, and no default value is defined.`);
this.throw("This custom variable does not have a value yet, and no default value is defined.");
}
return this.value;
}
/**
* TODO: Make it possible to prevent calling onChange callbacks:
* - Make it possible to call the callbacks later outside this class.
* - This makes it possible to prevent unnecessary CustomVariableView updates when multiple CustomVariables are assigned values in one go (via Shell command URI).
* - Store the old value into some kind of history list.
* - When calling the callbacks, the current CustomVariable should be passed as a parameter instead of the 'value' and 'old_value' parameters (which can be accessed via the CustomVariable object).
*
* @param value
*/
async setValue(value) {
const old_value = this.value;
debugLog(`CustomVariable ${this.variable_name}: Setting value to: ${value} (old was: ${old_value}).`);
this.value = value;
// Call the onChange hook.
await this.callOnChangeCallbacks(value, old_value ?? ""); // Use "" if old_value is null.
}
/**
* Retrieves variable_name and help_text properties from the associated CustomVariableInstance.
* Called when loading the CustomVariable and when the associated CustomVariableInstance's settings are changed.
*/
updateProperties() {
debugLog(`CustomVariable ${this.variable_name}: Updating variable name and help text.`);
this.variable_name = this.custom_variable_instance.getPrefixedName();
this.help_text = this.custom_variable_instance.configuration.description;
resetVariableAutocompleteItems(); // Make autocomplete lists reload their content in order to get the new variable name/help text.
}
getIdentifier() {
return this.custom_variable_instance.getID();
}
/**
* Adds the given callback function to a stack of functions that will be called whenever this CustomVariable's value changes.
* @param on_change_callback
*/
onChange(on_change_callback) {
this.on_change_callbacks.add(on_change_callback);
}
async callOnChangeCallbacks(new_value, old_value) {
debugLog(`CustomVariable ${this.variable_name}: Calling onChange callbacks.`);
for (const on_change_callback of this.on_change_callbacks) {
await on_change_callback(this, new_value, old_value);
}
}
getConfiguration() {
return this.custom_variable_instance.configuration;
}
getGlobalDefaultValueConfiguration() {
return this.custom_variable_instance.configuration.default_value;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* This class serves as an accessor to CustomVariable configurations. It's paired with the CustomVariable class, which acts
* as an operational class to implement the variable functionality.
*
* TODO: Decide a better name for this class. It's too easy to confuse with the CustomVariable class name.
*/
class CustomVariableInstance extends Instance {
constructor(model, configuration, parent_configuration) {
super(model, configuration, parent_configuration);
this.model = model;
this.custom_variable = null;
// Introduce the ID to an ID generator so that it won't accidentally generate the same ID again when creating new CustomVariableInstances.
getIDGenerator().addReservedID(configuration.id);
debugLog(`Loaded CustomVariableInstance ${this.getID()}.`);
}
getID() {
return this.configuration.id;
}
getFullName() {
return `{{${this.getPrefixedName()}}}`;
}
/**
* Adds an underscore in front of the name.
*/
getPrefixedName() {
return "_" + this.configuration.name;
}
getTitle() {
return this.getFullName();
}
getCustomVariable() {
if (!this.custom_variable) {
debugLog(`CustomVariableInstance ${this.getID()}: Cannot find a CustomVariable. Maybe it's not loaded?`);
throw new Error(this.constructor.name + ".getVariable(): Cannot find a CustomVariable. Maybe it's not loaded?");
}
return this.custom_variable;
}
createCustomVariable() {
debugLog(`CustomVariableInstance ${this.getID()}: Creating an operational CustomVariable.`);
this.custom_variable = new CustomVariable(this.model.plugin, this);
this.custom_variable.onChange(async () => await this.model.plugin.updateCustomVariableViews());
return this.custom_variable;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_onLayoutReady extends SC_Event {
constructor() {
super(...arguments);
this.register_after_changing_settings = false;
}
_register(t_shell_command) {
this.app.workspace.onLayoutReady(async () => await this.trigger(t_shell_command));
return false; // The base class does not need to register anything.
}
_unregister(t_shell_command) {
// No need to unregister, because this event happens only once when Obsidian starts. If the event is not enabled for a shell command, next time Obsidian starts, this event won't get registered.
}
}
SC_Event_onLayoutReady.event_code = "on-layout-ready";
SC_Event_onLayoutReady.event_title = "Obsidian starts";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_onQuit extends SC_WorkspaceEvent {
constructor() {
super(...arguments);
this.workspace_event = "quit";
}
}
SC_Event_onQuit.event_code = "on-quit";
SC_Event_onQuit.event_title = "Obsidian quits";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_onActiveLeafChanged extends SC_WorkspaceEvent {
constructor() {
super(...arguments);
this.workspace_event = "active-leaf-change";
}
}
SC_Event_onActiveLeafChanged.event_code = "on-active-leaf-changed";
SC_Event_onActiveLeafChanged.event_title = "Switching the active pane";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_EveryNSeconds extends SC_Event {
constructor() {
super(...arguments);
this.default_configuration = {
enabled: false,
seconds: 60,
};
this.intervals_ids = {};
}
_register(t_shell_command) {
const milliseconds = this.getConfiguration(t_shell_command).seconds * 1000;
const interval_id = window.setInterval(async () => await this.trigger(t_shell_command), milliseconds);
this.plugin.registerInterval(interval_id);
this.intervals_ids[t_shell_command.getId()] = interval_id;
return false; // The base class does not need to register anything.
}
_unregister(t_shell_command) {
window.clearInterval(this.intervals_ids[t_shell_command.getId()]);
}
/**
* Overridden only to change the return type.
* @param t_shell_command
* @protected
*/
getConfiguration(t_shell_command) {
return super.getConfiguration(t_shell_command);
}
createExtraSettingsFields(extra_settings_container, t_shell_command) {
const configuration = this.getConfiguration(t_shell_command);
let apply_seconds;
new obsidian.Setting(extra_settings_container)
.setName("Seconds")
.setDesc("Needs to be at least 1. Currently supports only integers.")
.addText(text => text
.setValue(configuration.seconds.toString())
.onChange((raw_value) => {
apply_seconds = parseInt(raw_value);
// Don't save here, because the user might still be editing the number.
}))
.addButton(button => button
.setButtonText("Apply")
.onClick(async () => {
if (undefined == apply_seconds || apply_seconds === this.getConfiguration(t_shell_command).seconds) {
new obsidian.Notice("You didn't change the seconds!");
}
else if (isNaN(apply_seconds)) {
new obsidian.Notice("The seconds need to be an integer!");
}
else if (apply_seconds <= 0) {
new obsidian.Notice("The seconds need to be at least 1!");
}
else {
// All ok, save.
this.getConfiguration(t_shell_command).seconds = apply_seconds;
await this.plugin.saveSettings();
// Re-register to apply the change
this.unregister(t_shell_command);
this.register(t_shell_command);
// Done
this.noticeAboutEnabling(t_shell_command);
}
}));
}
onAfterEnabling(t_shell_command) {
this.noticeAboutEnabling(t_shell_command);
}
noticeAboutEnabling(t_shell_command) {
new obsidian.Notice("The shell command will run every " + this.getConfiguration(t_shell_command).seconds + " seconds");
}
}
SC_Event_EveryNSeconds.event_code = "every-n-seconds";
SC_Event_EveryNSeconds.event_title = "Every n seconds";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Event_EditorMenu extends SC_MenuEvent {
constructor() {
super(...arguments);
this.workspace_event = "editor-menu";
}
getTrigger(t_shell_command) {
return async (menu, editor, view) => {
await this.addTShellCommandToMenu(t_shell_command, menu);
};
}
}
SC_Event_EditorMenu.event_code = "editor-menu";
SC_Event_EditorMenu.event_title = "Editor menu";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function getSC_Events(plugin) {
if (eventList.length === 0) {
// Cache the list of SC_Event objects
eventList.push(new SC_Event_onLayoutReady(plugin), new SC_Event_onQuit(plugin), new SC_Event_onActiveLeafChanged(plugin), new SC_Event_EveryNSeconds(plugin), new SC_Event_FileMenu(plugin), new SC_Event_FolderMenu(plugin), new SC_Event_EditorMenu(plugin), new SC_Event_FileContentModified(plugin), new SC_Event_FileCreated(plugin), new SC_Event_FileDeleted(plugin), new SC_Event_FileMoved(plugin), new SC_Event_FileRenamed(plugin), new SC_Event_FolderCreated(plugin), new SC_Event_FolderDeleted(plugin), new SC_Event_FolderMoved(plugin), new SC_Event_FolderRenamed(plugin));
}
return eventList;
}
const eventList = [];
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* A wrapper for Obsidian's setIcon(), but with the difference that this one does not need a container as a parameter.
*/
function getIconHTML(icon_id) {
if (!icon_id) {
return "";
}
const icon_container = document.body.createEl("div"); // A temporary element, will be deleted soon. Not nice to create a temporary element in the body, but I don't know any better way.
obsidian.setIcon(icon_container, icon_id);
const icon_html = icon_container.innerHTML;
icon_container.remove();
return icon_html;
}
/**
* @author The list is provided by phibr0.
* @link https://discord.com/channels/686053708261228577/840286264964022302/968248588641665075
* @description phibr0: "Updated Icon List for Obsidian v0.14.7+ (lucide icons v0.30.0 + obsidians own)"
* @copyright The copyright statement at the top of this file does not affect this list of icons.
* TODO: The list seems to miss some icons, at least 'gear'.
*/
const ICON_LIST = ["activity", "airplay", "alarm-check", "alarm-clock-off", "alarm-clock", "alarm-minus", "alarm-plus", "album", "alert-circle", "alert-octagon", "alert-triangle", "align-center-horizontal", "align-center-vertical", "align-center", "align-end-horizontal", "align-end-vertical", "align-horizontal-distribute-center", "align-horizontal-distribute-end", "align-horizontal-distribute-start", "align-horizontal-justify-center", "align-horizontal-justify-end", "align-horizontal-justify-start", "align-horizontal-space-around", "align-horizontal-space-between", "align-justify", "align-left", "align-right", "align-start-horizontal", "align-start-vertical", "align-vertical-distribute-center", "align-vertical-distribute-end", "align-vertical-distribute-start", "align-vertical-justify-center", "align-vertical-justify-end", "align-vertical-justify-start", "align-vertical-space-around", "align-vertical-space-between", "anchor", "aperture", "archive", "arrow-big-down", "arrow-big-left", "arrow-big-right", "arrow-big-up", "arrow-down-circle", "arrow-down-left", "arrow-down-right", "arrow-down", "arrow-left-circle", "arrow-left-right", "arrow-left", "arrow-right-circle", "arrow-right", "arrow-up-circle", "arrow-up-left", "arrow-up-right", "arrow-up", "asterisk", "at-sign", "award", "axe", "banknote", "bar-chart-2", "bar-chart", "baseline", "battery-charging", "battery-full", "battery-low", "battery-medium", "battery", "beaker", "bell-minus", "bell-off", "bell-plus", "bell-ring", "bell", "bike", "binary", "bitcoin", "bluetooth-connected", "bluetooth-off", "bluetooth-searching", "bluetooth", "bold", "book-open", "book", "bookmark-minus", "bookmark-plus", "bookmark", "bot", "box-select", "box", "briefcase", "brush", "bug", "building-2", "building", "bus", "calculator", "calendar", "camera-off", "camera", "car", "carrot", "cast", "check-circle-2", "check-circle", "check-square", "check", "chevron-down", "chevron-first", "chevron-last", "chevron-left", "chevron-right", "chevron-up", "chevrons-down-up", "chevrons-down", "chevrons-left", "chevrons-right", "chevrons-up-down", "chevrons-up", "chrome", "circle-slashed", "circle", "clipboard-check", "clipboard-copy", "clipboard-list", "clipboard-x", "clipboard", "clock-1", "clock-10", "clock-11", "clock-12", "clock-2", "clock-3", "clock-4", "clock-5", "clock-6", "clock-7", "clock-8", "clock-9", "clock", "cloud-drizzle", "cloud-fog", "cloud-hail", "cloud-lightning", "cloud-moon", "cloud-off", "cloud-rain-wind", "cloud-rain", "cloud-snow", "cloud-sun", "cloud", "cloudy", "clover", "code-2", "code", "codepen", "codesandbox", "coffee", "coins", "columns", "command", "compass", "contact", "contrast", "cookie", "copy", "copyleft", "copyright", "corner-down-left", "corner-down-right", "corner-left-down", "corner-left-up", "corner-right-down", "corner-right-up", "corner-up-left", "corner-up-right", "cpu", "credit-card", "crop", "cross", "crosshair", "crown", "currency", "database", "delete", "dice-1", "dice-2", "dice-3", "dice-4", "dice-5", "dice-6", "disc", "divide-circle", "divide-square", "divide", "dollar-sign", "download-cloud", "download", "dribbble", "droplet", "droplets", "drumstick", "edit-2", "edit-3", "edit", "egg", "equal-not", "equal", "eraser", "euro", "expand", "external-link", "eye-off", "eye", "facebook", "fast-forward", "feather", "figma", "file-check-2", "file-check", "file-code", "file-digit", "file-input", "file-minus-2", "file-minus", "file-output", "file-plus-2", "file-plus", "file-search", "file-text", "file-x-2", "file-x", "file", "files", "film", "filter", "flag-off", "flag-triangle-left", "flag-triangle-right", "flag", "flame", "flashlight-off", "flashlight", "flask-conical", "flask-round", "folder-minus", "folder-open", "folder-plus", "folder", "form-input", "forward", "frame", "framer", "frown", "function-square", "gamepad-2", "gamepad", "gauge", "gavel", "gem", "ghost", "gift", "git-branch-plus", "git-branch", "git-commit", "git-fork", "git-merge", "git-pull-request", "github", "gitlab", "glasses", "globe-2", "globe", "grab", "graduation-cap", "grid", "grip-horizontal", "grip-vertical", "hammer", "hand-metal", "hand", "hard-drive", "hard-hat", "hash", "haze", "headphones", "heart", "help-circle", "hexagon", "highlighter", "history", "home", "image-minus", "image-off", "image-plus", "image", "import", "inbox", "indent", "indian-rupee", "infinity", "info", "inspect", "instagram", "italic", "japanese-yen", "key", "keyboard", "landmark", "languages", "laptop-2", "laptop", "lasso-select", "lasso", "layers", "layout-dashboard", "layout-grid", "layout-list", "layout-template", "layout", "library", "life-buoy", "lightbulb-off", "lightbulb", "link-2-off", "link-2", "link", "linkedin", "list-checks", "list-minus", "list-ordered", "list-plus", "list-x", "list", "loader-2", "loader", "locate-fixed", "locate-off", "locate", "lock", "log-in", "log-out", "mail", "map-pin", "map", "maximize-2", "maximize", "megaphone", "meh", "menu", "message-circle", "message-square", "mic-off", "mic", "minimize-2", "minimize", "minus-circle", "minus-square", "minus", "monitor-off", "monitor-speaker", "monitor", "moon", "more-horizontal", "more-vertical", "mountain-snow", "mountain", "mouse-pointer-2", "mouse-pointer-click", "mouse-pointer", "mouse", "move-diagonal-2", "move-diagonal", "move-horizontal", "move-vertical", "move", "music", "navigation-2", "navigation", "network", "octagon", "option", "outdent", "package-check", "package-minus", "package-plus", "package-search", "package-x", "package", "palette", "palmtree", "paperclip", "pause-circle", "pause-octagon", "pause", "pen-tool", "pencil", "percent", "person-standing", "phone-call", "phone-forwarded", "phone-incoming", "phone-missed", "phone-off", "phone-outgoing", "phone", "pie-chart", "piggy-bank", "pin", "pipette", "plane", "play-circle", "play", "plug-zap", "plus-circle", "plus-square", "plus", "pocket", "podcast", "pointer", "pound-sterling", "power-off", "power", "printer", "qr-code", "quote", "radio-receiver", "radio", "redo", "refresh-ccw", "refresh-cw", "regex", "repeat-1", "repeat", "reply-all", "reply", "rewind", "rocket", "rocking-chair", "rotate-ccw", "rotate-cw", "rss", "ruler", "russian-ruble", "save", "scale", "scan-line", "scan", "scissors", "screen-share-off", "screen-share", "search", "send", "separator-horizontal", "separator-vertical", "server-crash", "server-off", "server", "settings-2", "settings", "share-2", "share", "sheet", "shield-alert", "shield-check", "shield-close", "shield-off", "shield", "shirt", "shopping-bag", "shopping-cart", "shovel", "shrink", "shuffle", "sidebar-close", "sidebar-open", "sidebar", "sigma", "signal-high", "signal-low", "signal-medium", "signal-zero", "signal", "skip-back", "skip-forward", "skull", "slack", "slash", "sliders", "smartphone-charging", "smartphone", "smile", "snowflake", "sort-asc", "sort-desc", "speaker", "sprout", "square", "star-half", "star", "stop-circle", "stretch-horizontal", "stretch-vertical", "strikethrough", "subscript", "sun", "sunrise", "sunset", "superscript", "swiss-franc", "switch-camera", "table", "tablet", "tag", "target", "tent", "terminal-square", "terminal", "text-cursor-input", "text-cursor", "thermometer-snowflake", "thermometer-sun", "thermometer", "thumbs-down", "thumbs-up", "ticket", "timer-off", "timer-reset", "timer", "toggle-left", "toggle-right", "tornado", "trash-2", "trash", "trello", "trending-down", "trending-up", "triangle", "truck", "tv-2", "tv", "twitch", "twitter", "type", "umbrella", "underline", "undo", "unlink-2", "unlink", "unlock", "upload-cloud", "upload", "user-check", "user-minus", "user-plus", "user-x", "user", "users", "verified", "vibrate", "video-off", "video", "view", "voicemail", "volume-1", "volume-2", "volume-x", "volume", "wallet", "wand", "watch", "waves", "webcam", "wifi-off", "wifi", "wind", "wrap-text", "wrench", "x-circle", "x-octagon", "x-square", "x", "youtube", "zap-off", "zap", "zoom-in", "zoom-out", "search-large", "search", "activity", "airplay", "alarm-check", "alarm-clock-off", "alarm-clock", "alarm-minus", "alarm-plus", "album", "alert-circle", "alert-octagon", "alert-triangle", "align-center-horizontal", "align-center-vertical", "align-center", "align-end-horizontal", "align-end-vertical", "align-horizontal-distribute-center", "align-horizontal-distribute-end", "align-horizontal-distribute-start", "align-horizontal-justify-center", "align-horizontal-justify-end", "align-horizontal-justify-start", "align-horizontal-space-around", "align-horizontal-space-between", "align-justify", "align-left", "align-right", "align-start-horizontal", "align-start-vertical", "align-vertical-distribute-center", "align-vertical-distribute-end", "align-vertical-distribute-start", "align-vertical-justify-center", "align-vertical-justify-end", "align-vertical-justify-start", "align-vertical-space-around", "align-vertical-space-between", "anchor", "aperture", "archive", "arrow-big-down", "arrow-big-left", "arrow-big-right", "arrow-big-up", "arrow-down-circle", "arrow-down-left", "arrow-down-right", "arrow-down", "arrow-left-circle", "arrow-left-right", "arrow-left", "arrow-right-circle", "arrow-right", "arrow-up-circle", "arrow-up-left", "arrow-up-right", "arrow-up", "asterisk", "at-sign", "award", "axe", "banknote", "bar-chart-2", "bar-chart", "baseline", "battery-charging", "battery-full", "battery-low", "battery-medium", "battery", "beaker", "bell-minus", "bell-off", "bell-plus", "bell-ring", "bell", "bike", "binary", "bitcoin", "bluetooth-connected", "bluetooth-off", "bluetooth-searching", "bluetooth", "bold", "book-open", "book", "bookmark-minus", "bookmark-plus", "bookmark", "bot", "box-select", "box", "briefcase", "brush", "bug", "building-2", "building", "bus", "calculator", "calendar", "camera-off", "camera", "car", "carrot", "cast", "check-circle-2", "check-circle", "check-square", "check", "chevron-down", "chevron-first", "chevron-last", "chevron-left", "chevron-right", "chevron-up", "chevrons-down-up", "chevrons-down", "chevrons-left", "chevrons-right", "chevrons-up-down", "chevrons-up", "chrome", "circle-slashed", "circle", "clipboard-check", "clipboard-copy", "clipboard-list", "clipboard-x", "clipboard", "clock-1", "clock-10", "clock-11", "clock-12", "clock-2", "clock-3", "clock-4", "clock-5", "clock-6", "clock-7", "clock-8", "clock-9", "lucide-clock", "cloud-drizzle", "cloud-fog", "cloud-hail", "cloud-lightning", "cloud-moon", "cloud-off", "cloud-rain-wind", "cloud-rain", "cloud-snow", "cloud-sun", "lucide-cloud", "cloudy", "clover", "code-2", "code", "codepen", "codesandbox", "coffee", "coins", "columns", "command", "compass", "contact", "contrast", "cookie", "copy", "copyleft", "copyright", "corner-down-left", "corner-down-right", "corner-left-down", "corner-left-up", "corner-right-down", "corner-right-up", "corner-up-left", "corner-up-right", "cpu", "credit-card", "crop", "lucide-cross", "crosshair", "crown", "currency", "database", "delete", "dice-1", "dice-2", "dice-3", "dice-4", "dice-5", "dice-6", "disc", "divide-circle", "divide-square", "divide", "dollar-sign", "download-cloud", "download", "dribbble", "droplet", "droplets", "drumstick", "edit-2", "edit-3", "edit", "egg", "equal-not", "equal", "eraser", "euro", "expand", "external-link", "eye-off", "eye", "facebook", "fast-forward", "feather", "figma", "file-check-2", "file-check", "file-code", "file-digit", "file-input", "file-minus-2", "file-minus", "file-output", "file-plus-2", "file-plus", "file-search", "file-text", "file-x-2", "file-x", "file", "files", "film", "filter", "flag-off", "flag-triangle-left", "flag-triangle-right", "flag", "flame", "flashlight-off", "flashlight", "flask-conical", "flask-round", "folder-minus", "folder-open", "folder-plus", "lucide-folder", "form-input", "forward", "frame", "framer", "frown", "function-square", "gamepad-2", "gamepad", "gauge", "gavel", "gem", "ghost", "gift", "git-branch-plus", "git-branch", "git-commit", "git-fork", "git-merge", "git-pull-request", "github", "gitlab", "glasses", "globe-2", "globe", "grab", "graduation-cap", "grid", "grip-horizontal", "grip-vertical", "hammer", "hand-metal", "hand", "hard-drive", "hard-hat", "hash", "haze", "headphones", "heart", "help-circle", "hexagon", "highlighter", "history", "home", "image-minus", "image-off", "image-plus", "image", "import", "inbox", "indent", "indian-rupee", "infinity", "lucide-info", "inspect", "instagram", "italic", "japanese-yen", "key", "keyboard", "landmark", "lucide-languages", "laptop-2", "laptop", "lasso-select", "lasso", "layers", "layout-dashboard", "layout-grid", "layout-list", "layout-template", "layout", "library", "life-buoy", "lightbulb-off", "lightbulb", "link-2-off", "link-2", "lucide-link", "linkedin", "list-checks", "list-minus", "list-ordered", "list-plus", "list-x", "list", "loader-2", "loader", "locate-fixed", "locate-off", "locate", "lock", "log-in", "log-out", "mail", "map-pin", "map", "maximize-2", "maximize", "megaphone", "meh", "menu", "message-circle", "message-square", "mic-off", "mic", "minimize-2", "minimize", "minus-circle", "minus-square", "minus", "monitor-off", "monitor-speaker", "monitor", "moon", "more-horizontal", "more-vertical", "mountain-snow", "mountain", "mouse-pointer-2", "mouse-pointer-click", "mouse-pointer", "mouse", "move-diagonal-2", "move-diagonal", "move-horizontal", "move-vertical", "move", "music", "navigation-2", "navigation", "network", "octagon", "option", "outdent", "package-check", "package-minus", "package-plus", "package-search", "package-x", "package", "palette", "palmtree", "paperclip", "pause-circle", "pause-octagon", "pause", "pen-tool", "lucide-pencil", "percent", "person-standing", "phone-call", "phone-forwarded", "phone-incoming", "phone-missed", "phone-off", "phone-outgoing", "phone", "pie-chart", "piggy-bank", "lucide-pin", "pipette", "plane", "play-circle", "play", "plug-zap", "plus-circle", "plus-square", "plus", "pocket", "podcast", "pointer", "pound-sterling", "power-off", "power", "printer", "qr-code", "quote", "radio-receiver", "radio", "redo", "refresh-ccw", "refresh-cw", "regex", "repeat-1", "repeat", "reply-all", "reply", "rewind", "rocket", "rocking-chair", "rotate-ccw", "rotate-cw", "rss", "ruler", "russian-ruble", "save", "scale", "scan-line", "scan", "scissors", "screen-share-off", "screen-share", "lucide-search", "send", "separator-horizontal", "separator-vertical", "server-crash", "server-off", "server", "settings-2", "settings", "share-2", "share", "sheet", "shield-alert", "shield-check", "shield-close", "shield-off", "shield", "shirt", "shopping-bag", "shopping-cart", "shovel", "shrink", "shuffle", "sidebar-close", "sidebar-open", "sidebar", "sigma", "signal-high", "signal-low", "signal-medium", "signal-zero", "signal", "skip-back", "skip-forward", "skull", "slack", "slash", "sliders", "smartphone-charging", "smartphone", "smile", "snowflake", "sort-asc", "sort-desc", "speaker", "sprout", "square", "star-half", "lucide-star", "stop-circle", "stretch-horizontal", "stretch-vertical", "strikethrough", "subscript", "sun", "sunrise", "sunset", "superscript", "swiss-franc", "switch-camera", "table", "tablet", "tag", "target", "tent", "terminal-square", "terminal", "text-cursor-input", "text-cursor", "thermometer-snowflake", "thermometer-sun", "thermometer", "thumbs-down", "thumbs-up", "ticket", "timer-off", "timer-reset", "timer", "toggle-left", "toggle-right", "tornado", "trash-2", "lucide-trash", "trello", "trending-down", "trending-up", "triangle", "truck", "tv-2", "tv", "twitch", "twitter", "type", "umbrella", "underline", "undo", "unlink-2", "unlink", "unlock", "upload-cloud", "upload", "user-check", "user-minus", "user-plus", "user-x", "user", "users", "verified", "vibrate", "video-off", "video", "view", "voicemail", "volume-1", "volume-2", "volume-x", "volume", "wallet", "wand", "watch", "waves", "webcam", "wifi-off", "wifi", "wind", "wrap-text", "wrench", "x-circle", "x-octagon", "x-square", "x", "youtube", "zap-off", "zap", "zoom-in", "zoom-out", "search-large", "lucide-search"];
/**
* The original ICON_LIST contains duplicate entries (e.g. two "activity" items) and is not in alphabetical order. This list improves it.
*/
const ICON_LIST_SORTED_UNIQUE = uniqueArray(ICON_LIST).sort();
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* TODO: Rename this class. Replace the T prefix with something else. The T stands for Type (kind of like TFile from Obsidian), but this is not a type, this is a class. Maybe ShellCommandInstance? It's not the best name, but I can't come up with a better one now.
*/
class TShellCommand {
constructor(plugin, configuration) {
this.plugin = plugin;
this.configuration = configuration;
// Introduce the ID to an ID generator so that it won't accidentally generate the same ID again when creating new shell commands.
getIDGenerator().addReservedID(configuration.id);
}
getPlugin() {
return this.plugin;
}
/**
* Use this when you need to alter the configuration values. if you only need to read configuration values, use get*()
* methods instead.
*/
getConfiguration() {
return this.configuration;
}
getId() {
return this.configuration.id;
}
getShell() {
// Check if the shell command has defined a specific shell.
const shell = this.configuration.shells[getOperatingSystem()];
if (undefined === shell) {
// The shell command does not define an explicit shell.
// Use a default shell from the plugin's settings.
return this.plugin.getDefaultShell();
}
else {
// The shell command has an explicit shell defined.
return shell;
}
}
getShells() {
return this.configuration.shells;
}
/**
* Returns a shell command string specific for the current operating system, or a generic shell command if this shell
* command does not have an explicit version for the current OS.
*/
getShellCommand() {
// Check if the shell command has defined a specific command for this operating system.
const platformSpecificShellCommand = this.configuration.platform_specific_commands[getOperatingSystem()];
if (undefined === platformSpecificShellCommand) {
// No command is defined specifically for this operating system.
// Return an "OS agnostic" command.
return this.configuration.platform_specific_commands.default;
}
else {
// The shell command has defined a specific command for this operating system.
return platformSpecificShellCommand;
}
}
/**
* Returns a version of the shell command that should be used if no platform specific command is defined for the
* current platform. If you plan to use this for execution, consider using getShellCommand() instead, as it takes the
* current platform into account.
*/
getDefaultShellCommand() {
return this.configuration.platform_specific_commands.default;
}
getPlatformSpecificShellCommands() {
return this.configuration.platform_specific_commands;
}
/**
* Returns a list of PlatformIds that have a shell command version defined. 'default' is never included in the list.
*
* TODO: Invent a better name for this method.
*/
getNonEmptyPlatformIds() {
const platform_specific_shell_commands = this.getPlatformSpecificShellCommands();
const platform_ids_with_non_empty_shell_commands = [];
let platform_id;
for (platform_id in PlatformNames) { // Note that this loop does not iterate 'default' platform id (= the fallback platform id that is used when a shell command does not have a version for the current platform).
const platform_specific_shell_command = platform_specific_shell_commands[platform_id];
if (platform_specific_shell_command && "" !== platform_specific_shell_command.trim()) {
platform_ids_with_non_empty_shell_commands.push(platform_id);
}
}
return platform_ids_with_non_empty_shell_commands;
}
getIconId() {
return this.configuration.icon;
}
getIconHTML() {
if (this.configuration.icon) {
// An icon is defined.
return getIconHTML(this.configuration.icon);
}
else {
// No icon is defined.
return "";
}
}
getAlias() {
return this.configuration.alias;
}
/**
* TODO: Use this method in all places where similar logic is needed.
*/
getAliasOrShellCommand() {
return this.configuration.alias || this.getShellCommand();
}
getConfirmExecution() {
return this.configuration.confirm_execution;
}
getIgnoreErrorCodes() {
return this.configuration.ignore_error_codes;
}
getInputChannels() {
return this.configuration.input_contents;
}
getOutputChannelOrder() {
return this.configuration.output_channel_order;
}
getOutputChannels() {
return this.configuration.output_channels;
}
getOutputHandlingMode() {
return this.configuration.output_handling_mode;
}
/**
* Finds an output wrapper that should be used for the given OutputStream. Returns null, if no OutputWrapper should
* be used.
*
* @param output_stream
*/
getOutputWrapper(output_stream) {
const output_wrapper_id = this.configuration.output_wrappers[output_stream];
if (!output_wrapper_id) {
// No output wrapper is defined for this output stream in this shell command.
return null;
}
for (const output_wrapper of this.plugin.getOutputWrappers().values()) {
// Check if this is the output wrapper defined for this shell command.
if (output_wrapper.getID() === output_wrapper_id) {
// The correct output wrapper was found.
return output_wrapper;
}
}
throw new Error("OutputWrapper with ID " + output_wrapper_id + " was not found.");
}
/**
* Checks if different output streams can be wrapped together. In addition to this, combining output streams also
* requires the OutputChannels to be the same, but that's not checked in this method.
*/
isOutputWrapperStdoutSameAsStderr() {
return this.configuration.output_wrappers["stdout"] === this.configuration.output_wrappers["stderr"];
}
getEventsConfiguration() {
return this.configuration.events;
}
getEventConfiguration(sc_event) {
return this.getEventsConfiguration()[sc_event.static().getCode()] || sc_event.getDefaultConfiguration(false);
}
isSC_EventEnabled(event_code) {
const events_configuration = this.getEventsConfiguration();
if (undefined === events_configuration[event_code]) {
// Not enabled
return false;
}
else {
// Maybe enabled
return events_configuration[event_code].enabled;
}
}
/**
* Called when changing event settings in ShellCommandExtraOptionsModal.
* plugin.saveSettings() needs to be called after this!
*
* @param sc_event
*/
enableSC_Event(sc_event) {
const event_code = sc_event.static().getCode();
const events_configuration = this.getEventsConfiguration();
if (undefined === events_configuration[event_code]) {
// Not enabled
// Enable
events_configuration[event_code] = sc_event.getDefaultConfiguration(true);
}
else {
// Maybe enabled
if (!events_configuration[event_code].enabled) {
events_configuration[event_code].enabled = true;
}
}
if (sc_event.canRegisterAfterChangingSettings()) {
this.registerSC_Event(sc_event);
}
sc_event.onAfterEnabling(this);
}
/**
* Called when changing event settings in ShellCommandExtraOptionsModal.
* plugin.saveSettings() needs to be called after this!
*
* @param sc_event
*/
disableSC_Event(sc_event) {
const event_code = sc_event.static().getCode();
const events_configuration = this.getEventsConfiguration();
if (undefined !== events_configuration[event_code]) {
// Maybe enabled
if (events_configuration[event_code].enabled) {
// Is enabled.
// Disable.
const configuration_property_names = Object.getOwnPropertyNames(events_configuration[event_code]);
if (configuration_property_names.length > 1) {
// There's more settings than just 'enable'.
// Disable by setting 'enable' to false, don't flush the settings, they can be useful if the event gets re-enabled.
events_configuration[event_code].enabled = false;
}
else {
// 'enabled' is the only setting.
// Disable by removing the configuration object completely to make the settings file cleaner.
delete events_configuration[event_code];
}
}
}
if (sc_event.canRegisterAfterChangingSettings()) {
this.unregisterSC_Event(sc_event);
}
}
/**
* Returns all SC_Events that are enabled fro this shell command.
*
* Private as it's currently only used domestically, but can be changed to public if needed.
*/
getSC_Events() {
const enabled_sc_events = [];
getSC_Events(this.plugin).forEach((sc_event) => {
if (this.isSC_EventEnabled(sc_event.static().getCode())) {
enabled_sc_events.push(sc_event);
}
});
return enabled_sc_events;
}
/**
* Private, if you need access from outside, use enableSC_Event().
*
* @param sc_event
* @private
*/
registerSC_Event(sc_event) {
sc_event.register(this);
}
/**
* Private, if you need access from outside, use disableSC_Event().
*
* @param sc_event
* @private
*/
unregisterSC_Event(sc_event) {
sc_event.unregister(this);
}
/**
* Set's up all events that are enabled for this shell command.
*
* @param called_after_changing_settings Set to: true, if this happens after changing configuration; false, if this happens during loading the plugin.
*/
registerSC_Events(called_after_changing_settings) {
this.getSC_Events().forEach((sc_event) => {
const can_register = !called_after_changing_settings || sc_event.canRegisterAfterChangingSettings();
if (can_register) {
this.registerSC_Event(sc_event);
}
});
}
unregisterSC_Events() {
this.getSC_Events().forEach((sc_event) => {
this.unregisterSC_Event(sc_event);
});
}
registerToCommandPalette() {
// TODO: Move the logic from plugin.registerShellCommand() to here, but split to multiple methods.
this.plugin.registerShellCommand(this);
}
unregisterFromCommandPalette() {
// FIXME: I think the unregistering does not work.
delete this.plugin.obsidian_commands[this.getId()];
}
/**
* Checks the configuration for command_palette_availability and returns:
* - true, if the value is "enabled" or "unlisted"
* - false, if the value is "disabled"
*
* Adding to command palette also enables hotkeys, which is why adding can be permitted, but showing denied, if a shell command should only be available via hotkeys.
*/
canAddToCommandPalette() {
return this.getConfiguration().command_palette_availability !== "disabled";
}
/**
* Another name for canAddToCommandPalette().
*/
canHaveHotkeys() {
return this.canAddToCommandPalette();
}
/**
* Checks the configuration for command_palette_availability and returns:
* - true, if the value is "enabled"
* - false, if the value is "disabled" or "unlisted"
*/
canShowInCommandPalette() {
return this.getConfiguration().command_palette_availability === "enabled";
}
/**
* Creates a new ParsingProcess instance and defines two sets of variables:
* - First set: All variables that are not tied to any preactions.
* - Second set: Variables that are tied to preactions. Can be an empty set.
* You need to still call ParsingProcess.process() to parse the first set. ShellCommandExecutor takes care of calling
* ParsingProcess.processRest() to process all non-processed sets.
*
* @See ParsingProcess class for a description of the process.
* @param sc_event Needed to get {{event_*}} variables parsed. Can be left out if working outside any SC_Event context, in which case {{event_*}} variables are inaccessible.
*/
createParsingProcess(sc_event) {
const stdout_output_wrapper = this.getOutputWrapper("stdout"); // Can be null
const stderr_output_wrapper = this.getOutputWrapper("stderr"); // Can be null
return new ParsingProcess(this.plugin, {
shell_command: this.getShellCommand(),
alias: this.getAlias(),
environment_variable_path_augmentation: getPATHAugmentation(this.plugin) ?? "",
stdinContent: this.configuration.input_contents.stdin ?? undefined,
output_wrapper_stdout: stdout_output_wrapper ? stdout_output_wrapper.getContent() : undefined,
output_wrapper_stderr: stderr_output_wrapper ? stderr_output_wrapper.getContent() : undefined,
}, this, sc_event, [
this.getNonPreactionsDependentVariables(),
this.getPreactionsDependentVariables(), // Second set: Variables that are tied to preactions. Can be an empty set.
], [
// Do not escape variables in stdin, because shells won't interpret special characters in stdin. All characters are considered literal.
"stdinContent",
// Do not escape variables in output wrappers, because they are not going through a shell and escape characters would be visible in the end result.
'output_wrapper_stdout',
'output_wrapper_stderr',
]);
}
setObsidianCommand(obsidian_command) {
this.obsidian_command = obsidian_command;
}
getObsidianCommand() {
return this.obsidian_command;
}
/**
* No renaming is done if the shell command is excluded from the command palette.
*/
renameObsidianCommand(shell_command, alias) {
// Rename the command in command palette
const prefix = this.plugin.getPluginName() + ": "; // Normally Obsidian prefixes all commands with the plugin name automatically, but now that we are actually _editing_ a command in the palette (not creating a new one), Obsidian won't do the prefixing for us.
// Check that the shell command is actually registered to Obsidian's command palette.
if (undefined !== this.obsidian_command) {
// Yes, the shell command is registered in Obsidian's command palette.
// Update the command palette name.
this.obsidian_command.name = prefix + generateObsidianCommandName(this.plugin, shell_command, alias);
}
// If the shell command's "command_palette_availability" settings is set to "disabled", then the shell command is not present in this.obsidian_command and so the command palette name does not need updating.
}
/**
* Clears an internal cache used by .getPreactions().
* Only needed to be called after creating new PreactionConfigurations or deleting old ones. Should not need to be called
* when modifying properties in existing PreactionConfigurations.
*/
resetPreactions() {
debugLog(`TShellCommand ${this.getId()}: Resetting preactions.`);
delete this.cached_preactions;
}
getPreactions() {
debugLog(`TShellCommand ${this.getId()}: Getting preactions.`);
if (!this.cached_preactions) {
this.cached_preactions = [];
let preaction_configuration;
for (preaction_configuration of this.getConfiguration().preactions) {
// Only create the preaction if it's enabled.
if (preaction_configuration.enabled) {
// Yes, it's enabled.
// Instantiate the Preaction.
this.cached_preactions.push(createPreaction(this.plugin, preaction_configuration, this));
}
}
}
return this.cached_preactions;
}
/**
* Returns Variables that are not dependent on any Preaction.
* @private Can be made public if needed.
*/
getNonPreactionsDependentVariables() {
debugLog(`TShellCommand ${this.getId()}: Getting non preactions dependent variables.`);
const all_variables = this.plugin.getVariables();
return removeFromSet(all_variables, this.getPreactionsDependentVariables());
}
/**
* @private Can be made public if needed.
*/
getPreactionsDependentVariables() {
debugLog(`TShellCommand ${this.getId()}: Getting preactions dependent variables.`);
let dependent_variables = new VariableSet();
for (const preaction of this.getPreactions()) {
dependent_variables = mergeSets(dependent_variables, preaction.getDependentVariables());
}
return dependent_variables;
}
/**
* @return Returns undefined, if no configuration is defined for this variable.
* @param variable
* @param canInherit If true, can get default value configuration from Variable configuration (= upper level configuration in this case). Can be set to false in situations where it's important to know what the shell command itself has defined or not defined.
*/
getDefaultValueConfigurationForVariable(variable, canInherit = true) {
const defaultValueConfiguration = this.configuration.variable_default_values[variable.getIdentifier()];
if (undefined === defaultValueConfiguration || defaultValueConfiguration.type === "inherit") {
// This shell command does not specify a default value.
if (canInherit) {
// Return a global configuration (but even that can be undefined).
return variable.getGlobalDefaultValueConfiguration(); // Can return undefined.
}
// If inheriting is denied, pass to return the defaultValueConfiguration that were gotten from this.configuration.variable_default_values.
}
return defaultValueConfiguration;
}
/**
* Returns an URI that can be used in links (in or outside of Obsidian) to execute this shell command. The URI also
* contains stubs for any possible CustomVariables that might be used in the shell command (if any).
*/
getExecutionURI() {
const execution_uri = this.plugin.getObsidianURI(SC_Plugin.SHELL_COMMANDS_URI_ACTION, { execute: this.getId() });
// Get a list CustomVariables that the shell command uses.
const custom_variables = new VariableSet();
for (const custom_variable of getUsedVariables(this.plugin, this.getShellCommand())) {
// Check that the variable IS a CustomVariable.
if (custom_variable instanceof CustomVariable) {
custom_variables.add(custom_variable);
}
}
// Exclude variables whose values will come from Preactions - they will not probably be needed in the URI.
const custom_variables_suitable_for_uri = removeFromSet(custom_variables, this.getPreactionsDependentVariables());
// Append the suitable custom variable names to the uri.
let execution_uri_with_variables = execution_uri;
for (const custom_variable of custom_variables_suitable_for_uri) {
execution_uri_with_variables += "&" + custom_variable.variable_name + "=";
}
// Finished.
return execution_uri_with_variables;
}
/**
* Returns an adjacent TShellCommand that appears next in the configuration list. Returns undefined, if this is the
* last TShellCommand. Used in settings to switch quickly from one TShellCommand to another.
*/
nextTShellCommand() {
const t_shell_commands = Object.values(this.plugin.getTShellCommands());
const this_index = t_shell_commands.indexOf(this);
if (this_index === t_shell_commands.length - 1) {
return undefined;
}
return t_shell_commands[this_index + 1];
}
/**
* Returns an adjacent TShellCommand that appears before in the configuration list. Returns undefined, if this is the
* first TShellCommand. Used in settings to switch quickly from one TShellCommand to another.
*/
previousTShellCommand() {
const t_shell_commands = Object.values(this.plugin.getTShellCommands());
const this_index = t_shell_commands.indexOf(this);
if (this_index === 0) {
return undefined;
}
return t_shell_commands[this_index - 1];
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function createVariableDefaultValueFields(plugin, containerElement, targetObject) {
// Add default value fields for each variable that can have a default value.
for (const variable of plugin.getVariables()) {
// Only add fields for variables that are not always accessible.
if (!variable.isAlwaysAvailable()) {
const setting = createVariableDefaultValueField(plugin, containerElement, variable.getFullName(), variable, targetObject);
// Documentation link
if (!(variable instanceof CustomVariable)) {
setting.addExtraButton(extraButton => extraButton
.setIcon("help")
.setTooltip("Documentation: " + variable.getFullName() + " variable")
.onClick(() => gotoURL(variable.getDocumentationLink())));
}
}
}
}
/**
*
* @param plugin
* @param containerElement
* @param settingName
* @param variable The variable whose default value will be configured by the created setting field.
* @param targetObject In which object's configuration the default value settings should be stored. Can be a TShellCommand or a Variable (either CustomVariable or a built-in one).
*/
function createVariableDefaultValueField(plugin, containerElement, settingName, variable, targetObject) {
if (undefined === targetObject) {
// No configuration target is defined, so use the variable as a target.
targetObject = variable;
}
const targetType = targetObject instanceof TShellCommand
? 'tShellCommand'
: targetObject instanceof CustomVariable
? 'customVariable'
: 'builtinVariable';
if ("customVariable" === targetType || "builtinVariable" === targetType) {
if (targetObject !== variable) {
throw new Error("If defining 'targetObject' argument as a Variable, it should be the same as the 'variable' argument.");
}
}
// Get an identifier for a variable (an id, if it's a CustomVariable, otherwise the variable's name).
const variableIdentifier = variable.getIdentifier();
// If a default value has been defined for this variable (and this targetObject), retrieve the configuration.
let defaultValueConfiguration;
switch (targetType) {
case "tShellCommand":
defaultValueConfiguration = targetObject.getDefaultValueConfigurationForVariable(variable, false);
break;
case "builtinVariable": // Both classes have...
case "customVariable": // ... the getGlobalDefaultValueConfiguration() method.
defaultValueConfiguration = targetObject.getGlobalDefaultValueConfiguration();
break;
}
// A function for creating configuration in onChange() callbacks if the variable does not yet have one for this configuration.
const createDefaultValueConfiguration = () => {
const configuration = {
type: "show-errors",
value: "",
};
// Store the configuration to the target object's configuration.
switch (targetType) {
case "tShellCommand":
targetObject.getConfiguration().variable_default_values[variableIdentifier] = configuration;
break;
case "builtinVariable":
if (undefined === plugin.settings.builtin_variables[variableIdentifier]) {
// Create a config object for this variable if it does not exist yet.
plugin.settings.builtin_variables[variableIdentifier] = { default_value: null };
}
plugin.settings.builtin_variables[variableIdentifier].default_value = configuration;
break;
case "customVariable":
targetObject.getConfiguration().default_value = configuration;
break;
}
return configuration;
};
let textareaComponent;
// A function for updating textareaComponent visibility.
const updateTextareaComponentVisibility = (type) => {
if ("value" === type) {
textareaComponent.inputEl.removeClass("SC-hide");
}
else {
textareaComponent.inputEl.addClass("SC-hide");
}
};
// Define a set of options for default value type
const defaultValueTypeOptions = {
"inherit": "",
"show-errors": "Cancel execution and show errors",
"cancel-silently": "Cancel execution silently",
"value": "Execute with value:",
};
switch (targetType) {
case "tShellCommand": {
// Shell commands can have the "inherit" type.
const globalDefaultValueConfiguration = variable.getGlobalDefaultValueConfiguration();
const globalDefaultValueType = globalDefaultValueConfiguration ? globalDefaultValueConfiguration.type : "show-errors";
defaultValueTypeOptions.inherit = "Inherit: " + defaultValueTypeOptions[globalDefaultValueType];
if ("value" === globalDefaultValueType) {
defaultValueTypeOptions.inherit += " " + globalDefaultValueConfiguration?.value;
}
break;
}
case "builtinVariable":
case "customVariable": {
// Variables do not have the "inherit" type.
// @ts-ignore Don't yell about removing a non-optional property "inherit".
delete defaultValueTypeOptions.inherit;
}
}
// Create the default value setting
const defaultValueSetting = new obsidian.Setting(containerElement)
.setName(settingName)
.setDesc("If not available, then:")
.setTooltip(variable.getAvailabilityTextPlain())
.addDropdown(dropdown => dropdown
.addOptions(defaultValueTypeOptions)
.setValue(defaultValueConfiguration
? defaultValueConfiguration.type
: "tShellCommand" === targetType
? "inherit" // If configuring a TShellCommand, then default config type should be "inherit".
: "show-errors" // If configuring a Variable, then default config type should be "show-errors", because "inherit" is not available.
)
.onChange(async (newType) => {
if (!defaultValueConfiguration) {
defaultValueConfiguration = createDefaultValueConfiguration();
}
// Set the new type
defaultValueConfiguration.type = newType;
if (targetType === "tShellCommand") {
// Shell commands:
if ("inherit" === newType && defaultValueConfiguration.value === "") {
// If "inherit" is selected and no text value is typed, the configuration file can be cleaned up by removing this configuration object completely.
// Prevent deleting, if a text value is present, because the user might want to keep it if they will later change 'type' to 'value'.
delete targetObject.getConfiguration().variable_default_values[variableIdentifier];
}
}
else {
// Variables:
if ("show-errors" === newType && defaultValueConfiguration.value === "") {
// If "show-errors" is selected and no text value is typed, the configuration file can be cleaned up by removing this configuration object completely.
// Prevent deleting, if a text value is present, because the user might want to keep it if they will later change 'type' to 'value'.
switch (targetType) {
case "builtinVariable":
plugin.settings.builtin_variables[variableIdentifier].default_value = null;
break;
case "customVariable":
targetObject.getConfiguration().default_value = null;
break;
}
}
}
// Show/hide the textarea
updateTextareaComponentVisibility(newType);
// Save the settings
await plugin.saveSettings();
}))
.addTextArea(textarea => textareaComponent = textarea
.setValue(defaultValueConfiguration ? defaultValueConfiguration.value : "")
.onChange(async (newValue) => {
if (!defaultValueConfiguration) {
defaultValueConfiguration = createDefaultValueConfiguration();
}
// Set the new text value
defaultValueConfiguration.value = newValue;
// Save the settings
await plugin.saveSettings();
}).then((textareaComponent) => {
// Autocomplete for the textarea.
if (plugin.settings.show_autocomplete_menu) {
createAutocomplete(plugin, textareaComponent.inputEl, () => textareaComponent.onChanged());
}
}));
updateTextareaComponentVisibility(defaultValueConfiguration
? defaultValueConfiguration.type
: targetType === "tShellCommand"
? "show-errors" // It does not really matter if passing "show-errors" ....
: "inherit");
return defaultValueSetting;
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class CustomVariableModel extends Model {
constructor() {
super(...arguments);
this.custom_variable_instances = new CustomVariableInstanceMap;
}
getSingularName() {
return "Custom variable";
}
defineParentConfigurationRelation(custom_variable_instance) {
debugLog(`CustomVariableModel: Defining parent configuration relation for CustomVariableInstance ${custom_variable_instance.getID()}.`);
return {
type: "one-to-many-id",
key: "custom_variables",
id: custom_variable_instance.getID(),
};
}
loadInstances(parent_configuration) {
debugLog(`CustomVariableModel: Loading CustomVariableInstances.`);
this.custom_variable_instances.clear();
parent_configuration.custom_variables.forEach((custom_variable_configuration) => {
this.custom_variable_instances.set(custom_variable_configuration.id, new CustomVariableInstance(this, custom_variable_configuration, parent_configuration));
});
return this.custom_variable_instances;
}
newInstance(parent_configuration) {
debugLog(`CustomVariableModel: Creating a new CustomVariableInstance.`);
// Create a default configuration object
const custom_variable_configuration = this.getDefaultConfiguration();
parent_configuration.custom_variables.push(custom_variable_configuration);
// Create a CustomVariableInstance for handling the configuration
const custom_variable_instance = new CustomVariableInstance(this, custom_variable_configuration, parent_configuration);
this.custom_variable_instances.set(custom_variable_configuration.id, custom_variable_instance);
// Create an operational variable.
this.plugin.getVariables().add(custom_variable_instance.createCustomVariable());
return custom_variable_instance;
// TODO: Move this logic to the base Model class.
}
_createSettingFields(instance, container_element) {
debugLog(`CustomVariableModel: Creating setting fields for CustomVariableInstance ${instance.getID()}.`);
// Make the fields appear closer together.
container_element.addClass("SC-setting-group");
// Heading setting
const heading_setting = new obsidian.Setting(container_element)
.setName(instance.getFullName())
.setHeading();
// Name setting
new obsidian.Setting(container_element)
.setName("Variable name")
.setDesc("Must contain at least one character. Allowed characters are letters a-z, numbers 0-9 and an underscore _")
.setClass("SC-custom-variable-name-setting")
.addText(text => text
.setValue(instance.configuration.name)
.onChange((new_name) => {
// TODO: Find a way to create this kind of trivial onChange() functions in the Model base class.
instance.setIfValid("name", new_name).then(async () => {
// Valid
heading_setting.setName(instance.getFullName()); // Also removes a possible warning message.
instance.getCustomVariable().updateProperties(); // Update the name also to the operational variable, not only in configuration.
await this.plugin.saveSettings();
await this.plugin.updateCustomVariableViews();
}, (reason) => {
// Not valid
if (typeof reason === "string") {
// This is a validation error message.
// Display a warning message.
heading_setting.setName(reason + " The name was not saved.");
}
else {
// Some other runtime error has occurred.
throw reason;
}
});
}));
// Description setting
new obsidian.Setting(container_element)
.setName("Description")
.setDesc("Appears in autocomplete lists along with the variable name, and also in the 'Custom variables' pane, if you use it.")
.addText(text => text
.setValue(instance.configuration.description)
.onChange(async (new_description) => {
// TODO: Find a way to create this kind of trivial onChange() functions in the Model base class.
instance.configuration.description = new_description;
instance.getCustomVariable().updateProperties(); // Update the description also to the operational variable, not only in configuration.
await this.plugin.saveSettings();
await this.plugin.updateCustomVariableViews();
}));
// Default value setting
createVariableDefaultValueField(this.plugin, container_element, "Default value", instance.getCustomVariable());
return heading_setting;
}
validateValue(custom_variable_instance, field, custom_variable_name) {
debugLog(`CustomVariableModel: Validating ${field} value ${custom_variable_name} for CustomVariableInstance ${custom_variable_instance.getID()}.`);
return new Promise((resolve, reject) => {
switch (field) {
case "name":
// Check that the name contains only characters a-z, 0-9 and/or underline _
if (!custom_variable_name.match(/^[\w\d]+$/u)) {
// Incorrect format.
reject(`The name {{_${custom_variable_name}}} does not meet the naming requirements.`);
return;
}
// Check if the name is a duplicate.
if (this.isCustomVariableNameDuplicate(custom_variable_name, custom_variable_instance)) {
// It's a duplicate.
reject(`The name {{_${custom_variable_name}}} is already reserved.`);
}
else {
// It's unique.
resolve();
}
return;
default:
// Other fields do not need validation.
resolve();
return;
}
});
}
getDefaultConfiguration() {
// Generate a unique name for the variable by using a sequential number.
let sequential_number = 1;
while (this.isCustomVariableNameDuplicate(String(sequential_number))) {
sequential_number++;
}
// Create a configuration object.
return {
id: getIDGenerator().generateID(),
name: String(sequential_number),
description: "",
default_value: null,
};
}
async _deleteInstance(custom_variable_instance) {
debugLog(`CustomVariableModel: Deleting CustomVariableInstance ${custom_variable_instance.getID()}.`);
// Remove the CustomVariableInstance from all PromptFields that use it.
for (const prompt of this.plugin.getPrompts().values()) {
for (const prompt_field of prompt.prompt_fields) {
if (custom_variable_instance.getID() === prompt_field.configuration.target_variable_id) {
// This prompt field uses this CustomVariableInstance.
// Remove the variable from use.
prompt_field.configuration.target_variable_id = "";
// Saving is done later, after the _deleteInstance() call.
}
}
}
// Delete CustomVariable
try {
this.plugin.getVariables().delete(custom_variable_instance.getCustomVariable());
}
catch (error) {
// If custom_variable_instance.getCustomVariable() failed, no need to do anything. It just means there is no CustomVariable, so there's nothing to delete.
}
// Delete CustomVariableInstance
this.custom_variable_instances.delete(custom_variable_instance.getID());
// remove the variable from custom variable side panes.
await this.plugin.updateCustomVariableViews();
}
/**
* Can be changed to public if needed.
*/
isCustomVariableNameDuplicate(custom_variable_name, ignore_custom_variable_instance) {
let is_duplicate = false;
this.custom_variable_instances.forEach((custom_variable2_instance, custom_variable_id) => {
// First check can the current custom variable attend to the duplicate test.
if (ignore_custom_variable_instance && custom_variable_id === ignore_custom_variable_instance.getID()) {
// Don't check this instance. This skipping is used for the current owner of the name.
return;
}
// Now do the actual duplicate test.
if (custom_variable_name.toLocaleLowerCase() === custom_variable2_instance.configuration.name.toLocaleLowerCase()) {
is_duplicate = true;
}
});
return is_duplicate;
}
}
class CustomVariableInstanceMap extends Map {
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class CustomVariableSettingsModal extends SC_Modal {
constructor(plugin, custom_variable_instance, on_after_creation, on_after_cancelling) {
super(plugin);
this.custom_variable_instance = custom_variable_instance;
this.on_after_creation = on_after_creation;
this.on_after_cancelling = on_after_cancelling;
this.created = false;
}
onOpen() {
super.onOpen();
const model = getModel(CustomVariableModel.name);
model.createSettingFields(this.custom_variable_instance, this.modalEl, false);
new obsidian.Setting(this.modalEl)
.addButton(button => button
.setButtonText("Create")
.onClick(() => this.approve()));
}
approve() {
this.created = true;
this.on_after_creation();
this.close();
}
onClose() {
super.onClose();
if (!this.created) {
this.on_after_cancelling();
}
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class CustomVariableView extends obsidian.ItemView {
constructor(plugin, leaf) {
super(leaf);
this.plugin = plugin;
}
getDisplayText() {
return "Custom variables";
}
getViewType() {
return CustomVariableView.ViewType;
}
getIcon() {
return "code-glyph";
}
async onOpen() {
this.container_element = this.containerEl.children[1].createDiv(); // I don't know why I cannot create elements directly under this.containerEl (they wouldn't show up). I did the same thing as was done here: https://marcus.se.net/obsidian-plugin-docs/guides/custom-views (referenced 2022-03-23).
this.container_element.addClass("container");
await this.updateContent();
}
async updateContent() {
this.container_element.empty();
this.container_element.createEl("h3", { text: "Custom variables" });
const variableListElement = this.container_element.createEl("ul");
for (const customVariableInstance of this.plugin.getCustomVariableInstances().values()) {
let customVariableValue = (await customVariableInstance.getCustomVariable().getValue()).value;
let customVariableState = null;
if (null === customVariableValue) {
// The variable has no value yet.
if ("value" === customVariableInstance.configuration.default_value?.type) {
// Indicate that the variable has a default value defined, which will practically be used as long as no overriding value is set.
if ("" === customVariableInstance.configuration.default_value.value.trim()) {
customVariableState = "No value yet, but defaults to: An empty text.";
}
else {
customVariableState = "No value yet, but defaults to: "; // The value will appear next to the state text later below.
customVariableValue = customVariableInstance.configuration.default_value.value;
}
}
else {
// No default value is defined, so no value is accessible.
customVariableState = "No value yet.";
}
}
else if ("" === customVariableValue) {
customVariableState = "An empty text.";
}
const variableListItemElement = variableListElement.createEl("li", {
text: customVariableInstance.getFullName(),
attr: {
"aria-label": customVariableInstance.configuration.description,
"class": "SC-custom-variable-view-list-item",
},
});
variableListItemElement.createEl("br");
if (null !== customVariableState) {
variableListItemElement.createEl("em").insertAdjacentText("beforeend", customVariableState);
}
if (null !== customVariableValue) {
// Bold normal values to make them more prominent in contrast to variable names and "No value yet."/"An empty text." texts.
variableListItemElement.createEl("strong").insertAdjacentText("beforeend", customVariableValue);
}
}
}
}
CustomVariableView.ViewType = "SC-custom-variables-view";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Preaction {
constructor(plugin, configuration, t_shell_command) {
this.plugin = plugin;
this.configuration = configuration;
this.t_shell_command = t_shell_command;
}
/**
* Maybe this wrapper method is unneeded, but have it for a while at least.
*/
perform(parsing_process, sc_event) {
return this.doPreaction(parsing_process, sc_event);
}
/**
* Returns variables that are dependent of this Preaction, i.e. variables whose value is set by this Preaction.
* If a variable is READ by a Preaction, it is NOT considered to be _dependent_ of the Preaction, as long as the variable's
* value is not changed by the Preaction.
*
* By default, it returns an empty VariableSet, because not all Preactions will use variables at all.
*/
getDependentVariables() {
return new VariableSet();
}
}
function createPreaction(plugin, preaction_configuration, t_shell_command) {
switch (preaction_configuration.type) {
case "prompt":
return new Preaction_Prompt(plugin, preaction_configuration, t_shell_command);
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Preaction_Prompt extends Preaction {
constructor(plugin, configuration, t_shell_command) {
super(plugin, configuration, t_shell_command);
this.configuration = configuration;
}
doPreaction(parsing_process, sc_event) {
// TODO: Now that doPreaction() returns a similar Promise as is received from openPrompt(), consider just returning the same Promise instead of creating a new one.
return new Promise((resolve) => {
this.getPrompt().openPrompt(this.t_shell_command, parsing_process, sc_event).then((execution_confirmed) => {
// The PromptModal has been closed.
// Check if user wanted to execute the shell command or cancel.
if (execution_confirmed) {
// User wants to execute.
resolve(true);
}
else {
// User wants to cancel.
resolve(false);
}
});
});
}
/**
* Returns all the CustomVariables whose values this Preaction's Prompt sets.
*/
getDependentVariables() {
const variables = new VariableSet();
for (const prompt_field of this.getPrompt().prompt_fields) {
// Check that the PromptField has a target variable defined. Otherwise getTargetVariable() would cause a crash.
if ("" !== prompt_field.configuration.target_variable_id) {
variables.add(prompt_field.getTargetVariable());
}
}
return variables;
}
/**
* TODO: Remove.
*/
getDefaultConfiguration() {
return {
type: "prompt",
enabled: false,
prompt_id: "",
};
}
getPrompt() {
const promptId = this.configuration.prompt_id;
if (undefined === promptId) {
throw new Error("Prompt id is undefined in configuration.");
}
const prompt = this.plugin.getPrompts().get(promptId);
if (undefined === prompt) {
throw new Error("Prompt with id '" + promptId + "' does not exist");
}
return prompt;
}
}
function getDefaultPreaction_Prompt_Configuration() {
return {
type: "prompt",
enabled: false,
prompt_id: "",
};
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class PromptField extends Instance {
constructor(model, prompt, configuration, prompt_field_index) {
super(model, configuration, prompt.configuration);
this.model = model;
this.prompt = prompt;
this.configuration = configuration;
this.prompt_field_index = prompt_field_index;
this.parsing_errors = [];
}
/**
*
* @param container_element
* @param t_shell_command
* @param sc_event Used when parsing variables for default_value and the inputted value. Needed so that also {{event_*}} variables can be used in prompts.
*/
async createField(container_element, t_shell_command, sc_event) {
await this._createField(container_element, t_shell_command, sc_event);
// Create a preview setting element. It will not contain any actual setting elements, just text.
this.preview_setting = new obsidian.Setting(container_element);
// Parse variables in the default value and insert it to the field.
// Note that this is a different "default value" than what TShellCommand considers as variables' default values! This is about a _field's_ default value, not a variable's default value. t_shell_command is passed in order to allow any possible variables in the field's default value to access the variables' default values (which come from TShellCommand).
await this.applyDefaultValue(t_shell_command, sc_event);
}
getTitle() {
return this.configuration.label === "" ? "Unlabelled field" : this.configuration.label;
}
/**
* Parses the default value and sets it to the form element.
* @param t_shell_command
* @param sc_event
* @private
*/
async applyDefaultValue(t_shell_command, sc_event) {
const default_value = this.configuration.default_value;
const parsing_result = await parseVariables(this.prompt.model.plugin, default_value, null, t_shell_command, sc_event);
if (!parsing_result.succeeded) {
// Parsing failed.
this.setValue(default_value); // Use the unparsed value. If default value contains a variable that cannot be parsed, a user can see the variable in the prompt modal and either fix it or change it to something else.
}
else {
// Parsing succeeded.
this.setValue(parsing_result.parsed_content);
}
await this.valueHasChanged(t_shell_command, sc_event);
}
getParsedValue() {
return this.parsed_value;
}
/**
* Tries to get a parsed value, but if it's not available (probably due to incorrect usage of variables), returns an
* unparsed value instead().
*/
getParsedOrRawValue() {
return this.parsed_value ?? this.getValue();
}
getParsingErrors() {
return this.parsing_errors;
}
/**
* Updates this.parsed_value, this.parsing_errors and this.preview_setting .
*
* @param t_shell_command
* @param sc_event
* @protected
*/
async valueHasChanged(t_shell_command, sc_event) {
let preview;
// Parse variables in the value.
const parsing_result = await parseVariables(this.prompt.model.plugin, this.getValue(), null, t_shell_command, sc_event);
if (!parsing_result.succeeded) {
// Parsing failed.
this.parsed_value = null;
if (parsing_result.error_messages.length > 0) {
// Display the first error message. If there are more, others can be omitted.
preview = parsing_result.error_messages[0];
}
else {
// If there are no error messages, then errors are silently ignored by user's variable configuration, in which case just show the original content.
preview = parsing_result.original_content;
}
this.parsing_errors = parsing_result.error_messages;
}
else {
// Parsing succeeded
this.parsed_value = parsing_result.parsed_content;
preview = parsing_result.parsed_content;
this.parsing_errors = []; // No errors.
}
// Update the preview element.
if (0 === parsing_result.count_parsed_variables) {
// If no variables were used, hide the description as it's not needed to repeat the value that already shows up in the form field.
preview = "";
}
this.preview_setting.setDesc(preview);
// Call a possible external callback
if (this.on_change_callback) {
this.on_change_callback();
}
}
/**
* @param on_change_callback A callback that will be called whenever the field's value is changed.
*/
onChange(on_change_callback) {
this.on_change_callback = on_change_callback;
}
/**
* @param on_focus_callback A callback that will be called whenever the field is focused.
*/
onFocus(on_focus_callback) {
this.on_focus_callback = on_focus_callback;
}
/**
* Should be called by the subclass when the field has gotten focus.
*/
hasGottenFocus() {
if (this.on_focus_callback) {
this.on_focus_callback(this);
}
}
/**
* Ensures that the field is filled, if it's mandatory. If the field is not mandatory, it's always valid.
*
* @return True when valid, false when not valid.
*/
validate() {
if (!this.configuration.required) {
// No need to validate, because the field is not mandatory.
return true;
}
// Ensure the field is filled
return this.isFilled();
}
getTargetVariableInstance() {
const target_variable_id = this.configuration.target_variable_id;
const custom_variable_instance = this.prompt.model.plugin.getCustomVariableInstances().get(target_variable_id);
if (!custom_variable_instance) {
throw new Error(this.constructor.name + ".getTargetVariableInstance(): CustomVariableInstance with ID '" + target_variable_id + "' was not found");
}
return custom_variable_instance;
}
getTargetVariable() {
const custom_variable_instance = this.getTargetVariableInstance();
return custom_variable_instance.getCustomVariable();
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class PromptFieldModel extends Model {
getSingularName() {
return "Field";
}
defineParentConfigurationRelation(prompt_field) {
return {
type: "one-to-many-index",
key: "fields",
index: prompt_field.prompt_field_index,
};
}
loadInstances(prompt) {
const prompt_fields = new PromptFieldSet;
prompt.configuration.fields.forEach((field_configuration, index) => {
prompt_fields.add(this.createInstance(prompt, field_configuration, index));
});
return prompt_fields;
}
newInstance(prompt) {
// TODO: Move this logic to the base Model class.
// Setup a default configuration
const prompt_field_configuration = this.getDefaultConfiguration();
// Instantiate a PromptField
const prompt_field = this.createInstance(prompt, prompt_field_configuration, prompt.configuration.fields.length);
// Store the configuration into the prompt's configuration
prompt.configuration.fields.push(prompt_field_configuration);
// Store the PromptField instance into its parent Prompt's list of fields.
prompt.prompt_fields.add(prompt_field);
// Return the PromptField
return prompt_field;
}
createInstance(prompt, prompt_field_configuration, prompt_field_index) {
// TODO: When the 'type' field gets implemented on PromptFieldConfiguration, implement some kind of switch structure here to create different types of PromptFields.
return new PromptField_Text(this, prompt, prompt_field_configuration, prompt_field_index);
}
_createSettingFields(prompt_field, container_element) {
const label_placeholders = [
"What is your name?",
"How big is the universe?",
"How long is eternity?",
"What is your lucky number?",
"What is your favorite song?",
"What is your favorite color?",
"How many books have you read?",
"What is the purpose of life?",
];
const default_value_placeholders = [
["Bond, James Bond", "John Doe", "Jane Doe", "Mr. Bean"],
["Very big, and still expanding", "93 billion light-years"],
["Infinite", "Too long to wait for"],
[String(randomInteger(0, 9)), "I don't have one"],
["We are the world (USA for Africa)", "Heal the world (Michael Jackson)", "Imagine (John Lennon)", "Circle of life (Elton John)"],
["Blue as deep as an ocean", "Red as love", "Grass-green", "Snow-white"],
["Thousands", "Many", "Countless", "None"],
["Thinking", "Being a being", "42"],
];
const label_placeholder_index = randomInteger(0, label_placeholders.length - 1);
const default_value_placeholders_subset = default_value_placeholders[label_placeholder_index];
// Create a list of custom variables
const custom_variable_options = {};
this.plugin.getCustomVariableInstances().forEach((custom_variable_instance, custom_variable_id) => {
custom_variable_options[custom_variable_id] = custom_variable_instance.getFullName();
});
const on_default_value_setting_change = async (new_default_value) => {
prompt_field.configuration.default_value = new_default_value;
await this.plugin.saveSettings();
};
// Create the setting fields
const setting_group_element = container_element.createDiv({ attr: { class: "SC-setting-group" } });
let label_setting_component;
let description_setting_component;
const setting_group = {
heading_setting: new obsidian.Setting(setting_group_element)
.setName("") // This will be set down below.
.setHeading(),
label_setting: new obsidian.Setting(setting_group_element)
.setName("Field label")
.addText(text => label_setting_component = text
.setValue(prompt_field.configuration.label)
.setPlaceholder(label_placeholders[label_placeholder_index])
.onChange(async (new_label) => {
prompt_field.configuration.label = new_label;
_update_heading();
await this.plugin.saveSettings();
})),
default_value_setting: new obsidian.Setting(setting_group_element)
.setName("Default value")
.addText(text => text
.setValue(prompt_field.configuration.default_value)
.setPlaceholder(prompt_field.configuration.label ? "" // If the label is defined, do not add a placeholder here, as the label's placeholder is not visible, so this placeholder would not make sense.
: default_value_placeholders_subset[randomInteger(0, default_value_placeholders_subset.length - 1)])
.onChange(on_default_value_setting_change)),
description_setting: new obsidian.Setting(setting_group_element)
.setName("Description")
.addText(text => description_setting_component = text
.setValue(prompt_field.configuration.description)
.onChange(async (new_description) => {
prompt_field.configuration.description = new_description;
await this.plugin.saveSettings();
})),
target_variable_setting: new obsidian.Setting(setting_group_element)
.setName("Target variable")
.setDesc("Where the inputted value will be stored in. You can use the variable in a shell command.")
.addDropdown(dropdown => dropdown
.addOption("", "") // An option for a situation when nothing is selected.
.addOptions(custom_variable_options)
.addOption("new", "Create a new custom variable")
.setValue(prompt_field.configuration.target_variable_id)
.onChange((new_target_variable_id) => {
if ("new" === new_target_variable_id) {
// Create a new custom variable.
const model = getModel(CustomVariableModel.name);
const custom_variable_instance = model.newInstance(this.plugin.settings);
this.plugin.saveSettings().then(() => {
const modal = new CustomVariableSettingsModal(this.plugin, custom_variable_instance, async () => {
// Variable is created.
dropdown.addOption(custom_variable_instance.getID(), custom_variable_instance.getTitle());
dropdown.setValue(custom_variable_instance.getID());
prompt_field.configuration.target_variable_id = custom_variable_instance.getID();
await this.plugin.saveSettings();
}, async () => {
dropdown.setValue(prompt_field.configuration.target_variable_id); // Reset the dropdown selection.
// Variable creation was cancelled.
model.deleteInstance(custom_variable_instance);
await this.plugin.saveSettings();
});
modal.open();
});
}
else {
// Use an existing target variable (or an empty id "").
// Check that this target variable is not reserved.
prompt_field.setIfValid("target_variable_id", new_target_variable_id).then(async () => {
// It can be used.
await this.plugin.saveSettings();
}, (error_message) => {
if (typeof error_message === "string") {
// This is a validation error message.
// The target variable is reserved.
dropdown.setValue(prompt_field.configuration.target_variable_id); // Reset the dropdown selection.
this.plugin.newNotification(error_message);
}
else {
// Some other runtime error has occurred.
throw error_message;
}
});
}
})),
required_setting: new obsidian.Setting(setting_group_element)
.setName("Is required")
.setDesc("If on, the field needs to be filled before the prompt can be submitted.")
.addToggle(toggle => toggle
.setValue(prompt_field.configuration.required)
.onChange(async (new_required) => {
prompt_field.configuration.required = new_required;
await this.plugin.saveSettings();
})),
};
_update_heading();
function _update_heading() {
setting_group.heading_setting.setName(prompt_field.getTitle());
}
// Autocomplete menu
if (this.plugin.settings.show_autocomplete_menu) {
// Show autocomplete menu (= a list of available variables).
const label_input_element = setting_group.label_setting.controlEl.find("input");
createAutocomplete(this.plugin, label_input_element, () => label_setting_component.onChanged());
const default_value_input_element = setting_group.default_value_setting.controlEl.find("input");
createAutocomplete(this.plugin, default_value_input_element, on_default_value_setting_change);
const description_input_element = setting_group.description_setting.controlEl.find("input");
createAutocomplete(this.plugin, description_input_element, () => description_setting_component.onChanged());
}
return setting_group.heading_setting;
}
validateValue(prompt_field, field, value) {
switch (field) {
case "target_variable_id": {
const new_target_variable_id = value; // A more descriptive name for 'value'.
// Always allow an empty target_variable_id. A Prompt cannot be opened if a field lacks a target_variable_id, but it's allowed to be stored in the configuration, because new Prompts cannot have a default selected target variable.
if ("" === new_target_variable_id) {
return Promise.resolve();
}
// Check that the target variable is not used by other fields of the same Prompt.
for (const other_prompt_field of prompt_field.prompt.prompt_fields) {
if (prompt_field !== other_prompt_field) { // Do not check the same field. Only check other fields.
// Check if this other field has the same target variable.
if (new_target_variable_id === other_prompt_field.configuration.target_variable_id) {
// They have the same target_variable_id.
// Return an error message.
const targetVariableInstance = this.plugin.getCustomVariableInstances().get(new_target_variable_id);
if (undefined === targetVariableInstance) {
throw new Error("Could not find target variable with id " + new_target_variable_id);
}
const target_variable_name = targetVariableInstance.getFullName();
return Promise.reject(`Target variable ${target_variable_name} is already used by another field in the same prompt. Select another variable.`);
}
}
}
// All fields have been checked and no collisions were found.
return Promise.resolve();
}
default: {
// No validation for other fields.
throw new Error(this.constructor.name + ".validateValue(): No validation is implemented for other fields.");
}
}
}
getDefaultConfiguration() {
return {
// type: "text",
label: "",
description: "",
default_value: "",
// TODO: Add 'placeholder'.
target_variable_id: "",
required: true,
};
}
_deleteInstance(prompt_field) {
prompt_field.prompt.prompt_fields.delete(prompt_field);
}
}
class PromptFieldSet extends Set {
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class PromptField_Text extends PromptField {
async _createField(container_element, t_shell_command, sc_event) {
const plugin = this.prompt.model.plugin;
// Create the field
const on_change = () => this.valueHasChanged(t_shell_command, sc_event);
const label_parsing_result = await parseVariables(this.prompt.model.plugin, this.configuration.label, null, t_shell_command, sc_event);
const description_parsing_result = await parseVariables(this.prompt.model.plugin, this.configuration.description, null, t_shell_command, sc_event);
const setting = new obsidian.Setting(container_element)
.setName(label_parsing_result.succeeded ? label_parsing_result.parsed_content : label_parsing_result.original_content)
.setDesc(description_parsing_result.succeeded ? description_parsing_result.parsed_content : description_parsing_result.original_content)
.addText((text_component) => {
this.text_component = text_component;
text_component.onChange(on_change);
});
// Set up onFocus hook.
this.text_component.inputEl.onfocus = () => {
this.hasGottenFocus();
};
// Show autocomplete menu (if enabled)
if (plugin.settings.show_autocomplete_menu) {
const input_element = setting.controlEl.find("input");
createAutocomplete(plugin, input_element, on_change);
}
}
setValue(value) {
this.text_component.setValue(value);
}
getValue() {
return this.text_component.getValue();
}
setFocus() {
this.text_component.inputEl.focus();
}
isFilled() {
return this.getValue().length > 0;
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class Prompt extends Instance {
constructor(model, plugin, configuration, parent_configuration) {
super(model, configuration, parent_configuration);
this.model = model;
this.plugin = plugin;
this.configuration = configuration;
this.parent_configuration = parent_configuration;
this.prompt_fields = new PromptFieldSet();
// Introduce the ID to an ID generator so that it won't accidentally generate the same ID again when creating new Prompts.
getIDGenerator().addReservedID(configuration.id);
this.createFields();
}
getID() {
return this.configuration.id;
}
getTitle() {
return this.configuration.title;
}
getConfiguration() {
return this.configuration;
}
getCSSClass() {
return Prompt.getCSSBaseClass() + "-" + this.getID();
}
static getCSSBaseClass() {
return "SC-prompt-modal";
}
getCSSClasses() {
return [
Prompt.getCSSBaseClass(),
this.getCSSClass(),
];
}
/**
* @param t_shell_command Can be null, if wanted to just preview the Prompt modal without really executing a shell command. Inputted values will still be assigned to target variables.
* @param parsing_process
* @param sc_event
* @return Promise The boolean value tells whether the user wants to execute a shell command (true) or cancel (false).
*/
openPrompt(t_shell_command, parsing_process, sc_event) {
const can_open_prompt_result = this.canOpenPrompt();
if (true !== can_open_prompt_result) {
// Some error is preventing opening the prompt.
// A human-readable error message is contained in can_open_prompt_result.
debugLog("Could not open Prompt " + this.getID() + " because of error: " + can_open_prompt_result);
this.plugin.newError(can_open_prompt_result);
return Promise.resolve(false); // false: Cancel execution (pretends that a user cancelled it, but it's ok).
}
debugLog("Opening Prompt " + this.getID());
const modal = new PromptModal(this.plugin, this.prompt_fields, t_shell_command, parsing_process, this, sc_event, () => { return this.validateFields(); });
modal.open();
return modal.promise;
}
canOpenPrompt() {
// Check that all PromptFields have a target variable defined.
for (const prompt_field of this.prompt_fields) {
if (!prompt_field.configuration.target_variable_id) {
return `Cannot open prompt '${this.getTitle()}': Field '${prompt_field.getTitle()}' does not have a target variable.`;
}
else {
try {
prompt_field.getTargetVariableInstance(); // Just try to get a CustomVariableInstance. No need to use it here, but if this fails, we know the variable is removed.
}
catch (error) {
return `Cannot open prompt '${this.getTitle()}': Field '${prompt_field.getTitle()}' uses a target variable which does not exist anymore.`;
}
}
}
// All ok.
return true;
}
/**
* Creates PromptField instances, NOT setting fields!
*/
createFields() {
debugLog("Creating fields for Prompt " + this.getID());
const prompt_field_model = getModel(PromptFieldModel.name);
this.prompt_fields = prompt_field_model.loadInstances(this);
}
/**
* Validates values in PromptField instances, NOT setting fields!
*/
validateFields() {
debugLog("Validating fields for Prompt " + this.getID());
// Iterate all fields and check their validity.
const error_messages = [];
this.prompt_fields.forEach((prompt_field) => {
// Check if the field has parsing errors.
const parsing_errors = prompt_field.getParsingErrors();
for (const parsing_error of parsing_errors) {
// This field has parsing error(s).
error_messages.push(`'${prompt_field.getTitle()}': ` + parsing_error);
}
// Check other validity.
if (!prompt_field.validate()) {
// This field failed to validate.
// TODO: Change this so that the message will come from prompt_field.validate().
error_messages.push(`'${prompt_field.getTitle()}' needs to be filled.`);
}
});
// Return the result.
if (0 === error_messages.length) {
return Promise.resolve();
}
else {
return Promise.reject(error_messages);
}
}
/**
* When previewing a PromptModal, there is no real shell command available (because no shell command has triggered the
* PromptModal). This method creates just a dummy shell command string that imitates a command that would echo variable values.
*/
getExampleShellCommand() {
const variable_names = [];
for (const prompt_field of this.prompt_fields) {
variable_names.push(prompt_field.getTargetVariableInstance().getFullName());
}
return "echo " + variable_names.join(" ");
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class PromptModal extends SC_Modal {
constructor(plugin, prompt_fields,
/** Can be null, if wanted to just preview the Prompt modal without really executing a shell command. Inputted values will still be assigned to target variables. */
t_shell_command, parsing_process, prompt, sc_event,
/** A function that is called when a user clicks the execution button. This function should check the form elements' validity and return false if there are unfilled fields. */
validator) {
super(plugin);
this.prompt_fields = prompt_fields;
this.t_shell_command = t_shell_command;
this.parsing_process = parsing_process;
this.prompt = prompt;
this.sc_event = sc_event;
this.validator = validator;
this.user_confirmed_ok = false;
this.promise = new Promise((resolve) => {
this.resolve_promise = resolve;
});
}
async onOpen() {
super.onOpen();
// Parse and display title
const title_parsing_result = await parseVariables(this.plugin, this.prompt.getTitle(), null, this.t_shell_command, this.sc_event);
this.setTitle(title_parsing_result.succeeded
? title_parsing_result.parsed_content
: title_parsing_result.original_content);
// Parse and display description
if (this.prompt.configuration.description) {
const description_parsing_result = await parseVariables(this.plugin, this.prompt.configuration.description, null, this.t_shell_command, this.sc_event);
const description = description_parsing_result.succeeded
? description_parsing_result.parsed_content
: description_parsing_result.original_content;
const description_element = createMultilineTextElement("p", description, this.modalEl);
description_element.addClass("setting-item-description"); // A CSS class defined by Obsidian.
}
// Preview the shell command (if wanted)
// TODO: Extract to a separate method, as this is a big block of code.
let update_shell_command_preview = null; // Stays null if .preview_shell_command is false.
let focused_prompt_field;
if (this.prompt.getConfiguration().preview_shell_command) {
let shell_command_preview_text;
if (this.t_shell_command?.getAlias()) {
this.modalEl.createEl("p", { text: this.t_shell_command.getAlias(), attr: { class: "SC-no-margin" } });
}
// Create "Show variable values" toggle
let preview_variable_values = true;
const variable_names_visible_icon = "code-glyph";
const variable_values_visible_glyph = "price-tag-glyph";
const preview_variable_values_setting = new obsidian.Setting(this.modalEl)
.addExtraButton(button => button
.setIcon(variable_values_visible_glyph)
.setTooltip("Toggle showing variable names or values.")
.onClick(() => {
preview_variable_values = !preview_variable_values;
button.setIcon(preview_variable_values
? variable_values_visible_glyph
: variable_names_visible_icon);
if (null === update_shell_command_preview) {
throw new Error("Toggle showing variable names or value: update_shell_command_preview function is not defined.");
}
update_shell_command_preview();
}));
// Decide what text to use in the preview
const shellCommandParsingResult = this.parsing_process?.getParsingResults().shell_command;
if (shellCommandParsingResult?.succeeded) {
// Show a real shell command. Use preparsed content (= content that might have some variables already parsed).
shell_command_preview_text = shellCommandParsingResult.parsed_content; // as string = if shellCommandParsingResult?.succeeded is true, then .parsed_content is always string.
}
else if (this.t_shell_command) {
// Show a real shell command. No preparsed content is available. This content does not have any variables parsed yet.
shell_command_preview_text = this.t_shell_command.getShellCommand();
}
else {
// Make up a fake "shell command" for previewing.
shell_command_preview_text = this.prompt.getExampleShellCommand();
this.modalEl.createEl("p", { text: "(This is not a real shell command, it's just an example for this preview when no real shell command is available.)", attr: { class: "SC-no-margin SC-small-font" } });
}
this.modalEl.createEl("hr");
// A function for handling preview text updates.
update_shell_command_preview = async () => {
let shell_command_preview_text_final = shell_command_preview_text;
if (preview_variable_values) {
// The preview should show the VALUES.
// Ensure the form fields do not contain any parsing errors. (If there are errors, an unparsed preview text will be shown).
if (this.getPromptFieldsParsingErrors().length === 0) {
// All fields are parsed ok (= individual parsing).
// Insert the field values into the shell command preview by parsing the preview text.
// Get current values from the prompt fields.
const fresh_values = this.getPromptFieldsValues(); // These PromptField values are fresh, so not yet stored in the actual variables.
// Parse variables in the shell command preview text.
const parsing_result = await parseVariables(this.plugin, shell_command_preview_text, this.getShell(), this.t_shell_command, this.sc_event, undefined, // Use all variables.
(variable, raw_value) => {
if (fresh_values.has(variable.variable_name)) {
// Change the value to the one in the prompt field.
raw_value.error_messages = []; // Remove any possible error messages.
raw_value.succeeded = true; // This needs to reflect that there are no error messages.
raw_value.value = fresh_values.get(variable.variable_name); // It's always a string because fresh_values.has() is used above.
}
// No modifications.
}, (variable, escaped_value) => {
// Emphasize the value that came from the currently focused field.
if (focused_prompt_field) {
if (variable.variable_name.toLocaleLowerCase() === focused_prompt_field.getTargetVariableInstance().getPrefixedName().toLocaleLowerCase()) {
// Make the value bold.
return `<strong>${escaped_value}</strong>`;
}
}
// No modifications.
return escaped_value;
});
if (parsing_result.succeeded) {
shell_command_preview_text_final = parsing_result.parsed_content;
}
}
}
else {
// The preview should show the VARIABLE NAMES.
if (focused_prompt_field) {
const pattern = new RegExp(focused_prompt_field.getTargetVariable().getPattern(), "igu"); // i: case-insensitive; g: match all occurrences instead of just the first one. u: support 4-byte unicode characters too.
shell_command_preview_text_final = shell_command_preview_text_final.replace(pattern, (replaceable_variable_name) => {
return "<strong>" + replaceable_variable_name + "</strong>";
});
}
}
preview_variable_values_setting.descEl.innerHTML = shell_command_preview_text_final;
};
}
// Create fields
let is_first_field = true;
for (const prompt_field of this.prompt_fields) {
await prompt_field.createField(this.modalEl.createDiv({ attr: { class: "SC-setting-group" } }), this.t_shell_command, this.sc_event);
if (update_shell_command_preview) {
prompt_field.onChange(update_shell_command_preview);
}
prompt_field.onFocus((prompt_field) => {
focused_prompt_field = prompt_field;
if (update_shell_command_preview) {
update_shell_command_preview();
}
});
if (is_first_field) {
// Focus on the first field.
is_first_field = false;
prompt_field.setFocus();
}
}
if (update_shell_command_preview) {
// Set a preview text. Must be done after fields are created, because their values are accessed.
update_shell_command_preview();
}
// Tip about variables
let tip = "";
if (this.prompt_fields.size > 0) {
// TODO: When implementing different field types, add a check that the tip is only shown when there are text/numeric fields present.
// Only show the tip if this modal actually contains fields. Prompts can also be used as custom 'confirmation prompts' without any fields.
tip = "Tip! You can use {{variables}} in text fields.";
}
// Execute button
const execute_button_text_parsing_result = await parseVariables(this.plugin, this.prompt.configuration.execute_button_text, null, this.t_shell_command, this.sc_event);
const execute_button_text = execute_button_text_parsing_result.succeeded
? execute_button_text_parsing_result.parsed_content
: execute_button_text_parsing_result.original_content;
new obsidian.Setting(this.modalEl)
.setDesc(tip)
.addButton(button => button
.setButtonText(execute_button_text)
.onClick(() => this.approve()));
if (!this.t_shell_command) {
// Notice that this is a preview only Prompt.
this.modalEl.createEl("p", { text: `This is a preview prompt. No shell command will be executed, but clicking the '${this.prompt.configuration.execute_button_text}' button will still store the inputted value(s) to variable(s).` }).addClass("SC-prompt-dry-run-notice");
}
// Add CSS classes so that custom styling can be done on a per-prompt modal basis (or for all prompt modals via a common class).
this.modalEl.addClasses(this.prompt.getCSSClasses());
}
approve() {
this.validator().then(async () => {
// The form fields are filled ok
await this.assignValuesToVariables();
this.resolve_promise(true);
this.user_confirmed_ok = true;
this.close();
}, (error_messages) => {
if (Array.isArray(error_messages)) {
// There were some problems with the fields.
this.plugin.newErrors(error_messages);
}
else {
// Some other runtime error has occurred.
throw error_messages;
}
});
}
onClose() {
super.onClose();
if (!this.user_confirmed_ok) { // TODO: Find out if there is a way to not use this kind of flag property. Can the status be checked from the promise itself?
this.resolve_promise(false);
}
}
async assignValuesToVariables() {
let promptField;
for (promptField of this.prompt_fields) {
await promptField.getTargetVariable().setValue(promptField.getParsedOrRawValue());
}
}
/**
* Gathers a Map of variable values typed in the form, but does not store the values into the variables. Called when
* generating a preview text, so the result of this method will not persist in any way.
* @private
*/
getPromptFieldsValues() {
const values = new Map();
for (const prompt_field of this.prompt_fields) {
values.set(prompt_field.getTargetVariable().variable_name, prompt_field.getParsedValue() ?? ""); // TODO: Should getParsedValue() ?? "" be changed to getParsedOrRawValue(), too?
}
return values;
}
getPromptFieldsParsingErrors() {
const parsing_errors = [];
for (const prompt_field of this.prompt_fields) {
parsing_errors.push(...prompt_field.getParsingErrors());
}
return parsing_errors;
}
getShell() {
if (this.t_shell_command) {
// This is a real usage of the PromptModal, so a TShellCommand is available. Look up the shell from that.
return this.t_shell_command.getShell();
}
else {
// Just trying the PromptModal. Just use some shell for variable escaping in an example preview.
return this.plugin.getDefaultShell();
}
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class PromptModel extends Model {
constructor() {
super(...arguments);
this.prompts = new PromptMap();
}
getSingularName() {
return "Prompt";
}
defineParentConfigurationRelation(prompt) {
return {
type: "one-to-many-id",
key: "prompts",
id: prompt.getID(),
};
}
loadInstances(parent_configuration) {
debugLog("Loading Prompt instances.");
this.prompts = new PromptMap();
parent_configuration.prompts.forEach((prompt_configuration) => {
const prompt = new Prompt(this, this.plugin, prompt_configuration, parent_configuration);
this.prompts.set(prompt_configuration.id, prompt);
});
return this.prompts;
}
newInstance(parent_configuration) {
debugLog("Creating a new Prompt instance.");
// TODO: Move this logic to the base Model class.
// Setup a default configuration and generate an ID
const prompt_configuration = this.getDefaultConfiguration();
// Instantiate a Prompt
const prompt = new Prompt(this, this.plugin, prompt_configuration, this.plugin.settings);
this.prompts.set(prompt.getID(), prompt);
// Store the configuration into plugin's settings
this.plugin.settings.prompts.push(prompt_configuration);
// Return the Prompt
return prompt;
}
_createSettingFields(prompt, container_element) {
debugLog("Creating setting fields for a Prompt instance.");
const prompt_name_setting = new obsidian.Setting(container_element)
// Configuration button
.setName(prompt.getTitle())
.addExtraButton(button => button
.setTooltip("Define prompt fields")
.setIcon("gear")
.onClick(() => {
this.openSettingsModal(prompt, prompt_name_setting);
}));
return prompt_name_setting;
}
validateValue(prompt, field, value) {
// This method is not used, so it can just resolve all the time.
return Promise.resolve(undefined);
}
openSettingsModal(prompt, prompt_name_setting) {
debugLog("Opening settings modal for a Prompt instance.");
const modal = new PromptSettingsModal(this.plugin, prompt, prompt_name_setting);
modal.open();
}
getDefaultConfiguration() {
return {
id: getIDGenerator().generateID(),
title: "",
description: "",
preview_shell_command: false,
fields: [],
execute_button_text: "Execute",
};
}
_deleteInstance(prompt) {
debugLog("Deleting a Prompt instance.");
// Remove the Prompt from all TShellCommands that use it.
const shell_commands = this.plugin.getTShellCommands();
for (const shell_command_id in shell_commands) {
const t_shell_command = shell_commands[shell_command_id];
for (const preaction_configuration of t_shell_command.getConfiguration().preactions) {
if ("prompt" === preaction_configuration.type) {
const preaction_prompt_configuration = preaction_configuration;
if (prompt.getID() === preaction_prompt_configuration.prompt_id) {
// This TShellCommand uses this Prompt.
// Remove the Prompt from use.
preaction_prompt_configuration.enabled = false;
preaction_prompt_configuration.prompt_id = undefined;
t_shell_command.resetPreactions();
// Saving is done later, after the _deleteInstance() call.
}
}
}
}
this.prompts.delete(prompt.getID());
}
}
class PromptMap extends Map {
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* @return Promise<InstanceClass> A promise that gets resolved if a user clicks the button. The promise is supplied with the newly created instance.
*/
function createNewModelInstanceButton(plugin, model_class_name, button_container_element, instance_container_element, parent_instance_or_configuration) {
debugLog("Creating a button for creating a new instance for model " + model_class_name + ".");
return new Promise((resolve_promise) => {
const model = getModel(model_class_name);
new obsidian.Setting(button_container_element)
.addButton(button => button
.setButtonText("New " + model.getSingularName().toLocaleLowerCase())
.onClick(async () => {
if (null === parent_instance_or_configuration) {
throw new Error("createNewModelInstanceButton(): Parent instance or configuration is null.");
}
const instance = model.newInstance(parent_instance_or_configuration);
const main_setting = model.createSettingFields(instance, instance_container_element);
resolve_promise({
"instance": instance,
"main_setting": main_setting,
});
await plugin.saveSettings();
}));
});
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class PromptSettingsModal extends SC_Modal {
constructor(plugin, prompt,
/** Can be undefined if the modal is created from a place where there is no name element. */
prompt_name_setting,
/** If defined, a button will be added and on_after_approval() / on_after_cancelling() will be called depending on whether the button was clicked or not. */
ok_button_text, on_after_approval, on_after_cancelling) {
super(plugin);
this.prompt = prompt;
this.prompt_name_setting = prompt_name_setting;
this.ok_button_text = ok_button_text;
this.on_after_approval = on_after_approval;
this.on_after_cancelling = on_after_cancelling;
this.approved = false;
}
onOpen() {
super.onOpen();
const container_element = this.modalEl;
const title_and_description_group_element = container_element.createDiv({ attr: { class: "SC-setting-group" } });
// Title
const title_setting = new obsidian.Setting(title_and_description_group_element)
.setName("Prompt title")
.addExtraButton(icon => icon
.setTooltip("Try the prompt without executing any shell command.")
.setIcon("run-command")
.onClick(() => {
// "Dry run" the Prompt
this.prompt.openPrompt(null, null, null).then();
}))
.addText(text => text
.setValue(this.prompt.getTitle())
.onChange(async (new_title) => {
this.prompt.getConfiguration().title = new_title;
await this.plugin.saveSettings();
// Update the title in a name setting. (Only if the modal was created from a place where a Prompt name element exists).
this.prompt_name_setting?.setName(new_title);
})
.then((title_setting_component) => {
// Autocomplete for Title.
if (this.plugin.settings.show_autocomplete_menu) {
createAutocomplete(this.plugin, title_setting_component.inputEl, () => title_setting_component.onChanged());
}
}));
const title_input_element = title_setting.controlEl.find("input");
// Focus on the title field.
title_input_element.focus();
// Description
new obsidian.Setting(title_and_description_group_element)
.setName("Description")
.setDesc("Displayed between the prompt title and fields. Both Description and Title support {{variables}}.")
.addTextArea(textarea => textarea
.setValue(this.prompt.configuration.description)
.onChange(async (new_description) => {
this.prompt.getConfiguration().description = new_description;
await this.plugin.saveSettings();
})
.then((description_component) => {
// Autocomplete for Description.
if (this.plugin.settings.show_autocomplete_menu) {
createAutocomplete(this.plugin, description_component.inputEl, () => description_component.onChanged());
}
}));
// Preview shell command
new obsidian.Setting(container_element)
.setName("Preview shell command in prompt")
.setDesc("If this is on, the prompt will display the executable shell command with variable names in it, and highlight the variable(s) that will be affected by the values inputted in the prompt.")
.addToggle(toggle => toggle
.setValue(this.prompt.getConfiguration().preview_shell_command)
.onChange(async (new_value) => {
this.prompt.getConfiguration().preview_shell_command = new_value;
await this.plugin.saveSettings();
}));
// Fields
new obsidian.Setting(container_element)
.setName("Fields")
.setDesc("Tip! You can use {{variables}} in 'Field label', 'Default value' and 'Description'.");
const prompt_field_model = getModel(PromptFieldModel.name);
const fields_container = container_element.createDiv();
this.prompt.prompt_fields.forEach((prompt_field) => {
prompt_field_model.createSettingFields(prompt_field, fields_container);
});
// New field button
createNewModelInstanceButton(this.plugin, PromptFieldModel.name, container_element, fields_container, this.prompt).then();
// Execute button text
new obsidian.Setting(container_element.createDiv({ attr: { class: "SC-setting-group" } }))
.setName("Execute button text")
.addText(text => text
.setValue(this.prompt.configuration.execute_button_text)
.onChange(async (new_execute_button_text) => {
this.prompt.configuration.execute_button_text = new_execute_button_text;
await this.plugin.saveSettings();
})
.then((execute_button_text_component) => {
// Autocomplete for the Execute button text.
if (this.plugin.settings.show_autocomplete_menu) {
createAutocomplete(this.plugin, execute_button_text_component.inputEl, () => execute_button_text_component.onChanged());
}
}));
// Ok button
const okButtonText = this.ok_button_text;
if (okButtonText) {
new obsidian.Setting(container_element)
.addButton(button => button
.setButtonText(okButtonText)
.onClick(() => this.approve()));
}
// A tip about CSS styling.
new obsidian.Setting(container_element)
.setDesc("Tip! You can customise the style of the prompt modal with CSS by using the class ." + this.prompt.getCSSClass() + " or ." + Prompt.getCSSBaseClass() + " (for all prompt modals).");
}
approve() {
if (this.on_after_approval) {
this.approved = true;
this.on_after_approval();
}
this.close();
}
onClose() {
super.onClose();
// Call a cancelling hook if one is defined (and if the closing happens due to cancelling, i.e. the ok button is NOT clicked).
if (!this.approved && this.on_after_cancelling) {
this.on_after_cancelling();
}
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function createPATHAugmentationFields(plugin, container_element, path_augmentations) {
const path_variable_name = getPATHEnvironmentVariableName();
new obsidian.Setting(container_element)
.setName(`Add directories to the ${path_variable_name} environment variable`)
.setHeading()
.setDesc(`This is sometimes needed in order to be able to call some user installed applications. The directories will be appended AFTER the default directories in ${path_variable_name}, unless {{!environment:${path_variable_name}}} is included. Other {{variables}} can be used, too, but they don't affect the appending order.`)
// An icon for showing the current PATH content.
.addExtraButton(button => button
.setIcon("bullet-list")
.setTooltip(`Show the current ${path_variable_name} content (without any additions).`)
.onClick(() => {
if (undefined === process.env.PATH) {
throw new Error("process.env.PATH is not a string.");
}
const modal = new ConfirmationModal(plugin, `Current ${path_variable_name} content`, process.env.PATH, "Close");
modal.open();
}))
// Help link
.addExtraButton(button => button
.setIcon("help")
.setTooltip(`Documentation: Additions to the ${path_variable_name} environment variable`)
.onClick(() => gotoURL(DocumentationPATHAugmentationsLink)));
// Create a field for each operating system.
const sub_container_element = container_element.createDiv();
sub_container_element.addClass("SC-setting-group");
Object.getOwnPropertyNames(PlatformNames).forEach((platform_id) => {
const platform_name = PlatformNames[platform_id];
new obsidian.Setting(sub_container_element).setName(platform_name + " " + getPATHEnvironmentVariableName(platform_id) + " additions")
.setDesc("Define each directory on a separate line, or multiple directories on one line, separated by " + getPATHSeparator(platform_id, true))
.addTextArea(textarea => textarea
.setValue(path_augmentations[platform_id] ?? "")
.onChange(async (new_path_augmentation) => {
// PATH augmentation has been changed.
// Update the configuration.
if (new_path_augmentation.length > 0) {
// The augmentation has content.
path_augmentations[platform_id] = new_path_augmentation;
}
else {
// The augmentation has been removed.
delete path_augmentations[platform_id];
}
await plugin.saveSettings();
})
.then((textarea_component) => {
// Add an autocomplete menu.
createAutocomplete(plugin, textarea_component.inputEl, () => textarea_component.onChanged());
}));
});
}
function getPATHSeparator(platform_id, verbose = false) {
switch (platform_id) {
case "linux":
case "darwin": // This is macOS.
return verbose ? "a colon :" : ":";
case "win32":
return verbose ? "a semicolon ;" : ";";
}
}
function convertNewlinesToPATHSeparators(path, platform_id) {
const separator = getPATHSeparator(platform_id);
return path.replace(/(\r\n|\r|\n)+/gu, // + means that multiple adjacent newlines can be combined into a single separator character.
() => separator);
}
/**
* Retrieves a PATH environment variable augmentation string (specific to the current operating system) from the plugin's
* configuration. Returns it WITHOUT parsing possible variables in the string. If the current operating system does not
* have a dedicated PATH augmentation string in the configuration, returns null.
*
* @param plugin
*/
function getPATHAugmentation(plugin) {
return plugin.settings.environment_variable_path_augmentations[getOperatingSystem()] ?? null;
}
/**
* Returns OS specific name for the PATH environment variable. For Windows its Path, but for macOS and Linux its PATH, so
* the only difference is casing.
*/
function getPATHEnvironmentVariableName(platform_id = getOperatingSystem()) {
switch (platform_id) {
case "darwin":
case "linux":
return "PATH";
case "win32":
return "Path";
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* ParsingProcess instances can be used in situations where it's uncertain can all variables be parsed at the time being,
* i.e. when parsing shell commands (and aliases), as they can have preactions which require parsing to be done in two phases.
*
* Also, shell commands are often parsed in advance for command palette and context menus. Then it's good to store the parsing
* result by using instances of this class.
*
* Then again, if the parsing use-case is simpler, e.g. Prompt description or prompt field values, it's more straightforward
* to just call parseVariables() without utilising this class. After all, this class is a wrapper for parseVariables().
*
* <ParsingMap> is a generalization for defining keys for an object that will be used for submitting the original parseable
* content. The same keys will then be used to form another object containing the parsing results.
*/
class ParsingProcess {
constructor(plugin, original_contents,
/** Used to get a shell (getShell()) and default values for variables. */
t_shell_command, sc_event,
/**
* When .process() is called, it will shift and process the first VariableSet present in this array. So, the next call
* will shift and process the next set.
*/
variable_sets,
/**
* This can be used to mark certain contents to always avoid escaping special characters in their variable values.
* This should only be used for content that is never submitted to a shell, i.e. output wrappers at the moment.
*
* This is a list of 'content keys'.
*/
avoid_escaping = []) {
this.plugin = plugin;
this.original_contents = original_contents;
this.t_shell_command = t_shell_command;
this.sc_event = sc_event;
this.variable_sets = variable_sets;
this.avoid_escaping = avoid_escaping;
this.parsing_results = {};
this.is_first_call = true;
debugLog("Parsing process: Count variable sets: " + this.variable_sets.length);
}
/**
* Performs the next step in the parsing process. The step can be the first one, or a subsequent step.
*
* @return True if parsing succeeded, false otherwise. Read the results by calling .getParsingResult().
*/
async process() {
if (this.variable_sets.length === 0) {
throw new Error("No variable sets are left for processing.");
}
const current_variables = this.variable_sets.shift(); // as VariableSet: Tell TypeScript that there is always a set of variables.
let success = true;
debugLog("Parsing process: Count variables in current set: " + current_variables.size);
// Multiple contents can be parsed in the same call. TShellCommand instances have 'shell_command' and 'alias'
// contents which are parsed at the same time. This multi-content support can be used for even more situations if
// needed in the future.
for (const content_key of this.getContentKeys()) {
let parse_content;
if (this.is_first_call) {
// Use original content.
parse_content = this.original_contents[content_key];
debugLog("Starting to parse '" + content_key + "': " + parse_content);
}
else {
// Continue parsing content from previous parsing result. This time parse variables that were not parse back then.
// FIXME: Problem: variable values that came from an earlier phase are exposed to repetitive parsing. Find a way to limit the parsing to only original parts of the shell command.
const previousParsingResult = this.parsing_results[content_key];
if (undefined === previousParsingResult) {
// This is just a type guard. this.getContentKeys() should only return keys that exist, so the checks should never throw errors in practise.
throw new Error("Parsing results do not contain key: " + content_key);
}
// Check that the previous parsing did not fail.
if (null === previousParsingResult.parsed_content) {
// Previous parsing had probably failed.
throw new Error("Tried to continue parsing, but previous parsing result is null. Probably previous parsing has failed.");
}
// Previous parsing was ok.
parse_content = previousParsingResult.parsed_content;
debugLog("Continuing parsing '" + content_key + "': " + parse_content);
}
// Parse the variables
const parsing_result = await parseVariables(this.plugin, parse_content, this.avoidEscaping(content_key) ? null : this.t_shell_command.getShell(), // If no escaping is needed, pass null.
this.t_shell_command, this.sc_event, current_variables);
// Check if the parsing succeeded or failed.
success = success && parsing_result.succeeded; // Flag as failed also if a previous phase has failed.
// Store the parsing result
this.mergeToParsingResults(content_key, parsing_result);
}
// Finish
this.is_first_call = false;
return success;
}
/**
* A wrapper for .process() that processes all the VariableSets that are still left unprocessed.
*
* @return True if parsing all sets succeeded, false otherwise.
*/
async processRest() {
// 1. Check a previous parsing result (if exists).
for (const content_key of this.getContentKeys()) {
const parsingResult = this.parsing_results[content_key];
if (parsingResult) {
// A previous parsing result exists.
// Ensure it has not failed.
debugLog("Previous parsing succeeded? " + parsingResult.succeeded);
if (!parsingResult.succeeded) {
// The previous parsing result has failed.
return false;
}
}
}
// 2. Process the rest of the VariableSets.
for (let i = 0; i < this.variable_sets.length; i++) {
if (!await this.process()) {
return false;
}
}
return true;
}
getParsingResults() {
return this.parsing_results;
}
/**
* Calls SC_Plugin.newErrors() to create visible error balloons for all the issues encountered during parsing.
*/
displayErrorMessages() {
this.plugin.newErrors(this.getErrorMessages());
}
/**
* @private Can be made public if needed.
*/
getErrorMessages() {
let error_messages = [];
for (const content_key of this.getContentKeys()) {
const parsingResult = this.parsing_results[content_key];
// Type guard
if (undefined === parsingResult) {
// This should never happen, because this.getContentKeys() should only return existing keys.
throw new Error("Parsing result is undefined.");
}
error_messages.push(...parsingResult.error_messages);
}
// Remove duplicate error messages. When parsing 'shell_command' and 'alias', they can contain same variables and
// therefore generate same error messages.
error_messages = uniqueArray(error_messages);
return error_messages;
}
getContentKeys() {
return Object.getOwnPropertyNames(this.original_contents);
}
/**
* Merges consecutive parsing results together so that information from both the old and new parsing results can be preserved.
*/
mergeToParsingResults(content_key, newParsingResult) {
const originalParsingResult = this.parsing_results[content_key];
if (undefined === originalParsingResult) {
// No need to merge. But clone the object so that possible future merges will not mess up the original object
// in case it's used somewhere else.
this.parsing_results[content_key] = cloneObject(newParsingResult);
// Note that originalParsingResult is still undefined. If you continue writing code here or after the if block
// (near the end of the function), do something like originalParsingResult = this.parsing_results[content_key]
// but that would require changing originalParsingResult from const to let.
}
else {
// Merge
// NOTE: originalParsingResult.original_content IS KEPT UNCHANGED! The newer "original" content is not actually original, because it's partly parsed. That's why the old one is preserved.
originalParsingResult.parsed_content = newParsingResult.parsed_content; // New parsed content overrides the old one.
originalParsingResult.succeeded &&= newParsingResult.succeeded; // Both the old and new parsing must have succeeded in order to consider the whole process succeeded.
originalParsingResult.error_messages.push(...newParsingResult.error_messages); // Include both old and new error messages.
originalParsingResult.count_parsed_variables += newParsingResult.count_parsed_variables; // Sum up the variable usage counts. At the time of writing, the sum is only used for determining if there were any variables parsed or not, so an accurate sum is not used atm.
}
}
/**
* Tells whether the given content_key has a mark that special characters in the content's variable values should not be escaped.
*
* @param content_key
* @private
*/
avoidEscaping(content_key) {
return this.avoid_escaping.contains(content_key);
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function newShellCommandConfiguration(shell_command_id, shell_command = "") {
return {
id: shell_command_id,
platform_specific_commands: {
default: shell_command,
},
shells: {},
alias: "",
icon: null,
confirm_execution: false,
ignore_error_codes: [],
input_contents: {
stdin: null,
},
output_channels: {
stdout: "ignore",
stderr: "notification",
},
output_wrappers: {
stdout: null,
stderr: null,
},
output_channel_order: "stdout-first",
output_handling_mode: "buffered",
events: {},
command_palette_availability: "enabled",
preactions: [],
variable_default_values: {},
};
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
async function RunMigrations(plugin) {
const should_save = [
EnsureMainFieldsExist(plugin),
MigrateCommandsToShellCommands(plugin),
MigrateShellCommandsObjectToArray(plugin),
MigrateShellCommandToPlatforms(plugin),
EnsureShellCommandsHaveAllFields(plugin),
EnsureCustomVariablesHaveAllFields(plugin),
DeleteEmptyCommandsField(plugin),
];
if (should_save.includes(true)) {
// Only save if there were changes to configuration.
debugLog("Saving migrations...");
backupSettingsFile(plugin); // Make a backup copy of the old file BEFORE writing the new, migrated settings file.
await plugin.saveSettings();
debugLog("Migrations saved...");
}
}
/**
* Can be removed in the future, but I haven't yet decided will it be done in 1.0 or later.
*/
function MigrateShellCommandsObjectToArray(plugin) {
// Check if the shell commands' container is an object.
if (!Array.isArray(plugin.settings.shell_commands)) {
// It is an object. It needs to be changed to an array in order to allow custom ordering.
const shell_commands_array = [];
for (const shell_command_id of Object.getOwnPropertyNames(plugin.settings.shell_commands)) { // Remember that plugin.settings.shell_commands is an object here! Not an array (yet).
// @ts-ignore I don't know why TypeScript thinks the index is incorrect.
const shell_command_configuration = plugin.settings.shell_commands[shell_command_id];
// Assign 'id' to ShellCommandConfiguration because it did not contain it before this migration.
shell_command_configuration.id = shell_command_id;
// Add the ShellCommandConfiguration to the new array container.
shell_commands_array.push(shell_command_configuration);
}
// Replace the old object container with the new array container.
plugin.settings.shell_commands = shell_commands_array; // Now plugin.settings.shell_commands changes to be an array instead of an object.
return true; // Save the changes.
}
else {
// The container is already migrated.
return false; // No need to save anything.
}
}
/**
* Can be removed in 1.0.0.
*
* @param plugin
* @constructor
*/
function MigrateCommandsToShellCommands(plugin) {
if (undefined === plugin.settings.commands) {
return false;
}
const count_shell_commands = plugin.settings.commands.length;
let save = false;
if (0 < count_shell_commands) {
let count_empty_commands = 0; // A counter for empty or null commands
debugLog("settings.commands is not empty, will migrate " + count_shell_commands + " commands to settings.shell_commands.");
for (const shell_command_id in plugin.settings.commands) {
const shell_command = plugin.settings.commands[shell_command_id];
// Ensure that the command is not empty. Just in case.
if (null === shell_command || 0 === shell_command.length) {
// The command is empty
debugLog("Migration failure for shell command #" + shell_command_id + ": The original shell command string is empty, so it cannot be migrated.");
count_empty_commands++;
}
else if (undefined !== plugin.getShellCommandConfigurationIndex(shell_command_id)) {
// A command with the same id already exists
debugLog("Migration failure for shell command #" + shell_command_id + ": A shell command with same ID already exists in settings.shell_commands.");
}
else {
// All OK, migrate.
plugin.settings.shell_commands.push(newShellCommandConfiguration(shell_command_id, shell_command)); // Creates a shell command with default values and defines the command for it.
delete plugin.settings.commands[shell_command_id]; // Leaves a null in place, but we can deal with it by deleting the whole array if it gets empty.
count_empty_commands++; // Account the null generated on the previous line.
save = true;
debugLog("Migrated shell command #" + shell_command_id + ": " + shell_command);
}
}
if (count_empty_commands === count_shell_commands) {
// The whole commands array now contains only empty/null commands.
// Delete it.
delete plugin.settings.commands;
}
}
else {
debugLog("settings.commands is empty, so no need to migrate commands. Good thing! :)");
}
return save;
}
/**
* This is a general migrator that adds new, missing properties to ShellCommandConfiguration objects. This is not tied to any specific version update, unlike MigrateCommandsToShellCommands().
*
* @param plugin
* @constructor
*/
function EnsureShellCommandsHaveAllFields(plugin) {
let save = false;
const shell_command_default_configuration = newShellCommandConfiguration("no-id"); // Use a dummy id here, because something needs to be used. This id should never end up being used in practice.
const shell_command_configurations = plugin.settings.shell_commands;
for (const shell_command_configuration of shell_command_configurations) {
for (const property_name in shell_command_default_configuration) {
// @ts-ignore property_default_value can have (almost) whatever datatype
const property_default_value = shell_command_default_configuration[property_name];
// @ts-ignore
if (undefined === shell_command_configuration[property_name] && property_name !== "id") { // The "id" check is just in case that MigrateShellCommandsObjectToArray() would not have added the "id" property, in which case the dummy "no-id" id should not be accidentally assigned to the shell command.
// This shell command does not have this property.
// Add the property to the shell command and use a default value.
debugLog("EnsureShellCommandsHaveAllFields(): Shell command #" + shell_command_configuration.id + " does not have a property '" + property_name + "'. Will create the property and assign a default value '" + property_default_value + "'.");
// @ts-ignore
shell_command_configuration[property_name] = property_default_value;
save = true;
}
}
}
return save;
}
function EnsureCustomVariablesHaveAllFields(plugin) {
let save = false;
const customVariableModel = getModel(CustomVariableModel.name);
const customVariableDefaultConfiguration = customVariableModel.getDefaultConfiguration();
let customVariableConfiguration;
for (customVariableConfiguration of plugin.settings.custom_variables) {
for (const propertyName in customVariableDefaultConfiguration) {
// @ts-ignore propertyDefaultValue can have (almost) whatever datatype
const propertyDefaultValue = customVariableDefaultConfiguration[propertyName];
// @ts-ignore
if (undefined === customVariableConfiguration[propertyName]) {
// This custom variable does not have this property.
// Add the property to it and use a default value.
debugLog("EnsureCustomVariablesHaveAllFields(): Custom variable #" + customVariableConfiguration.id + " does not have a property '" + propertyName + "'. Will create the property and assign a default value '" + propertyDefaultValue + "'.");
// @ts-ignore
customVariableConfiguration[propertyName] = propertyDefaultValue;
save = true;
}
}
}
return save;
}
/**
* This is a general migrator that adds new, missing properties to the main settings object. This is not tied to any specific version update, unlike MigrateCommandsToShellCommands().
*
* @param plugin
* @constructor
*/
function EnsureMainFieldsExist(plugin) {
let has_missing_fields = false;
const settings = plugin.settings;
const default_settings = getDefaultSettings(false);
for (const property_name in default_settings) {
// @ts-ignore
if (undefined === settings[property_name]) {
// The settings object does not have this property.
// @ts-ignore property_default_value can have (almost) whatever datatype
const property_default_value = default_settings[property_name];
debugLog("EnsureMainFieldsExist(): Main settings does not have property '" + property_name + "'. Will later create the property and assign a default value '" + property_default_value + "'.");
has_missing_fields = true;
}
}
if (has_missing_fields) {
debugLog("EnsureMainFieldsExist(): Doing the above-mentioned new field creations...");
plugin.settings = combineObjects(default_settings, plugin.settings);
debugLog("EnsureMainFieldsExist(): Done.");
return true; // Save the changes
}
debugLog("EnsureMainFieldsExist(): No new fields to create, all ok.");
return false; // Nothing to save.
}
/**
* Can be removed in 1.0.0.
*
* @param plugin
* @constructor
*/
function MigrateShellCommandToPlatforms(plugin) {
let save = false;
for (const shell_command_configuration of plugin.settings.shell_commands) {
if (undefined !== shell_command_configuration.shell_command) {
// The shell command should be migrated.
if (undefined === shell_command_configuration.platform_specific_commands || shell_command_configuration.platform_specific_commands.default === "") {
debugLog("Migrating shell command #" + shell_command_configuration.id + ": shell_command string will be moved to platforms.default: " + shell_command_configuration.shell_command);
shell_command_configuration.platform_specific_commands = {
default: shell_command_configuration.shell_command,
};
delete shell_command_configuration.shell_command;
save = true;
}
else {
debugLog("Migration failure for shell command #" + shell_command_configuration.id + ": platforms exists already.");
}
}
}
return save;
}
/**
* Can be removed in 1.0.0.
*
* @param plugin
* @constructor
*/
function DeleteEmptyCommandsField(plugin) {
let save = false;
if (undefined !== plugin.settings.commands) {
if (plugin.settings.commands.length === 0) {
delete plugin.settings.commands;
save = true;
}
}
return save;
}
/**
* Permanent, do not remove.
*
* @param plugin
*/
function backupSettingsFile(plugin) {
// plugin.app.fileManager.
// @ts-ignore
const current_settings_version = (plugin.settings.settings_version === "prior-to-0.7.0") ? "0.x" : plugin.settings.settings_version;
const plugin_path = getPluginAbsolutePath(plugin);
const settings_file_path = path__namespace.join(plugin_path, "data.json");
const backup_file_path_without_extension = path__namespace.join(plugin_path, "data-backup-version-" + current_settings_version + "-before-upgrading-to-" + SC_Plugin.SettingsVersion);
// Check that the current settings file can be found.
if (!fs__namespace.existsSync(settings_file_path)) {
// Not found. Probably the vault uses a different config folder than .obsidian.
debugLog("backupSettingsFile(): Cannot find data.json");
plugin.newError("Shell commands: Cannot create a backup of current settings file, because data.json is not found.");
return;
}
let backup_file_path = backup_file_path_without_extension + ".json";
let running_number = 1;
while (fs__namespace.existsSync(backup_file_path)) {
running_number++; // The first number will be 2.
backup_file_path = backup_file_path_without_extension + "-" + running_number + ".json";
if (running_number >= 1000) {
// There is some problem with detecting existing/inexisting files.
// Prevent hanging the program in an eternal loop.
throw new Error("backupSettingsFile(): Eternal loop detected.");
}
}
fs__namespace.copyFileSync(settings_file_path, backup_file_path);
}
// TODO: Add migration: shell command variable_default_values: if type is "show-errors", change it to "inherit", but only if old settings version was below 18.
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function createShellSelectionField(plugin, container_element, shells, is_global_settings) {
let platform_id;
for (platform_id in PlatformNames) {
const platform_name = PlatformNames[platform_id];
let options;
if (is_global_settings) {
const current_system_default = (getOperatingSystem() === platform_id) ? " (" + extractFileName(getUsersDefaultShell()) + ")" : "";
options = { "default": "Use system default" + current_system_default };
}
else {
options = { "default": "Use default" };
}
for (const shell_path in PlatformShells[platform_id]) {
// @ts-ignore // TODO: Get rid of these two ts-ignores.
const shell_name = PlatformShells[platform_id][shell_path];
// @ts-ignore
options[shell_path] = shell_name;
}
new obsidian.Setting(container_element)
.setName(platform_name + (is_global_settings ? " default shell" : " shell"))
.setDesc((is_global_settings ? "Can be overridden by each shell command. " : "") + ("win32" === platform_id ? "Powershell is recommended over cmd.exe, because this plugin does not support escaping variables in CMD." : ""))
.addDropdown(dropdown => dropdown
.addOptions(options)
.setValue(shells[platform_id] ?? "default")
.onChange(((_platform_id) => {
return async (value) => {
if ("default" === value) {
// When using default shell, the value should be unset.
delete shells[_platform_id];
}
else {
// Normal case: assign the shell value.
shells[_platform_id] = value;
}
await plugin.saveSettings();
};
})(platform_id)));
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* Makes a textarea grow and shrink based on the content height, and applies CSS styles on it to make it look more like an <input> element (not so much padding).
*/
function decorateMultilineField(plugin, textareaComponent, extraOnChange) {
const textareaElement = textareaComponent.inputEl;
textareaElement.addClass("SC-multiline");
const updateTextareaHeight = () => {
// Resize the shell command textarea to match the amount of lines in it.
const content = textareaElement.value;
const placeholder = textareaElement.placeholder;
const newlines_pattern = /\r\n|\r|\n/;
const count_lines_in_shell_command = content.split(newlines_pattern).length;
const count_lines_in_shell_command_placeholder = placeholder.split(newlines_pattern).length;
let count_lines_final = Math.max(count_lines_in_shell_command, count_lines_in_shell_command_placeholder);
if (plugin.settings.max_visible_lines_in_shell_command_fields) {
// Limit the height so that the field will not take up too much space.
count_lines_final = Math.min(plugin.settings.max_visible_lines_in_shell_command_fields, count_lines_final);
}
textareaElement.rows = count_lines_final;
};
updateTextareaHeight(); // Set a correct initial height.
textareaComponent.onChange(() => {
updateTextareaHeight(); // Update the height every time the field's value changes.
if (extraOnChange) {
extraOnChange(textareaElement.value);
}
});
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function CreateShellCommandFieldCore(plugin, container_element, setting_icon_and_name, shell_command, shell, t_shell_command, show_autocomplete_menu, extra_on_change, shell_command_placeholder = "Enter your command") {
async function on_change(shell_command) {
// Update preview
setting_group.preview_setting.descEl.innerHTML = ""; // Remove previous content.
createMultilineTextElement("span", // TODO: Maybe cleaner would be not to create a <span>, but to insert the content directly into descEl.
await getShellCommandPreview(plugin, shell_command, shell, t_shell_command, null /* No event is available during preview. */), setting_group.preview_setting.descEl);
// Let the caller extend this onChange, to preform saving the settings:
extra_on_change(shell_command);
}
const setting_group = {
name_setting: new obsidian.Setting(container_element)
.setClass("SC-name-setting")
.then((name_setting) => {
name_setting.nameEl.innerHTML = setting_icon_and_name;
}),
shell_command_setting: new obsidian.Setting(container_element)
.addTextArea(textareaComponent => {
textareaComponent
.setPlaceholder(shell_command_placeholder)
.setValue(shell_command);
decorateMultilineField(plugin, textareaComponent, on_change);
})
.setClass("SC-shell-command-setting"),
preview_setting: new obsidian.Setting(container_element)
.setClass("SC-preview-setting")
.then(async (setting) => {
setting.descEl.innerHTML = ""; // Remove previous content. Not actually needed here because it's empty already, but do it just in case.
createMultilineTextElement("span", // TODO: Maybe cleaner would be not to create a <span>, but to insert the content directly into descEl.
await getShellCommandPreview(plugin, shell_command, shell, t_shell_command, null /* No event is available during preview. */), setting.descEl);
}),
};
// Autocomplete menu
if (show_autocomplete_menu) {
createAutocomplete(plugin, setting_group.shell_command_setting.settingEl.find("textarea"), on_change);
}
return setting_group;
}
/**
*
* @param plugin
* @param shell_command
* @param shell
* @param t_shell_command
* @param sc_event
* @public Exported because createShellCommandField uses this.
*/
async function getShellCommandPreview(plugin, shell_command, shell, t_shell_command, sc_event) {
const parsing_result = await parseVariables(plugin, shell_command, shell, t_shell_command, sc_event);
if (!parsing_result.succeeded) {
// Variable parsing failed.
if (parsing_result.error_messages.length > 0) {
// Return all error messages, each in its own line. (Usually there's just one message).
return parsing_result.error_messages.join(os.EOL); // Newlines are converted to <br>'s by the consumers of this function.
}
else {
// If there are no error messages, then errors are silently ignored by user's variable configuration.
// The preview can then show the original, unparsed shell command.
return shell_command;
}
}
// Variable parsing succeeded
return parsing_result.parsed_content;
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function createPlatformSpecificShellCommandField(plugin, container_element, t_shell_command, platform_id, show_autocomplete_menu) {
const platform_name = PlatformNames[platform_id];
const setting_group = CreateShellCommandFieldCore(plugin, container_element, "Shell command on " + platform_name, t_shell_command.getPlatformSpecificShellCommands()[platform_id] ?? "", t_shell_command.getShell(), t_shell_command, show_autocomplete_menu, async (shell_command) => {
if (shell_command.length) {
// shell_command is not empty, so it's a normal command.
t_shell_command.getPlatformSpecificShellCommands()[platform_id] = shell_command;
}
else {
// shell_command is empty, so the default command should be used.
delete t_shell_command.getPlatformSpecificShellCommands()[platform_id];
}
await plugin.saveSettings();
}, t_shell_command.getDefaultShellCommand());
setting_group.name_setting.setDesc("If empty, the default shell command will be used on " + platform_name + ".");
return setting_group;
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
function createTabs(container_element, tabs) {
const tab_header = container_element.createEl("div", { attr: { class: "SC-tab-header" } });
const tab_content_containers = {};
const tab_buttons = {};
const tab_structure = {
header: tab_header,
active_tab_id: Object.keys(tabs)[0],
buttons: tab_buttons,
contentContainers: tab_content_containers,
};
let first_button;
for (const tab_id in tabs) {
const tab = tabs[tab_id];
// Create button
const button = tab_header.createEl("button", {
attr: {
class: "SC-tab-header-button",
activateTab: "SC-tab-" + tab_id,
},
});
button.onclick = function (event) {
const tab_button = this; // Use 'this' instead of event.target because this way we'll always get a button element, not an element inside the button (i.e. an icon).
// Hide all tab contents and get the max dimensions
let max_width = 0;
let max_height = 0;
const tab_header = tab_button.parentElement;
if (null === tab_header) {
throw new Error("Tab header is missing. Did not get a parent from tab button.");
}
const container_element = tab_header.parentElement;
if (null === container_element) {
throw new Error("Container element is missing. Did not get a parent from tab header.");
}
const tab_contents = container_element.findAll("div.SC-tab-content"); // Do not get all tab contents that exist, because there might be multiple tab systems open at the same time.
const is_main_settings_modal = container_element.hasClass("vertical-tab-content");
for (const index in tab_contents) {
const tab_content = tab_contents[index];
// Get the maximum tab dimensions so that all tabs can have the same dimensions.
// But don't do it if this is the main settings modal
if (!is_main_settings_modal) {
tab_content.addClass("SC-tab-active"); // Need to make the tab visible temporarily in order to get the dimensions.
if (tab_content.offsetHeight > max_height) {
max_height = tab_content.offsetHeight;
}
if (tab_content.offsetWidth > max_width) {
max_width = tab_content.offsetWidth;
}
}
// Finally hide the tab
tab_content.removeClass("SC-tab-active");
}
// Remove active status from all buttons
const adjacent_tab_buttons = tab_header.findAll(".SC-tab-header-button"); // Do not get all tab buttons that exist, because there might be multiple tab systems open at the same time.
for (const index in adjacent_tab_buttons) {
const tab_button = adjacent_tab_buttons[index];
tab_button.removeClass("SC-tab-active");
}
// Activate the clicked tab
tab_button.addClass("SC-tab-active");
const activateTabAttribute = tab_button.attributes.getNamedItem("activateTab");
if (null === activateTabAttribute) {
throw new Error("Tab button has no 'activateTab' HTML attribute! Murr!");
}
const activate_tab_id = activateTabAttribute.value;
const tab_content = document.getElementById(activate_tab_id);
if (null === tab_content) {
throw new Error("No tab content was found with activate_tab_id '" + activate_tab_id + "'! Hmph!");
}
tab_content.addClass("SC-tab-active");
// Mark the clicked tab as active in TabStructure (just to report which tab is currently active)
tab_structure.active_tab_id = activate_tab_id.replace(/^SC-tab-/, ""); // Remove "SC-tab" prefix.
// Focus an element (if a focusable element is present)
tab_content.find(".SC-focus-element-on-tab-opening")?.focus(); // ? = If not found, do nothing.
// Apply the max dimensions to this tab
// But don't do it if this is the main settings modal
if (!is_main_settings_modal) {
tab_content.style.width = max_width + "px";
tab_content.style.height = max_height + "px";
}
// Do nothing else (I don't know if this is needed or not)
event.preventDefault();
};
obsidian.setIcon(button, tab.icon);
button.insertAdjacentText("beforeend", " " + tab.title);
tab_buttons[tab_id] = button;
// Create content container
tab_content_containers[tab_id] = container_element.createEl("div", { attr: { class: "SC-tab-content", id: "SC-tab-" + tab_id } });
// Generate content
tab.content_generator(tab_content_containers[tab_id]);
// Memorize the first tab's button
if (undefined === first_button) {
first_button = button;
}
}
// Activate the first tab
if (undefined !== first_button) {
first_button.click();
}
// Return the TabStructure
return tab_structure;
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* TODO: Rename to ShellCommandSettingsModal
*/
class ExtraOptionsModal extends SC_Modal {
constructor(plugin, shell_command_id, setting_tab) {
super(plugin);
this.shell_command_id = shell_command_id;
this.t_shell_command = plugin.getTShellCommands()[shell_command_id];
this.name_setting = setting_tab.setting_groups[shell_command_id].name_setting;
this.setting_tab = setting_tab;
}
onOpen() {
super.onOpen();
this.modalEl.createEl("h2", { text: this.t_shell_command.getDefaultShellCommand() }); // TODO: Use this.setTitle() instead.
// Tabs
this.tab_structure = createTabs(this.modalEl, {
"extra-options-general": {
title: "General",
icon: "gear",
content_generator: (container_element) => {
this.tabGeneral(container_element);
},
},
"extra-options-preactions": {
title: "Preactions",
icon: "note-glyph",
content_generator: (container_element) => {
this.tabPreactions(container_element);
},
},
"extra-options-output": {
title: "Output",
icon: "lines-of-text",
content_generator: (container_element) => {
this.tabOutput(container_element);
},
},
"extra-options-environments": {
title: "Environments",
icon: "stacked-levels",
content_generator: (container_element) => {
this.tabEnvironments(container_element);
},
},
"extra-options-events": {
title: "Events",
icon: "dice",
content_generator: (container_element) => {
this.tabEvents(container_element);
},
},
"extra-options-variables": {
title: "Variables",
icon: "code-glyph",
content_generator: (container_element) => {
this.tabVariables(container_element);
},
},
});
// Hotkeys for moving to next/previous shell command
const switch_to_t_shell_command = (t_shell_command) => {
const new_modal = new ExtraOptionsModal(this.plugin, t_shell_command.getId(), this.setting_tab);
this.close(); // Needs to be closed before the new one is opened, otherwise the new one's tab content won't be shown.
new_modal.open();
new_modal.activateTab(this.tab_structure.active_tab_id);
};
this.scope.register(["Mod"], "ArrowUp", () => {
const previousTShellCommand = this.t_shell_command.previousTShellCommand();
if (previousTShellCommand) {
switch_to_t_shell_command(previousTShellCommand);
}
});
this.scope.register(["Mod"], "ArrowDown", () => {
const nextTShellCommand = this.t_shell_command.nextTShellCommand();
if (nextTShellCommand) {
switch_to_t_shell_command(nextTShellCommand);
}
});
new obsidian.Setting(this.modalEl)
.setDesc("Tip! Hit " + CmdOrCtrl() + " + up/down to switch to previous/next shell command.");
}
tabGeneral(container_element) {
// Alias field
const alias_container = container_element.createDiv({ attr: { class: "SC-setting-group" } });
new obsidian.Setting(alias_container)
.setName("Alias");
const on_alias_change = async (value) => {
// Change the actual alias value
this.t_shell_command.getConfiguration().alias = value;
// Update Obsidian command palette
this.t_shell_command.renameObsidianCommand(this.t_shell_command.getShellCommand(), this.t_shell_command.getAlias());
// UpdateShell commands settings panel
this.name_setting.nameEl.innerHTML = generateShellCommandFieldIconAndName(this.t_shell_command);
// Save
await this.plugin.saveSettings();
};
const alias_setting = new obsidian.Setting(alias_container)
.addText(text => text
.setValue(this.t_shell_command.getAlias())
.onChange(on_alias_change))
.setClass("SC-no-description");
const alias_input_element = alias_setting.controlEl.find("input");
alias_input_element.addClass("SC-focus-element-on-tab-opening"); // Focus without a need to click the field.
if (this.plugin.settings.show_autocomplete_menu) {
// Show autocomplete menu (= a list of available variables).
createAutocomplete(this.plugin, alias_input_element, on_alias_change);
}
alias_container.createEl("p", { text: "If not empty, the alias will be displayed in the command palette instead of the actual command. An alias is never executed as a command." });
alias_container.createEl("p", { text: "You can also use the same {{}} style variables in aliases that are used in shell commands. When variables are used in aliases, they do not affect the command execution in any way, but it's a nice way to reveal what values your command will use, even when an alias hides most of the other technical details. Starting a variable with {{! will prevent escaping special characters in command palette." });
// Icon field
const current_icon = this.t_shell_command.getConfiguration().icon;
const icon_setting = new obsidian.Setting(container_element)
.setDesc("If defined, the icon will be shown in file menu, folder menu, and editor menu in front of the alias text. It's also shown in the settings. It makes it easier to distinguish different shell commands visually from each other.")
.addDropdown(dropdown => dropdown
.addOption("no-icon", "No icon") // Need to use a non-empty string like "no-icon", because if 'value' would be "" then it becomes the same as 'display' from some reason, i.e. "No icon".
.then((dropdown) => {
// Iterate all available icons.
for (const icon_id of ICON_LIST_SORTED_UNIQUE) {
// Create an option for the icon.
dropdown.addOption(icon_id, icon_id);
}
dropdown.setValue(current_icon ?? ""); // "" == the 'No icon' option.
})
.onChange(async (new_icon) => {
if ("no-icon" === new_icon) {
// Disable icon
this.t_shell_command.getConfiguration().icon = null;
// Remove the icon from the modal
icon_setting.nameEl.innerHTML = "Icon";
}
else {
// Set or change the icon
this.t_shell_command.getConfiguration().icon = new_icon;
// Update the icon in the modal
icon_setting.nameEl.innerHTML = "Icon " + getIconHTML(new_icon);
}
// Update (or remove) the icon in the main settings panel
this.name_setting.nameEl.innerHTML = generateShellCommandFieldIconAndName(this.t_shell_command);
// Save settings
await this.plugin.saveSettings();
}));
icon_setting.nameEl.innerHTML = "Icon " + (current_icon ? getIconHTML(current_icon) : "");
// Confirm execution field
new obsidian.Setting(container_element)
.setName("Ask confirmation before execution")
.addToggle(toggle => toggle
.setValue(this.t_shell_command.getConfirmExecution())
.onChange(async (value) => {
this.t_shell_command.getConfiguration().confirm_execution = value;
const icon_container = this.name_setting.nameEl.find("span.shell-commands-confirm-execution-icon-container");
if (this.t_shell_command.getConfirmExecution()) {
// Show icon
icon_container.removeClass("SC-hide");
}
else {
// Hide icon
icon_container.addClass("SC-hide");
}
await this.plugin.saveSettings();
}));
// Stdin field
new obsidian.Setting(container_element)
.setName("Pass variables to standard input (stdin) (experimental)")
.setDesc("Used to pass long texts as input to the shell command. There is a limit to command line length, and e.g. {{note_content}} might provide a value too long to be used as an argument, so it works better when passed to stdin. Also, programs that ask multiple values interactively, can be fed with values using stdin. If there are multiple values that need to be inputted, put them on separate lines. Many shell programs interpret newlines as separators between different values.")
.addExtraButton(extraButtonComponent => extraButtonComponent
.setIcon("help")
.setTooltip("Documentation: Pass variables to stdin")
.onClick(() => gotoURL(DocumentationStdinContentLink)));
const stdinSettingContainer = container_element.createDiv({ attr: { class: "SC-setting-group" } });
const onStdinChange = async (newStdinContent) => {
if ("" === newStdinContent) {
// Set to null
this.t_shell_command.getConfiguration().input_contents.stdin = null;
}
else {
// Set value
this.t_shell_command.getConfiguration().input_contents.stdin = newStdinContent;
}
await this.plugin.saveSettings();
};
new obsidian.Setting(stdinSettingContainer)
.setDesc("Can contain {{variables}} and/or static text.")
.addTextArea(textareaComponent => {
textareaComponent
.setValue(this.t_shell_command.getInputChannels().stdin ?? "");
decorateMultilineField(this.plugin, textareaComponent, onStdinChange);
if (this.plugin.settings.show_autocomplete_menu) {
// Show autocomplete menu (= a list of available variables).
createAutocomplete(this.plugin, textareaComponent.inputEl, onStdinChange);
}
});
// Shell command id
new obsidian.Setting(container_element)
.setDesc(`Shell command id: ${this.shell_command_id}`)
.addExtraButton(button => button
.setIcon("documents")
.setTooltip(`Copy ${this.shell_command_id} to the clipboard.`)
.onClick(() => {
copyToClipboard(this.shell_command_id);
this.plugin.newNotification(`${this.shell_command_id} was copied to the clipboard.`);
}));
if (this.t_shell_command.canAddToCommandPalette()) {
// Only show Obsidian command palette id if the shell command is available in the command palette.
const obsidian_command_id = this.t_shell_command.getObsidianCommand().id;
new obsidian.Setting(container_element)
.setDesc(`Obsidian command palette id: ${obsidian_command_id}`)
.addExtraButton(button => button
.setIcon("documents")
.setTooltip(`Copy ${obsidian_command_id} to the clipboard.`)
.onClick(() => {
copyToClipboard(obsidian_command_id);
this.plugin.newNotification(`${obsidian_command_id} was copied to the clipboard.`);
}))
.settingEl.addClass("SC-no-top-border") // No horizontal ruler between the two id elements.
;
}
}
tabPreactions(container_element) {
container_element.createEl("p", { text: "Preactions are performed before the actual shell command gets executed, to do certain preparations for the shell command." });
const preactions_configuration = this.t_shell_command.getConfiguration().preactions;
// Load config values
let preaction_prompt_configuration = null;
for (const preaction_configuration of preactions_configuration) {
switch (preaction_configuration.type) {
case "prompt":
preaction_prompt_configuration = preaction_configuration;
break;
default:
throw new Error("Unrecognised preaction type: " + preaction_configuration.type);
}
}
// Preaction: Prompt
const prompt_options = {};
this.plugin.getPrompts().forEach((prompt) => {
prompt_options[prompt.getID()] = prompt.getTitle();
});
let old_selected_prompt_option = (preaction_prompt_configuration?.enabled) ? preaction_prompt_configuration.prompt_id : "no-prompt";
new obsidian.Setting(container_element)
.setName("Prompt")
.setDesc("Prompts are used to ask values from the user right before shell command execution. The values can be accessed in the shell command via custom variables. You can manage all prompts in the plugin's main settings view, under the 'Preactions' tab.")
.addDropdown(dropdown => dropdown
.addOption("no-prompt", "No prompt")
.addOptions(prompt_options)
.addOption("new", "Create a new prompt")
.setValue(old_selected_prompt_option)
.onChange(async (new_prompt_id) => {
// Create a PreactionPromptConfiguration if it does not exist.
if (!preaction_prompt_configuration) {
preaction_prompt_configuration = getDefaultPreaction_Prompt_Configuration();
preactions_configuration.push(preaction_prompt_configuration);
this.t_shell_command.resetPreactions();
}
// Interpret the selection
switch (new_prompt_id) {
case "new": {
// Create a new Prompt.
const model = getModel(PromptModel.name);
const new_prompt = model.newInstance(this.plugin.settings);
this.plugin.saveSettings().then(() => {
const modal = new PromptSettingsModal(this.plugin, new_prompt, undefined, "Create prompt", async () => {
// Prompt is created.
dropdown.addOption(new_prompt.getID(), new_prompt.getTitle());
dropdown.setValue(new_prompt.getID());
preaction_prompt_configuration.enabled = true; // 'as Preaction_Prompt_Configuration' tells TypeScript that the variable is not null.
preaction_prompt_configuration.prompt_id = new_prompt.getID();
await this.plugin.saveSettings();
old_selected_prompt_option = dropdown.getValue();
}, async () => {
// Prompt creation was cancelled.
dropdown.setValue(old_selected_prompt_option); // Reset the dropdown selection.
model.deleteInstance(new_prompt);
await this.plugin.saveSettings();
});
modal.open();
});
break;
}
case "no-prompt": {
// Disable the prompt.
preaction_prompt_configuration.enabled = false;
this.t_shell_command.resetPreactions();
await this.plugin.saveSettings();
old_selected_prompt_option = dropdown.getValue();
break;
}
default: {
// Use an existing prompt.
preaction_prompt_configuration.enabled = true;
preaction_prompt_configuration.prompt_id = new_prompt_id;
await this.plugin.saveSettings();
old_selected_prompt_option = dropdown.getValue();
break;
}
}
}));
}
tabOutput(container_element) {
// Output channeling
const stdout_channel_setting = this.newOutputChannelSetting(container_element, "Output channel for stdout", "stdout");
this.newOutputChannelSetting(container_element, "Output channel for stderr", "stderr", "If both stdout and stderr use the same channel, stderr will be combined to same message with stdout.");
// Output wrappers
this.newOutputWrapperSetting(container_element, "Output wrapper for stdout", "stdout", "Output wrappers can be used to surround output with predefined text, e.g. to put output into a code block. Note: If 'Output mode' is 'Realtime', wrappers will probably appear multiple times in output!");
this.newOutputWrapperSetting(container_element, "Output wrapper for stderr", "stderr");
// Output handling mode
new obsidian.Setting(container_element)
.setName("Output handling mode")
.setDesc("Set to 'Realtime' if your shell command runs for a long time AND you want output handling to start as soon as any outputted content is available. Output channels might be used multiple times during a single process. 'Wait until finished' postpones output handling until all output is received, and handles it as a single bunch. If uncertain, use the traditional 'Wait until finished'.")
.addDropdown(dropdown => dropdown
.addOptions({
"buffered": "Wait until finished",
"realtime": "Realtime (experimental)",
})
.setValue(this.t_shell_command.getConfiguration().output_handling_mode)
.onChange(async (newMode) => {
this.t_shell_command.getConfiguration().output_handling_mode = newMode;
await this.plugin.saveSettings();
}))
// Documentation link
.addExtraButton(icon => icon
.setIcon("help")
.onClick(() => gotoURL(DocumentationOutputHandlingModeLink))
.setTooltip("Documentation: Output handling mode"));
// Order of output channels
new obsidian.Setting(container_element)
.setName("Order of stdout/stderr output")
.setDesc("When output contains both errors and normal output, which one should be presented first? (Only matters if 'Output handling' is 'Wait until finished').")
.addDropdown(dropdown => dropdown
.addOptions({
"stdout-first": "Stdout first, then stderr.",
"stderr-first": "Stderr first, then stdout.",
})
.setValue(this.t_shell_command.getOutputChannelOrder())
.onChange(async (value) => {
this.t_shell_command.getConfiguration().output_channel_order = value;
await this.plugin.saveSettings();
}));
// Focus on the stdout channel dropdown field
stdout_channel_setting.controlEl.find("select").addClass("SC-focus-element-on-tab-opening");
// Ignore errors field
new obsidian.Setting(container_element)
.setName("Ignore error codes")
.setDesc("A comma separated list of numbers. If executing a shell command fails with one of these exit codes, no error message will be displayed, and the above stderr channel will be ignored. Stdout channel will still be used for stdout. Error codes must be integers and greater than or equal to 0. Anything else will be removed. Note: If 'Output handling' is 'Realtime', no exit code based ignoring can be done, as an error code is only received when a shell command process finishes.")
.addText(text => text
.setValue(this.t_shell_command.getIgnoreErrorCodes().join(","))
.onChange(async (value) => {
// Parse the string of comma separated numbers
const ignore_error_codes = [];
const raw_error_codes = value.split(",");
for (const i in raw_error_codes) {
const raw_error_code = raw_error_codes[i];
const error_code_candidate = parseInt(raw_error_code.trim()); // E.g. an empty string converts to NaN (= Not a Number).
// Ensure that the error code is not NaN, 0 or a negative number.
if (!isNaN(error_code_candidate) && error_code_candidate >= 0) {
// The candidate is legit.
ignore_error_codes.push(error_code_candidate);
}
}
// Save the validated error numbers
this.t_shell_command.getConfiguration().ignore_error_codes = ignore_error_codes;
await this.plugin.saveSettings();
// Update icon
const icon_container = this.name_setting.nameEl.find("span.shell-commands-ignored-error-codes-icon-container");
if (this.t_shell_command.getIgnoreErrorCodes().length) {
// Show icon
icon_container.setAttr("aria-label", generateIgnoredErrorCodesIconTitle(this.t_shell_command.getIgnoreErrorCodes()));
icon_container.removeClass("SC-hide");
}
else {
// Hide icon
icon_container.addClass("SC-hide");
}
}));
}
tabEnvironments(container_element) {
// Platform specific shell commands
let platform_id;
let is_first = true;
for (platform_id in PlatformNames) {
const setting_group = createPlatformSpecificShellCommandField(this.plugin, container_element, this.t_shell_command, platform_id, this.plugin.settings.show_autocomplete_menu);
if (is_first) {
// Focus on the first OS specific shell command field
setting_group.shell_command_setting.controlEl.find("textarea").addClass("SC-focus-element-on-tab-opening");
is_first = false;
}
}
// Platform specific shell selection
createShellSelectionField(this.plugin, container_element, this.t_shell_command.getShells(), false);
}
tabEvents(container_element) {
// Command palette
const command_palette_availability_setting = new obsidian.Setting(container_element)
.setName("Availability in Obsidian's command palette")
.addDropdown(dropdown => dropdown
.addOptions(CommandPaletteOptions)
.setValue(this.t_shell_command.getConfiguration().command_palette_availability)
.onChange(async (value) => {
// Store value
this.t_shell_command.getConfiguration().command_palette_availability = value;
// Update command palette
if (this.t_shell_command.canAddToCommandPalette()) {
// Register to command palette
this.t_shell_command.registerToCommandPalette();
}
else {
// Unregister from command palette
this.t_shell_command.unregisterFromCommandPalette();
}
// Save
await this.plugin.saveSettings();
}));
// Focus on the command palette availability field
command_palette_availability_setting.controlEl.find("select").addClass("SC-focus-element-on-tab-opening");
// Events
new obsidian.Setting(container_element)
.setName("Execute this shell command automatically when:")
.setHeading() // Make the name bold
;
getSC_Events(this.plugin).forEach((sc_event) => {
const is_event_enabled = this.t_shell_command.isSC_EventEnabled(sc_event.static().getCode());
const setting = new obsidian.Setting(container_element)
.setName(sc_event.static().getTitle())
.addToggle(toggle => toggle
.setValue(is_event_enabled)
.onChange(async (enable) => {
if (enable) {
// Enable the event
this.t_shell_command.enableSC_Event(sc_event);
extra_settings_container.style.display = "block"; // Show extra settings
}
else {
// Disable the event
this.t_shell_command.disableSC_Event(sc_event);
extra_settings_container.style.display = "none"; // Hide extra settings
}
// Save
await this.plugin.saveSettings();
}))
// Documentation icon
.addExtraButton(icon => icon
.setIcon("help")
.onClick(() => gotoURL(sc_event.static().getDocumentationLink()))
.setTooltip("Documentation: " + sc_event.static().getTitle() + " event"));
// Mention additional variables (if any)
if (sc_event.createSummaryOfEventVariables(setting.descEl)) {
setting.descEl.insertAdjacentText("afterbegin", "Additional variables: ");
}
// Extra settings
const extra_settings_container = container_element.createDiv();
extra_settings_container.style.display = is_event_enabled ? "block" : "none";
sc_event.createExtraSettingsFields(extra_settings_container, this.t_shell_command);
});
}
tabVariables(containerElement) {
// Default values for variables
new obsidian.Setting(containerElement)
.setName("Default values for variables")
.setDesc("Certain variables can be inaccessible during certain situations, e.g. {{file_name}} is not available when no file pane is focused. You can define default values that will be used when a variable is otherwise unavailable.")
.setHeading();
createVariableDefaultValueFields(this.plugin, containerElement, this.t_shell_command);
}
activateTab(tab_id) {
if (undefined === this.tab_structure.buttons[tab_id]) {
throw Error("Invalid tab id: " + tab_id);
}
this.tab_structure.buttons[tab_id].click();
}
newOutputChannelSetting(container_element, title, output_stream_name, description = "") {
const output_channel_options = getOutputChannelsOptionList(output_stream_name);
return new obsidian.Setting(container_element)
.setName(title)
.setDesc(description)
.addDropdown(dropdown => dropdown
.addOptions(output_channel_options)
.setValue(this.t_shell_command.getOutputChannels()[output_stream_name])
.onChange(async (value) => {
this.t_shell_command.getConfiguration().output_channels[output_stream_name] = value;
await this.plugin.saveSettings();
}));
}
newOutputWrapperSetting(container_element, title, output_stream_name, description = "") {
const output_wrapper_options = {};
this.plugin.getOutputWrappers().forEach((output_wrapper) => {
output_wrapper_options[output_wrapper.getID()] = output_wrapper.getTitle();
});
const output_wrappers = this.t_shell_command.getConfiguration().output_wrappers;
let old_selected_output_wrapper_option = output_wrappers[output_stream_name] ?? "no-output-wrapper";
return new obsidian.Setting(container_element)
.setName(title)
.setDesc(description)
.addDropdown(dropdown_component => dropdown_component
.addOption("no-output-wrapper", "No " + output_stream_name + " wrapper")
.addOptions(output_wrapper_options)
.addOption("new", "Create a new output wrapper")
.setValue(old_selected_output_wrapper_option)
.onChange(async (output_wrapper_id) => {
switch (output_wrapper_id) {
case "new": {
// Create a new OutputWrapper.
const output_wrapper_model = getModel(OutputWrapperModel.name);
const new_output_wrapper = output_wrapper_model.newInstance(this.plugin.settings);
this.plugin.saveSettings().then(() => {
const modal = new OutputWrapperSettingsModal(this.plugin, new_output_wrapper, undefined, "Create output wrapper", async () => {
// Output wrapper is created.
dropdown_component.addOption(new_output_wrapper.getID(), new_output_wrapper.getTitle());
dropdown_component.setValue(new_output_wrapper.getID());
output_wrappers[output_stream_name] = new_output_wrapper.getID();
await this.plugin.saveSettings();
old_selected_output_wrapper_option = dropdown_component.getValue();
}, async () => {
// Prompt creation was cancelled.
dropdown_component.setValue(old_selected_output_wrapper_option); // Reset the dropdown selection.
output_wrapper_model.deleteInstance(new_output_wrapper);
await this.plugin.saveSettings();
});
modal.open();
});
break;
}
case "no-output-wrapper": {
// Disable output wrapper.
output_wrappers[output_stream_name] = null;
await this.plugin.saveSettings();
break;
}
default: {
// Use an existing output wrapper.
output_wrappers[output_stream_name] = output_wrapper_id;
await this.plugin.saveSettings();
break;
}
}
}));
}
approve() {
// No need to perform any action, just close the modal.
this.close();
}
}
ExtraOptionsModal.GENERAL_OPTIONS_SUMMARY = "Alias, Icon, Confirmation, Stdin";
ExtraOptionsModal.PREACTIONS_OPTIONS_SUMMARY = "Preactions: Prompt for asking values from user";
ExtraOptionsModal.OUTPUT_OPTIONS_SUMMARY = "Stdout/stderr handling, Ignore errors";
ExtraOptionsModal.ENVIRONMENTS_OPTIONS_SUMMARY = "Shell selection, Operating system specific shell commands";
ExtraOptionsModal.EVENTS_SUMMARY = "Events";
ExtraOptionsModal.VARIABLES_SUMMARY = "Default values for variables";
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
* TODO: Rename to DeleteShellCommandModal
*/
class DeleteModal extends SC_Modal {
constructor(plugin, shell_command_id, setting_group, shell_command_element) {
super(plugin);
this.shell_command_id = shell_command_id;
this.t_shell_command = plugin.getTShellCommands()[shell_command_id];
this.setting_group = setting_group;
this.shell_command_element = shell_command_element;
}
onOpen() {
super.onOpen();
this.modalEl.createEl("h2", { text: "Delete: " + this.t_shell_command.getShellCommand() }); // TODO: Use this.setTitle() instead.
if (this.t_shell_command.getAlias()) {
this.modalEl.createEl("p", { text: "Alias: " + this.t_shell_command.getAlias() });
}
this.modalEl.createEl("p", { text: "Are you sure you want to delete this shell command?" });
const delete_button = this.modalEl.createEl("button", { text: "Yes, delete" });
delete_button.onclick = async () => this.approve();
}
async approve() {
// Unregister possible events in order to prevent them becoming ghosts that just keep executing even after removing the configuration.
this.t_shell_command.unregisterSC_Events();
// Remove the command
debugLog("Command " + this.shell_command_id + " gonna be removed.");
this.t_shell_command.unregisterFromCommandPalette(); // Remove from the command palette.
delete this.plugin.getTShellCommands()[this.shell_command_id]; // Remove the TShellCommand object.
// Remove from the plugin's settings.
const shellCommandIndex = this.plugin.getShellCommandConfigurationIndex(this.shell_command_id);
// Index probably always exists, but check just in case. Will make TypeScript compiler happy. :)
if (undefined == shellCommandIndex) {
throw new Error("Shell command deletion failed. Did not get shell command index in settings container.");
}
this.plugin.settings.shell_commands.splice(shellCommandIndex, 1);
// Remove the setting fields
this.shell_command_element.remove();
await this.plugin.saveSettings();
debugLog("Command removed.");
this.close();
}
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
/**
*
* @param plugin
* @param container_element
* @param setting_tab
* @param shell_command_id Either a string formatted integer ("0", "1" etc) or "new" if it's a field for a command that does not exist yet.
* @param show_autocomplete_menu
*/
function createShellCommandField(plugin, container_element, setting_tab, shell_command_id, show_autocomplete_menu) {
const is_new = "new" === shell_command_id;
let t_shell_command;
if (is_new) {
// Create an empty command
t_shell_command = plugin.newTShellCommand();
shell_command_id = t_shell_command.getId(); // Replace "new" with a real id.
}
else {
// Use an old shell command
t_shell_command = plugin.getTShellCommands()[shell_command_id];
}
debugLog("Create command field for command #" + shell_command_id + (is_new ? " (NEW)" : ""));
let shell_command;
if (is_new) {
shell_command = "";
}
else {
shell_command = t_shell_command.getDefaultShellCommand();
}
// Wrap all shell command setting elements in a single div.
const shell_command_element = container_element.createDiv();
shell_command_element.addClass("SC-id-" + shell_command_id);
const setting_group = CreateShellCommandFieldCore(plugin, shell_command_element, generateShellCommandFieldIconAndName(t_shell_command), shell_command, t_shell_command.getShell(), t_shell_command, show_autocomplete_menu, async (shell_command) => {
if (is_new) {
debugLog("Creating new command " + shell_command_id + ": " + shell_command);
}
else {
debugLog("Command " + shell_command_id + " gonna change to: " + shell_command);
}
// Do this in both cases, when creating a new command and when changing an old one:
t_shell_command.getConfiguration().platform_specific_commands.default = shell_command;
if (is_new) {
// Create a new command
// plugin.registerShellCommand(t_shell_command); // I don't think this is needed to be done anymore
debugLog("Command created.");
}
else {
// Change an old command
t_shell_command.renameObsidianCommand(t_shell_command.getShellCommand(), t_shell_command.getAlias()); // Change the command's name in Obsidian's command palette and in hotkey settings.
debugLog("Command changed.");
}
await plugin.saveSettings();
});
setting_tab.setting_groups[shell_command_id] = setting_group;
// Primary icon buttons
setting_group.name_setting
.addExtraButton(button => button
.setTooltip("Normal click: Execute now. " + CmdOrCtrl() + " + click: Execute and ask what to do with output.")
.setIcon("run-command")
.extraSettingsEl.addEventListener("click", async (event) => {
const ctrl_clicked = event.ctrlKey;
// Execute the shell command now (for trying it out in the settings)
const parsing_process = t_shell_command.createParsingProcess(null); // No SC_Event is available when executing shell commands manually.
if (await parsing_process.process()) {
const executor = new ShellCommandExecutor(plugin, t_shell_command, null); // No SC_Event is available when manually executing the shell command.
await executor.doPreactionsAndExecuteShellCommand(parsing_process, ctrl_clicked ? "modal" : undefined // If ctrl/cmd is pressed, override output channels with 'Ask after execution' modal. Otherwise, use undefined to indicate that the shell command's normal output channels should be used.
);
}
else {
parsing_process.displayErrorMessages();
}
}))
.addExtraButton(button => button
.setTooltip(ExtraOptionsModal.GENERAL_OPTIONS_SUMMARY)
.onClick(async () => {
// Open an extra options modal: General tab
const modal = new ExtraOptionsModal(plugin, shell_command_id, setting_tab);
modal.open();
modal.activateTab("extra-options-general");
}))
.addExtraButton(button => button
.setTooltip(ExtraOptionsModal.PREACTIONS_OPTIONS_SUMMARY)
.setIcon("note-glyph")
.onClick(async () => {
// Open an extra options modal: Preactions tab
const modal = new ExtraOptionsModal(plugin, shell_command_id, setting_tab);
modal.open();
modal.activateTab("extra-options-preactions");
}))
.addExtraButton(button => button
.setTooltip(ExtraOptionsModal.OUTPUT_OPTIONS_SUMMARY)
.setIcon("lines-of-text")
.onClick(async () => {
// Open an extra options modal: Output tab
const modal = new ExtraOptionsModal(plugin, shell_command_id, setting_tab);
modal.open();
modal.activateTab("extra-options-output");
}))
.addExtraButton(button => button
.setTooltip(ExtraOptionsModal.ENVIRONMENTS_OPTIONS_SUMMARY)
.setIcon("stacked-levels")
.onClick(async () => {
// Open an extra options modal: Environments tab
const modal = new ExtraOptionsModal(plugin, shell_command_id, setting_tab);
modal.open();
modal.activateTab("extra-options-environments");
}))
.addExtraButton(button => button
.setTooltip(ExtraOptionsModal.EVENTS_SUMMARY)
.setIcon("dice")
.onClick(async () => {
// Open an extra options modal: Events tab
const modal = new ExtraOptionsModal(plugin, shell_command_id, setting_tab);
modal.open();
modal.activateTab("extra-options-events");
}))
.addExtraButton(button => button
.setTooltip(ExtraOptionsModal.VARIABLES_SUMMARY)
.setIcon("code-glyph")
.onClick(async () => {
// Open an extra options modal: Variables tab
const modal = new ExtraOptionsModal(plugin, shell_command_id, setting_tab);
modal.open();
modal.activateTab("extra-options-variables");
}))
.addExtraButton(button => button
.setTooltip("Delete this shell command")
.setIcon("trash")
.onClick(async () => {
// Open a delete modal
const modal = new DeleteModal(plugin, shell_command_id, setting_group, shell_command_element);
modal.open();
}));
// Informational icons (= non-clickable)
const icon_container = setting_group.name_setting.nameEl.createEl("span", { attr: { class: "SC-main-icon-container" } });
// "Ask confirmation" icon.
const confirm_execution_icon_container = icon_container.createEl("span", { attr: { "aria-label": "Asks confirmation before execution.", class: "shell-commands-confirm-execution-icon-container" } });
obsidian.setIcon(confirm_execution_icon_container, "languages");
if (!t_shell_command.getConfirmExecution()) {
// Do not display the icon for commands that do not use confirmation.
confirm_execution_icon_container.addClass("SC-hide");
}
// "Ignored error codes" icon
const ignored_error_codes_icon_container = icon_container.createEl("span", { attr: { "aria-label": generateIgnoredErrorCodesIconTitle(t_shell_command.getIgnoreErrorCodes()), class: "shell-commands-ignored-error-codes-icon-container" } });
obsidian.setIcon(ignored_error_codes_icon_container, "strikethrough-glyph");
if (!t_shell_command.getIgnoreErrorCodes().length) {
// Do not display the icon for commands that do not ignore any errors.
ignored_error_codes_icon_container.addClass("SC-hide");
}
// Secondary icon buttons
setting_group.preview_setting.addExtraButton(button => button
.setIcon("link")
.setTooltip("Copy this shell command's Obsidian URI to the clipboard. Visiting the URI executes the shell command. " + CmdOrCtrl() + " + click: Copy a markdown link.")
// onClick() handler - use a custom one instead of ExtraButtonComponent.onClick(), because Obsidian API (at least v. 0.14.8) does not support detecting CTRL press. https://forum.obsidian.md/t/fr-settings-pass-mouseevent-to-extrabuttoncomponent-onclick/37177
.extraSettingsEl.addEventListener("click", (event) => {
const ctrl_clicked = event.ctrlKey;
const execution_uri = t_shell_command.getExecutionURI();
let result;
if (ctrl_clicked) {
// A full link is wanted.
result = `[${escapeMarkdownLinkCharacters(t_shell_command.getAlias())}](${escapeMarkdownLinkCharacters(execution_uri)})`;
}
else {
// Only the URI is wanted.
result = execution_uri;
}
copyToClipboard(result);
plugin.newNotification("Copied to clipboard: " + os.EOL + result);
}));
if (t_shell_command.canHaveHotkeys()) {
setting_group.preview_setting.addExtraButton(button => button
.setIcon("any-key")
.setTooltip("Go to hotkey settings.")
.onClick(() => {
// The most important parts of this closure function are copied 2022-04-27 from https://github.com/pjeby/hotkey-helper/blob/c8a032e4c52bd9ce08cb909cec15d1ed9d0a3439/src/plugin.js#L436-L442 (also from other lines of the same file).
// @ts-ignore This is private API access. Not good, but then again the feature is not crucial - if it breaks, it won't interrupt anything important.
plugin.app.setting?.openTabById("hotkeys");
// @ts-ignore
const hotkeys_settings_tab = plugin.app.setting.settingTabs.filter(tab => tab.id === "hotkeys").shift();
if (hotkeys_settings_tab && hotkeys_settings_tab.searchInputEl && hotkeys_settings_tab.updateHotkeyVisibility) {
debugLog("Hotkeys: Filtering by shell command " + t_shell_command.getObsidianCommand().name);
hotkeys_settings_tab.searchInputEl.value = t_shell_command.getObsidianCommand().name;
hotkeys_settings_tab.updateHotkeyVisibility();
}
else {
debugLog("Hotkeys: Cannot do filtering due to API changes.");
}
}));
}
// Add hotkey information
if (!is_new && t_shell_command.canHaveHotkeys()) {
const hotkeys = getHotkeysForShellCommand(plugin, shell_command_id);
if (hotkeys) {
let hotkeys_joined = "";
hotkeys.forEach((hotkey) => {
if (hotkeys_joined) {
hotkeys_joined += "<br>";
}
hotkeys_joined += HotkeyToString(hotkey);
});
const hotkey_div = setting_group.preview_setting.controlEl.createEl("div", { attr: { class: "setting-item-description SC-hotkey-info" } });
// Comment out the icon because it would look like a clickable button (as there are other clickable icons in the settings).
// setIcon(hotkey_div, "any-key", 22); // Hotkey icon
hotkey_div.insertAdjacentHTML("beforeend", " " + hotkeys_joined);
}
}
debugLog("Created.");
}
/**
* @param t_shell_command
* @public Exported because ShellCommandExtraOptionsModal uses this too.
*/
function generateShellCommandFieldIconAndName(t_shell_command) {
const icon_html = t_shell_command.getIconHTML() + " ";
if (t_shell_command.getAlias()) {
return icon_html + t_shell_command.getAlias();
}
return icon_html + "Shell command without alias";
}
/**
* @param ignored_error_codes
* @public Exported because ShellCommandExtraOptionsModal uses this too.
*/
function generateIgnoredErrorCodesIconTitle(ignored_error_codes) {
const plural = ignored_error_codes.length !== 1 ? "s" : "";
return "Ignored error" + plural + ": " + ignored_error_codes.join(",");
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_MainSettingsTab extends obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.setting_groups = {};
this.last_position = {
scroll_position: 0,
tab_name: "main-shell-commands",
};
this.plugin = plugin;
}
display() {
const { containerEl } = this;
containerEl.empty();
this.tab_structure = createTabs(containerEl, {
"main-shell-commands": {
title: "Shell commands",
icon: "run-command",
content_generator: (container_element) => {
this.tabShellCommands(container_element);
},
},
"main-environments": {
title: "Environments",
icon: "stacked-levels",
content_generator: (container_element) => {
this.tabEnvironments(container_element);
},
},
"main-preactions": {
title: "Preactions",
icon: "note-glyph",
content_generator: (container_element) => {
this.tabPreactions(container_element);
},
},
"main-output": {
title: "Output",
icon: "lines-of-text",
content_generator: (container_element) => {
this.tabOutput(container_element);
},
},
"main-events": {
title: "Events",
icon: "dice",
content_generator: (container_element) => {
this.tabEvents(container_element);
},
},
"main-variables": {
title: "Variables",
icon: "code-glyph",
content_generator: (container_element) => {
this.tabVariables(container_element);
},
},
});
// Documentation link & GitHub links
containerEl.createEl("p").insertAdjacentHTML("beforeend", "<a href=\"" + DocumentationMainLink + "\">Documentation</a> - " +
"<a href=\"" + GitHubLink + "\">SC on GitHub</a> - " +
"<a href=\"" + ChangelogLink + "\">SC version: " + this.plugin.getPluginVersion() + "</a>");
// Copyright notice
const copyright_paragraph = containerEl.createEl("p");
copyright_paragraph.addClass("SC-small-font");
copyright_paragraph.insertAdjacentHTML("beforeend", `
<em>Shell commands</em> plugin Copyright &copy; 2021 - 2023 Jarkko Linnanvirta. This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See more information in the license: <a href="${LicenseLink}">GNU GPL-3.0</a>.
`);
// KEEP THIS AFTER CREATING ALL ELEMENTS:
this.rememberLastPosition(containerEl);
}
tabShellCommands(container_element) {
// Show a search field
this.createSearchField(container_element);
// A <div> element for all command input fields. New command fields can be created at the bottom of this element.
const command_fields_container = container_element.createEl("div");
// Fields for modifying existing commands
let shell_commands_exist = false;
for (const command_id in this.plugin.getTShellCommands()) {
createShellCommandField(this.plugin, command_fields_container, this, command_id, this.plugin.settings.show_autocomplete_menu);
shell_commands_exist = true;
}
// 'No shell commands yet' paragraph.
const no_shell_commands_paragraph = container_element.createEl("p", { text: "No shell commands yet, click the 'New shell command' button below." });
if (shell_commands_exist) {
// Shell commands exist, so do not show the "No shell commands yet" text.
no_shell_commands_paragraph.hide();
}
// "New command" button
new obsidian.Setting(container_element)
.addButton(button => button
.setButtonText("New shell command")
.onClick(async () => {
createShellCommandField(this.plugin, command_fields_container, this, "new", this.plugin.settings.show_autocomplete_menu);
no_shell_commands_paragraph.hide();
debugLog("New empty command created.");
}));
}
createSearchField(container_element) {
const search_container = container_element.createDiv();
const search_title = "Search shell commands";
const search_setting = new obsidian.Setting(search_container)
.setName(search_title)
.setDesc("Looks up shell commands' aliases, commands, ids and icons.")
.addSearch(search_component => search_component
.onChange((search_term) => {
let count_matches = 0;
for (const shell_command_id in this.plugin.getTShellCommands()) {
let matched = false;
// Check if a search term was defined.
if ("" == search_term) {
// Show all shell commands.
matched = true;
}
else {
// A search term is defined.
// Define fields where to look for the search term
const t_shell_command = this.plugin.getTShellCommands()[shell_command_id];
const search_targets = [
t_shell_command.getId(),
t_shell_command.getConfiguration().alias,
];
search_targets.push(...Object.values(t_shell_command.getPlatformSpecificShellCommands()));
// Only include icon in the search if it's defined.
const icon = t_shell_command.getConfiguration().icon;
if (icon) {
search_targets.push(icon);
}
// Check if it's a match
search_targets.forEach((search_target) => {
if (search_target.toLocaleLowerCase().contains(search_term.toLocaleLowerCase())) {
matched = true;
debugLog("Search " + search_term + " MATCHED " + search_target);
}
});
}
// Show or hide the shell command.
const shell_command_element = document.querySelector("div.SC-id-" + shell_command_id);
if (!shell_command_element) {
throw new Error("Shell command setting element does not exist with selector div.SC-id-" + shell_command_id);
}
if (matched) {
shell_command_element.removeClass("SC-hide");
count_matches++;
}
else {
shell_command_element.addClass("SC-hide");
}
}
// Display match count
if ("" == search_term) {
// Don't show match count.
search_setting.setName(search_title);
}
else {
// Show match count.
switch (count_matches) {
case 0: {
search_setting.setName("No matches");
break;
}
case 1: {
search_setting.setName("1 match");
break;
}
default: {
search_setting.setName(count_matches + " matches");
break;
}
}
}
}).then((search_component) => {
// Focus on the search field.
search_component.inputEl.addClass("SC-focus-element-on-tab-opening");
}));
}
tabEvents(container_element) {
// A general description about events
container_element.createEl("p", { text: "Events introduce a way to execute shell commands automatically in certain situations, e.g. when Obsidian starts. They are set up for each shell command separately, but this tab contains general options for them." });
// Enable/disable all events
new obsidian.Setting(container_element)
.setName("Enable events")
.setDesc("This is a quick way to immediately turn off all events, if you want.")
.addToggle(toggle => toggle
.setValue(this.plugin.settings.enable_events)
.onChange(async (enable_events) => {
// The toggle was clicked.
this.plugin.settings.enable_events = enable_events;
if (enable_events) {
// Register events.
this.plugin.registerSC_Events(true);
}
else {
// Unregister events.
this.plugin.unregisterSC_Events();
}
await this.plugin.saveSettings();
}));
// A list of current enable events
container_element.createEl("p", { text: "The following gives just a quick glance over which events are enabled on which shell commands. To enable/disable events for a shell command, go to the particular shell command's settings via the 'Shell commands' tab. The list is only updated when you reopen the whole settings panel." });
let found_enabled_event = false;
getSC_Events(this.plugin).forEach((sc_event) => {
const event_enabled_t_shell_commands = sc_event.getTShellCommands();
// Has the event been enabled for any shell commands?
if (event_enabled_t_shell_commands.length) {
// Yes, it's enabled.
// Show a list of shell commands
const paragraph_element = container_element.createEl("p", { text: sc_event.static().getTitle() });
const list_element = paragraph_element.createEl("ul");
event_enabled_t_shell_commands.forEach((t_shell_command) => {
list_element.createEl("li", { text: t_shell_command.getAliasOrShellCommand() });
});
found_enabled_event = true;
}
});
if (!found_enabled_event) {
container_element.createEl("p", { text: "No events are enabled for any shell commands." });
}
}
tabVariables(container_element) {
// "Preview variables in command palette" field
new obsidian.Setting(container_element)
.setName("Preview variables in command palette and menus")
.setDesc("If on, variable names are substituted with their realtime values when you view your commands in the command palette and right click context menus (if used). A nice way to ensure your commands will use correct values.")
.addToggle(checkbox => checkbox
.setValue(this.plugin.settings.preview_variables_in_command_palette)
.onChange(async (value) => {
debugLog("Changing preview_variables_in_command_palette to " + value);
this.plugin.settings.preview_variables_in_command_palette = value;
await this.plugin.saveSettings();
}));
// "Show autocomplete menu" field
new obsidian.Setting(container_element)
.setName("Show autocomplete menu")
.setDesc("If on, a dropdown menu shows up when you begin writing {{variable}} names, showing matching variables and their instructions. Also allows defining custom suggestions in autocomplete.yaml file - see the documentation.")
.addToggle(checkbox => checkbox
.setValue(this.plugin.settings.show_autocomplete_menu)
.onChange(async (value) => {
debugLog("Changing show_autocomplete_menu to " + value);
this.plugin.settings.show_autocomplete_menu = value;
this.display(); // Re-render the whole settings view to apply the change.
await this.plugin.saveSettings();
}))
.addExtraButton(extra_button => extra_button
.setIcon("help")
.setTooltip("Documentation: Autocomplete")
.onClick(() => {
gotoURL(DocumentationAutocompleteLink);
}));
// Custom variables
new obsidian.Setting(container_element)
.setName("Custom variables")
.setHeading() // Make the "Variables" text bold.
.addExtraButton(extra_button => extra_button
.setIcon("pane-layout")
.setTooltip("Open a pane that displays all custom variables and their values.")
.onClick(() => {
this.plugin.createCustomVariableView();
}))
.addExtraButton(extra_button => extra_button
.setIcon("help")
.setTooltip("Documentation: Custom variables")
.onClick(() => {
gotoURL(DocumentationCustomVariablesLink);
}));
// Settings for each CustomVariable
const custom_variable_model = getModel(CustomVariableModel.name);
const custom_variable_container = container_element.createDiv();
this.plugin.getCustomVariableInstances().forEach((custom_variable_instance) => {
custom_variable_model.createSettingFields(custom_variable_instance, custom_variable_container);
});
createNewModelInstanceButton(this.plugin, CustomVariableModel.name, container_element, custom_variable_container, this.plugin.settings).then();
// Built-in variable instructions
new obsidian.Setting(container_element)
.setName("Built-in variables")
.setHeading() // Make the "Variables" text bold.
.addExtraButton(extra_button => extra_button
.setIcon("help")
.setTooltip("Documentation: Built-in variables")
.onClick(() => {
gotoURL(DocumentationBuiltInVariablesIndexLink);
}));
for (const variable of this.plugin.getVariables()) {
if (!(variable instanceof CustomVariable)) {
const variableSettingGroupElement = container_element.createDiv();
variableSettingGroupElement.addClass("SC-setting-group");
// Variable name and documentation link
const variableHeadingSetting = new obsidian.Setting(variableSettingGroupElement) // Use container_element instead of variableSettingGroup.
.setHeading()
.addExtraButton(extraButton => extraButton
.setIcon("help")
.setTooltip("Documentation: " + variable.getFullName() + " variable")
.onClick(() => gotoURL(variable.getDocumentationLink())));
variableHeadingSetting.nameEl.insertAdjacentHTML("afterbegin", variable.getHelpName());
// Variable description
const variableDescriptionSetting = new obsidian.Setting(variableSettingGroupElement)
.setClass("SC-full-description") // Without this, description would be shrunk to 50% of space. This setting does not have control elements, so 100% width is ok.
;
variableDescriptionSetting.descEl.insertAdjacentHTML("afterbegin", variable.help_text);
const availability_text = variable.getAvailabilityText();
if (availability_text) {
variableDescriptionSetting.descEl.insertAdjacentHTML("beforeend", "<br>" + availability_text);
}
// Variable default value
const defaultValueSettingTitle = "Default value for " + variable.getFullName();
if (variable.isAlwaysAvailable()) {
new obsidian.Setting(variableSettingGroupElement)
.setName(defaultValueSettingTitle)
.setDesc(variable.getFullName() + " is always available, so it cannot have a default value.");
}
else {
createVariableDefaultValueField(this.plugin, variableSettingGroupElement, defaultValueSettingTitle, variable);
}
}
}
container_element.createEl("p", { text: "When you type variables into commands, a preview text appears under the command field to show how the command will look like when it gets executed with variables substituted with their real values." });
container_element.createEl("p", { text: "Special characters in variable values are tried to be escaped (except if you use CMD as the shell in Windows). This is to improve security so that a variable won't accidentally cause bad things to happen. If you want to use a raw, unescaped value, add an exclamation mark before the variable's name, e.g. {{!title}}, but be careful, it's dangerous!" });
container_element.createEl("p", { text: "There is no way to prevent variable parsing. If you need {{ }} characters in your command, they won't be parsed as variables as long as they do not contain any of the variable names listed above. If you need to pass e.g. {{title}} literally to your command, there is no way to do it atm, please create a discussion in GitHub." });
container_element.createEl("p", { text: "All variables that access the current file, may cause the command preview to fail if you had no file panel active when you opened the settings window - e.g. you had focus on graph view instead of a note = no file is currently active. But this does not break anything else than the preview." });
}
tabEnvironments(container_element) {
// "Working directory" field
new obsidian.Setting(container_element)
.setName("Working directory")
.setDesc("A directory where your commands will be run. If empty, defaults to your vault's location. Can be relative (= a folder in the vault) or absolute (= complete from filesystem root).")
.addText(text => text
.setPlaceholder(getVaultAbsolutePath(this.app))
.setValue(this.plugin.settings.working_directory)
.onChange(async (value) => {
debugLog("Changing working_directory to " + value);
this.plugin.settings.working_directory = value;
await this.plugin.saveSettings();
}));
// Platforms' default shells
createShellSelectionField(this.plugin, container_element, this.plugin.settings.default_shells, true);
// PATH environment variable fields
createPATHAugmentationFields(this.plugin, container_element, this.plugin.settings.environment_variable_path_augmentations);
}
tabPreactions(container_element) {
// Prompts
const prompt_model = getModel(PromptModel.name);
new obsidian.Setting(container_element)
.setName("Prompts")
.setHeading() // Make the "Prompts" text to appear as a heading.
;
const prompts_container_element = container_element.createDiv();
this.plugin.getPrompts().forEach((prompt) => {
prompt_model.createSettingFields(prompt, prompts_container_element);
});
// 'New prompt' button
const new_prompt_button_promise = createNewModelInstanceButton(this.plugin, PromptModel.name, container_element, prompts_container_element, this.plugin.settings);
new_prompt_button_promise.then((result) => {
prompt_model.openSettingsModal(result.instance, result.main_setting); // Open the prompt settings modal, as the user will probably want to configure it now anyway.
});
}
tabOutput(container_element) {
// Output wrappers
const output_wrapper_model = getModel(OutputWrapperModel.name);
new obsidian.Setting(container_element)
.setName("Output wrappers")
.setHeading() // Make the "Output wrappers" text to appear as a heading.
.addExtraButton(extra_button => extra_button
.setIcon("help")
.setTooltip("Documentation: Output wrappers")
.onClick(() => gotoURL(DocumentationOutputWrappersLink)));
const output_wrappers_container_element = container_element.createDiv();
this.plugin.getOutputWrappers().forEach((output_wrapper) => {
output_wrapper_model.createSettingFields(output_wrapper, output_wrappers_container_element);
});
// 'New output wrapper' button
const new_output_wrapper_button_promise = createNewModelInstanceButton(this.plugin, OutputWrapperModel.name, container_element, output_wrappers_container_element, this.plugin.settings);
new_output_wrapper_button_promise.then((result) => {
output_wrapper_model.openSettingsModal(result.instance, result.main_setting); // Open the output wrapper settings modal, as the user will probably want to configure it now anyway.
});
// "Error message duration" field
this.createNotificationDurationField(container_element, "Error message duration", "Concerns messages about failed shell commands.", "error_message_duration");
// "Notification message duration" field
this.createNotificationDurationField(container_element, "Notification message duration", "Concerns informational, non-fatal messages, e.g. output directed to 'Notification balloon'.", "notification_message_duration");
// "Show a notification when executing shell commands" field
new obsidian.Setting(container_element)
.setName("Show a notification when executing shell commands")
.addDropdown(dropdown_component => dropdown_component
.addOptions({
"disabled": "Do not show",
"quick": "Show for " + this.plugin.settings.notification_message_duration + " seconds",
"permanent": "Show until the process is finished",
"if-long": "Show only if executing takes long",
})
.setValue(this.plugin.settings.execution_notification_mode)
.onChange(async (new_execution_notification_mode) => {
// Save the change.
this.plugin.settings.execution_notification_mode = new_execution_notification_mode;
await this.plugin.saveSettings();
}));
// "Output channel 'Clipboard' displays a notification message, too" field
new obsidian.Setting(container_element)
.setName("Output channel 'Clipboard' displays a notification message, too")
.setDesc("If a shell command's output is directed to the clipboard, also show the output in a popup box on the top right corner. This helps to notice what was inserted into clipboard.")
.addToggle(checkbox => checkbox
.setValue(this.plugin.settings.output_channel_clipboard_also_outputs_to_notification)
.onChange(async (value) => {
this.plugin.settings.output_channel_clipboard_also_outputs_to_notification = value;
await this.plugin.saveSettings();
}));
}
createNotificationDurationField(container_element, title, description, setting_name) {
new obsidian.Setting(container_element)
.setName(title)
.setDesc(description + " In seconds, between 1 and 180.")
.addText(field => field
.setValue(String(this.plugin.settings[setting_name]))
.onChange(async (duration_string) => {
const duration = parseInt(duration_string);
if (duration >= 1 && duration <= 180) {
debugLog("Change " + setting_name + " from " + this.plugin.settings[setting_name] + " to " + duration);
this.plugin.settings[setting_name] = duration;
await this.plugin.saveSettings();
debugLog("Changed.");
}
// Don't show a notice if duration is not between 1 and 180, because this function is called every time a user types in this field, so the value might not be final.
}));
}
rememberLastPosition(container_element) {
const last_position = this.last_position;
// Go to last position now
this.tab_structure.buttons[last_position.tab_name].click();
window.setTimeout(() => {
container_element.scrollTo({
top: this.last_position.scroll_position,
behavior: "auto",
});
}, 0); // 'timeout' can be 0 ms, no need to wait any longer.
// Listen to changes
container_element.addEventListener("scroll", (event) => {
this.last_position.scroll_position = container_element.scrollTop;
});
for (const tab_name in this.tab_structure.buttons) {
const button = this.tab_structure.buttons[tab_name];
button.onClickEvent((event) => {
last_position.tab_name = tab_name;
});
}
}
}
/**
* Copied 2021-10-29 from https://gist.github.com/TheDistantSea/8021359
* Modifications:
* - Made compatible with TypeScript by adding type definitions.
* - Changed var to let.
*
* Compares two software version numbers (e.g. "1.7.1" or "1.2b").
*
* This function was born in http://stackoverflow.com/a/6832721.
*
* @param {string} v1 The first version to be compared.
* @param {string} v2 The second version to be compared.
* @param {object} [options] Optional flags that affect comparison behavior:
* <ul>
* <li>
* <tt>lexicographical: true</tt> compares each part of the version strings lexicographically instead of
* naturally; this allows suffixes such as "b" or "dev" but will cause "1.10" to be considered smaller than
* "1.2".
* </li>
* <li>
* <tt>zeroExtend: true</tt> changes the result if one version string has less parts than the other. In
* this case the shorter string will be padded with "zero" parts instead of being considered smaller.
* </li>
* </ul>
* @returns {number|NaN}
* <ul>
* <li>0 if the versions are equal</li>
* <li>a negative integer iff v1 < v2</li>
* <li>a positive integer iff v1 > v2</li>
* <li>NaN if either version string is in the wrong format</li>
* </ul>
*
* @copyright by Jon Papaioannou (["john", "papaioannou"].join(".") + "@gmail.com")
* @license This function is in the public domain. Do what you want with it, no strings attached.
*/
function versionCompare(v1, v2, options = {}) {
let lexicographical = options && options.lexicographical, zeroExtend = options && options.zeroExtend, v1parts = v1.split('.'), v2parts = v2.split('.');
function isValidPart(x) {
return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x);
}
if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
return NaN;
}
if (zeroExtend) {
while (v1parts.length < v2parts.length)
v1parts.push("0");
while (v2parts.length < v1parts.length)
v2parts.push("0");
}
if (!lexicographical) {
v1parts = v1parts.map(Number);
v2parts = v2parts.map(Number);
}
for (let i = 0; i < v1parts.length; ++i) {
if (v2parts.length == i) {
return 1;
}
if (v1parts[i] == v2parts[i]) {
continue;
}
else if (v1parts[i] > v2parts[i]) {
return 1;
}
else {
return -1;
}
}
if (v1parts.length != v2parts.length) {
return -1;
}
return 0;
}
/*
* 'Shell commands' plugin for Obsidian.
* Copyright (C) 2021 - 2023 Jarkko Linnanvirta
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.0 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Contact the author (Jarkko Linnanvirta): https://github.com/Taitava/
*/
class SC_Plugin extends obsidian.Plugin {
constructor() {
super(...arguments);
this.obsidian_commands = {};
this.t_shell_commands = {};
/**
* Holder for shell commands and aliases, whose variables are parsed before the actual execution during command
* palette preview. This array gets emptied after every time a shell command is executed via the command palette.
*
* This is only used for command palette, not when executing a shell command from the settings panel, nor when
* executing shell commands via SC_Events.
*
* @private
*/
this.cached_parsing_processes = {};
this.autocompleteMenus = [];
}
async onload() {
debugLog('loading plugin');
// Load settings
if (!await this.loadSettings()) {
// Loading the settings has failed due to an unsupported settings file version.
// The plugin should not be used, and it has actually disabled itself, but the code execution needs to be
// stopped manually.
return;
}
// Define models
introduceModels(this);
// Run possible configuration migrations
await RunMigrations(this);
// Generate TShellCommand objects from configuration (only after configuration migrations are done)
this.loadTShellCommands();
// Load Prompts
const prompt_model = getModel(PromptModel.name);
this.prompts = prompt_model.loadInstances(this.settings);
// Load CustomVariables (configuration instances)
const custom_variable_model = getModel(CustomVariableModel.name);
this.custom_variable_instances = custom_variable_model.loadInstances(this.settings);
// Load variables (both built-in and custom ones). Do this AFTER loading configs for custom variables!
this.variables = loadVariables(this);
// Load output wrappers
const output_wrapper_model = getModel(OutputWrapperModel.name);
this.output_wrappers = output_wrapper_model.loadInstances(this.settings);
// Make all defined shell commands to appear in the Obsidian command palette.
const shell_commands = this.getTShellCommands();
for (const shell_command_id in shell_commands) {
const t_shell_command = shell_commands[shell_command_id];
if (t_shell_command.canAddToCommandPalette()) {
this.registerShellCommand(t_shell_command);
}
}
// Perform event registrations, if enabled.
if (this.settings.enable_events) {
this.registerSC_Events(false);
}
// Load a custom autocomplete list if it exists.
this.loadCustomAutocompleteList();
// Create a SettingsTab.
this.addSettingTab(new SC_MainSettingsTab(this.app, this));
// Make it possible to create CustomVariableViews.
this.registerView(CustomVariableView.ViewType, (leaf) => new CustomVariableView(this, leaf));
// Debug reserved IDs
debugLog("IDGenerator's reserved IDs:");
debugLog(getIDGenerator().getReservedIDs());
// Register an URI handler.
this.registerURIHandler();
}
loadTShellCommands() {
this.t_shell_commands = {}; // TODO: Consider changing this to either an array or a Map.
const shell_command_configurations = this.getShellCommandConfigurations();
for (const shell_command_configuration of shell_command_configurations) {
this.t_shell_commands[shell_command_configuration.id] = new TShellCommand(this, shell_command_configuration);
}
}
getTShellCommands() {
return this.t_shell_commands;
}
getVariables() {
return this.variables;
}
getPrompts() {
return this.prompts;
}
getCustomVariableInstances() {
return this.custom_variable_instances;
}
getShellCommandConfigurations() {
return this.settings.shell_commands;
}
getOutputWrappers() {
return this.output_wrappers;
}
/**
* Tries to find an index at which a ShellCommandConfiguration object is located in this.settings.shell_commands.
* Returns undefined, if it's not found.
*
* DO NOT EXPOSE THE INDEX OUTSIDE THE PLUGIN! It's not a stable reference to a shell command, because shell commands
* can be reordered (well, at least in some future version of the plugin). Always use the ID as a stable, externally
* safe reference!
*
* @param shell_command_id
*/
getShellCommandConfigurationIndex(shell_command_id) {
return this.settings.shell_commands.findIndex((shell_command_configuration) => {
return shell_command_configuration.id == shell_command_id;
});
}
/**
* Returns an Obsidian URI that complies with the format obsidian://action/?vault=XYZ and that may contain possible
* custom arguments at the end.
*
* Note that if 'action' is 'open' and a 'file' argument is present in 'uri_arguments', the URI will use the shorthand syntax described here: https://help.obsidian.md/Advanced+topics/Using+obsidian+URI#Shorthand+formats
*
* @param action
* @param uri_arguments
*/
getObsidianURI(action, uri_arguments = {}) {
const encoded_vault_name = encodeURIComponent(this.app.vault.getName());
let base_uri;
// Check which kind of uri type should be used: shorthand or normal
if ("open" === action && uri_arguments.file !== undefined) {
// Use shorthand uri type for opening a file.
const encoded_file = encodeURIComponent(uri_arguments.file);
base_uri = `obsidian://vault/${encoded_vault_name}/${encoded_file}`;
delete uri_arguments.file; // Prevent adding an extra '&file=' argument to the end of the URI.
}
else {
// Use normal uri type for everything else.
base_uri = `obsidian://${action}/?vault=${encoded_vault_name}`;
}
let concatenated_uri_arguments = "";
for (const uri_argument_name in uri_arguments) {
const uri_argument_value = encodeURIComponent(uri_arguments[uri_argument_name]);
concatenated_uri_arguments += `&${uri_argument_name}=${uri_argument_value}`;
}
return base_uri + concatenated_uri_arguments;
}
/**
* Creates a new shell command object and registers it to Obsidian's command palette, but does not save the modified
* configuration to disk. To save the addition, call saveSettings().
*/
newTShellCommand() {
const shell_command_id = getIDGenerator().generateID();
const shell_command_configuration = newShellCommandConfiguration(shell_command_id);
this.settings.shell_commands.push(shell_command_configuration);
const t_shell_command = new TShellCommand(this, shell_command_configuration);
this.t_shell_commands[shell_command_id] = t_shell_command;
if (t_shell_command.canAddToCommandPalette()) { // This is probably always true, because the default configuration enables adding to the command palette, but check just in case.
this.registerShellCommand(t_shell_command);
}
return t_shell_command;
}
/**
* TODO: Move to TShellCommand.registerToCommandPalette(), but split to multiple methods.
*
* @param t_shell_command
*/
registerShellCommand(t_shell_command) {
const shell_command_id = t_shell_command.getId();
debugLog("Registering shell command #" + shell_command_id + "...");
// Define a function for executing the shell command.
const executor = async (parsing_process) => {
if (!parsing_process) {
parsing_process = t_shell_command.createParsingProcess(null); // No SC_Event is available when executing shell commands via the command palette / hotkeys.
// Try to process variables that can be processed before performing preactions.
await parsing_process.process();
}
if (parsing_process.getParsingResults().shell_command?.succeeded) { // .shell_command should always be present (even if parsing did not succeed), but if it's not, show errors in the else block.
// The command was parsed correctly.
const executor_instance = new ShellCommandExecutor(// Named 'executor_instance' because 'executor' is another constant.
this, t_shell_command, null // No SC_Event is available when executing via command palette or hotkey.
);
await executor_instance.doPreactionsAndExecuteShellCommand(parsing_process);
}
else {
// The command could not be parsed correctly.
// Display error messages
parsing_process.displayErrorMessages();
}
};
// Register an Obsidian command
const obsidian_command = {
id: this.generateObsidianCommandId(shell_command_id),
name: generateObsidianCommandName(this, t_shell_command.getShellCommand(), t_shell_command.getAlias()),
// Use 'checkCallback' instead of normal 'callback' because we also want to get called when the command palette is opened.
checkCallback: (is_opening_command_palette) => {
if (is_opening_command_palette) {
// The user is currently opening the command palette.
// Check can the shell command be shown in command palette
if (!t_shell_command.canShowInCommandPalette()) {
// Cancel preview and deny showing in command palette.
debugLog("Shell command #" + t_shell_command.getId() + " won't be shown in command palette.");
return false;
}
// Do not execute the command yet, but parse variables for preview, if enabled in the settings.
debugLog("Getting command palette preview for shell command #" + t_shell_command.getId());
if (this.settings.preview_variables_in_command_palette) {
// Preparse variables
const parsing_process = t_shell_command.createParsingProcess(null); // No SC_Event is available when executing shell commands via the command palette / hotkeys.
parsing_process.process().then((parsing_succeeded) => {
if (parsing_succeeded) {
// Parsing succeeded
// Rename Obsidian command
const parsingResults = parsing_process.getParsingResults();
/** Don't confuse this name with ShellCommandParsingResult interface! The properties are very different. TODO: Rename ShellCommandParsingResult to something else. */
const shellCommandParsingResult = parsingResults["shell_command"]; // Use 'as' to denote that properties exist on this line and below.
const aliasParsingResult = parsingResults["alias"];
const parsedShellCommand = shellCommandParsingResult.parsed_content;
const parsedAlias = aliasParsingResult.parsed_content;
t_shell_command.renameObsidianCommand(parsedShellCommand, parsedAlias);
// Store the preparsed variables so that they will be used if this shell command gets executed.
this.cached_parsing_processes[t_shell_command.getId()] = parsing_process;
}
else {
// Parsing failed, so use unparsed t_shell_command.getShellCommand() and t_shell_command.getAlias().
t_shell_command.renameObsidianCommand(t_shell_command.getShellCommand(), t_shell_command.getAlias());
this.cached_parsing_processes[t_shell_command.getId()] = undefined;
}
});
}
else {
// Parsing is disabled, so use unparsed t_shell_command.getShellCommand() and t_shell_command.getAlias().
t_shell_command.renameObsidianCommand(t_shell_command.getShellCommand(), t_shell_command.getAlias());
this.cached_parsing_processes[t_shell_command.getId()] = undefined;
}
return true; // Tell Obsidian this command can be shown in command palette.
}
else {
// The user has instructed to execute the command.
executor(this.cached_parsing_processes[t_shell_command.getId()]).then(() => {
// Delete the whole array of preparsed commands. Even though we only used just one command from it, we need to notice that opening a command
// palette might generate multiple preparsed commands in the array, but as the user selects and executes only one command, all these temporary
// commands are now obsolete. Delete them just in case the user toggles the variable preview feature off in the settings, or executes commands via hotkeys. We do not want to
// execute obsolete commands accidentally.
// This deletion also needs to be done even if the executed command was not a preparsed command, because
// even when preparsing is turned on in the settings, some commands may fail to parse, and therefore they would not be in this array, but other
// commands might be.
this.cached_parsing_processes = {}; // Removes obsolete preparsed variables from all shell commands.
return; // When we are not in the command palette check phase, there's no need to return a value. Just have this 'return' statement because all other return points have a 'return' too.
});
}
}
};
this.addCommand(obsidian_command);
this.obsidian_commands[shell_command_id] = obsidian_command; // Store the reference so that we can edit the command later in ShellCommandsSettingsTab if needed. TODO: Use tShellCommand instead.
t_shell_command.setObsidianCommand(obsidian_command);
debugLog("Registered.");
}
/**
* Goes through all events and all shell commands, and for each shell command, registers all the events that the shell
* command as enabled in its configuration. Does not modify the configurations.
*
* @param called_after_changing_settings Set to: true, if this happens after changing configuration; false, if this happens during loading the plugin.
*/
registerSC_Events(called_after_changing_settings) {
// Make sure that Obsidian is fully loaded before allowing any events to trigger.
this.app.workspace.onLayoutReady(() => {
// Even after Obsidian is fully loaded, wait a while in order to prevent SC_Event_onActiveLeafChanged triggering right after start-up.
// At least on Obsidian 0.12.19 it's not enough to delay until onLayoutReady, need to wait a bit more in order to avoid the miss-triggering.
window.setTimeout(() => {
// Iterate all shell commands and register possible events.
const shell_commands = this.getTShellCommands();
for (const shell_command_id in shell_commands) {
const t_shell_command = shell_commands[shell_command_id];
t_shell_command.registerSC_Events(called_after_changing_settings);
}
}, 0); // 0 means to call the callback on "the next event cycle", according to window.setTimeout() documentation. It should be a long enough delay. But if SC_Event_onActiveLeafChanged still gets triggered during start-up, this value can be raised to for example 1000 (= one second).
});
}
/**
* Goes through all events and all shell commands, and makes sure all of them are unregistered, e.g. will not trigger
* automatically. Does not modify the configurations.
*/
unregisterSC_Events() {
// Iterate all events
getSC_Events(this).forEach((sc_event) => {
// Iterate all shell commands
const shell_commands = this.getTShellCommands();
for (const shell_command_id in shell_commands) {
const t_shell_command = shell_commands[shell_command_id];
sc_event.unregister(t_shell_command);
}
});
}
/**
* Defines an Obsidian protocol handler that allows receiving requests via obsidian://shell-commands URI.
* @private
*/
registerURIHandler() {
this.registerObsidianProtocolHandler(SC_Plugin.SHELL_COMMANDS_URI_ACTION, async (parameters) => {
const parameter_names = Object.getOwnPropertyNames(parameters);
// Assign values to custom variables (also delete some unneeded entries from parameter_names)
let custom_variable_assignments_failed = false;
for (const parameter_index in parameter_names) {
const parameter_name = parameter_names[parameter_index];
// Check if the parameter name is a custom variable
if (parameter_name.match(/^_/)) {
// This parameter defines a value for a custom variable
// Find the variable.
let found_custom_variable = false;
for (const variable of this.getVariables()) {
if (variable instanceof CustomVariable && variable.variable_name === parameter_name) {
// Found the correct variable.
found_custom_variable = true;
// Assign the given value to the custom variable.
await variable.setValue(parameters[parameter_name]);
}
}
if (!found_custom_variable) {
this.newError("Shell commands URI: A custom variable does not exist: " + parameter_name);
custom_variable_assignments_failed = true;
}
}
}
if (!custom_variable_assignments_failed) {
// Determine action
if (undefined !== parameters.execute) {
// Execute a shell command.
const executable_shell_command_id = parameters.execute;
parameter_names.remove("execute"); // Mark the parameter as handled. Prevents showing an error message for an unrecognised parameter.
// Find the executable shell command
let found_t_shell_command = false;
const shell_commands = this.getTShellCommands();
for (const shell_command_id in shell_commands) {
const t_shell_command = shell_commands[shell_command_id];
if (t_shell_command.getId() === executable_shell_command_id) {
// This is the correct shell command.
found_t_shell_command = true;
// Execute it.
const executor = new ShellCommandExecutor(this, t_shell_command, null);
await executor.doPreactionsAndExecuteShellCommand();
}
}
if (!found_t_shell_command) {
this.newError("Shell commands URI: A shell command id does not exist: " + executable_shell_command_id);
}
}
}
// Raise errors for any left-over parameters, if exists.
for (const parameter_name of parameter_names) {
switch (parameter_name) {
case "": // For some reason Obsidian 0.14.5 adds an empty-named parameter if there are no ?query=parameters present.
case "action": // Obsidian provides this always. Don't show an error message for this.
case "vault": // Obsidian handles this parameter automatically. Just make sure no error message is displayed when this is present.
// Do nothing
break;
default:
if (parameter_name.match(/^_/)) ;
else {
// Throw an error for everything else.
this.newError("Shell commands URI: Unrecognised parameter: " + parameter_name);
}
}
}
});
}
generateObsidianCommandId(shell_command_id) {
return "shell-command-" + shell_command_id;
}
onunload() {
debugLog('Unloading Shell commands plugin.');
// Close CustomVariableViews.
this.app.workspace.detachLeavesOfType(CustomVariableView.ViewType);
// Close autocomplete menus.
for (const autocompleteMenu of this.autocompleteMenus) {
autocompleteMenu?.destroy();
}
}
/**
*
* @param current_settings_version
* @private
* @return True if the given settings version is supported by this plugin version, or an error message string if it's not supported.
*/
isSettingsVersionSupported(current_settings_version) {
if (current_settings_version === "prior-to-0.7.0") {
// 0.x.y supports all old settings formats that do not define a version number. This support will be removed in 1.0.0.
return true;
}
else {
// Compare the version number
/** Note that the plugin version may be different than what will be used in the version comparison. The plugin version will be displayed in possible error messages. */
const plugin_version = this.getPluginVersion();
const version_comparison = versionCompare(SC_Plugin.SettingsVersion, current_settings_version);
if (version_comparison === 0) {
// The versions are equal.
// Supported.
return true;
}
else if (version_comparison < 0) {
// The compared version is newer than what the plugin can support.
return "The settings file is saved by a newer version of this plugin, so this plugin does not support the structure of the settings file. Please upgrade this plugin to at least version " + current_settings_version + ". Now the plugin version is " + plugin_version;
}
else {
// The compared version is older than the version that the plugin currently uses to write settings.
// 0.x.y supports all old settings versions. In 1.0.0, some old settings formats might lose their support, but that's not yet certain.
return true;
}
}
}
getPluginVersion() {
return this.manifest.version;
}
async loadSettings() {
// Try to read a settings file
let all_settings;
this.settings = await this.loadData(); // May have missing main settings fields, if the settings file is from an older version of SC. It will be migrated later.
if (null === this.settings) {
// The settings file does not exist.
// Use default settings
this.settings = getDefaultSettings(true);
all_settings = this.settings;
}
else {
// Succeeded to load a settings file.
// In case the settings file does not have 'debug' or 'settings_version' fields, create them.
all_settings = combineObjects(getDefaultSettings(false), this.settings); // This temporary settings object always has all fields defined (except sub fields, such as shell command specific fields, may still be missing, but they are not needed this early). This is used so that it's certain that the fields 'debug' and 'settings_version' exist.
}
// Update debug status - before this line debugging is always OFF!
setDEBUG_ON(all_settings.debug);
// Ensure that the loaded settings file is supported.
const version_support = this.isSettingsVersionSupported(all_settings.settings_version);
if (typeof version_support === "string") {
// The settings version is not supported.
new obsidian.Notice("SHELL COMMANDS PLUGIN HAS DISABLED ITSELF in order to prevent misinterpreting settings / corrupting the settings file!", 120 * 1000);
new obsidian.Notice(version_support, 120 * 1000);
await this.disablePlugin();
return false; // The plugin should not be used.
}
return true; // Settings are loaded and the plugin can be used.
}
async saveSettings() {
// Update settings version in case it's old.
this.settings.settings_version = SC_Plugin.SettingsVersion;
// Write settings
await this.saveData(this.settings);
}
loadCustomAutocompleteList() {
const custom_autocomplete_file_name = "autocomplete.yaml";
const custom_autocomplete_file_path = path__namespace.join(getPluginAbsolutePath(this), custom_autocomplete_file_name);
if (fs__namespace.existsSync(custom_autocomplete_file_path)) {
debugLog("loadCustomAutocompleteList(): " + custom_autocomplete_file_name + " exists, will load it now.");
const custom_autocomplete_content = fs__namespace.readFileSync(custom_autocomplete_file_path).toLocaleString();
const result = addCustomAutocompleteItems(custom_autocomplete_content);
if (true === result) {
// OK
debugLog("loadCustomAutocompleteList(): " + custom_autocomplete_file_name + " loaded.");
}
else {
// An error has occurred.
debugLog("loadCustomAutocompleteList(): " + result);
this.newError("Shell commands: Unable to parse " + custom_autocomplete_file_name + ": " + result);
}
}
else {
debugLog("loadCustomAutocompleteList(): " + custom_autocomplete_file_name + " does not exists, so won't load it. This is perfectly ok.");
}
}
/**
* Puts the given Autocomplete menu into a list of menus that will be destroyed when the plugin unloads.
* @param autocompleteMenu
*/
registerAutocompleteMenu(autocompleteMenu) {
this.autocompleteMenus.push(autocompleteMenu);
}
async disablePlugin() {
// This unfortunately accesses a private API.
// @ts-ignore
await this.app.plugins.disablePlugin(this.manifest.id);
}
getPluginId() {
return this.manifest.id;
}
getPluginName() {
return this.manifest.name;
}
newError(message, timeout = this.getErrorMessageDurationMs()) {
return new obsidian.Notice(message, timeout);
}
newErrors(messages) {
messages.forEach((message) => {
this.newError(message);
});
}
/**
*
* @param message
* @param timeout Custom timeout in milliseconds. If not set, the timeout will be fetched from user configurable settings. Use 0 if you want to disable the timeout, i.e. show the notification until it's explicitly hidden by clinking it, or via code.
*/
newNotification(message, timeout = this.getNotificationMessageDurationMs()) {
return new obsidian.Notice(message, timeout);
}
getNotificationMessageDurationMs() {
return this.settings.notification_message_duration * 1000; // * 1000 = convert seconds to milliseconds.
}
getErrorMessageDurationMs() {
return this.settings.error_message_duration * 1000; // * 1000 = convert seconds to milliseconds.
}
getDefaultShell() {
const operating_system = getOperatingSystem();
let shell_name = this.settings.default_shells[operating_system]; // Can also be undefined.
if (undefined === shell_name) {
shell_name = getUsersDefaultShell();
}
return shell_name;
}
createCustomVariableView() {
const leaf = this.app.workspace.getRightLeaf(false);
leaf.setViewState({
type: CustomVariableView.ViewType,
active: true,
}).then();
this.app.workspace.revealLeaf(leaf);
}
/**
* Called when CustomVariable values are changed.
*/
async updateCustomVariableViews() {
for (const leaf of this.app.workspace.getLeavesOfType(CustomVariableView.ViewType)) {
await leaf.view.updateContent();
}
}
/**
* Used by OutputChannel_StatusBar.
* TODO: Make it possible to have multiple status bar elements. It should be a shell command level setting, where a shell command opts for either to use their own status bar element, or a common one.
*/
getOutputStatusBarElement() {
if (!this.statusBarElement) {
this.statusBarElement = this.addStatusBarItem();
}
return this.statusBarElement;
}
/**
* Creates an icon button that when clicked, will send a request to terminate shell command execution intermittently.
*
* @param containerElement
* @param processTerminator A callback that will actually terminate the shell command execution process.
*/
createRequestTerminatingButton(containerElement, processTerminator) {
const button = containerElement.createEl('a', {
prepend: true,
attr: {
"aria-label": "Request to terminate the process",
class: "SC-icon-terminate-process",
},
});
obsidian.setIcon(button, "power");
button.onclick = (event) => {
processTerminator();
event.preventDefault();
event.stopPropagation();
};
}
}
/**
* Defines the settings structure version. Change this when a new plugin version is released, but only if that plugin
* version introduces changes to the settings structure. Do not change if the settings structure stays unchanged.
*/
SC_Plugin.SettingsVersion = "0.18.0";
SC_Plugin.SHELL_COMMANDS_URI_ACTION = "shell-commands";
module.exports = SC_Plugin;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsic3JjL1NDX01vZGFsLnRzIiwic3JjL0NvbmZpcm1hdGlvbk1vZGFsLnRzIiwic3JjL0RlYnVnLnRzIiwic3JjL0lER2VuZXJhdG9yLnRzIiwic3JjL0NvbW1vbi50cyIsInNyYy9saWIvZXNjYXBlUmVnRXhwLnRzIiwic3JjL0RvY3VtZW50YXRpb24udHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlLnRzIiwic3JjL3ZhcmlhYmxlcy9WYXJpYWJsZV9PdXRwdXQudHMiLCJzcmMvdmFyaWFibGVzL2VzY2FwZXJzL0VzY2FwZXIudHMiLCJzcmMvdmFyaWFibGVzL2VzY2FwZXJzL0FsbFNwZWNpYWxDaGFyYWN0ZXJzRXNjYXBlci50cyIsInNyYy92YXJpYWJsZXMvZXNjYXBlcnMvU2hFc2NhcGVyLnRzIiwic3JjL3ZhcmlhYmxlcy9lc2NhcGVycy9Qb3dlclNoZWxsRXNjYXBlci50cyIsInNyYy92YXJpYWJsZXMvZXNjYXBlcnMvRXNjYXBlVmFsdWUudHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlX0NsaXBib2FyZC50cyIsInNyYy92YXJpYWJsZXMvRWRpdG9yVmFyaWFibGUudHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlX0NhcmV0UG9zaXRpb24udHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlX0RhdGUudHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlSGVscGVycy50cyIsInNyYy92YXJpYWJsZXMvRmlsZVZhcmlhYmxlLnRzIiwic3JjL3ZhcmlhYmxlcy9WYXJpYWJsZV9GaWxlRXh0ZW5zaW9uLnRzIiwic3JjL3ZhcmlhYmxlcy9WYXJpYWJsZV9GaWxlTmFtZS50cyIsInNyYy92YXJpYWJsZXMvVmFyaWFibGVfRmlsZVBhdGgudHMiLCJzcmMvdmFyaWFibGVzL0ZvbGRlclZhcmlhYmxlLnRzIiwic3JjL3ZhcmlhYmxlcy9WYXJpYWJsZV9Gb2xkZXJOYW1lLnRzIiwic3JjL3ZhcmlhYmxlcy9WYXJpYWJsZV9Gb2xkZXJQYXRoLnRzIiwic3JjL3ZhcmlhYmxlcy9WYXJpYWJsZV9TZWxlY3Rpb24udHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlX1RhZ3MudHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlX1RpdGxlLnRzIiwic3JjL3ZhcmlhYmxlcy9WYXJpYWJsZV9WYXVsdFBhdGgudHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlX1dvcmtzcGFjZS50cyIsInNyYy92YXJpYWJsZXMvVmFyaWFibGVfUGFzc3Rocm91Z2gudHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlX1lBTUxWYWx1ZS50cyIsInNyYy92YXJpYWJsZXMvZXZlbnRfdmFyaWFibGVzL0V2ZW50VmFyaWFibGUudHMiLCJzcmMvZXZlbnRzL1NDX0V2ZW50LnRzIiwic3JjL2V2ZW50cy9TQ19Xb3Jrc3BhY2VFdmVudC50cyIsInNyYy9ldmVudHMvU0NfTWVudUV2ZW50LnRzIiwic3JjL2V2ZW50cy9TQ19BYnN0cmFjdEZpbGVNZW51RXZlbnQudHMiLCJzcmMvZXZlbnRzL1NDX0V2ZW50X0ZpbGVNZW51LnRzIiwic3JjL2V2ZW50cy9TQ19WYXVsdEV2ZW50LnRzIiwic3JjL2V2ZW50cy9TQ19FdmVudF9GaWxlQ3JlYXRlZC50cyIsInNyYy9ldmVudHMvU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZC50cyIsInNyYy9ldmVudHMvU0NfRXZlbnRfRmlsZURlbGV0ZWQudHMiLCJzcmMvZXZlbnRzL1NDX1ZhdWx0TW92ZU9yUmVuYW1lRXZlbnQudHMiLCJzcmMvZXZlbnRzL1NDX0V2ZW50X0ZpbGVSZW5hbWVkLnRzIiwic3JjL2V2ZW50cy9TQ19FdmVudF9GaWxlTW92ZWQudHMiLCJzcmMvdmFyaWFibGVzL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudEZpbGVOYW1lLnRzIiwic3JjL3ZhcmlhYmxlcy9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnRGaWxlUGF0aC50cyIsInNyYy9ldmVudHMvU0NfRXZlbnRfRm9sZGVyTWVudS50cyIsInNyYy9ldmVudHMvU0NfRXZlbnRfRm9sZGVyQ3JlYXRlZC50cyIsInNyYy9ldmVudHMvU0NfRXZlbnRfRm9sZGVyRGVsZXRlZC50cyIsInNyYy9ldmVudHMvU0NfRXZlbnRfRm9sZGVyUmVuYW1lZC50cyIsInNyYy9ldmVudHMvU0NfRXZlbnRfRm9sZGVyTW92ZWQudHMiLCJzcmMvdmFyaWFibGVzL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudEZvbGRlck5hbWUudHMiLCJzcmMvdmFyaWFibGVzL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudEZvbGRlclBhdGgudHMiLCJzcmMvdmFyaWFibGVzL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudFRpdGxlLnRzIiwic3JjL3ZhcmlhYmxlcy9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnRGaWxlRXh0ZW5zaW9uLnRzIiwic3JjL3ZhcmlhYmxlcy9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnRUYWdzLnRzIiwic3JjL3ZhcmlhYmxlcy9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnRZQU1MVmFsdWUudHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlX0Vudmlyb25tZW50LnRzIiwic3JjL3ZhcmlhYmxlcy9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnRPbGRGaWxlTmFtZS50cyIsInNyYy92YXJpYWJsZXMvZXZlbnRfdmFyaWFibGVzL1ZhcmlhYmxlX0V2ZW50T2xkRmlsZVBhdGgudHMiLCJzcmMvdmFyaWFibGVzL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudE9sZEZvbGRlck5hbWUudHMiLCJzcmMvdmFyaWFibGVzL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudE9sZEZvbGRlclBhdGgudHMiLCJzcmMvdmFyaWFibGVzL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudE9sZFRpdGxlLnRzIiwic3JjL3ZhcmlhYmxlcy9WYXJpYWJsZV9OZXdOb3RlRm9sZGVyTmFtZS50cyIsInNyYy92YXJpYWJsZXMvVmFyaWFibGVfTmV3Tm90ZUZvbGRlclBhdGgudHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlX0ZpbGVVUkkudHMiLCJzcmMvdmFyaWFibGVzL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudEZpbGVVUkkudHMiLCJzcmMvdmFyaWFibGVzL1ZhcmlhYmxlX05vdGVDb250ZW50LnRzIiwic3JjL3ZhcmlhYmxlcy9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnROb3RlQ29udGVudC50cyIsInNyYy92YXJpYWJsZXMvVmFyaWFibGVfRmlsZUNvbnRlbnQudHMiLCJzcmMvdmFyaWFibGVzL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudEZpbGVDb250ZW50LnRzIiwic3JjL3ZhcmlhYmxlcy9WYXJpYWJsZV9DYXJldFBhcmFncmFwaC50cyIsInNyYy92YXJpYWJsZXMvVmFyaWFibGVfTmV3bGluZS50cyIsInNyYy92YXJpYWJsZXMvVmFyaWFibGVfWUFNTENvbnRlbnQudHMiLCJzcmMvdmFyaWFibGVzL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudFlBTUxDb250ZW50LnRzIiwic3JjL3ZhcmlhYmxlcy9sb2FkVmFyaWFibGVzLnRzIiwic3JjL3ZhcmlhYmxlcy9wYXJzZVZhcmlhYmxlcy50cyIsInNyYy9vdXRwdXRfY2hhbm5lbHMvT3V0cHV0Q2hhbm5lbC50cyIsInNyYy9vdXRwdXRfY2hhbm5lbHMvT3V0cHV0Q2hhbm5lbF9Ob3RpZmljYXRpb24udHMiLCJzcmMvb3V0cHV0X2NoYW5uZWxzL091dHB1dENoYW5uZWxfQ3VycmVudEZpbGUudHMiLCJzcmMvb3V0cHV0X2NoYW5uZWxzL091dHB1dENoYW5uZWxfQ3VycmVudEZpbGVDYXJldC50cyIsInNyYy9vdXRwdXRfY2hhbm5lbHMvT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZVRvcC50cyIsInNyYy9vdXRwdXRfY2hhbm5lbHMvT3V0cHV0Q2hhbm5lbF9TdGF0dXNCYXIudHMiLCJzcmMvb3V0cHV0X2NoYW5uZWxzL091dHB1dENoYW5uZWxfQ3VycmVudEZpbGVCb3R0b20udHMiLCJzcmMvb3V0cHV0X2NoYW5uZWxzL091dHB1dENoYW5uZWxfQ2xpcGJvYXJkLnRzIiwic3JjL0hvdGtleXMudHMiLCJzcmMvb3V0cHV0X2NoYW5uZWxzL091dHB1dENoYW5uZWxfTW9kYWwudHMiLCJzcmMvb3V0cHV0X2NoYW5uZWxzL091dHB1dENoYW5uZWxfT3BlbkZpbGVzLnRzIiwic3JjL291dHB1dF9jaGFubmVscy9PdXRwdXRDaGFubmVsRnVuY3Rpb25zLnRzIiwic3JjL1NoZWxsLnRzIiwic3JjL3NldHRpbmdzL1NDX01haW5TZXR0aW5ncy50cyIsInNyYy9TaGVsbENvbW1hbmRFeGVjdXRvci50cyIsInNyYy9tb2RlbHMvSW5zdGFuY2UudHMiLCJzcmMvbW9kZWxzL01vZGVsLnRzIiwic3JjL21vZGVscy9vdXRwdXRfd3JhcHBlci9PdXRwdXRXcmFwcGVyLnRzIiwibm9kZV9tb2R1bGVzL2F1dG9jb21wbGV0ZXIvYXV0b2NvbXBsZXRlLmpzIiwic3JjL3ZhcmlhYmxlcy9nZXRWYXJpYWJsZUF1dG9jb21wbGV0ZUl0ZW1zLnRzIiwic3JjL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvQXV0b2NvbXBsZXRlLnRzIiwic3JjL21vZGVscy9vdXRwdXRfd3JhcHBlci9PdXRwdXRXcmFwcGVyU2V0dGluZ3NNb2RhbC50cyIsInNyYy9tb2RlbHMvb3V0cHV0X3dyYXBwZXIvT3V0cHV0V3JhcHBlck1vZGVsLnRzIiwic3JjL21vZGVscy9tb2RlbHMudHMiLCJzcmMvdmFyaWFibGVzL0N1c3RvbVZhcmlhYmxlLnRzIiwic3JjL21vZGVscy9jdXN0b21fdmFyaWFibGUvQ3VzdG9tVmFyaWFibGVJbnN0YW5jZS50cyIsInNyYy9ldmVudHMvU0NfRXZlbnRfb25MYXlvdXRSZWFkeS50cyIsInNyYy9ldmVudHMvU0NfRXZlbnRfb25RdWl0LnRzIiwic3JjL2V2ZW50cy9TQ19FdmVudF9vbkFjdGl2ZUxlYWZDaGFuZ2VkLnRzIiwic3JjL2V2ZW50cy9TQ19FdmVudF9FdmVyeU5TZWNvbmRzLnRzIiwic3JjL2V2ZW50cy9TQ19FdmVudF9FZGl0b3JNZW51LnRzIiwic3JjL2V2ZW50cy9TQ19FdmVudExpc3QudHMiLCJzcmMvSWNvbnMudHMiLCJzcmMvVFNoZWxsQ29tbWFuZC50cyIsInNyYy9zZXR0aW5ncy9zZXR0aW5nX2VsZW1lbnRzL2NyZWF0ZVZhcmlhYmxlRGVmYXVsdFZhbHVlRmllbGRzLnRzIiwic3JjL21vZGVscy9jdXN0b21fdmFyaWFibGUvQ3VzdG9tVmFyaWFibGVNb2RlbC50cyIsInNyYy9tb2RlbHMvY3VzdG9tX3ZhcmlhYmxlL0N1c3RvbVZhcmlhYmxlU2V0dGluZ3NNb2RhbC50cyIsInNyYy9tb2RlbHMvY3VzdG9tX3ZhcmlhYmxlL0N1c3RvbVZhcmlhYmxlVmlldy50cyIsInNyYy9wcmVhY3Rpb25zL1ByZWFjdGlvbi50cyIsInNyYy9wcmVhY3Rpb25zL1ByZWFjdGlvbl9Qcm9tcHQudHMiLCJzcmMvbW9kZWxzL3Byb21wdC9wcm9tcHRfZmllbGRzL1Byb21wdEZpZWxkLnRzIiwic3JjL21vZGVscy9wcm9tcHQvcHJvbXB0X2ZpZWxkcy9Qcm9tcHRGaWVsZE1vZGVsLnRzIiwic3JjL21vZGVscy9wcm9tcHQvcHJvbXB0X2ZpZWxkcy9Qcm9tcHRGaWVsZF9UZXh0LnRzIiwic3JjL21vZGVscy9wcm9tcHQvUHJvbXB0LnRzIiwic3JjL21vZGVscy9wcm9tcHQvUHJvbXB0TW9kYWwudHMiLCJzcmMvbW9kZWxzL3Byb21wdC9Qcm9tcHRNb2RlbC50cyIsInNyYy9tb2RlbHMvY3JlYXRlTmV3TW9kZWxJbnN0YW5jZUJ1dHRvbi50cyIsInNyYy9tb2RlbHMvcHJvbXB0L1Byb21wdFNldHRpbmdzTW9kYWwudHMiLCJzcmMvc2V0dGluZ3Mvc2V0dGluZ19lbGVtZW50cy9QYXRoRW52aXJvbm1lbnRWYXJpYWJsZUZ1bmN0aW9ucy50cyIsInNyYy92YXJpYWJsZXMvUGFyc2luZ1Byb2Nlc3MudHMiLCJzcmMvc2V0dGluZ3MvU2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbi50cyIsInNyYy9NaWdyYXRpb25zLnRzIiwic3JjL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvQ3JlYXRlU2hlbGxTZWxlY3Rpb25GaWVsZC50cyIsInNyYy9zZXR0aW5ncy9zZXR0aW5nX2VsZW1lbnRzL211bHRpbGluZUZpZWxkLnRzIiwic3JjL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvQ3JlYXRlU2hlbGxDb21tYW5kRmllbGRDb3JlLnRzIiwic3JjL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvQ3JlYXRlUGxhdGZvcm1TcGVjaWZpY1NoZWxsQ29tbWFuZEZpZWxkLnRzIiwic3JjL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvVGFicy50cyIsInNyYy9zZXR0aW5ncy9FeHRyYU9wdGlvbnNNb2RhbC50cyIsInNyYy9zZXR0aW5ncy9EZWxldGVNb2RhbC50cyIsInNyYy9zZXR0aW5ncy9zZXR0aW5nX2VsZW1lbnRzL0NyZWF0ZVNoZWxsQ29tbWFuZEZpZWxkLnRzIiwic3JjL3NldHRpbmdzL1NDX01haW5TZXR0aW5nc1RhYi50cyIsInNyYy9saWIvdmVyc2lvbl9jb21wYXJlLnRzIiwic3JjL21haW4udHMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge01vZGFsfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi9tYWluXCI7XHJcblxyXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgU0NfTW9kYWwgZXh0ZW5kcyBNb2RhbCB7XHJcblxyXG4gICAgcHJpdmF0ZSBfaXNPcGVuID0gZmFsc2U7XHJcblxyXG4gICAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yIChcclxuICAgICAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgcGx1Z2luOiBTQ19QbHVnaW5cclxuICAgICkge1xyXG4gICAgICAgIHN1cGVyKHBsdWdpbi5hcHApO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbk9wZW4oKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5faXNPcGVuID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgLy8gTWFrZSB0aGUgbW9kYWwgc2Nyb2xsYWJsZSBpZiBpdCBoYXMgbW9yZSBjb250ZW50IHRoYW4gd2hhdCBmaXRzIGluIHRoZSBzY3JlZW4uXHJcbiAgICAgICAgdGhpcy5tb2RhbEVsLmFkZENsYXNzKFwiU0MtbW9kYWxcIiwgXCJTQy1zY3JvbGxhYmxlXCIpO1xyXG5cclxuICAgICAgICAvLyBBcHByb3ZlIHRoZSBtb2RhbCBieSBwcmVzc2luZyB0aGUgZW50ZXIga2V5IChpZiBlbmFibGVkKS5cclxuICAgICAgICBpZiAodGhpcy5wbHVnaW4uc2V0dGluZ3MuYXBwcm92ZV9tb2RhbHNfYnlfcHJlc3NpbmdfZW50ZXJfa2V5KSB7XHJcbiAgICAgICAgICAgIHRoaXMuc2NvcGUucmVnaXN0ZXIoW10sIFwiZW50ZXJcIiwgKGV2ZW50OiBLZXlib2FyZEV2ZW50KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAvLyBDaGVjayB0aGF0IG5vIHRleHRhcmVhIGlzIGZvY3VzZWQgYW5kIG5vIGF1dG9jb21wbGV0ZSBtZW51IGlzIG9wZW4uXHJcbiAgICAgICAgICAgICAgICBpZiAoXHJcbiAgICAgICAgICAgICAgICAgICAgMCA9PT0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChcInRleHRhcmVhOmZvY3VzXCIpLmxlbmd0aCAmJlxyXG4gICAgICAgICAgICAgICAgICAgIDAgPT09IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXCJkaXYuU0MtYXV0b2NvbXBsZXRlXCIpLmxlbmd0aFxyXG4gICAgICAgICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gTm8gdGV4dGFyZWFzIHdpdGggZm9jdXMgYW5kIG5vIG9wZW4gYXV0b2NvbXBsZXRlIG1lbnVzIHdlcmUgZm91bmQuXHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5hcHByb3ZlKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICAgICAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBpc09wZW4oKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2lzT3BlbjtcclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgc2V0VGl0bGUodGl0bGU6IHN0cmluZykge1xyXG4gICAgICAgIHRoaXMudGl0bGVFbC5pbm5lclRleHQgPSB0aXRsZTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENhbGxlZCBhZnRlciBhIHVzZXIgcHJlc3NlcyB0aGUgZW50ZXIga2V5IChpZiBhcHByb3ZpbmcgbW9kYWxzIGJ5IGVudGVyIGtleSBwcmVzcyBpcyBlbmFibGVkIGluIHNldHRpbmdzKS4gVGhlIHB1cnBvc2VcclxuICAgICAqIG9mIHRoZSBtZXRob2QgaXMgdG8gYXBwcm92ZS9wZXJmb3JtIHRoZSBhY3Rpb24gdGhlIG1vZGFsIGlzIGFza2luZy9wcmVwYXJpbmcuIFRoZSBtZXRob2Qgc2hvdWxkIHRoZW4gY2xvc2UgdGhlIG1vZGFsXHJcbiAgICAgKiBieSBjYWxsaW5nIHRoaXMuY2xvc2UoKSAuXHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCBhcHByb3ZlKCk6IHZvaWQ7XHJcblxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX01vZGFsfSBmcm9tIFwiLi9TQ19Nb2RhbFwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuL21haW5cIjtcclxuaW1wb3J0IHtTZXR0aW5nfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBDb25maXJtYXRpb25Nb2RhbCBleHRlbmRzIFNDX01vZGFsIHtcclxuXHJcbiAgICBwdWJsaWMgcHJvbWlzZTogUHJvbWlzZTxib29sZWFuPjtcclxuICAgIHByaXZhdGUgcmVzb2x2ZV9wcm9taXNlOiAodmFsdWU6IChib29sZWFuIHwgUHJvbWlzZUxpa2U8Ym9vbGVhbj4pKSA9PiB2b2lkO1xyXG4gICAgcHJpdmF0ZSBhcHByb3ZlZCA9IGZhbHNlO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIHBsdWdpbjogU0NfUGx1Z2luLFxyXG4gICAgICAgIHRpdGxlOiBzdHJpbmcsXHJcbiAgICAgICAgcHJpdmF0ZSBxdWVzdGlvbjogc3RyaW5nLFxyXG4gICAgICAgIHByaXZhdGUgeWVzX2J1dHRvbl90ZXh0OiBzdHJpbmcsXHJcbiAgICApIHtcclxuICAgICAgICBzdXBlcihwbHVnaW4pO1xyXG4gICAgICAgIHRoaXMuc2V0VGl0bGUodGl0bGUpO1xyXG4gICAgICAgIHRoaXMucHJvbWlzZSA9IG5ldyBQcm9taXNlPGJvb2xlYW4+KChyZXNvbHZlKSA9PiB7XHJcbiAgICAgICAgICAgIHRoaXMucmVzb2x2ZV9wcm9taXNlID0gcmVzb2x2ZTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgb25PcGVuKCk6IHZvaWQge1xyXG4gICAgICAgIHN1cGVyLm9uT3BlbigpO1xyXG5cclxuICAgICAgICAvLyBEaXNwbGF5IHRoZSBxdWVzdGlvblxyXG4gICAgICAgIHRoaXMubW9kYWxFbC5jcmVhdGVFbChcInBcIiwge3RleHQ6IHRoaXMucXVlc3Rpb259KTtcclxuXHJcbiAgICAgICAgLy8gRGlzcGxheSB0aGUgeWVzIGJ1dHRvblxyXG4gICAgICAgIG5ldyBTZXR0aW5nKHRoaXMubW9kYWxFbClcclxuICAgICAgICAgICAgLmFkZEJ1dHRvbihidXR0b24gPT4gYnV0dG9uXHJcbiAgICAgICAgICAgICAgICAuc2V0QnV0dG9uVGV4dCh0aGlzLnllc19idXR0b25fdGV4dClcclxuICAgICAgICAgICAgICAgIC5vbkNsaWNrKCgpID0+IHRoaXMuYXBwcm92ZSgpKVxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG5cclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgYXBwcm92ZSgpOiB2b2lkIHtcclxuICAgICAgICAvLyBHb3QgYSBjb25maXJtYXRpb24gZnJvbSBhIHVzZXJcclxuICAgICAgICB0aGlzLnJlc29sdmVfcHJvbWlzZSh0cnVlKTtcclxuICAgICAgICB0aGlzLmFwcHJvdmVkID0gdHJ1ZTtcclxuICAgICAgICB0aGlzLmNsb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIG9uQ2xvc2UoKTogdm9pZCB7XHJcbiAgICAgICAgc3VwZXIub25DbG9zZSgpO1xyXG5cclxuICAgICAgICBpZiAoIXRoaXMuYXBwcm92ZWQpIHsgLy8gVE9ETzogRmluZCBvdXQgaWYgdGhlcmUgaXMgYSB3YXkgdG8gbm90IHVzZSB0aGlzIGtpbmQgb2YgZmxhZyBwcm9wZXJ0eS4gQ2FuIHRoZSBzdGF0dXMgYmUgY2hlY2tlZCBmcm9tIHRoZSBwcm9taXNlIGl0c2VsZj9cclxuICAgICAgICAgICAgdGhpcy5yZXNvbHZlX3Byb21pc2UoZmFsc2UpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufSIsIlxyXG4vKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBJZiB0cnVlLCBsb2dnaW5nIHN0dWZmIHRvIGNvbnNvbGUubG9nKCkgd2lsbCBiZSBlbmFibGVkLlxyXG4gKiBNaWdodCBhbHNvIGVuYWJsZSBzb21lIHRlc3Rpbmcge3t2YXJpYWJsZXN9fSBpbiB0aGUgZnV0dXJlLCBwZXJoYXBzLlxyXG4gKi9cclxuZXhwb3J0IGxldCBERUJVR19PTiA9IGZhbHNlO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIHNldERFQlVHX09OKHZhbHVlOiBib29sZWFuKSB7XHJcbiAgICBERUJVR19PTiA9IHZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogQ2FsbHMgY29uc29sZS5sb2coKSwgYnV0IG9ubHkgaWYgZGVidWdnaW5nIGlzIGVuYWJsZWQuXHJcbiAqIEBwYXJhbSBtZXNzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZGVidWdMb2cobWVzc2FnZTogdW5rbm93bikge1xyXG4gICAgaWYgKERFQlVHX09OKSB7XHJcbiAgICAgICAgY29uc29sZS5sb2cobWVzc2FnZSk7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7ZGVidWdMb2d9IGZyb20gXCIuL0RlYnVnXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgSURHZW5lcmF0b3Ige1xyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcHJpdmF0ZSByZXNlcnZlZF9pZHM6IHN0cmluZ1tdID0gW10sXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBtaW5fbGVuZ3RoID0gMTAsXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBjaGFyYWN0ZXJzID0gXCJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODlcIixcclxuICAgICkge31cclxuXHJcbiAgICBwdWJsaWMgYWRkUmVzZXJ2ZWRJRChpZDogc3RyaW5nKSB7XHJcbiAgICAgICAgZGVidWdMb2coSURHZW5lcmF0b3IubmFtZSArIFwiOiBBZGRpbmcgaWQgXCIgKyBpZCArIFwiIHRvIHRoZSBsaXN0IG9mIHJlc2VydmVkIGlkcy5cIik7XHJcbiAgICAgICAgdGhpcy5yZXNlcnZlZF9pZHMucHVzaChpZCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdlbmVyYXRlSUQoKTogc3RyaW5nIHtcclxuICAgICAgICBsZXQgZ2VuZXJhdGVkX2lkID0gXCJcIjtcclxuICAgICAgICB3aGlsZSAoZ2VuZXJhdGVkX2lkLmxlbmd0aCA8IHRoaXMubWluX2xlbmd0aCB8fCB0aGlzLmlzSURSZXNlcnZlZChnZW5lcmF0ZWRfaWQpKSB7XHJcbiAgICAgICAgICAgIGdlbmVyYXRlZF9pZCArPSB0aGlzLmdlbmVyYXRlQ2hhcmFjdGVyKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMucmVzZXJ2ZWRfaWRzLnB1c2goZ2VuZXJhdGVkX2lkKTtcclxuICAgICAgICBkZWJ1Z0xvZyhJREdlbmVyYXRvci5uYW1lICsgXCI6IEdlbmVyYXRlZCBpZCBcIiArIGdlbmVyYXRlZF9pZCk7XHJcbiAgICAgICAgcmV0dXJuIGdlbmVyYXRlZF9pZDtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0UmVzZXJ2ZWRJRHMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMucmVzZXJ2ZWRfaWRzO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgZ2VuZXJhdGVDaGFyYWN0ZXIoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jaGFyYWN0ZXJzLmNoYXJBdChcclxuICAgICAgICAgICAgTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogdGhpcy5jaGFyYWN0ZXJzLmxlbmd0aClcclxuICAgICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgaXNJRFJlc2VydmVkKGlkOiBzdHJpbmcpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5yZXNlcnZlZF9pZHMuY29udGFpbnMoaWQpO1xyXG4gICAgfVxyXG59XHJcblxyXG5jb25zdCBpZF9nZW5lcmF0b3I6IElER2VuZXJhdG9yID0gbmV3IElER2VuZXJhdG9yKCk7XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZ2V0SURHZW5lcmF0b3IoKSB7XHJcbiAgICByZXR1cm4gaWRfZ2VuZXJhdG9yO1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1xyXG4gICAgQXBwLFxyXG4gICAgRWRpdG9yLFxyXG4gICAgRWRpdG9yUG9zaXRpb24sXHJcbiAgICBGaWxlU3lzdGVtQWRhcHRlcixcclxuICAgIEZyb250TWF0dGVyQ2FjaGUsXHJcbiAgICBNYXJrZG93blZpZXcsXHJcbiAgICBub3JtYWxpemVQYXRoLFxyXG4gICAgVEZpbGUsXHJcbn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7UGxhdGZvcm1JZH0gZnJvbSBcIi4vc2V0dGluZ3MvU0NfTWFpblNldHRpbmdzXCI7XHJcbmltcG9ydCB7cGxhdGZvcm19IGZyb20gXCJvc1wiO1xyXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJwYXRoXCI7XHJcbmltcG9ydCB7ZGVidWdMb2d9IGZyb20gXCIuL0RlYnVnXCI7XHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4vbWFpblwiO1xyXG4vLyBAdHMtaWdub3JlXHJcbmltcG9ydCB7c2hlbGx9IGZyb20gXCJlbGVjdHJvblwiO1xyXG4vLyBAdHMtaWdub3JlIEVsZWN0cm9uIGlzIGluc3RhbGxlZC5cclxuaW1wb3J0IHtjbGlwYm9hcmR9IGZyb20gXCJlbGVjdHJvblwiO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFZhdWx0QWJzb2x1dGVQYXRoKGFwcDogQXBwKSB7XHJcbiAgICAvLyBPcmlnaW5hbCBjb2RlIHdhcyBjb3BpZWQgMjAyMS0wOC0yMiBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9waGlicjAvb2JzaWRpYW4tb3Blbi13aXRoL2Jsb2IvODRmMGUyNWJhOGU4MzU1ZmY4M2IyMmY0MDUwYWRkZTRjYzY3NjNlYS9tYWluLnRzI0w2Ni1MNjdcclxuICAgIC8vIEJ1dCB0aGUgY29kZSBoYXMgYmVlbiByZXdyaXR0ZW4gMjAyMS0wOC0yNyBhcyBwZXIgaHR0cHM6Ly9naXRodWIuY29tL29ic2lkaWFubWQvb2JzaWRpYW4tcmVsZWFzZXMvcHVsbC80MzMjaXNzdWVjb21tZW50LTkwNjA4NzA5NVxyXG4gICAgY29uc3QgYWRhcHRlciA9IGFwcC52YXVsdC5hZGFwdGVyO1xyXG4gICAgaWYgKGFkYXB0ZXIgaW5zdGFuY2VvZiBGaWxlU3lzdGVtQWRhcHRlcikge1xyXG4gICAgICAgIHJldHVybiBhZGFwdGVyLmdldEJhc2VQYXRoKCk7XHJcbiAgICB9XHJcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgcmV0cmlldmUgdmF1bHQgcGF0aC4gTm8gRGF0YUFkYXB0ZXIgd2FzIGZvdW5kIGZyb20gYXBwLnZhdWx0LmFkYXB0ZXIuXCIpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UGx1Z2luQWJzb2x1dGVQYXRoKHBsdWdpbjogU0NfUGx1Z2luKSB7XHJcbiAgICByZXR1cm4gbm9ybWFsaXplUGF0aDIocGF0aC5qb2luKFxyXG4gICAgICAgIGdldFZhdWx0QWJzb2x1dGVQYXRoKHBsdWdpbi5hcHApLFxyXG4gICAgICAgIHBsdWdpbi5hcHAudmF1bHQuY29uZmlnRGlyLFxyXG4gICAgICAgIFwicGx1Z2luc1wiLFxyXG4gICAgICAgIHBsdWdpbi5nZXRQbHVnaW5JZCgpKSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGb3Igc29tZSByZWFzb24gdGhlcmUgaXMgbm8gUGxhdGZvcm0uaXNXaW5kb3dzIC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc1dpbmRvd3MoKSB7XHJcbiAgICByZXR1cm4gcHJvY2Vzcy5wbGF0Zm9ybSA9PT0gXCJ3aW4zMlwiO1xyXG59XHJcblxyXG4vKipcclxuICogVGhpcyBpcyBqdXN0IGEgd3JhcHBlciBhcm91bmQgcGxhdGZvcm0oKSBpbiBvcmRlciB0byBjYXN0IHRoZSB0eXBlIHRvIFBsYXRmb3JtSWQuXHJcbiAqIFRPRE86IENvbnNpZGVyIHJlbmFtaW5nIHRoaXMgdG8gZ2V0UGxhdGZvcm1JZCgpLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE9wZXJhdGluZ1N5c3RlbSgpOiBQbGF0Zm9ybUlkICB7XHJcbiAgICAvLyBAdHMtaWdub3JlIEluIHRoZW9yeSwgcGxhdGZvcm0oKSBjYW4gcmV0dXJuIGFuIE9TIG5hbWUgbm90IGluY2x1ZGVkIGluIE9wZXJhdGluZ1N5c3RlbU5hbWUuIEJ1dCBhcyBPYnNpZGlhblxyXG4gICAgLy8gY3VycmVudGx5IGRvZXMgbm90IHN1cHBvcnQgYW55dGhpbmcgZWxzZSB0aGFuIFdpbmRvd3MsIE1hYyBhbmQgTGludXggKGV4Y2VwdCBtb2JpbGUgcGxhdGZvcm1zLCBidXQgdGhleSBhcmVcclxuICAgIC8vIHJ1bGVkIG91dCBieSB0aGUgbWFuaWZlc3Qgb2YgdGhpcyBwbHVnaW4pLCBpdCBzaG91bGQgYmUgc2FmZSB0byBhc3N1bWUgdGhhdCB0aGUgY3VycmVudCBPUyBpcyBvbmUgb2YgdGhvc2VcclxuICAgIC8vIHRocmVlLlxyXG4gICAgcmV0dXJuIHBsYXRmb3JtKCk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRWaWV3KGFwcDogQXBwKSB7XHJcbiAgICBjb25zdCB2aWV3ID0gYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVWaWV3T2ZUeXBlKE1hcmtkb3duVmlldyk7XHJcbiAgICBpZiAoIXZpZXcpIHtcclxuICAgICAgICBkZWJ1Z0xvZyhcImdldFZpZXcoKTogQ291bGQgbm90IGdldCBhIHZpZXcuIFdpbGwgcmV0dXJuIG51bGwuXCIpO1xyXG4gICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHZpZXc7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRFZGl0b3IoYXBwOiBBcHApOiBFZGl0b3IgfCBudWxsIHtcclxuXHJcbiAgICBjb25zdCB2aWV3ID0gZ2V0VmlldyhhcHApO1xyXG4gICAgaWYgKG51bGwgPT09IHZpZXcpIHtcclxuICAgICAgICAvLyBDb3VsZCBub3QgZ2V0IGEgdmlldy5cclxuICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBFbnN1cmUgdGhhdCB2aWV3LmVkaXRvciBleGlzdHMhIEl0IGV4aXN0cyBhdCBsZWFzdCBpZiB0aGlzIGlzIGEgTWFya0Rvd25WaWV3LlxyXG4gICAgaWYgKFwiZWRpdG9yXCIgaW4gdmlldykge1xyXG4gICAgICAgIC8vIEdvb2QsIGl0IGV4aXN0cy5cclxuICAgICAgICAvLyBAdHMtaWdub3JlIFdlIGFscmVhZHkga25vdyB0aGF0IHZpZXcuZWRpdG9yIGV4aXN0cy5cclxuICAgICAgICByZXR1cm4gdmlldy5lZGl0b3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGlkIG5vdCBmaW5kIGFuIGVkaXRvci5cclxuICAgIGRlYnVnTG9nKFwiZ2V0RWRpdG9yKCk6ICd2aWV3JyBkb2VzIG5vdCBoYXZlIGEgcHJvcGVydHkgbmFtZWQgJ2VkaXRvcicuIFdpbGwgcmV0dXJuIG51bGwuXCIpO1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbn1cclxuXHJcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvYmFuLXR5cGVzXHJcbmV4cG9ydCBmdW5jdGlvbiBjbG9uZU9iamVjdDxPYmplY3RUeXBlPihvYmplY3Q6IE9iamVjdCk6IE9iamVjdFR5cGV7XHJcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0KSBhcyBPYmplY3RUeXBlO1xyXG59XHJcblxyXG4vKipcclxuICogTWVyZ2VzIHR3byBvciBtb3JlIG9iamVjdHMgdG9nZXRoZXIuIElmIHRoZXkgaGF2ZSBzYW1lIHByb3BlcnR5IG5hbWVzLCBmb3JtZXIgb2JqZWN0cycgcHJvcGVydGllcyBnZXQgb3ZlcndyaXR0ZW4gYnkgbGF0ZXIgb2JqZWN0cycgcHJvcGVydGllcy5cclxuICpcclxuICogQHBhcmFtIG9iamVjdHNcclxuICovXHJcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvYmFuLXR5cGVzXHJcbmV4cG9ydCBmdW5jdGlvbiBjb21iaW5lT2JqZWN0cyguLi5vYmplY3RzOiBPYmplY3RbXSkge1xyXG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oe30sIC4uLm9iamVjdHMpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gbWVyZ2VTZXRzPFNldFR5cGU+KHNldDE6IFNldDxTZXRUeXBlPiwgc2V0MjogU2V0PFNldFR5cGU+KTogU2V0PFNldFR5cGU+IHtcclxuICAgIHJldHVybiBuZXcgU2V0PFNldFR5cGU+KFsuLi5zZXQxLCAuLi5zZXQyXSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIGEgbmV3IFNldCBjbG9uZWQgZnJvbSAnZnJvbV9zZXQnLCB3aXRoIGFsbCBpdGVtcyBwcmVzZW50ZWQgaW4gJ3JlbW92ZScgcmVtb3ZlZCBmcm9tIGl0LlxyXG4gKlxyXG4gKiBAcGFyYW0gZnJvbV9zZXRcclxuICogQHBhcmFtIHJlbW92ZSBDYW4gYmUgZWl0aGVyIGEgU2V0IG9mIHJlbW92YWJsZSBpdGVtcywgb3IgYSBzaW5nbGUgaXRlbS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiByZW1vdmVGcm9tU2V0PFNldFR5cGU+KGZyb21fc2V0OiBTZXQ8U2V0VHlwZT4sIHJlbW92ZTogU2V0PFNldFR5cGU+IHwgU2V0VHlwZSk6IFNldDxTZXRUeXBlPiB7XHJcbiAgICBjb25zdCByZWR1Y2VkX3NldCA9IG5ldyBTZXQoZnJvbV9zZXQpO1xyXG4gICAgaWYgKHJlbW92ZSBpbnN0YW5jZW9mIFNldCkge1xyXG4gICAgICAgIGZvciAoY29uc3QgcmVtb3ZhYmxlIG9mIHJlbW92ZSkge1xyXG4gICAgICAgICAgICByZWR1Y2VkX3NldC5kZWxldGUocmVtb3ZhYmxlKTtcclxuICAgICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIHJlZHVjZWRfc2V0LmRlbGV0ZShyZW1vdmUpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHJlZHVjZWRfc2V0O1xyXG59XHJcblxyXG4vKipcclxuICogU2FtZSBhcyBub3JtYWxpemVQYXRoKCksIGJ1dCBmaXhlcyB0aGVzZSBnbGl0Y2hlczpcclxuICogLSBMZWFkaW5nIGZvcndhcmQgc2xhc2hlcyAvIGJhY2t3YXJkIHNsYXNoZXMgc2hvdWxkIG5vdCBiZSByZW1vdmVkLlxyXG4gKiAtIFxcIHNob3VsZCBub3QgYmUgY29udmVydGVkIHRvIC8gaWYgcGxhdGZvcm0gaXMgV2luZG93cy4gSW4gb3RoZXIgd29yZHMsIC8gc2hvdWxkIGJlIGNvbnZlcnRlZCB0byBcXCBpZiBwbGF0Zm9ybSBpcyBXaW5kb3dzLlxyXG4gKlxyXG4gKiBUT0RPOiBJJ3ZlIG9wZW5lZCBhIGRpc2N1c3Npb24gYWJvdXQgdGhpcyBvbiBPYnNpZGlhbidzIGZvcnVtcy4gSWYgYW55dGhpbmcgbmV3IGNvbWVzIHVwIGluIHRoZSBkaXNjdXNzaW9uLCBtYWtlIGNoYW5nZXMgYWNjb3JkaW5nbHkuIGh0dHBzOi8vZm9ydW0ub2JzaWRpYW4ubWQvdC9ub3JtYWxpemVwYXRoLXJlbW92ZXMtYS1sZWFkaW5nLzI0NzEzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplUGF0aDIocGF0aDogc3RyaW5nKSB7XHJcbiAgICAvLyAxLiBQcmVwYXJhdGlvbnNcclxuICAgIHBhdGggPSBwYXRoLnRyaW0oKTtcclxuICAgIGNvbnN0IGxlYWRpbmdfc2xhc2hlc19yZWdleHAgPSAvXlsvXFxcXF0qL2d1OyAvLyBHZXQgYXMgbWFueSAvIG9yIFxcIHNsYXNoZXMgYXMgdGhlcmUgYXJlIGluIHRoZSB2ZXJ5IGJlZ2lubmluZyBvZiBwYXRoLiBDYW4gYWxzbyBiZSBcIlwiIChhbiBlbXB0eSBzdHJpbmcpLlxyXG4gICAgY29uc3QgbGVhZGluZ19zbGFzaGVzX2FycmF5ID0gbGVhZGluZ19zbGFzaGVzX3JlZ2V4cC5leGVjKHBhdGgpOyAvLyBBbiBhcnJheSB3aXRoIG9ubHkgb25lIGl0ZW0uXHJcbiAgICBpZiAobnVsbCA9PT0gbGVhZGluZ19zbGFzaGVzX2FycmF5KSB7XHJcbiAgICAgICAgLy8gSXQgc2hvdWxkIGFsd2F5cyBtYXRjaC4gVGhpcyBleGNlcHRpb24gc2hvdWxkIG5ldmVyIGhhcHBlbiwgYnV0IGhhdmUgaXQganVzdCBpbiBjYXNlLlxyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIm5vcm1hbGl6ZVBhdGgyKCk6IGxlYWRpbmdfc2xhc2hlc19yZWdleHAgZGlkIG5vdCBtYXRjaC5cIik7XHJcbiAgICB9XHJcbiAgICBsZXQgbGVhZGluZ19zbGFzaGVzID0gbGVhZGluZ19zbGFzaGVzX2FycmF5WzBdO1xyXG5cclxuICAgIC8vIDIuIFJ1biB0aGUgb3JpZ2luYWwgbm9ybWFsaXplUGF0aCgpXHJcbiAgICBwYXRoID0gbm9ybWFsaXplUGF0aChwYXRoKTtcclxuXHJcbiAgICAvLyAzLiBGaXhlc1xyXG4gICAgLy8gQ2hlY2sgdGhhdCBjb3JyZWN0IHNsYXNoZXMgYXJlIHVzZWQuXHJcbiAgICBpZiAoaXNXaW5kb3dzKCkpIHtcclxuICAgICAgICAvLyBUaGUgcGxhdGZvcm0gaXMgV2luZG93cy5cclxuICAgICAgICAvLyBDb252ZXJ0IC8gdG8gXFxcclxuICAgICAgICBwYXRoID0gcGF0aC5yZXBsYWNlKC9cXC8vZ3UsIFwiXFxcXFwiKTsgLy8gTmVlZCB0byB1c2UgYSByZWdleHAgaW5zdGVhZCBvZiBhIG5vcm1hbCBcIi9cIiAtPiBcIlxcXFxcIiByZXBsYWNlIGJlY2F1c2UgdGhlIG5vcm1hbCByZXBsYWNlIHdvdWxkIG9ubHkgcmVwbGFjZSBmaXJzdCBvY2N1cnJlbmNlIG9mIC8uXHJcbiAgICAgICAgbGVhZGluZ19zbGFzaGVzID0gbGVhZGluZ19zbGFzaGVzLnJlcGxhY2UoL1xcLy9ndSwgXCJcXFxcXCIpOyAvLyBTYW1lIGhlcmUuXHJcbiAgICB9XHJcbiAgICAvLyBOb3cgZW5zdXJlIHRoYXQgcGF0aCBzdGlsbCBjb250YWlucyBsZWFkaW5nIHNsYXNoZXMgKGlmIHRoZXJlIHdlcmUgYW55IGJlZm9yZSBjYWxsaW5nIG5vcm1hbGl6ZVBhdGgoKSkuXHJcbiAgICAvLyBDaGVjayB0aGF0IHRoZSBwYXRoIHNob3VsZCBoYXZlIGEgc2ltaWxhciBzZXQgb2YgbGVhZGluZyBzbGFzaGVzIGF0IHRoZSBiZWdpbm5pbmcuIEl0IGNhbiBiZSBhdCBsZWFzdCBcIi9cIiAob24gbGludXgvTWFjKSwgb3IgXCJcXFxcXCIgKG9uIFdpbmRvd3Mgd2hlbiBpdCdzIGEgbmV0d29yayBwYXRoKSwgaW4gdGhlb3J5IGV2ZW4gXCIvLy9cIiBvciBcIlxcXFxcXFxcXFxcIiB3aGF0ZXZlci5cclxuICAgIC8vIG5vcm1hbGl6ZVBhdGgoKSBzZWVtcyB0byByZW1vdmUgbGVhZGluZyBzbGFzaGVzIChhbmQgdGhleSBhcmUgbmVlZGVkIHRvIGJlIHJlLWFkZGVkKSwgYnV0IGl0J3MgbmVlZGVkIHRvIGNoZWNrIGZpcnN0LCBvdGhlcndpc2UgdGhlIHBhdGggd291bGQgaGF2ZSBkb3VibGUgbGVhZGluZyBzbGFzaGVzIGlmIG5vcm1hbGl6ZVBhdGgoKSBnZXRzIGZpeGVkIGluIHRoZSBmdXR1cmUuXHJcbiAgICBpZiAobGVhZGluZ19zbGFzaGVzLmxlbmd0aCAmJiBwYXRoLnNsaWNlKDAsIGxlYWRpbmdfc2xhc2hlcy5sZW5ndGgpICE9PSBsZWFkaW5nX3NsYXNoZXMpIHtcclxuICAgICAgICAvLyBUaGUgcGF0aCBkb2VzIG5vdCBjb250YWluIHRoZSByZXF1aXJlZCBzZXQgb2YgbGVhZGluZyBzbGFzaGVzLCBzbyBhZGQgdGhlbS5cclxuICAgICAgICBwYXRoID0gbGVhZGluZ19zbGFzaGVzICsgcGF0aDtcclxuICAgIH1cclxuXHJcbiAgICAvLyA0LiBEb25lXHJcbiAgICByZXR1cm4gcGF0aDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RGaWxlTmFtZShmaWxlX3BhdGg6IHN0cmluZywgd2l0aF9leHRlbnNpb24gPSB0cnVlKSB7XHJcbiAgICBpZiAod2l0aF9leHRlbnNpb24pIHtcclxuICAgICAgICByZXR1cm4gcGF0aC5wYXJzZShmaWxlX3BhdGgpLmJhc2U7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIHJldHVybiBwYXRoLnBhcnNlKGZpbGVfcGF0aCkubmFtZTtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RGaWxlUGFyZW50UGF0aChmaWxlX3BhdGg6IHN0cmluZykge1xyXG4gICAgcmV0dXJuIHBhdGgucGFyc2UoZmlsZV9wYXRoKS5kaXI7XHJcbn1cclxuXHJcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvYmFuLXR5cGVzXHJcbmV4cG9ydCBmdW5jdGlvbiBqb2luT2JqZWN0UHJvcGVydGllcyhvYmplY3Q6IHt9LCBnbHVlOiBzdHJpbmcpIHtcclxuICAgIGxldCByZXN1bHQgPSBcIlwiO1xyXG4gICAgZm9yIChjb25zdCBwcm9wZXJ0eV9uYW1lIGluIG9iamVjdCkge1xyXG4gICAgICAgIGlmIChyZXN1bHQubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgIHJlc3VsdCArPSBnbHVlO1xyXG4gICAgICAgIH1cclxuICAgICAgICAvLyBAdHMtaWdub3JlXHJcbiAgICAgICAgcmVzdWx0ICs9IG9iamVjdFtwcm9wZXJ0eV9uYW1lXTtcclxuICAgIH1cclxuICAgIHJldHVybiByZXN1bHQ7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZW1vdmVzIGFsbCBkdXBsaWNhdGVzIGZyb20gYW4gYXJyYXkuXHJcbiAqXHJcbiAqIElkZWEgaXMgY29waWVkIDIwMjEtMTAtMDYgZnJvbSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzMxMjE4ODAvMjc1NDAyNlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHVuaXF1ZUFycmF5KGFycmF5OiBhbnlbXSkge1xyXG4gICAgcmV0dXJuIFsuLi5uZXcgU2V0KGFycmF5KV07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBPcGVucyBhIHdlYiBicm93c2VyIGluIHRoZSBzcGVjaWZpZWQgVVJMLlxyXG4gKiBAcGFyYW0gdXJsXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ290b1VSTCh1cmw6IHN0cmluZykge1xyXG4gICAgc2hlbGwub3BlbkV4dGVybmFsKHVybCk7IC8vIFRoaXMgcmV0dXJucyBhIHByb21pc2UsIGJ1dCBpdCBjYW4gYmUgaWdub3JlZCBhcyB0aGVyZSdzIG5vdGhpbmcgdG8gZG8gYWZ0ZXIgb3BlbmluZyB0aGUgYnJvd3Nlci5cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlT2JzaWRpYW5Db21tYW5kTmFtZShwbHVnaW46IFNDX1BsdWdpbiwgc2hlbGxfY29tbWFuZDogc3RyaW5nLCBhbGlhczogc3RyaW5nKSB7XHJcbiAgICBjb25zdCBwcmVmaXggPSBwbHVnaW4uc2V0dGluZ3Mub2JzaWRpYW5fY29tbWFuZF9wYWxldHRlX3ByZWZpeDtcclxuICAgIGlmIChhbGlhcykge1xyXG4gICAgICAgIC8vIElmIGFuIGFsaWFzIGlzIHNldCBmb3IgdGhlIGNvbW1hbmQsIE9ic2lkaWFuJ3MgY29tbWFuZCBwYWxldHRlIHNob3VsZCBkaXNwbGF5IHRoZSBhbGlhcyB0ZXh0IGluc3RlYWQgb2YgdGhlIGFjdHVhbCBjb21tYW5kLlxyXG4gICAgICAgIHJldHVybiBwcmVmaXggKyBhbGlhcztcclxuICAgIH1cclxuICAgIHJldHVybiBwcmVmaXggKyBzaGVsbF9jb21tYW5kO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gaXNJbnRlZ2VyKHZhbHVlOiBzdHJpbmcsIGFsbG93X21pbnVzOiBib29sZWFuKTogYm9vbGVhbiB7XHJcbiAgICBpZiAoYWxsb3dfbWludXMpIHtcclxuICAgICAgICByZXR1cm4gISF2YWx1ZS5tYXRjaCgvXi0/XFxkKyQvdSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIHJldHVybiAhIXZhbHVlLm1hdGNoKC9eXFxkKyQvdSk7XHJcbiAgICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBUcmFuc2xhdGVzIDEtaW5kZXhlZCBjYXJldCBsaW5lIGFuZCBjb2x1bW4gdG8gYSAwLWluZGV4ZWQgRWRpdG9yUG9zaXRpb24gb2JqZWN0LiBBbHNvIHRyYW5zbGF0ZXMgYSBwb3NzaWJseSBuZWdhdGl2ZSBsaW5lXHJcbiAqIHRvIGEgcG9zaXRpdmUgbGluZSBmcm9tIHRoZSBlbmQgb2YgdGhlIGZpbGUsIGFuZCBhIHBvc3NpYmx5IG5lZ2F0aXZlIGNvbHVtbiB0byBhIHBvc2l0aXZlIGNvbHVtbiBmcm9tIHRoZSBlbmQgb2YgdGhlIGxpbmUuXHJcbiAqIEBwYXJhbSBlZGl0b3JcclxuICogQHBhcmFtIGNhcmV0X2xpbmVcclxuICogQHBhcmFtIGNhcmV0X2NvbHVtblxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByZXBhcmVFZGl0b3JQb3NpdGlvbihlZGl0b3I6IEVkaXRvciwgY2FyZXRfbGluZTogbnVtYmVyLCBjYXJldF9jb2x1bW46IG51bWJlcik6IEVkaXRvclBvc2l0aW9uIHtcclxuICAgIC8vIERldGVybWluZSBsaW5lXHJcbiAgICBpZiAoY2FyZXRfbGluZSA8IDApIHtcclxuICAgICAgICAvLyBOZWdhdGl2ZSBsaW5lIG1lYW5zIHRvIGNhbGN1bGF0ZSBpdCBmcm9tIHRoZSBlbmQgb2YgdGhlIGZpbGUuXHJcbiAgICAgICAgY2FyZXRfbGluZSA9IE1hdGgubWF4KDAsIGVkaXRvci5sYXN0TGluZSgpICsgY2FyZXRfbGluZSArIDEpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBQb3NpdGl2ZSBsaW5lIG5lZWRzIGp1c3QgYSBzbWFsbCBhZGp1c3RtZW50LlxyXG4gICAgICAgIC8vIEVkaXRvciBsaW5lIGlzIHplcm8taW5kZXhlZCwgbGluZSBudW1iZXJzIGFyZSAxLWluZGV4ZWQuXHJcbiAgICAgICAgY2FyZXRfbGluZSAtPSAxO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERldGVybWluZSBjb2x1bW5cclxuICAgIGlmIChjYXJldF9jb2x1bW4gPCAwKSB7XHJcbiAgICAgICAgLy8gTmVnYXRpdmUgY29sdW1uIG1lYW5zIHRvIGNhbGN1bGF0ZSBpdCBmcm9tIHRoZSBlbmQgb2YgdGhlIGxpbmUuXHJcbiAgICAgICAgY2FyZXRfY29sdW1uID0gTWF0aC5tYXgoMCwgZWRpdG9yLmdldExpbmUoY2FyZXRfbGluZSkubGVuZ3RoICsgY2FyZXRfY29sdW1uICsgMSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFBvc2l0aXZlIGNvbHVtbiBuZWVkcyBqdXN0IGEgc21hbGwgYWRqdXN0bWVudC5cclxuICAgICAgICAvLyBFZGl0b3IgY29sdW1uIGlzIHplcm8taW5kZXhlZCwgY29sdW1uIG51bWJlcnMgYXJlIDEtaW5kZXhlZC5cclxuICAgICAgICBjYXJldF9jb2x1bW4gLT0gMTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAgIGxpbmU6IGNhcmV0X2xpbmUsXHJcbiAgICAgICAgY2g6IGNhcmV0X2NvbHVtbixcclxuICAgIH07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRTZWxlY3Rpb25Gcm9tVGV4dGFyZWEodGV4dGFyZWFfZWxlbWVudDogSFRNTFRleHRBcmVhRWxlbWVudCwgcmV0dXJuX251bGxfaWZfZW1wdHk6IHRydWUpOiBzdHJpbmcgfCBudWxsO1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2VsZWN0aW9uRnJvbVRleHRhcmVhKHRleHRhcmVhX2VsZW1lbnQ6IEhUTUxUZXh0QXJlYUVsZW1lbnQsIHJldHVybl9udWxsX2lmX2VtcHR5OiBmYWxzZSk6IHN0cmluZztcclxuZXhwb3J0IGZ1bmN0aW9uIGdldFNlbGVjdGlvbkZyb21UZXh0YXJlYSh0ZXh0YXJlYV9lbGVtZW50OiBIVE1MVGV4dEFyZWFFbGVtZW50LCByZXR1cm5fbnVsbF9pZl9lbXB0eTogYm9vbGVhbik6IHN0cmluZyB8IG51bGwge1xyXG4gICAgY29uc3Qgc2VsZWN0ZWRfdGV4dCA9IHRleHRhcmVhX2VsZW1lbnQudmFsdWUuc3Vic3RyaW5nKHRleHRhcmVhX2VsZW1lbnQuc2VsZWN0aW9uU3RhcnQsIHRleHRhcmVhX2VsZW1lbnQuc2VsZWN0aW9uRW5kKTtcclxuICAgIHJldHVybiBcIlwiID09PSBzZWxlY3RlZF90ZXh0ICYmIHJldHVybl9udWxsX2lmX2VtcHR5ID8gbnVsbCA6IHNlbGVjdGVkX3RleHQ7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIEhUTUxFbGVtZW50ICh3aXRoIGZyZWVseSBkZWNpZGFibGUgdGFnKSBhbmQgYWRkcyB0aGUgZ2l2ZW4gY29udGVudCBpbnRvIGl0IGFzIG5vcm1hbCB0ZXh0LiBObyBIVE1MIGZvcm1hdHRpbmdcclxuICogaXMgc3VwcG9ydGVkLCBpLmUuIHBvc3NpYmxlIEhUTUwgc3BlY2lhbCBjaGFyYWN0ZXJzIGFyZSBzaG93biBhcy1pcy4gTmV3bGluZSBjaGFyYWN0ZXJzIGFyZSBjb252ZXJ0ZWQgdG8gPGJyPiBlbGVtZW50cy5cclxuICpcclxuICogQHBhcmFtIHRhZ1xyXG4gKiBAcGFyYW0gY29udGVudFxyXG4gKiBAcGFyYW0gcGFyZW50X2VsZW1lbnRcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVNdWx0aWxpbmVUZXh0RWxlbWVudCh0YWc6IGtleW9mIEhUTUxFbGVtZW50VGFnTmFtZU1hcCwgY29udGVudDogc3RyaW5nLCBwYXJlbnRfZWxlbWVudDogSFRNTEVsZW1lbnQpIHtcclxuICAgIGNvbnN0IGNvbnRlbnRfZWxlbWVudCA9IHBhcmVudF9lbGVtZW50LmNyZWF0ZUVsKHRhZyk7XHJcblxyXG4gICAgLy8gSW5zZXJ0IGNvbnRlbnQgbGluZS1ieS1saW5lXHJcbiAgICBjb25zdCBjb250ZW50X2xpbmVzID0gY29udGVudC5zcGxpdCgvXFxyXFxufFxccnxcXG4vZyk7IC8vIERvbid0IHVzZSAoICkgd2l0aCB8IGJlY2F1c2UgLnNwbGl0KCkgd291bGQgdGhlbiBpbmNsdWRlIHRoZSBuZXdsaW5lIGNoYXJhY3RlcnMgaW4gdGhlIHJlc3VsdGluZyBhcnJheS5cclxuICAgIGNvbnRlbnRfbGluZXMuZm9yRWFjaCgoY29udGVudF9saW5lOiBzdHJpbmcsIGNvbnRlbnRfbGluZV9pbmRleDogbnVtYmVyKSA9PiB7XHJcbiAgICAgICAgLy8gSW5zZXJ0IHRoZSBsaW5lLlxyXG4gICAgICAgIGNvbnRlbnRfZWxlbWVudC5pbnNlcnRBZGphY2VudFRleHQoXCJiZWZvcmVlbmRcIiwgY29udGVudF9saW5lKTtcclxuXHJcbiAgICAgICAgLy8gSW5zZXJ0IGEgbGluZWJyZWFrIDxicj4gaWYgbmVlZGVkLlxyXG4gICAgICAgIGlmIChjb250ZW50X2xpbmVfaW5kZXggPCBjb250ZW50X2xpbmVzLmxlbmd0aCAtIDEpIHtcclxuICAgICAgICAgICAgY29udGVudF9lbGVtZW50Lmluc2VydEFkamFjZW50SFRNTChcImJlZm9yZWVuZFwiLCBcIjxicj5cIik7XHJcbiAgICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICByZXR1cm4gY29udGVudF9lbGVtZW50O1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gcmFuZG9tSW50ZWdlcihtaW46IG51bWJlciwgbWF4OiBudW1iZXIpIHtcclxuICAgIGNvbnN0IHJhbmdlID0gbWF4IC0gbWluICsgMTtcclxuICAgIHJldHVybiBtaW4gKyBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiByYW5nZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBEb2VzIHRoZSBmb2xsb3dpbmcgcHJlZml4aW5nczpcclxuICogICBcXCB3aWxsIGJlY29tZSBcXFxcXHJcbiAqICAgWyB3aWxsIGJlY29tZSBcXFtcclxuICogICBdIHdpbGwgYmVjb21lIFxcXVxyXG4gKiAgICggd2lsbCBiZWNvbWUgXFwoXHJcbiAqICAgKSB3aWxsIGJlY29tZSBcXClcclxuICpcclxuICogQHBhcmFtIGNvbnRlbnRcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlc2NhcGVNYXJrZG93bkxpbmtDaGFyYWN0ZXJzKGNvbnRlbnQ6IHN0cmluZykge1xyXG4gICAgLy8gVE9ETzogXFxbIGNhbiBiZSByZXBsYWNlZCB3aXRoIFsgYXMgZXNsaW50IHN1Z2dlc3RzIGFuZCB0ZW4gcmVtb3ZlIHRoZSBpZ25vcmUgbGluZSBiZWxvdy4gSSdtIG5vdCBkb2luZyBpdCBub3cgYmVjYXVzZSBpdCB3b3VsZCBiZSBvdXRzaWRlIG9mIHRoZSBzY29wZSBvZiB0aGlzIGNvbW1pdC9pc3N1ZSAjNzAuXHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdXNlbGVzcy1lc2NhcGVcclxuICAgIHJldHVybiBjb250ZW50LnJlcGxhY2UoL1tcXFxcKClcXFtcXF1dL2d1LCBcIlxcXFwkJlwiKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNvcHlUb0NsaXBib2FyZCh0ZXh0OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIHJldHVybiBjbGlwYm9hcmQud3JpdGVUZXh0KHRleHQpO1xyXG59XHJcblxyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0RmlsZUNvbnRlbnRXaXRob3V0WUFNTChhcHA6IEFwcCwgZmlsZTogVEZpbGUpOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XHJcbiAgICAgICAgLy8gVGhlIGxvZ2ljIGlzIGJvcnJvd2VkIDIwMjItMDktMDEgZnJvbSBodHRwczovL2ZvcnVtLm9ic2lkaWFuLm1kL3QvaG93LXRvLWdldC1jdXJyZW50LWZpbGUtY29udGVudC13aXRob3V0LXlhbWwtZnJvbnRtYXR0ZXIvMjYxOTcvMlxyXG4gICAgICAgIC8vIFRoYW5rIHlvdSwgZW5kb3JhbWEhIDwzXHJcbiAgICAgICAgY29uc3QgZmlsZV9jb250ZW50ID0gYXBwLnZhdWx0LnJlYWQoZmlsZSk7XHJcbiAgICAgICAgZmlsZV9jb250ZW50LnRoZW4oKGZpbGVfY29udGVudDogc3RyaW5nKSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IGZyb250bWF0dGVyX2NhY2hlOiBGcm9udE1hdHRlckNhY2hlIHwgdW5kZWZpbmVkID0gYXBwLm1ldGFkYXRhQ2FjaGUuZ2V0RmlsZUNhY2hlKGZpbGUpPy5mcm9udG1hdHRlcjtcclxuICAgICAgICAgICAgaWYgKGZyb250bWF0dGVyX2NhY2hlKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBBIFlBTUwgZnJvbnRtYXR0ZXIgaXMgcHJlc2VudCBpbiB0aGUgZmlsZS5cclxuICAgICAgICAgICAgICAgIGNvbnN0IGZyb250bWF0dGVyX2VuZF9saW5lX251bWJlciA9IGZyb250bWF0dGVyX2NhY2hlLnBvc2l0aW9uLmVuZC5saW5lICsgMTsgLy8gKyAxOiBUYWtlIHRoZSBsYXN0IC0tLSBsaW5lIGludG8gYWNjb3VudCwgdG9vLlxyXG4gICAgICAgICAgICAgICAgY29uc3QgZmlsZV9jb250ZW50X3dpdGhvdXRfZnJvbnRtYXR0ZXI6IHN0cmluZyA9IGZpbGVfY29udGVudC5zcGxpdChcIlxcblwiKS5zbGljZShmcm9udG1hdHRlcl9lbmRfbGluZV9udW1iZXIpLmpvaW4oXCJcXG5cIik7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzb2x2ZShmaWxlX2NvbnRlbnRfd2l0aG91dF9mcm9udG1hdHRlcik7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBObyBZQU1MIGZyb250bWF0dGVyIGlzIHByZXNlbnQgaW4gdGhlIGZpbGUuXHJcbiAgICAgICAgICAgICAgICAvLyBSZXR1cm4gdGhlIHdob2xlIGZpbGUgY29udGVudCwgYmVjYXVzZSB0aGVyZSdzIG5vdGhpbmcgdG8gcmVtb3ZlLlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlc29sdmUoZmlsZV9jb250ZW50KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRGaWxlWUFNTChhcHA6IEFwcCwgZmlsZTogVEZpbGUsIHdpdGhEYXNoZXM6IGJvb2xlYW4pOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcclxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xyXG4gICAgICAgIC8vIFRoZSBsb2dpYyBpcyBib3Jyb3dlZCAyMDIyLTA5LTAxIGZyb20gaHR0cHM6Ly9mb3J1bS5vYnNpZGlhbi5tZC90L2hvdy10by1nZXQtY3VycmVudC1maWxlLWNvbnRlbnQtd2l0aG91dC15YW1sLWZyb250bWF0dGVyLzI2MTk3LzJcclxuICAgICAgICAvLyBUaGFuayB5b3UsIGVuZG9yYW1hISA8M1xyXG4gICAgICAgIGNvbnN0IGZpbGVDb250ZW50ID0gYXBwLnZhdWx0LnJlYWQoZmlsZSk7XHJcbiAgICAgICAgZmlsZUNvbnRlbnQudGhlbigoZmlsZV9jb250ZW50OiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgY29uc3QgZnJvbnRtYXR0ZXJDYWNoZTogRnJvbnRNYXR0ZXJDYWNoZSB8IHVuZGVmaW5lZCA9IGFwcC5tZXRhZGF0YUNhY2hlLmdldEZpbGVDYWNoZShmaWxlKT8uZnJvbnRtYXR0ZXI7XHJcbiAgICAgICAgICAgIGlmIChmcm9udG1hdHRlckNhY2hlKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBBIFlBTUwgZnJvbnRtYXR0ZXIgaXMgcHJlc2VudCBpbiB0aGUgZmlsZS5cclxuICAgICAgICAgICAgICAgIGNvbnN0IGZyb250bWF0dGVyRW5kTGluZU51bWJlciA9IGZyb250bWF0dGVyQ2FjaGUucG9zaXRpb24uZW5kLmxpbmUgKyAxOyAvLyArIDE6IFRha2UgdGhlIGxhc3QgLS0tIGxpbmUgaW50byBhY2NvdW50LCB0b28uXHJcbiAgICAgICAgICAgICAgICBsZXQgZmlyc3RMaW5lOiBudW1iZXI7XHJcbiAgICAgICAgICAgICAgICBsZXQgbGFzdExpbmU6IG51bWJlcjtcclxuICAgICAgICAgICAgICAgIGlmICh3aXRoRGFzaGVzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGFrZSBmdWxsIFlBTUwgY29udGVudCwgaW5jbHVkaW5nIC0tLSBsaW5lcyBhdCB0aGUgdG9wIGFuZCBib3R0b20uXHJcbiAgICAgICAgICAgICAgICAgICAgZmlyc3RMaW5lID0gMDtcclxuICAgICAgICAgICAgICAgICAgICBsYXN0TGluZSA9IGZyb250bWF0dGVyRW5kTGluZU51bWJlcjtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gRXhjbHVkZSAtLS0gbGluZXMuXHJcbiAgICAgICAgICAgICAgICAgICAgZmlyc3RMaW5lID0gMTtcclxuICAgICAgICAgICAgICAgICAgICBsYXN0TGluZSA9IGZyb250bWF0dGVyRW5kTGluZU51bWJlci0xO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgY29uc3QgZnJvbnRtYXR0ZXJDb250ZW50OiBzdHJpbmcgPSBmaWxlX2NvbnRlbnQuc3BsaXQoXCJcXG5cIikuc2xpY2UoZmlyc3RMaW5lLGxhc3RMaW5lKS5qb2luKFwiXFxuXCIpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlc29sdmUoZnJvbnRtYXR0ZXJDb250ZW50KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIE5vIFlBTUwgZnJvbnRtYXR0ZXIgaXMgcHJlc2VudCBpbiB0aGUgZmlsZS5cclxuICAgICAgICAgICAgICAgIHJldHVybiByZXNvbHZlKG51bGwpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICB9KTtcclxufSIsIlxyXG4vKipcclxuICogRXNjYXBlcyBhIHN0cmluZyB0aGF0IHdpbGwgYmUgdXNlZCBhcyBhIHBhdHRlcm4gaW4gYSByZWd1bGFyIGV4cHJlc3Npb24uXHJcbiAqXHJcbiAqIE5vdGUgdGhhdCB0aGlzIGRvZXMgbm90IGVzY2FwZSBtaW51czogLSAuIEl0J3MgcHJvYmFibHkgb2sgYXMgbG9uZyBhcyB5b3Ugd29uJ3Qgd3JhcCB0aGUgcmVzdWx0IG9mIHRoaXMgZnVuY3Rpb24gaW4gc3F1YXJlIGJyYWNrZXRzIFsgXSAuIEZvciBtb3JlIGluZm9ybWF0aW9uLCByZWFkIGEgY29tbWVudCBieSBjb29sYWo4NiBvbiBOb3YgMjksIDIwMTkgYXQgMjo0NCBpbiB0aGlzIFN0YWNrIE92ZXJmbG93IGFuc3dlcjogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzY5Njk0ODYvMjc1NDAyNlxyXG4gKlxyXG4gKiBDb3BpZWQgMjAyMi0wMy0xMCBmcm9tIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvR3VpZGUvUmVndWxhcl9FeHByZXNzaW9ucyNlc2NhcGluZ1xyXG4gKiBNb2RpZmljYXRpb25zOlxyXG4gKiAgLSBBZGRlZCBUeXBlU2NyaXB0IGRhdGEgdHlwZSBoaW50cyBmb3IgdGhlIHBhcmFtZXRlciBhbmQgcmV0dXJuIHZhbHVlLlxyXG4gKiAgLSBBZGRlZCAnZXhwb3J0JyBrZXl3b3JkLlxyXG4gKiAgLSBBZGRlZCB0aGlzIEpTRG9jLlxyXG4gKiAgLSBObyBvdGhlciBjaGFuZ2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0gc3RyaW5nXHJcbiAqIEByZXR1cm4gc3RyaW5nXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZXNjYXBlUmVnRXhwKHN0cmluZzogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBzdHJpbmcucmVwbGFjZSgvWy4qKz9eJHt9KCl8W1xcXVxcXFxdL2csICdcXFxcJCYnKTsgLy8gJCYgbWVhbnMgdGhlIHdob2xlIG1hdGNoZWQgc3RyaW5nXHJcbn1cclxuIiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5leHBvcnQgY29uc3QgRG9jdW1lbnRhdGlvbk1haW5MaW5rID0gXCJodHRwczovL3B1Ymxpc2gub2JzaWRpYW4ubWQvc2hlbGxjb21tYW5kc1wiO1xyXG5leHBvcnQgY29uc3QgRG9jdW1lbnRhdGlvbkJ1aWx0SW5WYXJpYWJsZXNCYXNlTGluayA9IFwiaHR0cHM6Ly9wdWJsaXNoLm9ic2lkaWFuLm1kL3NoZWxsY29tbWFuZHMvVmFyaWFibGVzL1wiOyAvLyBXaGVuIHVzZWQsIGEgdmFyaWFibGUncyBuYW1lIHdpbGwgYmUgYXBwZW5kZWQgdG8gdGhlIGVuZC4gS2VlcCB0aGUgdHJhaWxpbmcgc2xhc2ghXHJcbmV4cG9ydCBjb25zdCBEb2N1bWVudGF0aW9uQnVpbHRJblZhcmlhYmxlc0luZGV4TGluayA9IFwiaHR0cHM6Ly9wdWJsaXNoLm9ic2lkaWFuLm1kL3NoZWxsY29tbWFuZHMvVmFyaWFibGVzL1ZhcmlhYmxlcystK2dlbmVyYWwrcHJpbmNpcGxlcyNBbGwrdmFyaWFibGVzXCI7XHJcbmV4cG9ydCBjb25zdCBEb2N1bWVudGF0aW9uQ3VzdG9tVmFyaWFibGVzTGluayA9IFwiaHR0cHM6Ly9wdWJsaXNoLm9ic2lkaWFuLm1kL3NoZWxsY29tbWFuZHMvVmFyaWFibGVzL0N1c3RvbSt2YXJpYWJsZXNcIjtcclxuZXhwb3J0IGNvbnN0IERvY3VtZW50YXRpb25BdXRvY29tcGxldGVMaW5rID0gXCJodHRwczovL3B1Ymxpc2gub2JzaWRpYW4ubWQvc2hlbGxjb21tYW5kcy9WYXJpYWJsZXMvQXV0b2NvbXBsZXRlL0F1dG9jb21wbGV0ZVwiO1xyXG5leHBvcnQgY29uc3QgRG9jdW1lbnRhdGlvbkV2ZW50c0ZvbGRlckxpbmsgPSBcImh0dHBzOi8vcHVibGlzaC5vYnNpZGlhbi5tZC9zaGVsbGNvbW1hbmRzL0V2ZW50cy9cIjtcclxuZXhwb3J0IGNvbnN0IERvY3VtZW50YXRpb25QQVRIQXVnbWVudGF0aW9uc0xpbmsgPSBcImh0dHBzOi8vcHVibGlzaC5vYnNpZGlhbi5tZC9zaGVsbGNvbW1hbmRzL0Vudmlyb25tZW50cy9BZGRpdGlvbnMrdG8rdGhlK1BBVEgrZW52aXJvbm1lbnQrdmFyaWFibGVcIjtcclxuZXhwb3J0IGNvbnN0IERvY3VtZW50YXRpb25PdXRwdXRXcmFwcGVyc0xpbmsgPSBcImh0dHBzOi8vcHVibGlzaC5vYnNpZGlhbi5tZC9zaGVsbGNvbW1hbmRzL091dHB1dCtoYW5kbGluZy9PdXRwdXQrd3JhcHBlcnNcIjtcclxuZXhwb3J0IGNvbnN0IERvY3VtZW50YXRpb25PdXRwdXRIYW5kbGluZ01vZGVMaW5rID0gXCJodHRwczovL3B1Ymxpc2gub2JzaWRpYW4ubWQvc2hlbGxjb21tYW5kcy9PdXRwdXQraGFuZGxpbmcvUmVhbHRpbWUrb3V0cHV0K2hhbmRsaW5nXCI7XHJcbmV4cG9ydCBjb25zdCBEb2N1bWVudGF0aW9uU3RkaW5Db250ZW50TGluayA9IFwiaHR0cHM6Ly9wdWJsaXNoLm9ic2lkaWFuLm1kL3NoZWxsY29tbWFuZHMvVmFyaWFibGVzL1Bhc3MrdmFyaWFibGVzK3RvK3N0ZGluXCI7XHJcbmV4cG9ydCBjb25zdCBHaXRIdWJMaW5rID0gXCJodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9vYnNpZGlhbi1zaGVsbGNvbW1hbmRzXCI7XHJcbmV4cG9ydCBjb25zdCBDaGFuZ2Vsb2dMaW5rID0gXCJodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9vYnNpZGlhbi1zaGVsbGNvbW1hbmRzL2Jsb2IvbWFpbi9DSEFOR0VMT0cubWRcIjtcclxuZXhwb3J0IGNvbnN0IExpY2Vuc2VMaW5rID0gXCJodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9vYnNpZGlhbi1zaGVsbGNvbW1hbmRzL2Jsb2IvbWFpbi9MSUNFTlNFXCI7IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0FwcH0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uL21haW5cIjtcclxuaW1wb3J0IHtJQXV0b2NvbXBsZXRlSXRlbX0gZnJvbSBcIi4uL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvQXV0b2NvbXBsZXRlXCI7XHJcbmltcG9ydCB7U0NfRXZlbnR9IGZyb20gXCIuLi9ldmVudHMvU0NfRXZlbnRcIjtcclxuaW1wb3J0IHtlc2NhcGVSZWdFeHB9IGZyb20gXCIuLi9saWIvZXNjYXBlUmVnRXhwXCI7XHJcbmltcG9ydCB7VFNoZWxsQ29tbWFuZH0gZnJvbSBcIi4uL1RTaGVsbENvbW1hbmRcIjtcclxuaW1wb3J0IHtkZWJ1Z0xvZ30gZnJvbSBcIi4uL0RlYnVnXCI7XHJcbmltcG9ydCB7UGFyc2luZ1Jlc3VsdH0gZnJvbSBcIi4vcGFyc2VWYXJpYWJsZXNcIjtcclxuaW1wb3J0IHtEb2N1bWVudGF0aW9uQnVpbHRJblZhcmlhYmxlc0Jhc2VMaW5rfSBmcm9tIFwiLi4vRG9jdW1lbnRhdGlvblwiO1xyXG5pbXBvcnQge0VPTH0gZnJvbSBcIm9zXCI7XHJcblxyXG4vKipcclxuICogVmFyaWFibGVzIHRoYXQgY2FuIGJlIHVzZWQgdG8gaW5qZWN0IHZhbHVlcyB0byBzaGVsbCBjb21tYW5kcyB1c2luZyB7e3ZhcmlhYmxlOmFyZ3VtZW50fX0gc3ludGF4LlxyXG4gKi9cclxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFZhcmlhYmxlIHtcclxuICAgIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IHBhcmFtZXRlcl9zZXBhcmF0b3IgPSBcIjpcIjtcclxuICAgIHByb3RlY3RlZCByZWFkb25seSBhcHA6IEFwcDtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lOiBzdHJpbmc7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0OiBzdHJpbmc7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJZiB0aGlzIGlzIGZhbHNlLCB0aGUgdmFyaWFibGUgY2FuIGJlIGFzc2lnbmVkIGEgZGVmYXVsdCB2YWx1ZSB0aGF0IGNhbiBiZSB1c2VkIGluIHNpdHVhdGlvbnMgd2hlcmUgdGhlIHZhcmlhYmxlIGlzIHVuYXZhaWxhYmxlLlxyXG4gICAgICogVE9ETzogU2V0IHRvIGZhbHNlLCBhcyBtb3N0IFZhcmlhYmxlcyBhcmUgbm90IGFsd2F5cyBhdmFpbGFibGUuIFRoZW4gcmVtb3ZlIGFsbCAnYWx3YXlzX2F2YWlsYWJsZSA9IGZhbHNlJyBsaW5lcyBmcm9tIHN1YmNsYXNzZXMsIGFuZCBhZGQgJ2Fsd2F5c19hdmFpbGFibGUgPSB0cnVlJyB0byB0aG9zZSBzdWJjbGFzc2VzIHRoYXQgbmVlZCBpdC5cclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGFsd2F5c19hdmFpbGFibGUgPSB0cnVlO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQSBkZWZpbml0aW9uIGZvciB3aGF0IHBhcmFtZXRlcnMgdGhpcyB2YXJpYWJsZXMgdGFrZXMuXHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgcGFyYW1ldGVyczogSVBhcmFtZXRlcnMgPSB7fTtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICApIHtcclxuICAgICAgICB0aGlzLmFwcCA9IHBsdWdpbi5hcHA7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldFZhbHVlKFxyXG4gICAgICAgIHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCB8IG51bGwgPSBudWxsLFxyXG4gICAgICAgIHNjX2V2ZW50OiBTQ19FdmVudCB8IG51bGwgPSBudWxsLFxyXG4gICAgICAgIHZhcmlhYmxlQXJndW1lbnRzOiBJUmF3QXJndW1lbnRzID0ge30sXHJcblxyXG4gICAgICAgIC8qKlxyXG4gICAgICAgICAqIFdpbGwgcGFyc2UgdmFyaWFibGVzIGluIGEgZGVmYXVsdCB2YWx1ZSAob25seSB1c2VkIGlmIHRoaXMgdmFyaWFibGUgaXMgbm90IGF2YWlsYWJsZSB0aGlzIHRpbWUpLiBUaGUgY2FsbGJhY2tcclxuICAgICAgICAgKiBpcyBvbmx5IHVzZWQsIGlmIHRfc2hlbGxfY29tbWFuZCBpcyBnaXZlbi4gU2V0IHRvIG51bGwsIGlmIG5vIHZhcmlhYmxlIHBhcnNpbmcgaXMgbmVlZGVkIGZvciBkZWZhdWx0IHZhbHVlcy5cclxuICAgICAgICAgKiAqL1xyXG4gICAgICAgIGRlZmF1bHRfdmFsdWVfcGFyc2VyOiAoKGNvbnRlbnQ6IHN0cmluZykgPT4gUHJvbWlzZTxQYXJzaW5nUmVzdWx0PikgfCBudWxsID0gbnVsbCxcclxuICAgICk6IFByb21pc2U8VmFyaWFibGVWYWx1ZVJlc3VsdD4ge1xyXG5cclxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2U8VmFyaWFibGVWYWx1ZVJlc3VsdD4oKHJlc29sdmUpID0+IHtcclxuICAgICAgICAgICAgLy8gQ2FzdCBhcmd1bWVudHMgKGlmIGFueSkgdG8gdGhlaXIgY29ycmVjdCBkYXRhIHR5cGVzXHJcbiAgICAgICAgICAgIGNvbnN0IGNhc3RlZEFyZ3VtZW50cyA9IHRoaXMuY2FzdEFyZ3VtZW50cyh2YXJpYWJsZUFyZ3VtZW50cyk7XHJcblxyXG4gICAgICAgICAgICAvLyBHZW5lcmF0ZSBhIHZhbHVlLCBvciBjYXRjaCBhbiBleGNlcHRpb24gaWYgb25lIG9jY3Vycy5cclxuICAgICAgICAgICAgdGhpcy5nZW5lcmF0ZVZhbHVlKGNhc3RlZEFyZ3VtZW50cywgc2NfZXZlbnQpLnRoZW4oKHZhbHVlOiBzdHJpbmcgfCBudWxsKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAvLyBWYWx1ZSBnZW5lcmF0aW9uIHN1Y2NlZWRlZC5cclxuICAgICAgICAgICAgICAgIHJldHVybiByZXNvbHZlKHtcclxuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdmFsdWUsXHJcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JfbWVzc2FnZXM6IFtdLFxyXG4gICAgICAgICAgICAgICAgICAgIHN1Y2NlZWRlZDogdHJ1ZSxcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9KS5jYXRjaCgoZXJyb3IpID0+IHtcclxuICAgICAgICAgICAgICAgIC8vIENhdWdodCBhIFZhcmlhYmxlRXJyb3Igb3IgYW4gRXJyb3IuXHJcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBWYXJpYWJsZUVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIHZhcmlhYmxlIGlzIG5vdCBhdmFpbGFibGUgaW4gdGhpcyBzaXR1YXRpb24uXHJcbiAgICAgICAgICAgICAgICAgICAgZGVidWdMb2codGhpcy5jb25zdHJ1Y3Rvci5uYW1lICsgXCIuZ2V0VmFsdWUoKTogQ2F1Z2h0IGEgVmFyaWFibGVFcnJvciBhbmQgd2lsbCBkZXRlcm1pbmUgaG93IHRvIGhhbmRsZSBpdDogXCIgKyBlcnJvci5tZXNzYWdlKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gQ2hlY2sgd2hhdCBzaG91bGQgYmUgZG9uZS5cclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBkZWZhdWx0X3ZhbHVlX2NvbmZpZ3VyYXRpb24gPSB0X3NoZWxsX2NvbW1hbmQ/LmdldERlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb25Gb3JWYXJpYWJsZSh0aGlzKTsgLy8gVGhlIG1ldGhvZCBjYW4gcmV0dXJuIHVuZGVmaW5lZCwgYW5kIHRfc2hlbGxfY29tbWFuZCBjYW4gYmUgbnVsbC5cclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBkZWZhdWx0X3ZhbHVlX3R5cGUgPSBkZWZhdWx0X3ZhbHVlX2NvbmZpZ3VyYXRpb24gPyBkZWZhdWx0X3ZhbHVlX2NvbmZpZ3VyYXRpb24udHlwZSA6IFwic2hvdy1lcnJvcnNcIjtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBkZWJ1Z19tZXNzYWdlX2Jhc2UgPSBcIlZhcmlhYmxlIFwiICsgdGhpcy5nZXRGdWxsTmFtZSgpICsgXCIgaXMgbm90IGF2YWlsYWJsZS4gXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChkZWZhdWx0X3ZhbHVlX3R5cGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcInNob3ctZXJyb3JzXCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHZW5lcmF0ZSBlcnJvciBtZXNzYWdlcyBieSBjYWxsaW5nIGdlbmVyYXRlVmFsdWUoKS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKGRlYnVnX21lc3NhZ2VfYmFzZSArIFwiV2lsbCBwcmV2ZW50IHNoZWxsIGNvbW1hbmQgZXhlY3V0aW9uIGFuZCBzaG93IHZpc2libGUgZXJyb3IgbWVzc2FnZXMuXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc29sdmUoe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX21lc3NhZ2VzOiBbZXJyb3IubWVzc2FnZV0sIC8vIEN1cnJlbnRseSwgZXJyb3JfbWVzc2FnZXMgd2lsbCBuZXZlciBjb250YWluIG11bHRpcGxlIG1lc3NhZ2VzLiBUT0RPOiBDb25zaWRlciByZW5hbWluZyBlcnJvcl9tZXNzYWdlcyB0byBzaW5ndWxhciBmb3JtLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Y2NlZWRlZDogZmFsc2UsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcImNhbmNlbC1zaWxlbnRseVwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUHJldmVudCBleGVjdXRpb24sIGJ1dCBkbyBub3Qgc2hvdyBhbnkgZXJyb3JzXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhkZWJ1Z19tZXNzYWdlX2Jhc2UgKyBcIldpbGwgcHJldmVudCBzaGVsbCBjb21tYW5kIGV4ZWN1dGlvbiBzaWxlbnRseSB3aXRob3V0IHZpc2libGUgZXJyb3IgbWVzc2FnZXMuXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc29sdmUoe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX21lc3NhZ2VzOiBbXSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWNjZWVkZWQ6IGZhbHNlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJ2YWx1ZVwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmV0dXJuIGEgZGVmYXVsdCB2YWx1ZS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZGVmYXVsdF92YWx1ZV9jb25maWd1cmF0aW9uKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyBzaG91bGQgbm90IGhhcHBlbiwgYmVjYXVzZSBkZWZhdWx0X3ZhbHVlX3R5cGUgaXMgbmV2ZXIgXCJ2YWx1ZVwiIHdoZW4gZGVmYXVsdF92YWx1ZV9jb25maWd1cmF0aW9uIGlzIHVuZGVmaW5lZCBvciBudWxsLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoaXMgY2hlY2sgaXMganVzdCBmb3IgVHlwZVNjcmlwdCBjb21waWxlciB0byB1bmRlcnN0YW5kIHRoYXQgZGVmYXVsdF92YWx1ZV9jb25maWd1cmF0aW9uIGlzIGRlZmluZWQgd2hlbiBpdCdzIGFjY2Vzc2VkIGJlbG93LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkRlZmF1bHQgdmFsdWUgY29uZmlndXJhdGlvbiBpcyB1bmRlZmluZWQuXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVidWdMb2coZGVidWdfbWVzc2FnZV9iYXNlICsgXCJXaWxsIHVzZSBhIGRlZmF1bHQgdmFsdWU6IFwiICsgZGVmYXVsdF92YWx1ZV9jb25maWd1cmF0aW9uLnZhbHVlKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkZWZhdWx0X3ZhbHVlX3BhcnNlcikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBhcnNlIHBvc3NpYmxlIHZhcmlhYmxlcyBpbiB0aGUgZGVmYXVsdCB2YWx1ZS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0X3ZhbHVlX3BhcnNlcihkZWZhdWx0X3ZhbHVlX2NvbmZpZ3VyYXRpb24udmFsdWUpLnRoZW4oKGRlZmF1bHRfdmFsdWVfcGFyc2luZ19yZXN1bHQ6IFBhcnNpbmdSZXN1bHQpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc29sdmUoe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdF92YWx1ZV9wYXJzaW5nX3Jlc3VsdC5zdWNjZWVkZWRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyBkZWZhdWx0X3ZhbHVlX3BhcnNpbmdfcmVzdWx0LnBhcnNlZF9jb250ZW50XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogZGVmYXVsdF92YWx1ZV9wYXJzaW5nX3Jlc3VsdC5vcmlnaW5hbF9jb250ZW50XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvcl9tZXNzYWdlczogZGVmYXVsdF92YWx1ZV9wYXJzaW5nX3Jlc3VsdC5lcnJvcl9tZXNzYWdlcyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Y2NlZWRlZDogZGVmYXVsdF92YWx1ZV9wYXJzaW5nX3Jlc3VsdC5zdWNjZWVkZWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTm8gdmFyaWFibGUgcGFyc2luZyBpcyB3YW50ZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc29sdmUoe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogZGVmYXVsdF92YWx1ZV9jb25maWd1cmF0aW9uLnZhbHVlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvcl9tZXNzYWdlczogW10sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Y2NlZWRlZDogdHJ1ZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVW5yZWNvZ25pc2VkIGRlZmF1bHQgdmFsdWUgdHlwZTogXCIgKyBkZWZhdWx0X3ZhbHVlX3R5cGUpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gQSBwcm9ncmFtIGxvZ2ljIGVycm9yIGhhcyBoYXBwZW5lZC5cclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyh0aGlzLmNvbnN0cnVjdG9yLm5hbWUgKyBcIi5nZXRWYWx1ZSgpOiBDYXVnaHQgYW4gdW5yZWNvZ25pc2VkIGVycm9yIG9mIGNsYXNzOiBcIiArIGVycm9yLmNvbnN0cnVjdG9yLm5hbWUgKyBcIi4gV2lsbCByZXRocm93IGl0LlwiKTtcclxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUT0RPOiBDb25zaWRlciBjYW4gdGhlIHNjX2V2ZW50IHBhcmFtZXRlciBiZSBtb3ZlZCBzbyB0aGF0IGl0IHdvdWxkIG9ubHkgZXhpc3QgaW4gRXZlbnRWYXJpYWJsZSBhbmQgaXQncyBjaGlsZCBjbGFzc2VzPyBTYW1lIGZvciBnZXRWYWx1ZSgpIG1ldGhvZC5cclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGdlbmVyYXRlVmFsdWUodmFyaWFibGVBcmd1bWVudHM6IElDYXN0ZWRBcmd1bWVudHMsIHNjX2V2ZW50OiBTQ19FdmVudCB8IG51bGwpOiBQcm9taXNlPHN0cmluZz47XHJcblxyXG4gICAgcHJvdGVjdGVkIGdldFBhcmFtZXRlcnMoKSB7XHJcbiAgICAgICAgY29uc3QgY2hpbGRfY2xhc3MgPSB0aGlzLmNvbnN0cnVjdG9yIGFzIHR5cGVvZiBWYXJpYWJsZTtcclxuICAgICAgICByZXR1cm4gY2hpbGRfY2xhc3MucGFyYW1ldGVycztcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGdldFBhcmFtZXRlclNlcGFyYXRvcigpIHtcclxuICAgICAgICBjb25zdCBjaGlsZF9jbGFzcyA9IHRoaXMuY29uc3RydWN0b3IgYXMgdHlwZW9mIFZhcmlhYmxlO1xyXG4gICAgICAgIHJldHVybiBjaGlsZF9jbGFzcy5wYXJhbWV0ZXJfc2VwYXJhdG9yO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRQYXR0ZXJuKCkge1xyXG4gICAgICAgIGNvbnN0IGVycm9yX3ByZWZpeCA9IHRoaXMudmFyaWFibGVfbmFtZSArIFwiLmdldFBhdHRlcm4oKTogXCI7XHJcbiAgICAgICAgbGV0IHBhdHRlcm4gPSAnXFxcXHtcXFxceyE/JyArIGVzY2FwZVJlZ0V4cCh0aGlzLnZhcmlhYmxlX25hbWUpO1xyXG4gICAgICAgIGZvciAoY29uc3QgcGFyYW1ldGVyX25hbWUgaW4gdGhpcy5nZXRQYXJhbWV0ZXJzKCkpIHtcclxuICAgICAgICAgICAgY29uc3QgcGFyYW1ldGVyID0gdGhpcy5nZXRQYXJhbWV0ZXJzKClbcGFyYW1ldGVyX25hbWVdO1xyXG4gICAgICAgICAgICBsZXQgcGFyYW1ldGVyX3R5cGVfcGF0dGVybjogc3RyaW5nID0gdGhpcy5nZXRQYXJhbWV0ZXJTZXBhcmF0b3IoKTsgIC8vIEhlcmUgdGhpcy5wYXJhbWV0ZXJfc2VwYXJhdG9yICg9IDogKSBpcyBpbmNsdWRlZCBpbiB0aGUgcGFyYW1ldGVyIHZhbHVlIGp1c3Qgc28gdGhhdCBpdCdzIG5vdCBuZWVkZWQgdG8gZG8gbmVzdGVkIHBhcmVudGhlc2lzIHRvIGFjY29tcGxpc2ggcG9zc2libGUgb3B0aW9uYWxpdHk6ICg6KCkpPy4gcGFyc2VTaGVsbENvbW1hbmRWYXJpYWJsZXMoKSB3aWxsIHJlbW92ZSB0aGUgbGVhZGluZyA6IC5cclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIHNob3VsZCB3ZSB1c2UgcGFyYW1ldGVyLm9wdGlvbnMgb3IgcGFyYW1ldGVyLnR5cGUuXHJcbiAgICAgICAgICAgIGlmIChcclxuICAgICAgICAgICAgICAgIHVuZGVmaW5lZCA9PT0gcGFyYW1ldGVyLm9wdGlvbnMgJiZcclxuICAgICAgICAgICAgICAgIHVuZGVmaW5lZCA9PT0gcGFyYW1ldGVyLnR5cGVcclxuICAgICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBOZWl0aGVyIGlzIGRlZmluZWQgOihcclxuICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGVycm9yX3ByZWZpeCArIFwiUGFyYW1ldGVyICdcIiArIHBhcmFtZXRlcl9uYW1lICsgXCInIHNob3VsZCBkZWZpbmUgZWl0aGVyICd0eXBlJyBvciAnb3B0aW9ucycsIG5laXRoZXIgaXMgZGVmaW5lZCFcIik7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICAgICAgICAgICB1bmRlZmluZWQgIT09IHBhcmFtZXRlci5vcHRpb25zICYmXHJcbiAgICAgICAgICAgICAgICB1bmRlZmluZWQgIT09IHBhcmFtZXRlci50eXBlXHJcbiAgICAgICAgICAgICkge1xyXG4gICAgICAgICAgICAgICAgLy8gQm90aCBhcmUgZGVmaW5lZCA6KFxyXG4gICAgICAgICAgICAgICAgdGhyb3cgRXJyb3IoZXJyb3JfcHJlZml4ICsgXCJQYXJhbWV0ZXIgJ1wiICsgcGFyYW1ldGVyX25hbWUgKyBcIicgc2hvdWxkIGRlZmluZSBlaXRoZXIgJ3R5cGUnIG9yICdvcHRpb25zJywgbm90IGJvdGghXCIpO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKHVuZGVmaW5lZCAhPT0gcGFyYW1ldGVyLm9wdGlvbnMpIHtcclxuICAgICAgICAgICAgICAgIC8vIFVzZSBwYXJhbWV0ZXIub3B0aW9uc1xyXG4gICAgICAgICAgICAgICAgcGFyYW1ldGVyX3R5cGVfcGF0dGVybiArPSBwYXJhbWV0ZXIub3B0aW9ucy5qb2luKFwifFwiICsgdGhpcy5nZXRQYXJhbWV0ZXJTZXBhcmF0b3IoKSk7IC8vIEUuZy4gXCJhYnNvbHV0ZXw6cmVsYXRpdmVcIiBmb3Ige3tmaWxlX3BhdGg6bW9kZX19IHZhcmlhYmxlJ3MgJ21vZGUnIHBhcmFtZXRlci5cclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIFVzZSBwYXJhbWV0ZXIudHlwZVxyXG4gICAgICAgICAgICAgICAgc3dpdGNoIChwYXJhbWV0ZXIudHlwZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNhc2UgXCJzdHJpbmdcIjpcclxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1ldGVyX3R5cGVfcGF0dGVybiArPSBcIi4qP1wiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICBjYXNlIFwiaW50ZWdlclwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJhbWV0ZXJfdHlwZV9wYXR0ZXJuICs9IFwiXFxcXGQrXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IEVycm9yKGVycm9yX3ByZWZpeCArIFwiUGFyYW1ldGVyICdcIiArIHBhcmFtZXRlcl9uYW1lICsgXCInIGhhcyBhbiB1bnJlY29nbmlzZWQgdHlwZTogXCIgKyBwYXJhbWV0ZXIudHlwZSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCB0aGUgc3VicGF0dGVybiB0byAncGF0dGVybicuXHJcbiAgICAgICAgICAgIHBhdHRlcm4gKz0gXCIoXCIgKyBwYXJhbWV0ZXJfdHlwZV9wYXR0ZXJuICsgXCIpXCI7XHJcbiAgICAgICAgICAgIGlmICghcGFyYW1ldGVyLnJlcXVpcmVkKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBNYWtlIHRoZSBwYXJhbWV0ZXIgb3B0aW9uYWwuXHJcbiAgICAgICAgICAgICAgICBwYXR0ZXJuICs9IFwiP1wiO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgIH1cclxuICAgICAgICBwYXR0ZXJuICs9ICdcXFxcfVxcXFx9JztcclxuICAgICAgICByZXR1cm4gcGF0dGVybjtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0UGFyYW1ldGVyTmFtZXMoKSB7XHJcbiAgICAgICAgcmV0dXJuIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHRoaXMuZ2V0UGFyYW1ldGVycygpKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSB2YXJpYWJsZUFyZ3VtZW50cyBTdHJpbmcgdHlwZWQgYXJndW1lbnRzLiBBcmd1bWVudHMgdGhhdCBzaG91bGQgYmUgdHlwZWQgb3RoZXJseSwgd2lsbCBiZSBjYXN0IHRvIG90aGVyIHR5cGVzLiBUaGVuIGFsbCBhcmd1bWVudHMgYXJlIHJldHVybmVkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgY2FzdEFyZ3VtZW50cyh2YXJpYWJsZUFyZ3VtZW50czogSVJhd0FyZ3VtZW50cyk6IElDYXN0ZWRBcmd1bWVudHMge1xyXG4gICAgICAgIGNvbnN0IGNhc3RlZEFyZ3VtZW50czogSUNhc3RlZEFyZ3VtZW50cyA9IHt9O1xyXG4gICAgICAgIGZvciAoY29uc3QgcGFyYW1ldGVyTmFtZSBvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyh2YXJpYWJsZUFyZ3VtZW50cykpIHtcclxuICAgICAgICAgICAgY29uc3QgcGFyYW1ldGVyX3R5cGUgPSB0aGlzLmdldFBhcmFtZXRlcnMoKVtwYXJhbWV0ZXJOYW1lXS50eXBlID8/IFwic3RyaW5nXCI7IC8vIElmIHRoZSB2YXJpYWJsZSB1c2VzIFwib3B0aW9uc1wiIGluc3RlYWQgb2YgXCJ0eXBlXCIsIHRoZW4gdGhlIHR5cGUgaXMgYWx3YXlzIFwic3RyaW5nXCIuXHJcbiAgICAgICAgICAgIGNvbnN0IGFyZ3VtZW50ID0gdmFyaWFibGVBcmd1bWVudHNbcGFyYW1ldGVyTmFtZV07XHJcbiAgICAgICAgICAgIHN3aXRjaCAocGFyYW1ldGVyX3R5cGUpIHtcclxuICAgICAgICAgICAgICAgIGNhc2UgXCJzdHJpbmdcIjpcclxuICAgICAgICAgICAgICAgICAgICBjYXN0ZWRBcmd1bWVudHNbcGFyYW1ldGVyTmFtZV0gPSBhcmd1bWVudDtcclxuICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgIGNhc2UgXCJpbnRlZ2VyXCI6XHJcbiAgICAgICAgICAgICAgICAgICAgY2FzdGVkQXJndW1lbnRzW3BhcmFtZXRlck5hbWVdID0gcGFyc2VJbnQoYXJndW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBjYXN0ZWRBcmd1bWVudHM7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDcmVhdGVzIGEgVmFyaWFibGVFcnJvciBhbmQgcGFzc2VzIGl0IHRvIGEgcmVqZWN0b3IgZnVuY3Rpb24sIHdoaWNoIHdpbGwgcGFzcyB0aGUgVmFyaWFibGVFcnJvciB0byBWYXJpYWJsZS5nZXRWYWx1ZSgpLlxyXG4gICAgICogVGhlbiBpdCB3aWxsIGJlIGhhbmRsZWQgdGhlcmUgYWNjb3JkaW5nIHRvIHVzZXIgcHJlZmVyZW5jZXMuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIG1lc3NhZ2VcclxuICAgICAqIEBwYXJhbSByZWplY3RvclxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgcmVqZWN0KG1lc3NhZ2U6IHN0cmluZywgcmVqZWN0b3I6IChlcnJvcjogVmFyaWFibGVFcnJvcikgPT4gdm9pZCk6IHZvaWQge1xyXG4gICAgICAgIHJlamVjdG9yKHRoaXMubmV3VmFyaWFibGVFcnJvcihtZXNzYWdlKSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTaW1pbGFyIHRvIFZhcmlhYmxlLnJlamVjdCgpLCBidXQgdXNlcyBhIHRyYWRpdGlvbmFsIHRocm93LiBDYW4gYmUgdXNlZCBpbiBhc3luYyBtZXRob2RzLiBGb3IgbWV0aG9kcyB0aGF0IGNyZWF0ZVxyXG4gICAgICogUHJvbWlzZXMgbWFudWFsbHksIFZhcmlhYmxlLnJlamVjdCgpIHNob3VsZCBiZSB1c2VkLCBiZWNhdXNlIGVycm9ycyB0aHJvd24gaW4gbWFudWFsbHkgY3JlYXRlZCBQcm9taXNlcyBhcmUgbm90IGNhdWdodFxyXG4gICAgICogYnkgVmFyaWFibGUuZ2V0VmFsdWUoKSdzIFByb21pc2UuY2F0Y2goKSBjYWxsYmFjay5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gbWVzc2FnZVxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgdGhyb3cobWVzc2FnZTogc3RyaW5nKTogbmV2ZXIge1xyXG4gICAgICAgIHRocm93IHRoaXMubmV3VmFyaWFibGVFcnJvcihtZXNzYWdlKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIG5ld1ZhcmlhYmxlRXJyb3IobWVzc2FnZTogc3RyaW5nKSB7XHJcbiAgICAgICAgY29uc3QgcHJlZml4ID0gdGhpcy5nZXRGdWxsTmFtZSgpICsgXCI6IFwiO1xyXG4gICAgICAgIHJldHVybiBuZXcgVmFyaWFibGVFcnJvcihwcmVmaXggKyBtZXNzYWdlKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QXV0b2NvbXBsZXRlSXRlbXMoKTogSUF1dG9jb21wbGV0ZUl0ZW1bXSB7XHJcblxyXG4gICAgICAgIC8vIENoZWNrIGlmIHRoZSB2YXJpYWJsZSBoYXMgYXQgbGVhc3Qgb25lIF9tYW5kYXRvcnlfIHBhcmFtZXRlci5cclxuICAgICAgICBsZXQgcGFyYW1ldGVyX2luZGljYXRvciA9IFwiXCI7XHJcbiAgICAgICAgY29uc3QgcGFyYW1ldGVyX25hbWVzID1cclxuICAgICAgICAgICAgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModGhpcy5nZXRQYXJhbWV0ZXJzKCkpXHJcbiAgICAgICAgICAgICAgICAuZmlsdGVyKHBhcmFtZXRlcl9uYW1lID0+IHRoaXMuZ2V0UGFyYW1ldGVycygpW3BhcmFtZXRlcl9uYW1lXS5yZXF1aXJlZCA9PT0gdHJ1ZSkgLy8gT25seSBpbmNsdWRlIG1hbmRhdG9yeSBwYXJhbWV0ZXJzXHJcbiAgICAgICAgO1xyXG4gICAgICAgIGlmIChwYXJhbWV0ZXJfbmFtZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICBwYXJhbWV0ZXJfaW5kaWNhdG9yID0gVmFyaWFibGUucGFyYW1ldGVyX3NlcGFyYXRvcjsgLy8gV2hlbiB0aGUgdmFyaWFibGUgbmFtZSBlbmRzIHdpdGggYSBwYXJhbWV0ZXIgc2VwYXJhdG9yIGNoYXJhY3RlciwgaXQgaW5kaWNhdGVzIHRvIGEgdXNlciB0aGF0IGFuIGFyZ3VtZW50IHNob3VsZCBiZSBzdXBwbGllZC5cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgIC8vIE5vcm1hbCB2YXJpYWJsZVxyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3tcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIHBhcmFtZXRlcl9pbmRpY2F0b3IgKyBcIn19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6ICh0aGlzLmhlbHBfdGV4dCArIFwiIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCkpLnRyaW0oKSwgLy8gLnRyaW0oKSByZW1vdmVzIFwiIFwiIGlmIGhlbHBfdGV4dCBvciBnZXRBdmFpbGFiaWxpdHlUZXh0KCkgaXMgZW1wdHkuXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwibm9ybWFsLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG5cclxuICAgICAgICAgICAgLy8gVW5lc2NhcGVkIHZlcnNpb24gb2YgdGhlIHZhcmlhYmxlXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7eyFcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIHBhcmFtZXRlcl9pbmRpY2F0b3IgKyBcIn19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6ICh0aGlzLmhlbHBfdGV4dCArIFwiIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCkpLnRyaW0oKSwgLy8gLnRyaW0oKSByZW1vdmVzIFwiIFwiIGlmIGhlbHBfdGV4dCBvciBnZXRBdmFpbGFiaWxpdHlUZXh0KCkgaXMgZW1wdHkuXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwidW5lc2NhcGVkLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgIF07XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEhlbHBOYW1lKCkge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+XCIgKyB0aGlzLmdldEZ1bGxOYW1lKCkgKyBcIjwvc3Ryb25nPlwiO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmV0dXJucyB0aGUgVmFyaWFibGUncyBuYW1lIHdyYXBwZWQgaW4ge3sgYW5kIH19LlxyXG4gICAgICpcclxuICAgICAqIFRPRE86IENoYW5nZSBoYXJkY29kZWQge3sgfX0gZW50cmllcyB0byB1c2UgdGhpcyBtZXRob2QgYWxsIGFyb3VuZCB0aGUgY29kZS5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldEZ1bGxOYW1lKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIFwie3tcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwifX1cIjtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFRPRE86IENyZWF0ZSBhIGNsYXNzIEJ1aWx0aW5WYXJpYWJsZSBhbmQgbW92ZSB0aGlzIG1ldGhvZCB0aGVyZS4gVGhpcyBzaG91bGQgbm90IGJlIHByZXNlbnQgZm9yIEN1c3RvbVZhcmlhYmxlcy5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldERvY3VtZW50YXRpb25MaW5rKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIERvY3VtZW50YXRpb25CdWlsdEluVmFyaWFibGVzQmFzZUxpbmsgKyBlbmNvZGVVUkkodGhpcy5nZXRGdWxsTmFtZSgpKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFRPRE86IENyZWF0ZSBhIGNsYXNzIEJ1aWx0aW5WYXJpYWJsZSBhbmQgbW92ZSB0aGlzIG1ldGhvZCB0aGVyZS4gVGhpcyBzaG91bGQgbm90IGJlIHByZXNlbnQgZm9yIEN1c3RvbVZhcmlhYmxlcy5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGNyZWF0ZURvY3VtZW50YXRpb25MaW5rRWxlbWVudChjb250YWluZXI6IEhUTUxFbGVtZW50XHJcbiAgICApOiB2b2lkIHtcclxuICAgICAgICBjb25zdCBkZXNjcmlwdGlvbiA9XHJcbiAgICAgICAgICAgIHRoaXMuZ2V0RnVsbE5hbWUoKSArIFwiOiBcIiArIHRoaXMuaGVscF90ZXh0XHJcbiAgICAgICAgICAgICsgRU9MICsgRU9MICtcclxuICAgICAgICAgICAgXCJDbGljayBmb3IgZXh0ZXJuYWwgZG9jdW1lbnRhdGlvbi5cIlxyXG4gICAgICAgIDtcclxuICAgICAgICBjb250YWluZXIuY3JlYXRlRWwoXCJhXCIsIHtcclxuICAgICAgICAgICAgdGV4dDogdGhpcy5nZXRGdWxsTmFtZSgpLFxyXG4gICAgICAgICAgICBocmVmOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIGF0dHI6IHtcImFyaWEtbGFiZWxcIjogZGVzY3JpcHRpb259LFxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmV0dXJucyBhIHVuaXF1ZSBzdHJpbmcgdGhhdCBjYW4gYmUgdXNlZCBpbiBkZWZhdWx0IHZhbHVlIGNvbmZpZ3VyYXRpb25zLlxyXG4gICAgICogQHJldHVybiBOb3JtYWwgdmFyaWFibGUgbmFtZSwgaWYgdGhpcyBpcyBhIGJ1aWx0LWluIHZhcmlhYmxlOyBvciBhbiBJRCBzdHJpbmcgaWYgdGhpcyBpcyBhIEN1c3RvbVZhcmlhYmxlLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZ2V0SWRlbnRpZmllcigpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmdldEZ1bGxOYW1lKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUaGlzIGNhbiBiZSB1c2VkIHRvIGRldGVybWluZSBpZiB0aGUgdmFyaWFibGUgY2FuIHNvbWV0aW1lcyBiZSB1bmF2YWlsYWJsZS4gVXNlZCBpbiBzZXR0aW5ncyB0byBhbGxvdyBhIHVzZXIgdG8gZGVmaW5lXHJcbiAgICAgKiBkZWZhdWx0IHZhbHVlcyBmb3IgdmFyaWFibGVzIHRoYXQgYXJlIG5vdCBhbHdheXMgYXZhaWxhYmxlLCBmaWx0ZXJpbmcgb3V0IGFsd2F5cyBhdmFpbGFibGUgdmFyaWFibGVzIGZvciB3aGljaCBkZWZhdWx0XHJcbiAgICAgKiB2YWx1ZXMgd291bGQgbm90IG1ha2Ugc2Vuc2UuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBpc0Fsd2F5c0F2YWlsYWJsZSgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5hbHdheXNfYXZhaWxhYmxlO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRm9yIHZhcmlhYmxlcyB0aGF0IGFyZSBhbHdheXMgYXZhaWxhYmxlLCByZXR1cm5zIGFuIGVtcHR5IHN0cmluZy5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldEF2YWlsYWJpbGl0eVRleHQoKSB7XHJcbiAgICAgICAgcmV0dXJuIFwiXCI7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTYW1lIGFzIGdldEF2YWlsYWJpbGl0eVRleHQoKSwgYnV0IHJlbW92ZXMgSFRNTCBmcm9tIHRoZSByZXN1bHQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXRBdmFpbGFiaWxpdHlUZXh0UGxhaW4oKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCkucmVwbGFjZSgvPFxcLz9zdHJvbmc+L2lnLCBcIlwiKTsgLy8gUmVtb3ZlIDxzdHJvbmc+IGFuZCA8L3N0cm9uZz4gbWFya2luZ3MgZnJvbSB0aGUgaGVscCB0ZXh0XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIGEgZGVmYXVsdCB2YWx1ZSBjb25maWd1cmF0aW9uIG9iamVjdCB0aGF0IHNob3VsZCBiZSB1c2VkIGlmIGEgc2hlbGwgY29tbWFuZCBkb2VzIG5vdCBkZWZpbmUgaXRzIG93blxyXG4gICAgICogZGVmYXVsdCB2YWx1ZSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldEdsb2JhbERlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24oKTogR2xvYmFsVmFyaWFibGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uIHwgbnVsbCB7XHJcbiAgICAgICAgLy8gV29ya3MgZm9yIGJ1aWx0LWluIHZhcmlhYmxlcyBvbmx5LiBDdXN0b21WYXJpYWJsZSBjbGFzcyBuZWVkcyB0byBvdmVycmlkZSB0aGlzIG1ldGhvZCBhbmQgbm90IGNhbGwgdGhlIHBhcmVudCFcclxuICAgICAgICByZXR1cm4gdGhpcy5wbHVnaW4uc2V0dGluZ3MuYnVpbHRpbl92YXJpYWJsZXNbdGhpcy5nZXRJZGVudGlmaWVyKCldPy5kZWZhdWx0X3ZhbHVlOyAvLyBDYW4gcmV0dXJuIG51bGxcclxuICAgIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFyZ3VtZW50cyB0aGF0IGFyZSBjYXN0IHRvIHRoZWlyIGRlc2lnbmVkIGRhdGEgdHlwZXMsIGkuZS4gc3RyaW5ncyBvciBpbnRlZ2VycyBhdCB0aGUgbW9tZW50LlxyXG4gKi9cclxuZXhwb3J0IGludGVyZmFjZSBJQ2FzdGVkQXJndW1lbnRzIHtcclxuICAgIFtrZXk6IHN0cmluZ106IHVua25vd247XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTYW1lIGFzIElDYXN0ZWRBcmd1bWVudHMsIGJ1dCBub3QgeWV0IGNhc3QgdG8gdGhlIHRhcmdldCBkYXRhIHR5cGVzLlxyXG4gKi9cclxuZXhwb3J0IGludGVyZmFjZSBJUmF3QXJndW1lbnRzIHtcclxuICAgIFtrZXk6IHN0cmluZ106IHN0cmluZztcclxufVxyXG5cclxuLyoqXHJcbiAqIGtleSA9IHN0cmluZywgcGFyYW1ldGVyIG5hbWVcclxuICogdmFsdWUgPSBib29sZWFuLCBpcyB0aGUgcGFyYW1ldGVyIG1hbmRhdG9yeSBvciBub3Q/XHJcbiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIElQYXJhbWV0ZXJzIHtcclxuICAgIFtrZXk6IHN0cmluZ106IHtcclxuICAgICAgICAvKiogV2hhdCBkYXRhIHR5cGUgaXMgYWxsb3dlZC4gKE5ldyB0eXBlcyBjYW4gYmUgYWRkZWQgbGF0ZXIpLiBTaG91bGQgYmUgb21pdHRlZCwgaWYgJ29wdGlvbnMnIGlzIHVzZWQuICovXHJcbiAgICAgICAgdHlwZT86IFwic3RyaW5nXCIgfCBcImludGVnZXJcIjtcclxuICAgICAgICAvKiogVGhpcyBjYW4gZGVmaW5lIHN0YXRpYyB2YWx1ZXMgZm9yIHRoaXMgcGFyYW1ldGVyLiBTaG91bGQgYmUgb21pdHRlZCwgaWYgJ3R5cGUnIGlzIHVzZWQuICovXHJcbiAgICAgICAgb3B0aW9ucz86IHN0cmluZ1tdO1xyXG4gICAgICAgIC8qKiBJcyB0aGlzIHBhcmFtZXRlciBtYW5kYXRvcnk/ICovXHJcbiAgICAgICAgcmVxdWlyZWQ6IGJvb2xlYW47XHJcbiAgICB9O1xyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFZhcmlhYmxlVmFsdWVSZXN1bHQge1xyXG4gICAgdmFsdWU6IHN0cmluZyB8IG51bGwsXHJcbiAgICBlcnJvcl9tZXNzYWdlczogc3RyaW5nW10sXHJcblxyXG4gICAgLyoqIEluIHByYWN0aXNlLCB0aGlzIGlzIHRydWUgZXZlcnkgdGltZSBlcnJvcl9tZXNzYWdlcyBpcyBlbXB0eSwgc28gdGhpcyBpcyBqdXN0IGEgc2hvcnRoYW5kIHNvIHRoYXQgZXJyb3JfbWVzc2FnZXMubGVuZ3RoIGRvZXMgbm90IG5lZWQgdG8gYmUgY2hlY2tlZCBieSB0aGUgY29uc3VtZXIuICovXHJcbiAgICBzdWNjZWVkZWQ6IGJvb2xlYW4sXHJcbn1cclxuXHJcbi8qKlxyXG4gKiBUaHJvd24gd2hlbiBWYXJpYWJsZXMgZW5jb3VudGVyIGVycm9ycyB0aGF0IHVzZXJzIHNob3VsZCBzb2x2ZS4gVmFyaWFibGUuZ2V0VmFsdWUoKSB3aWxsIGNhdGNoIHRoZXNlIGFuZCBzaG93IHRvIHVzZXJcclxuICogKHVubGVzcyBlcnJvcnMgYXJlIGlnbm9yZWQpLlxyXG4gKi9cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlRXJyb3IgZXh0ZW5kcyBFcnJvciB7fVxyXG5cclxuZXhwb3J0IHR5cGUgVmFyaWFibGVEZWZhdWx0VmFsdWVUeXBlID0gXCJzaG93LWVycm9yc1wiIHwgXCJjYW5jZWwtc2lsZW50bHlcIiB8IFwidmFsdWVcIjtcclxuXHJcbmV4cG9ydCB0eXBlIFZhcmlhYmxlRGVmYXVsdFZhbHVlVHlwZVdpdGhJbmhlcml0ID0gVmFyaWFibGVEZWZhdWx0VmFsdWVUeXBlIHwgXCJpbmhlcml0XCI7XHJcblxyXG4vKipcclxuICogSW50ZXJmYWNlIGZvciBhIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRoYXQgY2FuIG9wdCBmb3IgcmV0cmlldmluZyB0aGUgY29uZmlndXJhdGlvbiBmcm9tIGFuIHVwcGVyIGxldmVsIGJ5IGRlZmluaW5nIGl0c1xyXG4gKiAndHlwZScgcHJvcGVydHkgaGF2ZSB2YWx1ZSAnaW5oZXJpdCcuXHJcbiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIEluaGVyaXRhYmxlVmFyaWFibGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uIHtcclxuICAgIHR5cGU6IFZhcmlhYmxlRGVmYXVsdFZhbHVlVHlwZVdpdGhJbmhlcml0LFxyXG4gICAgdmFsdWU6IHN0cmluZyxcclxufVxyXG5cclxuLyoqXHJcbiAqIEludGVyZmFjZSBmb3IgYSBjb25maWd1cmF0aW9uIG9iamVjdCB0aGF0IGlzIG9uIGEgcm9vdCBsZXZlbCBhbmQgc28gY2Fubm90IGluaGVyaXQgY29uZmlndXJhdGlvbiBmcm9tIGFuIHVwcGVyIGxldmVsLFxyXG4gKiBiZWNhdXNlIHRoZXJlIGlzIG5vIHVwcGVyIGxldmVsLiBPYmplY3RzIGltcGxlbWVudGluZyB0aGlzIGludGVyZmFjZSBjYW5ub3Qgc2V0IHRoZWlyICd0eXBlJyBwcm9wZXJ0eSB0byAnaW5oZXJpdCcuXHJcbiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIEdsb2JhbFZhcmlhYmxlRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbiB7XHJcbiAgICB0eXBlOiBWYXJpYWJsZURlZmF1bHRWYWx1ZVR5cGUsXHJcbiAgICB2YWx1ZTogc3RyaW5nLFxyXG59XHJcbiIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtWYXJpYWJsZX0gZnJvbSBcIi4vVmFyaWFibGVcIjtcclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi4vbWFpblwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX091dHB1dCBleHRlbmRzIFZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJvdXRwdXRcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIHRleHQgb3V0cHV0dGVkIGJ5IGEgc2hlbGwgY29tbWFuZCBhZnRlciBpdCdzIGV4ZWN1dGVkLlwiO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIHBsdWdpbjogU0NfUGx1Z2luLFxyXG4gICAgICAgIHByaXZhdGUgb3V0cHV0X2NvbnRlbnQ6IHN0cmluZyxcclxuICAgICkge1xyXG4gICAgICAgIHN1cGVyKHBsdWdpbik7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoKTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICByZXR1cm4gdGhpcy5vdXRwdXRfY29udGVudDtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QXZhaWxhYmlsaXR5VGV4dCgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+T25seSBhdmFpbGFibGU8L3N0cm9uZz4gaW4gPGVtPm91dHB1dCB3cmFwcGVyczwvZW0+LCBjYW5ub3QgYmUgdXNlZCBhcyBpbnB1dCBmb3Igc2hlbGwgY29tbWFuZHMuXCI7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBFc2NhcGVyIHtcclxuICAgIHByb3RlY3RlZCByYXdfdmFsdWU6IHN0cmluZztcclxuXHJcbiAgICBwdWJsaWMgY29uc3RydWN0b3IocmF3X3ZhbHVlOiBzdHJpbmcpIHtcclxuICAgICAgICB0aGlzLnJhd192YWx1ZSA9IHJhd192YWx1ZTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgYWJzdHJhY3QgZXNjYXBlKCk6IHN0cmluZztcclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtFc2NhcGVyfSBmcm9tIFwiLi9Fc2NhcGVyXCI7XHJcblxyXG4vKipcclxuICogUHJlZml4ZXMgYWxsIGNoYXJhY3RlcnMgdGhhdCBhcmUgbm90IGxldHRlcnMsIG51bWJlcnMgb3IgdW5kZXJzY29yZXMgd2l0aCBhIHByZWZpeCBjaGFyYWN0ZXIgdGhhdCBjYW4gYmUgZGVmaW5lZCBieSBjaGlsZCBjbGFzc2VzLlxyXG4gKi9cclxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEFsbFNwZWNpYWxDaGFyYWN0ZXJzRXNjYXBlciBleHRlbmRzIEVzY2FwZXIge1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IHByZWZpeDogc3RyaW5nO1xyXG5cclxuICAgIHB1YmxpYyBlc2NhcGUoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5yYXdfdmFsdWUucmVwbGFjZSgvW15cXHdcXGRdL2d1LCAoc3BlY2lhbF9jaGFyYWN0ZXI6IHN0cmluZykgPT4geyAgLy8gL2cgbWVhbnMgdG8gcmVwbGFjZSBhbGwgb2NjdXJyZW5jZXMgaW5zdGVhZCBvZiBqdXN0IHRoZSBmaXJzdCBvbmUuIC91IG1lYW5zIHRvIGhhbmRsZSBmb3VyLWJ5dGUgdW5pY29kZSBjaGFyYWN0ZXJzIGNvcnJlY3RseSBhcyBvbmUgY2hhcmFjdGVyLCBub3QgYXMgdHdvIHNlcGFyYXRlIGNoYXJhY3RlcnMuXHJcbiAgICAgICAgICAgIC8vIERvIHRoZSByZXBsYWNpbmcgaW4gYSBmdW5jdGlvbiBpbiBvcmRlciB0byBhdm9pZCBhIHBvc3NpYmxlICQgY2hhcmFjdGVyIHRvIGJlIGludGVycHJldGVkIGJ5IEphdmFTY3JpcHQgdG8gaW50ZXJhY3Qgd2l0aCB0aGUgcmVnZXguXHJcbiAgICAgICAgICAgIC8vIE1vcmUgaW5mb3JtYXRpb246IGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL1N0cmluZy9yZXBsYWNlI3NwZWNpZnlpbmdfYV9zdHJpbmdfYXNfYV9wYXJhbWV0ZXIgKHJlZmVyZW5jZWQgMjAyMS0xMS0wMi5cclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucHJlZml4ICsgc3BlY2lhbF9jaGFyYWN0ZXI7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7QWxsU3BlY2lhbENoYXJhY3RlcnNFc2NhcGVyfSBmcm9tIFwiLi9BbGxTcGVjaWFsQ2hhcmFjdGVyc0VzY2FwZXJcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBTaEVzY2FwZXIgZXh0ZW5kcyBBbGxTcGVjaWFsQ2hhcmFjdGVyc0VzY2FwZXIge1xyXG4gICAgcHJvdGVjdGVkIHByZWZpeCA9IFwiXFxcXFwiOyAvLyBJbiAqc2gsIGVzY2FwaW5nIHNob3VsZCB1c2UgYSBiYWNrc2xhc2gsIGUuZy4gXCJIZWxsbywgd29ybGQhXCIgYmVjb21lcyBcXFwiSGVsbG9cXCxcXCB3b3JsZFxcIVxcXCJcclxuXHJcbiAgICBwdWJsaWMgZXNjYXBlKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMucmVwbGFjZV9uZXdsaW5lcyhzdXBlci5lc2NhcGUoKSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDb252ZXJ0cyBlc2NhcGVkIG5ld2xpbmUgY2hhcmFjdGVycyB0byBhIGZvcm0gdGhhdCB0aGUgQm91cm5lIGZhbWlseSBzaGVsbHMgd2lsbCBpbnRlcnByZXQgYXMgbGl0ZXJhbCBuZXdsaW5lcyxcclxuICAgICAqIG5vdCBhcyBpZ25vcmFibGUgY2hhcmFjdGVycy5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gZXNjYXBlZF92YWx1ZVxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSByZXBsYWNlX25ld2xpbmVzKGVzY2FwZWRfdmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIGVzY2FwZWRfdmFsdWVcclxuICAgICAgICAgICAgLnJlcGxhY2VBbGwodGhpcy5wcmVmaXgrXCJcXHJcIiwgdGhpcy5wcmVmaXgrdGhpcy5wcmVmaXgrXCJyXCIpIC8vIFJlcGxhY2UgYSByZWFsIGxpbmVmZWVkIHdpdGggYSBsaXRlcmFsIFwiXFxcXHJcIi5cclxuICAgICAgICAgICAgLnJlcGxhY2VBbGwodGhpcy5wcmVmaXgrXCJcXG5cIiwgdGhpcy5wcmVmaXgrdGhpcy5wcmVmaXgrXCJuXCIpIC8vIFJlcGxhY2UgYSByZWFsIG5ld2xpbmUgd2l0aCBhIGxpdGVyYWwgXCJcXFxcblwiLlxyXG4gICAgICAgIDtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtBbGxTcGVjaWFsQ2hhcmFjdGVyc0VzY2FwZXJ9IGZyb20gXCIuL0FsbFNwZWNpYWxDaGFyYWN0ZXJzRXNjYXBlclwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFBvd2VyU2hlbGxFc2NhcGVyIGV4dGVuZHMgQWxsU3BlY2lhbENoYXJhY3RlcnNFc2NhcGVyIHtcclxuICAgIHByb3RlY3RlZCBwcmVmaXggPSBcImBcIjsgLy8gSW4gUG93ZXJTaGVsbCwgZXNjYXBpbmcgc2hvdWxkIHVzZSBhIGAgY2hhcmFjdGVyLCBlLmcuIFwiSGVsbG8sIHdvcmxkIVwiIGJlY29tZXMgYFwiSGVsbG9gLGAgd29ybGRgIWBcIlxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0VzY2FwZXJ9IGZyb20gXCIuL0VzY2FwZXJcIjtcclxuaW1wb3J0IHtTaEVzY2FwZXJ9IGZyb20gXCIuL1NoRXNjYXBlclwiO1xyXG5pbXBvcnQge1Bvd2VyU2hlbGxFc2NhcGVyfSBmcm9tIFwiLi9Qb3dlclNoZWxsRXNjYXBlclwiO1xyXG5pbXBvcnQge05vdGljZX0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7ZXh0cmFjdEZpbGVOYW1lfSBmcm9tIFwiLi4vLi4vQ29tbW9uXCI7XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZXNjYXBlVmFsdWUoc2hlbGw6IHN0cmluZywgcmF3X3ZhbHVlOiBzdHJpbmcpIHtcclxuICAgIHNoZWxsID0gZXh0cmFjdEZpbGVOYW1lKHNoZWxsLnRvTG93ZXJDYXNlKCkpO1xyXG4gICAgbGV0IGVzY2FwZXI6IEVzY2FwZXI7XHJcbiAgICBzd2l0Y2ggKHNoZWxsKSB7XHJcbiAgICAgICAgY2FzZSBcImJhc2hcIjpcclxuICAgICAgICBjYXNlIFwiZGFzaFwiOlxyXG4gICAgICAgIGNhc2UgXCJ6c2hcIjpcclxuICAgICAgICBjYXNlIFwic2hcIjogLy8gTWF5IHNvbWV0aW1lcyBhcHBlYXIgd2hlbiB1c2luZyB0aGUgXCJVc2Ugc3lzdGVtIGRlZmF1bHQgKHNoKVwiIG9wdGlvbiBhcyBhIGRlZmF1bHQgc2hlbGwuXHJcbiAgICAgICAgICAgIGVzY2FwZXIgPSBuZXcgU2hFc2NhcGVyKHJhd192YWx1ZSk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIGNhc2UgXCJwb3dlcnNoZWxsLmV4ZVwiOiAgLy8gUG93ZXJTaGVsbCA1IGlzIG9ubHkgYXZhaWxhYmxlIGZvciBXaW5kb3dzLlxyXG4gICAgICAgIGNhc2UgXCJwd3NoLmV4ZVwiOiAgICAgICAgLy8gSW4gV2luZG93cy5cclxuICAgICAgICBjYXNlIFwicHdzaFwiOiAgICAgICAgICAgIC8vIEluIExpbnV4IGFuZCBNYWMuIChTQyBkb2VzIG5vdCBhY3R1YWxseSBzdXBwb3J0IHVzaW5nIFBvd2VyU2hlbGwgb24gTGludXgvTWFjIGp1c3QgeWV0LCBidXQgc3VwcG9ydCBjYW4gYmUgYWRkZWQpLlxyXG4gICAgICAgICAgICBlc2NhcGVyID0gbmV3IFBvd2VyU2hlbGxFc2NhcGVyKHJhd192YWx1ZSk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIGNhc2UgXCJjbWQuZXhlXCI6XHJcbiAgICAgICAgICAgIC8vIEV4Y2VwdGlvbjogVGhlcmUgaXMgbm8gZXNjYXBpbmcgc3VwcG9ydCBmb3IgQ01ELCBzbyBhbGwgdmFsdWVzIHdpbGwgYmUgbGVmdCB1bmVzY2FwZWQgd2hlbiBDTUQgaXMgdXNlZC4gOihcclxuICAgICAgICAgICAgcmV0dXJuIHJhd192YWx1ZTtcclxuICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICAvLyBTaGVsbCB3YXMgbm90IHJlY29nbmlzZWQuXHJcbiAgICAgICAgICAgIG5ldyBOb3RpY2UoXCJFc2NhcGVWYWx1ZSgpOiBVbnJlY29nbmlzZWQgc2hlbGw6IFwiICsgc2hlbGwpO1xyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJFc2NhcGVWYWx1ZSgpOiBVbnJlY29nbmlzZWQgc2hlbGw6IFwiICsgc2hlbGwpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGVzY2FwZXIuZXNjYXBlKCk7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7VmFyaWFibGV9IGZyb20gXCIuL1ZhcmlhYmxlXCI7XHJcbi8vIEB0cy1pZ25vcmUgXCJlbGVjdHJvblwiIGlzIGluc3RhbGxlZC5cclxuaW1wb3J0IHtjbGlwYm9hcmR9IGZyb20gXCJlbGVjdHJvblwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0NsaXBib2FyZCBleHRlbmRzIFZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJjbGlwYm9hcmRcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIHRoZSBjb250ZW50IHlvdSBsYXN0IGNvcGllZCB0byB5b3VyIGNsaXBib2FyZC5cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZSgpOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHJldHVybiBjbGlwYm9hcmQucmVhZFRleHQoKTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtWYXJpYWJsZX0gZnJvbSBcIi4vVmFyaWFibGVcIjtcclxuaW1wb3J0IHtcclxuICAgIGdldEVkaXRvcixcclxuICAgIGdldFZpZXcsXHJcbn0gZnJvbSBcIi4uL0NvbW1vblwiO1xyXG5pbXBvcnQge1xyXG4gICAgRWRpdG9yLFxyXG4gICAgTWFya2Rvd25WaWV3LFxyXG59IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQge2RlYnVnTG9nfSBmcm9tIFwiLi4vRGVidWdcIjtcclxuXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBFZGl0b3JWYXJpYWJsZSBleHRlbmRzIFZhcmlhYmxlIHtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYWx3YXlzX2F2YWlsYWJsZSA9IGZhbHNlO1xyXG5cclxuICAgIHByb3RlY3RlZCBnZXRFZGl0b3JPclRocm93KCk6IEVkaXRvciB8IG5ldmVyIHtcclxuICAgICAgICBjb25zdCBlZGl0b3IgPSBnZXRFZGl0b3IodGhpcy5hcHApO1xyXG4gICAgICAgIGlmIChudWxsID09PSBlZGl0b3IpIHtcclxuICAgICAgICAgICAgLy8gTm8gZWRpdG9yLlxyXG4gICAgICAgICAgICB0aGlzLnRocm93KFwiQ291bGQgbm90IGdldCBhbiBlZGl0b3IgaW5zdGFuY2UhIFBsZWFzZSBjcmVhdGUgYSBkaXNjdXNzaW9uIGluIEdpdEh1Yi5cIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBlZGl0b3I7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDYW4gYmUgbWFkZSBwcm90ZWN0ZWQgaWYgbmVlZGVkIHRvIGJlIGFjY2Vzc2VkIGJ5IHN1YmNsYXNzZXMuXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGdldFZpZXdPclRocm93KCk6IE1hcmtkb3duVmlldyB7XHJcbiAgICAgICAgY29uc3QgdmlldyA9IGdldFZpZXcodGhpcy5hcHApO1xyXG4gICAgICAgIGlmIChudWxsID09PSB2aWV3KSB7XHJcbiAgICAgICAgICAgIC8vIE5vIHZpZXcuXHJcbiAgICAgICAgICAgIHRoaXMudGhyb3coXCJDb3VsZCBub3QgZ2V0IGEgdmlldyBpbnN0YW5jZSEgUGxlYXNlIGNyZWF0ZSBhIGRpc2N1c3Npb24gaW4gR2l0SHViLlwiKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHZpZXc7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIHJlcXVpcmVWaWV3TW9kZVNvdXJjZSgpOiB2b2lkIHtcclxuICAgICAgICBjb25zdCB2aWV3OiBNYXJrZG93blZpZXcgPSB0aGlzLmdldFZpZXdPclRocm93KCk7XHJcbiAgICAgICAgY29uc3Qgdmlld19tb2RlID0gdmlldy5nZXRNb2RlKCk7IC8vIFwicHJldmlld1wiIG9yIFwic291cmNlXCIgKFwibGl2ZVwiIHdhcyByZW1vdmVkIGZyb20gT2JzaWRpYW4gQVBJIGluIDAuMTMuOCBvbiAyMDIxLTEyLTEwKS5cclxuXHJcbiAgICAgICAgc3dpdGNoICh2aWV3X21vZGUpIHtcclxuICAgICAgICAgICAgY2FzZSBcInByZXZpZXdcIjpcclxuICAgICAgICAgICAgICAgIC8vIFRoZSBsZWFmIGlzIGluIHByZXZpZXcgbW9kZSwgd2hpY2ggbWFrZXMgdGhpbmdzIGRpZmZpY3VsdC5cclxuICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBNYWtlIGl0IHBvc3NpYmxlIHRvIHVzZSB0aGlzIGZlYXR1cmUgYWxzbyBpbiBwcmV2aWV3IG1vZGUuXHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkVkaXRvclZhcmlhYmxlOiAndmlldycgaXMgaW4gcHJldmlldyBtb2RlLCBhbmQgdGhlIHBvb3IgZ3V5IHdobyB3cm90ZSB0aGlzIGNvZGUsIGRvZXMgbm90IGtub3cgaG93IHRvIHJldHVybiBhbiBlZGl0b3IgaW5zdGFuY2UgdGhhdCBjb3VsZCBiZSB1c2VkIGZvciBnZXR0aW5nIHRleHQgc2VsZWN0aW9uLlwiKTtcclxuICAgICAgICAgICAgICAgIHRoaXMudGhyb3coXCJZb3UgbmVlZCB0byB0dXJuIGVkaXRpbmcgbW9kZSBvbiwgdW5mb3J0dW5hdGVseSB0aGlzIHZhcmlhYmxlIGRvZXMgbm90IHdvcmsgaW4gcHJldmlldyBtb2RlLlwiKTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICBjYXNlIFwic291cmNlXCI6XHJcbiAgICAgICAgICAgICAgICAvLyBHb29kLCB0aGUgZWRpdG9yIGlzIGluIFwic291cmNlXCIgbW9kZSwgc28gaXQncyBwb3NzaWJsZSB0byBnZXQgYSBzZWxlY3Rpb24sIGNhcmV0IHBvc2l0aW9uIG9yIG90aGVyIGVkaXRpbmcgcmVsYXRlZCBpbmZvcm1hdGlvbi5cclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgICAgIHRoaXMudGhyb3coXCJVbnJlY29nbmlzZWQgdmlldyBtb2RlOiBcIiArIHZpZXdfbW9kZSk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEF2YWlsYWJpbGl0eVRleHQoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gXCI8c3Ryb25nPk9ubHkgYXZhaWxhYmxlPC9zdHJvbmc+IHdoZW4gYSBub3RlIHBhbmUgaXMgb3Blbiwgbm90IGluIGdyYXBoIHZpZXcsIG5vciB3aGVuIHZpZXdpbmcgbm9uLXRleHQgZmlsZXMuXCI7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0OlxyXG4gKiAgLSBWaW5heSBSYWp1cjogaHR0cHM6Ly9naXRodWIuY29tL3ZyYWp1clxyXG4gKiAgLSBKYXJra28gTGlubmFudmlydGE6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7SVBhcmFtZXRlcnN9IGZyb20gXCIuL1ZhcmlhYmxlXCI7XHJcbmltcG9ydCB7SUF1dG9jb21wbGV0ZUl0ZW19IGZyb20gXCIuLi9zZXR0aW5ncy9zZXR0aW5nX2VsZW1lbnRzL0F1dG9jb21wbGV0ZVwiO1xyXG5pbXBvcnQge0VkaXRvclZhcmlhYmxlfSBmcm9tIFwiLi9FZGl0b3JWYXJpYWJsZVwiO1xyXG5pbXBvcnQge0VkaXRvcn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfQ2FyZXRQb3NpdGlvbiBleHRlbmRzIEVkaXRvclZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJjYXJldF9wb3NpdGlvblwiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiR2l2ZXMgdGhlIGxpbmUgbnVtYmVyIGFuZCBjb2x1bW4gcG9zaXRpb24gb2YgdGhlIGN1cnJlbnQgY2FyZXQgcG9zaXRpb24gYXMgJ2xpbmU6Y29sdW1uJy4gR2V0IG9ubHkgdGhlIGxpbmUgbnVtYmVyIHVzaW5nIHt7Y2FyZXRfcG9zaXRpb246bGluZX19LCBhbmQgb25seSB0aGUgY29sdW1uIHdpdGgge3tjYXJldF9wb3NpdGlvbjpjb2x1bW59fS4gTGluZSBhbmQgY29sdW1uIG51bWJlcnMgYXJlIDEtaW5kZXhlZC5cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHBhcmFtZXRlcnM6IElQYXJhbWV0ZXJzID0ge1xyXG4gICAgICAgIG1vZGU6IHtcclxuICAgICAgICAgICAgb3B0aW9uczogW1wibGluZVwiLCBcImNvbHVtblwiXSxcclxuICAgICAgICAgICAgcmVxdWlyZWQ6IGZhbHNlLFxyXG4gICAgICAgIH0sXHJcbiAgICB9O1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKGNhc3RlZEFyZ3VtZW50czoge21vZGU/OiBzdHJpbmd9KTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICAvLyBDaGVjayB0aGF0IHdlIGFyZSBhYmxlIHRvIGdldCBhbiBlZGl0b3JcclxuICAgICAgICBjb25zdCBlZGl0b3I6IEVkaXRvciA9IHRoaXMuZ2V0RWRpdG9yT3JUaHJvdygpO1xyXG5cclxuICAgICAgICBjb25zdCBwb3NpdGlvbiA9IGVkaXRvci5nZXRDdXJzb3IoJ3RvJyk7XHJcbiAgICAgICAgY29uc3QgbGluZSA9IHBvc2l0aW9uLmxpbmUgKyAxOyAvLyBlZGl0b3IgcG9zaXRpb24gaXMgemVyby1pbmRleGVkLCBsaW5lIG51bWJlcnMgYXJlIDEtaW5kZXhlZFxyXG4gICAgICAgIGNvbnN0IGNvbHVtbiA9IHBvc2l0aW9uLmNoICsgMTsgLy8gZWRpdG9yIHBvc2l0aW9uIGlzIHplcm8taW5kZXhlZCwgY29sdW1uIHBvc2l0aW9ucyBhcmUgMS1pbmRleGVkXHJcblxyXG4gICAgICAgIGlmICh1bmRlZmluZWQgIT09IGNhc3RlZEFyZ3VtZW50cy5tb2RlKSB7XHJcbiAgICAgICAgICAgIHN3aXRjaCAoY2FzdGVkQXJndW1lbnRzLm1vZGUudG9Mb3dlckNhc2UoKSkge1xyXG4gICAgICAgICAgICAgICAgY2FzZSBcImxpbmVcIjpcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYCR7bGluZX1gO1xyXG4gICAgICAgICAgICAgICAgY2FzZSBcImNvbHVtblwiOlxyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBgJHtjb2x1bW59YDtcclxuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50aHJvdyhcIlVucmVjb2duaXNlZCBhcmd1bWVudDogXCIrY2FzdGVkQXJndW1lbnRzLm1vZGUpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gZGVmYXVsdCBjYXNlIHdoZW4gbm8gYXJncyBwcm92aWRlZFxyXG4gICAgICAgICAgICByZXR1cm4gYCR7bGluZX06JHtjb2x1bW59YDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEF1dG9jb21wbGV0ZUl0ZW1zKCkge1xyXG4gICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgIC8vIE5vcm1hbCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7XCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIn19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgdGhlIGxpbmUgbnVtYmVyIGFuZCBjb2x1bW4gcG9zaXRpb24gb2YgdGhlIGN1cnJlbnQgY2FyZXQgcG9zaXRpb24gYXMgJ2xpbmU6Y29sdW1uJy4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6bGluZX19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgdGhlIGxpbmUgbnVtYmVyIG9mIHRoZSBjdXJyZW50IGNhcmV0IHBvc2l0aW9uLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5vcm1hbC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7XCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjpjb2x1bW59fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSBjb2x1bW4gbnVtYmVyIG9mIHRoZSBjdXJyZW50IGNhcmV0IHBvc2l0aW9uLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5vcm1hbC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuXHJcbiAgICAgICAgICAgIC8vIFVuZXNjYXBlZCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7IVwiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCJ9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSBsaW5lIG51bWJlciBhbmQgY29sdW1uIHBvc2l0aW9uIG9mIHRoZSBjdXJyZW50IGNhcmV0IHBvc2l0aW9uIGFzICdsaW5lOmNvbHVtbicuIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwidW5lc2NhcGVkLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3shXCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjpsaW5lfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyB0aGUgbGluZSBudW1iZXIgb2YgdGhlIGN1cnJlbnQgY2FyZXQgcG9zaXRpb24uIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwidW5lc2NhcGVkLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3shXCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjpjb2x1bW59fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSBjb2x1bW4gbnVtYmVyIG9mIHRoZSBjdXJyZW50IGNhcmV0IHBvc2l0aW9uLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRIZWxwTmFtZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+e3tjYXJldF9wb3NpdGlvbn19PC9zdHJvbmc+LCA8c3Ryb25nPnt7Y2FyZXRfcG9zaXRpb246bGluZX19PC9zdHJvbmc+IG9yIDxzdHJvbmc+e3tjYXJldF9wb3NpdGlvbjpjb2x1bW59fTwvc3Ryb25nPlwiO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRBdmFpbGFiaWxpdHlUZXh0KCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIHN1cGVyLmdldEF2YWlsYWJpbGl0eVRleHQoKSArIFwiIE5vdCBhdmFpbGFibGUgaW4gcHJldmlldyBtb2RlLlwiO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge21vbWVudH0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7SVBhcmFtZXRlcnMsIFZhcmlhYmxlfSBmcm9tIFwiLi9WYXJpYWJsZVwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0RhdGUgZXh0ZW5kcyBWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiZGF0ZVwiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiR2l2ZXMgYSBkYXRlL3RpbWUgc3RhbXAgYXMgcGVyIHlvdXIgbGlraW5nLiBUaGUgXFxcImZvcm1hdFxcXCIgcGFydCBjYW4gYmUgY3VzdG9taXplZCBhbmQgaXMgbWFuZGF0b3J5LiBGb3JtYXR0aW5nIG9wdGlvbnM6IGh0dHBzOi8vbW9tZW50anMuY29tL2RvY3MvIy9kaXNwbGF5aW5nL2Zvcm1hdC9cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHBhcmFtZXRlcnM6IElQYXJhbWV0ZXJzID0ge1xyXG4gICAgICAgIGZvcm1hdDoge1xyXG4gICAgICAgICAgICB0eXBlOiBcInN0cmluZ1wiLFxyXG4gICAgICAgICAgICByZXF1aXJlZDogdHJ1ZSxcclxuICAgICAgICB9LFxyXG4gICAgfTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZShjYXN0ZWRBcmd1bWVudHM6IHtmb3JtYXQ6IHN0cmluZ30pOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHJldHVybiBtb21lbnQoKS5mb3JtYXQoY2FzdGVkQXJndW1lbnRzLmZvcm1hdCk7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7Z2V0VmF1bHRBYnNvbHV0ZVBhdGgsIG5vcm1hbGl6ZVBhdGgyLCB1bmlxdWVBcnJheX0gZnJvbSBcIi4uL0NvbW1vblwiO1xyXG5pbXBvcnQge0FwcCwgZ2V0QWxsVGFncywgVEZpbGUsIFRGb2xkZXJ9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5cclxuLyoqXHJcbiAqIFRPRE86IENvbnNpZGVyIGNyZWF0aW5nIGEgZGVjb3JhdG9yIGNsYXNzIGZvciBURm9sZGVyIGFuZCBtb3ZpbmcgdGhpcyBmdW5jdGlvbiB0byBiZSBhIG1ldGhvZCBpbiBpdC5cclxuICpcclxuICogQHBhcmFtIGFwcFxyXG4gKiBAcGFyYW0gZm9sZGVyXHJcbiAqIEBwYXJhbSBtb2RlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0Rm9sZGVyUGF0aChhcHA6IEFwcCwgZm9sZGVyOiBURm9sZGVyLCBtb2RlOiBcImFic29sdXRlXCIgfCBcInJlbGF0aXZlXCIpIHtcclxuICAgIHN3aXRjaCAobW9kZS50b0xvd2VyQ2FzZSgpIGFzIFwiYWJzb2x1dGVcIiB8IFwicmVsYXRpdmVcIikge1xyXG4gICAgICAgIGNhc2UgXCJhYnNvbHV0ZVwiOlxyXG4gICAgICAgICAgICByZXR1cm4gbm9ybWFsaXplUGF0aDIoZ2V0VmF1bHRBYnNvbHV0ZVBhdGgoYXBwKSArIFwiL1wiICsgZm9sZGVyLnBhdGgpO1xyXG4gICAgICAgIGNhc2UgXCJyZWxhdGl2ZVwiOlxyXG4gICAgICAgICAgICBpZiAoZm9sZGVyLmlzUm9vdCgpKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBPYnNpZGlhbiBBUEkgZG9lcyBub3QgZ2l2ZSBhIGNvcnJlY3QgZm9sZGVyLnBhdGggdmFsdWUgZm9yIHRoZSB2YXVsdCdzIHJvb3QgZm9sZGVyLlxyXG4gICAgICAgICAgICAgICAgLy8gVE9ETzogU2VlIHRoaXMgZGlzY3Vzc2lvbiBhbmQgYXBwbHkgcG9zc2libGUgY2hhbmdlcyBpZiBzb21ldGhpbmcgd2lsbCBjb21lIHVwOiBodHRwczovL2ZvcnVtLm9ic2lkaWFuLm1kL3QvdmF1bHQtcm9vdC1mb2xkZXJzLXJlbGF0aXZlLXBhdGgtZ2l2ZXMvMjQ4NTdcclxuICAgICAgICAgICAgICAgIHJldHVybiBcIi5cIjtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIFRoaXMgaXMgYSBub3JtYWwgc3ViZm9sZGVyXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gbm9ybWFsaXplUGF0aDIoZm9sZGVyLnBhdGgpOyAvLyBOb3JtYWxpemUgdG8gZ2V0IGEgY29ycmVjdCBzbGFzaCBiZXR3ZWVuIGRpcmVjdG9yaWVzIGRlcGVuZGluZyBvbiBwbGF0Zm9ybS4gT24gV2luZG93cyBpdCBzaG91bGQgYmUgXFwgLlxyXG4gICAgICAgICAgICB9XHJcbiAgICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBUT0RPOiBDb25zaWRlciBjcmVhdGluZyBhIGRlY29yYXRvciBjbGFzcyBmb3IgVEZpbGUgYW5kIG1vdmluZyB0aGlzIGZ1bmN0aW9uIHRvIGJlIGEgbWV0aG9kIGluIGl0LlxyXG4gKlxyXG4gKiBAcGFyYW0gYXBwXHJcbiAqIEBwYXJhbSBmaWxlXHJcbiAqIEBwYXJhbSBtb2RlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0RmlsZVBhdGgoYXBwOiBBcHAsIGZpbGU6IFRGaWxlLCBtb2RlOiBcImFic29sdXRlXCIgfCBcInJlbGF0aXZlXCIpIHtcclxuICAgIHN3aXRjaCAobW9kZS50b0xvd2VyQ2FzZSgpIGFzIFwiYWJzb2x1dGVcIiB8IFwicmVsYXRpdmVcIikge1xyXG4gICAgICAgIGNhc2UgXCJhYnNvbHV0ZVwiOlxyXG4gICAgICAgICAgICByZXR1cm4gbm9ybWFsaXplUGF0aDIoZ2V0VmF1bHRBYnNvbHV0ZVBhdGgoYXBwKSArIFwiL1wiICsgZmlsZS5wYXRoKTtcclxuICAgICAgICBjYXNlIFwicmVsYXRpdmVcIjpcclxuICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZVBhdGgyKGZpbGUucGF0aCk7IC8vIE5vcm1hbGl6ZSB0byBnZXQgYSBjb3JyZWN0IHNsYXNoIGRlcGVuZGluZyBvbiBwbGF0Zm9ybS4gT24gV2luZG93cyBpdCBzaG91bGQgYmUgXFwgLlxyXG4gICAgfVxyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIFRPRE86IENvbnNpZGVyIGNyZWF0aW5nIGEgZGVjb3JhdG9yIGNsYXNzIGZvciBURmlsZSBhbmQgbW92aW5nIHRoaXMgZnVuY3Rpb24gdG8gYmUgYSBtZXRob2QgaW4gaXQuXHJcbiAqIEBwYXJhbSBmaWxlXHJcbiAqIEBwYXJhbSB3aXRoX2RvdFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEZpbGVFeHRlbnNpb24oZmlsZTogVEZpbGUsIHdpdGhfZG90OiBib29sZWFuKSB7XHJcbiAgICBjb25zdCBmaWxlX2V4dGVuc2lvbiA9IGZpbGUuZXh0ZW5zaW9uO1xyXG5cclxuICAgIC8vIFNob3VsZCB0aGUgZXh0ZW5zaW9uIGJlIGdpdmVuIHdpdGggb3Igd2l0aG91dCBhIGRvdD9cclxuICAgIGlmICh3aXRoX2RvdCkge1xyXG4gICAgICAgIC8vIEEgcHJlY2VkaW5nIGRvdCBtdXN0IGJlIGluY2x1ZGVkLlxyXG4gICAgICAgIGlmIChmaWxlX2V4dGVuc2lvbi5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgIC8vIEJ1dCBvbmx5IGlmIHRoZSBleHRlbnNpb24gaXMgbm90IGVtcHR5LlxyXG4gICAgICAgICAgICByZXR1cm4gXCIuXCIgKyBmaWxlX2V4dGVuc2lvbjtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTm8gZG90IHNob3VsZCBiZSBpbmNsdWRlZCwgb3IgdGhlIGV4dGVuc2lvbiBpcyBlbXB0eVxyXG4gICAgcmV0dXJuIGZpbGVfZXh0ZW5zaW9uO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZ2V0RmlsZVRhZ3MoYXBwOiBBcHAsIGZpbGU6IFRGaWxlKSB7XHJcbiAgICBjb25zdCBjYWNoZSA9IGFwcC5tZXRhZGF0YUNhY2hlLmdldEZpbGVDYWNoZShmaWxlKTtcclxuICAgIGlmICghY2FjaGUpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgZ2V0IG1ldGFkYXRhIGNhY2hlLlwiKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGFncy4gTWF5IGluY2x1ZGUgZHVwbGljYXRlcywgaWYgYSB0YWcgaXMgZGVmaW5lZCBtdWx0aXBsZSB0aW1lcyBpbiB0aGUgc2FtZSBmaWxlLlxyXG4gICAgY29uc3QgdGFnc0luY2x1ZGluZ0R1cGxpY2F0ZXM6IHN0cmluZ1tdID0gZ2V0QWxsVGFncyhjYWNoZSkgPz8gW107IC8vID8/IFtdID0gaW4gY2FzZSBudWxsIGlzIHJldHVybmVkLCBjb252ZXJ0IGl0IHRvIGFuIGVtcHR5IGFycmF5LiBJIGhhdmUgbm8gY2x1ZSBpbiB3aGljaCBzaXR1YXRpb24gdGhpcyBtaWdodCBoYXBwZW4uIE1heWJlIGlmIHRoZSBmaWxlIGRvZXMgbm90IGNvbnRhaW4gYW55IHRhZ3M/XHJcblxyXG4gICAgLy8gSXJvbiBvdXQgcG9zc2libGUgZHVwbGljYXRlcy5cclxuICAgIGNvbnN0IHRhZ3NXaXRob3V0RHVwbGljYXRlczogc3RyaW5nW10gPSB1bmlxdWVBcnJheSh0YWdzSW5jbHVkaW5nRHVwbGljYXRlcyk7XHJcblxyXG4gICAgLy8gUmVtb3ZlIHByZWNlZGluZyBoYXNoIGNoYXJhY3RlcnMuIEUuZy4gI3RhZyBiZWNvbWVzIHRhZ1xyXG4gICAgdGFnc1dpdGhvdXREdXBsaWNhdGVzLmZvckVhY2goKHRhZzogc3RyaW5nLCBpbmRleCkgPT4ge1xyXG4gICAgICAgIHRhZ3NXaXRob3V0RHVwbGljYXRlc1tpbmRleF0gPSB0YWcucmVwbGFjZShcIiNcIiwgXCJcIik7XHJcbiAgICB9KTtcclxuICAgIHJldHVybiB0YWdzV2l0aG91dER1cGxpY2F0ZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBAcGFyYW0gYXBwXHJcbiAqIEBwYXJhbSBmaWxlXHJcbiAqIEBwYXJhbSBwcm9wZXJ0eV9wYXRoXHJcbiAqIEByZXR1cm4gc3RyaW5nfHN0cmluZ1tdIEVpdGhlciBhIHJlc3VsdCBzdHJpbmcsIG9yIGFuIGFycmF5IG9mIGVycm9yIG1lc3NhZ2VzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEZpbGVZQU1MVmFsdWUoYXBwOiBBcHAsIGZpbGU6IFRGaWxlLCBwcm9wZXJ0eV9wYXRoOiBzdHJpbmcpIHtcclxuICAgIGNvbnN0IGVycm9yX21lc3NhZ2VzOiBzdHJpbmdbXSA9IFtdO1xyXG4gICAgY29uc3QgcHJvcGVydHlfcGFydHMgPSBwcm9wZXJ0eV9wYXRoLnNwbGl0KFwiLlwiKTtcclxuXHJcbiAgICAvLyBWYWxpZGF0ZSBhbGwgcHJvcGVydHkgbmFtZXMgYWxvbmcgdGhlIHBhdGhcclxuICAgIHByb3BlcnR5X3BhcnRzLmZvckVhY2goKHByb3BlcnR5X25hbWU6IHN0cmluZykgPT4ge1xyXG4gICAgICAgIGlmICgwID09PSBwcm9wZXJ0eV9uYW1lLmxlbmd0aCkge1xyXG4gICAgICAgICAgICBlcnJvcl9tZXNzYWdlcy5wdXNoKFwiWUFNTCBwcm9wZXJ0eSAnXCIgKyBwcm9wZXJ0eV9wYXRoICsgXCInIGhhcyBhbiBlbXB0eSBwcm9wZXJ0eSBuYW1lLiBSZW1vdmUgcG9zc2libGUgZG91YmxlIGRvdHMgb3IgYSBwcmVjZWRpbmcvdHJhaWxpbmcgZG90LlwiKTtcclxuICAgICAgICB9XHJcbiAgICB9KTtcclxuICAgIGlmIChlcnJvcl9tZXNzYWdlcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgLy8gRmFpbHVyZSBpbiBwcm9wZXJ0eSBuYW1lKHMpLlxyXG4gICAgICAgIHJldHVybiBlcnJvcl9tZXNzYWdlcztcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBmcm9udG1hdHRlciA9IGFwcC5tZXRhZGF0YUNhY2hlLmdldEZpbGVDYWNoZShmaWxlKT8uZnJvbnRtYXR0ZXI7XHJcbiAgICAvLyBDaGVjayB0aGF0IGEgWUFNTCBzZWN0aW9uIGlzIGF2YWlsYWJsZSBpbiB0aGUgZmlsZVxyXG4gICAgaWYgKHVuZGVmaW5lZCA9PT0gZnJvbnRtYXR0ZXIpIHtcclxuICAgICAgICAvLyBObyBpdCBhaW4ndC5cclxuICAgICAgICBlcnJvcl9tZXNzYWdlcy5wdXNoKFwiTm8gWUFNTCBmcm9udG1hdHRlciBzZWN0aW9uIGlzIGRlZmluZWQgZm9yIHRoZSBjdXJyZW50IGZpbGUuXCIpO1xyXG4gICAgICAgIHJldHVybiBlcnJvcl9tZXNzYWdlcztcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQSBZQU1MIHNlY3Rpb24gaXMgYXZhaWxhYmxlLlxyXG4gICAgICAgIC8vIFJlYWQgdGhlIHByb3BlcnR5J3MgdmFsdWUuXHJcbiAgICAgICAgcmV0dXJuIG5lc3RlZF9yZWFkKHByb3BlcnR5X3BhcnRzLCBwcm9wZXJ0eV9wYXRoLCBmcm9udG1hdHRlcik7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBAcGFyYW0gcHJvcGVydHlfcGFydHMgUHJvcGVydHkgcGF0aCBzcGxpdCBpbnRvIHBhcnRzICg9IHByb3BlcnR5IG5hbWVzKS4gVGhlIGRlZXBlciB0aGUgbmVzdGluZyBnb2VzLCB0aGUgZmV3ZXIgdmFsdWVzIHdpbGwgYmUgbGVmdCBpbiB0aGlzIGFycmF5LiBUaGlzIHNob3VsZCBhbHdheXMgY29udGFpbiBhdCBsZWFzdCBvbmUgcGFydCEgSWYgbm90LCBhbiBFcnJvciBpcyB0aHJvd24uXHJcbiAgICAgKiBAcGFyYW0gcHJvcGVydHlfcGF0aCBUaGUgb3JpZ2luYWwsIHdob2xlIHByb3BlcnR5IHBhdGggc3RyaW5nLlxyXG4gICAgICogQHBhcmFtIHlhbWxfb2JqZWN0XHJcbiAgICAgKiBAcmV0dXJuIHN0cmluZ3xzdHJpbmdbXSBFaXRoZXIgYSByZXN1bHQgc3RyaW5nLCBvciBhbiBhcnJheSBvZiBlcnJvciBtZXNzYWdlcy5cclxuICAgICAqL1xyXG4gICAgZnVuY3Rpb24gbmVzdGVkX3JlYWQocHJvcGVydHlfcGFydHM6IHN0cmluZ1tdLCBwcm9wZXJ0eV9wYXRoOiBzdHJpbmcsIHlhbWxfb2JqZWN0OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IG9iamVjdCB9KTogc3RyaW5nIHwgc3RyaW5nW10ge1xyXG4gICAgICAgIC8vIENoZWNrIHRoYXQgcHJvcGVydHlfcGFydHMgY29udGFpbnMgYXQgbGVhc3Qgb25lIHBhcnQuXHJcbiAgICAgICAgaWYgKHByb3BlcnR5X3BhcnRzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyBtb3JlIHByb3BlcnR5IHBhcnRzIHRvIHJlYWQhXCIpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZXQgcHJvcGVydHlfbmFtZTogc3RyaW5nID0gcHJvcGVydHlfcGFydHMuc2hpZnQoKSBhcyBzdHJpbmc7IC8vIGFzIHN0cmluZzogVGVsbCBUeXBlU2NyaXB0IHRoYXQgdGhlIHJlc3VsdCBpcyBub3QgdW5kZWZpbmVkLCBiZWNhdXNlIHRoZSBhcnJheSBpcyBub3QgZW1wdHkuXHJcblxyXG4gICAgICAgIC8vIENoZWNrIGlmIHRoZSBwcm9wZXJ0eSBuYW1lIGlzIGEgbmVnYXRpdmUgbnVtZXJpYyBpbmRleC5cclxuICAgICAgICBpZiAocHJvcGVydHlfbmFtZS5tYXRjaCgvXi1cXGQrJC91KSkge1xyXG4gICAgICAgICAgICAvLyBUaGUgcHJvcGVydHkgbmFtZSBpcyBhIG5lZ2F0aXZlIG51bWJlci5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhhdCB5YW1sX29iamVjdCBjb250YWlucyBhdCBsZWFzdCBvbmUgZWxlbWVudC5cclxuICAgICAgICAgICAgY29uc3QgeWFtbF9vYmplY3Rfa2V5cyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHlhbWxfb2JqZWN0KS5maWx0ZXIoa2V5ID0+IGtleSAhPT0gXCJsZW5ndGhcIik7IC8vIEFsbCBfcmVhbGx5IGN1c3RvbV8geWFtbCBrZXlzLCBub3QgLmxlbmd0aFxyXG4gICAgICAgICAgICBpZiAoeWFtbF9vYmplY3Rfa2V5cy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBDaGVjayBpZiB5YW1sX29iamVjdCBoYXBwZW5zIHRvIGJlIGFuIGluZGV4ZWQgbGlzdC5cclxuICAgICAgICAgICAgICAgIGxldCBpc19pbmRleGVkX2xpc3QgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgeWFtbF9vYmplY3Rfa2V5cy5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoIWtleS5tYXRjaCgvXlxcZCskL3UpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEF0IGxlYXN0IG9uZSBub24tbnVtZXJpYyBrZXkgd2FzIGZvdW5kLCBzbyBjb25zaWRlciB0aGUgb2JqZWN0IG5vdCB0byBiZSBhbiBpbmRleGVkIGxpc3QuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzX2luZGV4ZWRfbGlzdCA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgaWYgKGlzX2luZGV4ZWRfbGlzdCkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZSBvYmplY3QgaXMgYW4gaW5kZXhlZCBsaXN0IGFuZCBwcm9wZXJ0eV9uYW1lIGlzIGEgbmVnYXRpdmUgaW5kZXggbnVtYmVyLlxyXG4gICAgICAgICAgICAgICAgICAgIC8vIFRyYW5zbGF0ZSBwcm9wZXJ0eV9uYW1lIHRvIGEgcG9zaXRpdmUgaW5kZXggZnJvbSB0aGUgZW5kIG9mIHRoZSBsaXN0LlxyXG4gICAgICAgICAgICAgICAgICAgIHByb3BlcnR5X25hbWUgPSBNYXRoLm1heCgwLCAvLyBJZiBhIGdyZWF0bHkgbmVnYXRpdmUgaW5kZXggaXMgdXNlZCAoZS5nLiAtOTk5KSwgZG9uJ3QgYWxsb3cgdGhlIG5ldyBpbmRleCB0byBiZSBuZWdhdGl2ZSBhZ2Fpbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgeWFtbF9vYmplY3Rfa2V5cy5sZW5ndGhcclxuICAgICAgICAgICAgICAgICAgICAgICAgKyBwYXJzZUludChwcm9wZXJ0eV9uYW1lKSAvLyBBbHRob3VnaCArIGlzIHVzZWQsIHRoaXMgd2lsbCBiZSBhIHN1YnRyYWN0aW9uLCBiZWNhdXNlIHByb3BlcnR5X25hbWUgaXMgcHJlZml4ZWQgd2l0aCBhIG1pbnVzLlxyXG4gICAgICAgICAgICAgICAgICAgICkudG9TdHJpbmcoKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gR2V0IGEgdmFsdWVcclxuICAgICAgICBjb25zdCBwcm9wZXJ0eV92YWx1ZSA9IHlhbWxfb2JqZWN0W3Byb3BlcnR5X25hbWVdO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpZiB0aGUgdmFsdWUgaXMgZWl0aGVyOiBub3QgZm91bmQsIG9iamVjdCwgb3IgbGl0ZXJhbC5cclxuICAgICAgICBpZiAodW5kZWZpbmVkID09PSBwcm9wZXJ0eV92YWx1ZSkge1xyXG4gICAgICAgICAgICAvLyBQcm9wZXJ0eSB3YXMgbm90IGZvdW5kLlxyXG4gICAgICAgICAgICBlcnJvcl9tZXNzYWdlcy5wdXNoKFwiWUFNTCBwcm9wZXJ0eSAnXCIgKyBwcm9wZXJ0eV9uYW1lICsgXCInIGlzIG5vdCBmb3VuZC5cIik7XHJcbiAgICAgICAgICAgIHJldHVybiBlcnJvcl9tZXNzYWdlcztcclxuICAgICAgICB9IGVsc2UgaWYgKG51bGwgPT09IHByb3BlcnR5X3ZhbHVlKSB7XHJcbiAgICAgICAgICAgIC8vIFByb3BlcnR5IGlzIGZvdW5kLCBidXQgaGFzIGFuIGVtcHR5IHZhbHVlLiBFeGFtcGxlOlxyXG4gICAgICAgICAgICAvLyAgIC0tLVxyXG4gICAgICAgICAgICAvLyAgIGl0ZW1BOiB2YWx1ZUFcclxuICAgICAgICAgICAgLy8gICBpdGVtQjpcclxuICAgICAgICAgICAgLy8gICBpdGVtQzogdmFsdWVDXHJcbiAgICAgICAgICAgIC8vICAgLS0tXHJcbiAgICAgICAgICAgIC8vIEhlcmUgYGl0ZW1CYCB3b3VsZCBoYXZlIGEgbnVsbCB2YWx1ZS5cclxuICAgICAgICAgICAgZXJyb3JfbWVzc2FnZXMucHVzaChcIllBTUwgcHJvcGVydHkgJ1wiICsgcHJvcGVydHlfbmFtZSArIFwiJyBoYXMgYSBudWxsIHZhbHVlLiBNYWtlIHN1cmUgdGhlIHByb3BlcnR5IGlzIG5vdCBhY2NpZGVudGFsbHkgbGVmdCBlbXB0eS5cIik7XHJcbiAgICAgICAgICAgIHJldHVybiBlcnJvcl9tZXNzYWdlcztcclxuICAgICAgICB9IGVsc2UgaWYgKFwib2JqZWN0XCIgPT09IHR5cGVvZiBwcm9wZXJ0eV92YWx1ZSkge1xyXG4gICAgICAgICAgICAvLyBUaGUgdmFsdWUgaXMgYW4gb2JqZWN0LlxyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB3ZSBoYXZlIHN0aWxsIGRvdCBub3RhdGlvbiBwYXJ0cyBsZWZ0IGluIHRoZSBwcm9wZXJ0eSBwYXRoLlxyXG4gICAgICAgICAgICBpZiAoMCA9PT0gcHJvcGVydHlfcGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBObyBkb3Qgbm90YXRpb24gcGFydHMgYXJlIGxlZnQuXHJcbiAgICAgICAgICAgICAgICAvLyBGcmVhayBvdXQuXHJcbiAgICAgICAgICAgICAgICBjb25zdCBuZXN0ZWRfZWxlbWVudHNfa2V5cyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHByb3BlcnR5X3ZhbHVlKTtcclxuICAgICAgICAgICAgICAgIGlmIChuZXN0ZWRfZWxlbWVudHNfa2V5cy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JfbWVzc2FnZXMucHVzaChcIllBTUwgcHJvcGVydHkgJ1wiICsgcHJvcGVydHlfbmFtZSArIFwiJyBjb250YWlucyBhIG5lc3RlZCBlbGVtZW50IHdpdGgga2V5czogXCIgKyBuZXN0ZWRfZWxlbWVudHNfa2V5cy5qb2luKFwiLCBcIikgKyBcIi4gVXNlIGUuZy4gJ1wiICsgcHJvcGVydHlfcGF0aCArIFwiLlwiICsgbmVzdGVkX2VsZW1lbnRzX2tleXNbMF0gKyBcIicgdG8gZ2V0IGl0cyB2YWx1ZS5cIik7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yX21lc3NhZ2VzLnB1c2goXCJZQU1MIHByb3BlcnR5ICdcIiArIHByb3BlcnR5X25hbWUgKyBcIicgY29udGFpbnMgYSBuZXN0ZWQgZWxlbWVudC4gVXNlIGEgcHJvcGVydHkgbmFtZSB0aGF0IHBvaW50cyB0byBhIGxpdGVyYWwgdmFsdWUgaW5zdGVhZC5cIik7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gZXJyb3JfbWVzc2FnZXM7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBEb3Qgbm90YXRpb24gcGF0aCBzdGlsbCBoYXMgYW5vdGhlciBwcm9wZXJ0eSBuYW1lIGxlZnQsIHNvIGNvbnRpbnVlIHRoZSBodW50LlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG5lc3RlZF9yZWFkKHByb3BlcnR5X3BhcnRzLCBwcm9wZXJ0eV9wYXRoLCBwcm9wZXJ0eV92YWx1ZSBhcyB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB8IG51bWJlciB8IG9iamVjdCB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIFRoZSB2YWx1ZSBpcyBsaXRlcmFsLCBpLmUuIGEgc3RyaW5nIG9yIG51bWJlci5cclxuICAgICAgICAgICAgaWYgKHByb3BlcnR5X3BhcnRzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgIGVycm9yX21lc3NhZ2VzLnB1c2goXCJZQU1MIHByb3BlcnR5ICdcIiArIHByb3BlcnR5X25hbWUgKyBcIicgZ2l2ZXMgYWxyZWFkeSBhIGxpdGVyYWwgdmFsdWUgJ1wiICsgcHJvcGVydHlfdmFsdWUudG9TdHJpbmcoKSArIFwiJywgYnV0IHRoZSBhcmd1bWVudCAnXCIgKyBwcm9wZXJ0eV9wYXRoICsgXCInIGFzc3VtZXMgdGhlIHByb3BlcnR5IHdvdWxkIGNvbnRhaW4gYSBuZXN0ZWQgZWxlbWVudCB3aXRoIHRoZSBrZXkgJ1wiICsgcHJvcGVydHlfcGFydHNbMF0gKyBcIicuXCIpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGVycm9yX21lc3NhZ2VzO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHByb3BlcnR5X3ZhbHVlLnRvU3RyaW5nKCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1ZhcmlhYmxlfSBmcm9tIFwiLi9WYXJpYWJsZVwiO1xyXG5pbXBvcnQge1RGaWxlfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBGaWxlVmFyaWFibGUgZXh0ZW5kcyBWYXJpYWJsZSB7XHJcblxyXG4gICAgcHJvdGVjdGVkIGFsd2F5c19hdmFpbGFibGUgPSBmYWxzZTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgZ2V0RmlsZU9yVGhyb3coKTogVEZpbGUgfCBuZXZlciB7XHJcbiAgICAgICAgY29uc3QgY3VycmVudEZpbGUgPSB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlRmlsZSgpO1xyXG4gICAgICAgIGlmICghY3VycmVudEZpbGUpIHtcclxuICAgICAgICAgICAgdGhpcy50aHJvdyhcIk5vIGZpbGUgaXMgYWN0aXZlIGF0IHRoZSBtb21lbnQuIE9wZW4gYSBmaWxlIG9yIGNsaWNrIGEgcGFuZSB0aGF0IGhhcyBhIGZpbGUgb3Blbi5cIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBjdXJyZW50RmlsZTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QXZhaWxhYmlsaXR5VGV4dCgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+T25seSBhdmFpbGFibGU8L3N0cm9uZz4gd2hlbiB0aGUgYWN0aXZlIHBhbmUgY29udGFpbnMgYSBmaWxlLCBub3QgaW4gZ3JhcGggdmlldyBvciBvdGhlciBub24tZmlsZSB2aWV3LlwiO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0lQYXJhbWV0ZXJzfSBmcm9tIFwiLi9WYXJpYWJsZVwiO1xyXG5pbXBvcnQge0lBdXRvY29tcGxldGVJdGVtfSBmcm9tIFwiLi4vc2V0dGluZ3Mvc2V0dGluZ19lbGVtZW50cy9BdXRvY29tcGxldGVcIjtcclxuaW1wb3J0IHtnZXRGaWxlRXh0ZW5zaW9ufSBmcm9tIFwiLi9WYXJpYWJsZUhlbHBlcnNcIjtcclxuaW1wb3J0IHtGaWxlVmFyaWFibGV9IGZyb20gXCIuL0ZpbGVWYXJpYWJsZVwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0ZpbGVFeHRlbnNpb24gZXh0ZW5kcyBGaWxlVmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcImZpbGVfZXh0ZW5zaW9uXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyB0aGUgY3VycmVudCBmaWxlIG5hbWUncyBlbmRpbmcuIFVzZSB7e2ZpbGVfZXh0ZW5zaW9uOndpdGgtZG90fX0gdG8gaW5jbHVkZSBhIHByZWNlZGluZyBkb3QuIElmIHRoZSBleHRlbnNpb24gaXMgZW1wdHksIG5vIGRvdCBpcyBhZGRlZC4ge3tmaWxlX2V4dGVuc2lvbjpuby1kb3R9fSBuZXZlciBpbmNsdWRlcyBhIGRvdC5cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHBhcmFtZXRlcnM6IElQYXJhbWV0ZXJzID0ge1xyXG4gICAgICAgIFwiZG90XCI6IHtcclxuICAgICAgICAgICAgb3B0aW9uczogW1wid2l0aC1kb3RcIiwgXCJuby1kb3RcIl0sXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH0sXHJcbiAgICB9O1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKGNhc3RlZEFyZ3VtZW50czoge1wiZG90XCI6IFwid2l0aC1kb3RcIiB8IFwibm8tZG90XCJ9KTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICByZXR1cm4gZ2V0RmlsZUV4dGVuc2lvbih0aGlzLmdldEZpbGVPclRocm93KCksIGNhc3RlZEFyZ3VtZW50cy5kb3QgPT09IFwid2l0aC1kb3RcIik7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEF1dG9jb21wbGV0ZUl0ZW1zKCkge1xyXG4gICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgIC8vIE5vcm1hbCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7XCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjpuby1kb3R9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSBjdXJyZW50IGZpbGUgbmFtZSdzIGVuZGluZyB3aXRob3V0IGEgcHJlY2VkaW5nIGRvdC4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6d2l0aC1kb3R9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSBjdXJyZW50IGZpbGUgbmFtZSdzIGVuZGluZyB3aXRoIGEgcHJlY2VkaW5nIGRvdC4gSWYgdGhlIGV4dGVuc2lvbiBpcyBlbXB0eSwgbm8gZG90IGlzIGluY2x1ZGVkLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5vcm1hbC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuXHJcbiAgICAgICAgICAgIC8vIFVuZXNjYXBlZCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7IVwiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6bm8tZG90fX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyB0aGUgY3VycmVudCBmaWxlIG5hbWUncyBlbmRpbmcgd2l0aG91dCBhIHByZWNlZGluZyBkb3QuIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwidW5lc2NhcGVkLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3shXCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjp3aXRoLWRvdH19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgdGhlIGN1cnJlbnQgZmlsZSBuYW1lJ3MgZW5kaW5nIHdpdGggYSBwcmVjZWRpbmcgZG90LiBJZiB0aGUgZXh0ZW5zaW9uIGlzIGVtcHR5LCBubyBkb3QgaXMgaW5jbHVkZWQuIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwidW5lc2NhcGVkLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgIF07XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEhlbHBOYW1lKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIFwiPHN0cm9uZz57e2ZpbGVfZXh0ZW5zaW9uOndpdGgtZG90fX08L3N0cm9uZz4gb3IgPHN0cm9uZz57e2ZpbGVfZXh0ZW5zaW9uOm5vLWRvdH19PC9zdHJvbmc+XCI7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7RmlsZVZhcmlhYmxlfSBmcm9tIFwiLi9GaWxlVmFyaWFibGVcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9GaWxlTmFtZSBleHRlbmRzIEZpbGVWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiZmlsZV9uYW1lXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyB0aGUgY3VycmVudCBmaWxlIG5hbWUgd2l0aCBhIGZpbGUgZXh0ZW5zaW9uLiBJZiB5b3UgbmVlZCBpdCB3aXRob3V0IHRoZSBleHRlbnNpb24sIHVzZSB7e3RpdGxlfX0gaW5zdGVhZC5cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZSgpOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmdldEZpbGVPclRocm93KCkubmFtZTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtJUGFyYW1ldGVyc30gZnJvbSBcIi4vVmFyaWFibGVcIjtcclxuaW1wb3J0IHtJQXV0b2NvbXBsZXRlSXRlbX0gZnJvbSBcIi4uL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvQXV0b2NvbXBsZXRlXCI7XHJcbmltcG9ydCB7RmlsZVZhcmlhYmxlfSBmcm9tIFwiLi9GaWxlVmFyaWFibGVcIjtcclxuaW1wb3J0IHtnZXRGaWxlUGF0aH0gZnJvbSBcIi4vVmFyaWFibGVIZWxwZXJzXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfRmlsZVBhdGggZXh0ZW5kcyBGaWxlVmFyaWFibGV7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiZmlsZV9wYXRoXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyBwYXRoIHRvIHRoZSBjdXJyZW50IGZpbGUsIGVpdGhlciBhcyBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbSwgb3IgYXMgcmVsYXRpdmUgZnJvbSB0aGUgcm9vdCBvZiB0aGUgT2JzaWRpYW4gdmF1bHQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBwYXJhbWV0ZXJzOiBJUGFyYW1ldGVycyA9IHtcclxuICAgICAgICBtb2RlOiB7XHJcbiAgICAgICAgICAgIG9wdGlvbnM6IFtcImFic29sdXRlXCIsIFwicmVsYXRpdmVcIl0sXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH0sXHJcbiAgICB9O1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKGNhc3RlZEFyZ3VtZW50czoge21vZGU6IFwiYWJzb2x1dGVcIiB8IFwicmVsYXRpdmVcIn0pOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHJldHVybiBnZXRGaWxlUGF0aCh0aGlzLmFwcCwgdGhpcy5nZXRGaWxlT3JUaHJvdygpLCBjYXN0ZWRBcmd1bWVudHMubW9kZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEF1dG9jb21wbGV0ZUl0ZW1zKCkge1xyXG4gICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgIC8vIE5vcm1hbCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7XCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjphYnNvbHV0ZX19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgcGF0aCB0byB0aGUgY3VycmVudCBmaWxlLCBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbS4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6cmVsYXRpdmV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHBhdGggdG8gdGhlIGN1cnJlbnQgZmlsZSwgcmVsYXRpdmUgZnJvbSB0aGUgcm9vdCBvZiB0aGUgT2JzaWRpYW4gdmF1bHQuIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwibm9ybWFsLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG5cclxuICAgICAgICAgICAgLy8gVW5lc2NhcGVkIHZhcmlhYmxlc1xyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3shXCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjphYnNvbHV0ZX19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgcGF0aCB0byB0aGUgY3VycmVudCBmaWxlLCBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbS4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJ1bmVzY2FwZWQtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7eyFcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOnJlbGF0aXZlfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyBwYXRoIHRvIHRoZSBjdXJyZW50IGZpbGUsIHJlbGF0aXZlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIE9ic2lkaWFuIHZhdWx0LiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRIZWxwTmFtZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+e3tmaWxlX3BhdGg6cmVsYXRpdmV9fTwvc3Ryb25nPiBvciA8c3Ryb25nPnt7ZmlsZV9wYXRoOmFic29sdXRlfX08L3N0cm9uZz5cIjtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtGaWxlVmFyaWFibGV9IGZyb20gXCIuL0ZpbGVWYXJpYWJsZVwiO1xyXG5pbXBvcnQge1xyXG4gICAgVEZpbGUsXHJcbiAgICBURm9sZGVyLFxyXG59IGZyb20gXCJvYnNpZGlhblwiO1xyXG5cclxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEZvbGRlclZhcmlhYmxlIGV4dGVuZHMgRmlsZVZhcmlhYmxlIHtcclxuXHJcbiAgICBwcm90ZWN0ZWQgZ2V0Rm9sZGVyT3JUaHJvdygpOiBURm9sZGVyIHwgbmV2ZXIge1xyXG4gICAgICAgIC8vIEdldCBjdXJyZW50IGZpbGUncyBwYXJlbnQgZm9sZGVyLlxyXG4gICAgICAgIGNvbnN0IGZpbGU6IFRGaWxlID0gdGhpcy5nZXRGaWxlT3JUaHJvdygpO1xyXG4gICAgICAgIGNvbnN0IGN1cnJlbnRGb2xkZXI6IFRGb2xkZXIgPSBmaWxlLnBhcmVudDtcclxuICAgICAgICBpZiAoIWN1cnJlbnRGb2xkZXIpIHtcclxuICAgICAgICAgICAgLy8gTm8gcGFyZW50IGZvbGRlci5cclxuICAgICAgICAgICAgdGhpcy50aHJvdyhcIlRoZSBjdXJyZW50IGZpbGUgZG9lcyBub3QgaGF2ZSBhIHBhcmVudCBmb3Igc29tZSBzdHJhbmdlIHJlYXNvbi5cIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBjdXJyZW50Rm9sZGVyO1xyXG4gICAgfVxyXG5cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtGb2xkZXJWYXJpYWJsZX0gZnJvbSBcIi4vRm9sZGVyVmFyaWFibGVcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9Gb2xkZXJOYW1lIGV4dGVuZHMgRm9sZGVyVmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcImZvbGRlcl9uYW1lXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyB0aGUgY3VycmVudCBmaWxlJ3MgcGFyZW50IGZvbGRlciBuYW1lLCBvciBhIGRvdCBpZiB0aGUgZm9sZGVyIGlzIHRoZSB2YXVsdCdzIHJvb3QuIE5vIGFuY2VzdG9yIGZvbGRlcnMgYXJlIGluY2x1ZGVkLlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKCk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgY29uc3QgZm9sZGVyID0gdGhpcy5nZXRGb2xkZXJPclRocm93KCk7XHJcbiAgICAgICAgcmV0dXJuIGZvbGRlci5pc1Jvb3QoKVxyXG4gICAgICAgICAgICA/IFwiLlwiIC8vIFJldHVybiBhIGRvdCBpbnN0ZWFkIG9mIGFuIGVtcHR5IHN0cmluZy5cclxuICAgICAgICAgICAgOiBmb2xkZXIubmFtZVxyXG4gICAgICAgIDtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtJUGFyYW1ldGVyc30gZnJvbSBcIi4vVmFyaWFibGVcIjtcclxuaW1wb3J0IHtJQXV0b2NvbXBsZXRlSXRlbX0gZnJvbSBcIi4uL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvQXV0b2NvbXBsZXRlXCI7XHJcbmltcG9ydCB7Rm9sZGVyVmFyaWFibGV9IGZyb20gXCIuL0ZvbGRlclZhcmlhYmxlXCI7XHJcbmltcG9ydCB7Z2V0Rm9sZGVyUGF0aH0gZnJvbSBcIi4vVmFyaWFibGVIZWxwZXJzXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfRm9sZGVyUGF0aCBleHRlbmRzIEZvbGRlclZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJmb2xkZXJfcGF0aFwiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiR2l2ZXMgcGF0aCB0byB0aGUgY3VycmVudCBmaWxlJ3MgcGFyZW50IGZvbGRlciwgZWl0aGVyIGFzIGFic29sdXRlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIGZpbGUgc3lzdGVtLCBvciBhcyByZWxhdGl2ZSBmcm9tIHRoZSByb290IG9mIHRoZSBPYnNpZGlhbiB2YXVsdC5cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHBhcmFtZXRlcnM6IElQYXJhbWV0ZXJzID0ge1xyXG4gICAgICAgIG1vZGU6IHtcclxuICAgICAgICAgICAgb3B0aW9uczogW1wiYWJzb2x1dGVcIiwgXCJyZWxhdGl2ZVwiXSxcclxuICAgICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZShjYXN0ZWRBcmd1bWVudHM6IHttb2RlOiBcImFic29sdXRlXCIgfCBcInJlbGF0aXZlXCJ9KTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICByZXR1cm4gZ2V0Rm9sZGVyUGF0aCh0aGlzLmFwcCwgdGhpcy5nZXRGb2xkZXJPclRocm93KCksIGNhc3RlZEFyZ3VtZW50cy5tb2RlKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QXV0b2NvbXBsZXRlSXRlbXMoKSB7XHJcbiAgICAgICAgcmV0dXJuIFtcclxuICAgICAgICAgICAgLy8gTm9ybWFsIHZhcmlhYmxlc1xyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3tcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOmFic29sdXRlfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyBwYXRoIHRvIHRoZSBjdXJyZW50IGZpbGUncyBwYXJlbnQgZm9sZGVyLCBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbS4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6cmVsYXRpdmV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHBhdGggdG8gdGhlIGN1cnJlbnQgZmlsZSdzIHBhcmVudCBmb2xkZXIsIHJlbGF0aXZlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIE9ic2lkaWFuIHZhdWx0LiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5vcm1hbC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuXHJcbiAgICAgICAgICAgIC8vIFVuZXNjYXBlZCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7IVwiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6YWJzb2x1dGV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHBhdGggdG8gdGhlIGN1cnJlbnQgZmlsZSdzIHBhcmVudCBmb2xkZXIsIGFic29sdXRlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIGZpbGUgc3lzdGVtLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7IVwiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6cmVsYXRpdmV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHBhdGggdG8gdGhlIGN1cnJlbnQgZmlsZSdzIHBhcmVudCBmb2xkZXIsIHJlbGF0aXZlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIE9ic2lkaWFuIHZhdWx0LiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRIZWxwTmFtZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+e3tmb2xkZXJfcGF0aDpyZWxhdGl2ZX19PC9zdHJvbmc+IG9yIDxzdHJvbmc+e3tmb2xkZXJfcGF0aDphYnNvbHV0ZX19PC9zdHJvbmc+XCI7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7RWRpdG9yVmFyaWFibGV9IGZyb20gXCIuL0VkaXRvclZhcmlhYmxlXCI7XHJcbmltcG9ydCB7RU9MfSBmcm9tIFwib3NcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9TZWxlY3Rpb24gZXh0ZW5kcyBFZGl0b3JWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwic2VsZWN0aW9uXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyB0aGUgY3VycmVudGx5IHNlbGVjdGVkIHRleHQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoKTogUHJvbWlzZTxzdHJpbmc+IHtcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgdGhhdCB3ZSBhcmUgYWJsZSB0byBnZXQgYW4gZWRpdG9yXHJcbiAgICAgICAgY29uc3QgZWRpdG9yID0gdGhpcy5nZXRFZGl0b3JPclRocm93KCk7XHJcblxyXG4gICAgICAgIC8vIENoZWNrIHRoZSB2aWV3IG1vZGVcclxuICAgICAgICB0aGlzLnJlcXVpcmVWaWV3TW9kZVNvdXJjZSgpO1xyXG5cclxuICAgICAgICAvLyBHb29kLCB0aGUgZWRpdG9yIGlzIGluIFwic291cmNlXCIgbW9kZSwgc28gaXQncyBwb3NzaWJsZSB0byBnZXQgYSBzZWxlY3Rpb24uXHJcbiAgICAgICAgaWYgKGVkaXRvci5zb21ldGhpbmdTZWxlY3RlZCgpKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBlZGl0b3IuZ2V0U2VsZWN0aW9uKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMudGhyb3coXCJOb3RoaW5nIGlzIHNlbGVjdGVkLiBcIitFT0wrRU9MK1wiKFRoaXMgZXJyb3IgbWVzc2FnZSB3YXMgYWRkZWQgaW4gU0MgMC4xOC4wLiBFYXJsaWVyIHRoZSB2YXJpYWJsZSBnYXZlIGFuIGVtcHR5IHRleHQgaW4gdGhpcyBzaXR1YXRpb24uIElmIHlvdSB3YW50IHRvIHJlc3RvcmUgdGhlIG9sZCBiZWhhdmlvciwgZ28gdG8gU0Mgc2V0dGluZ3MsIHRoZW4gdG8gVmFyaWFibGVzIHRhYiwgYW5kIGRlZmluZSBhIGRlZmF1bHQgdmFsdWUgZm9yIHt7c2VsZWN0aW9ufX0uKVwiKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QXZhaWxhYmlsaXR5VGV4dCgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+T25seSBhdmFpbGFibGU8L3N0cm9uZz4gd2hlbiBzb21ldGhpbmcgaXMgc2VsZWN0ZWQgaW4gPGVtPkVkaXRpbmc8L2VtPi88ZW0+TGl2ZSBwcmV2aWV3PC9lbT4gbW9kZSwgPHN0cm9uZz5ub3Q8L3N0cm9uZz4gaW4gPGVtPlJlYWRpbmc8L2VtPiBtb2RlLlwiO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0lQYXJhbWV0ZXJzfSBmcm9tIFwiLi9WYXJpYWJsZVwiO1xyXG5pbXBvcnQge0ZpbGVWYXJpYWJsZX0gZnJvbSBcIi4vRmlsZVZhcmlhYmxlXCI7XHJcbmltcG9ydCB7Z2V0RmlsZVRhZ3N9IGZyb20gXCIuL1ZhcmlhYmxlSGVscGVyc1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX1RhZ3MgZXh0ZW5kcyBGaWxlVmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcInRhZ3NcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIGFsbCB0YWdzIGRlZmluZWQgaW4gdGhlIGN1cnJlbnQgbm90ZS4gUmVwbGFjZSB0aGUgXFxcInNlcGFyYXRvclxcXCIgcGFydCB3aXRoIGEgY29tbWEsIHNwYWNlIG9yIHdoYXRldmVyIGNoYXJhY3RlcnMgeW91IHdhbnQgdG8gdXNlIGFzIGEgc2VwYXJhdG9yIGJldHdlZW4gdGFncy4gQSBzZXBhcmF0b3IgaXMgYWx3YXlzIG5lZWRlZCB0byBiZSBkZWZpbmVkLlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgcGFyYW1ldGVyczogSVBhcmFtZXRlcnMgPSB7XHJcbiAgICAgICAgc2VwYXJhdG9yOiB7XHJcbiAgICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoY2FzdGVkQXJndW1lbnRzOiB7c2VwYXJhdG9yOiBzdHJpbmd9KTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICByZXR1cm4gZ2V0RmlsZVRhZ3ModGhpcy5hcHAsIHRoaXMuZ2V0RmlsZU9yVGhyb3coKSkuam9pbihjYXN0ZWRBcmd1bWVudHMuc2VwYXJhdG9yKTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtGaWxlVmFyaWFibGV9IGZyb20gXCIuL0ZpbGVWYXJpYWJsZVwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX1RpdGxlIGV4dGVuZHMgRmlsZVZhcmlhYmxle1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcInRpdGxlXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyB0aGUgY3VycmVudCBmaWxlIG5hbWUgd2l0aG91dCBhIGZpbGUgZXh0ZW5zaW9uLiBJZiB5b3UgbmVlZCBpdCB3aXRoIHRoZSBleHRlbnNpb24sIHVzZSB7e2ZpbGVfbmFtZX19IGluc3RlYWQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoKTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICByZXR1cm4gdGhpcy5nZXRGaWxlT3JUaHJvdygpLmJhc2VuYW1lO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge2dldFZhdWx0QWJzb2x1dGVQYXRofSBmcm9tIFwiLi4vQ29tbW9uXCI7XHJcbmltcG9ydCB7VmFyaWFibGV9IGZyb20gXCIuL1ZhcmlhYmxlXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfVmF1bHRQYXRoIGV4dGVuZHMgVmFyaWFibGV7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwidmF1bHRfcGF0aFwiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiR2l2ZXMgdGhlIE9ic2lkaWFuIHZhdWx0J3MgYWJzb2x1dGUgcGF0aCBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlc3lzdGVtLiBUaGlzIGlzIHRoZSBzYW1lIHRoYXQgaXMgdXNlZCBhcyBhIGRlZmF1bHQgd29ya2luZyBkaXJlY3RvcnkgaWYgeW91IGRvIG5vdCBkZWZpbmUgb25lIG1hbnVhbGx5LiBJZiB5b3UgZGVmaW5lIGEgd29ya2luZyBkaXJlY3RvcnkgbWFudWFsbHksIHRoaXMgdmFyaWFibGUgd29uJ3QgZ2l2ZSB5b3UgeW91ciBtYW51YWxseSBkZWZpbmVkIGRpcmVjdG9yeSwgaXQgYWx3YXlzIGdpdmVzIHRoZSB2YXVsdCdzIHJvb3QgZGlyZWN0b3J5LlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKCk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgcmV0dXJuIGdldFZhdWx0QWJzb2x1dGVQYXRoKHRoaXMuYXBwKTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtWYXJpYWJsZX0gZnJvbSBcIi4vVmFyaWFibGVcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9Xb3Jrc3BhY2UgZXh0ZW5kcyBWYXJpYWJsZXtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJ3b3Jrc3BhY2VcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIHRoZSBjdXJyZW50IHdvcmtzcGFjZSdzIG5hbWUuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIGFsd2F5c19hdmFpbGFibGUgPSBmYWxzZTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZSgpOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIC8vIElkZWEgaG93IHRvIGFjY2VzcyB0aGUgd29ya3NwYWNlcyBwbHVnaW4gaXMgY29waWVkIDIwMjEtMDktMTUgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vVmluemVudDAzL29ic2lkaWFuLWFkdmFuY2VkLXVyaS9ibG9iL2Y3ZWY4MGQ1MjUyNDgxMjQyZTY5NDk2MjA4ZTkyNTg3NDIwOWY0YWEvbWFpbi50cyNMMTY4LUwxNzlcclxuICAgICAgICAvLyBAdHMtaWdub3JlIGludGVybmFsUGx1Z2lucyBleGlzdHMsIGFsdGhvdWdoIGl0J3Mgbm90IGluIG9ic2lkaWFuLmQudHMuXHJcbiAgICAgICAgY29uc3Qgd29ya3NwYWNlc19wbHVnaW4gPSB0aGlzLmFwcC5pbnRlcm5hbFBsdWdpbnM/LnBsdWdpbnM/LndvcmtzcGFjZXM7XHJcbiAgICAgICAgaWYgKCF3b3Jrc3BhY2VzX3BsdWdpbikge1xyXG4gICAgICAgICAgICB0aGlzLnRocm93KFwiV29ya3NwYWNlcyBjb3JlIHBsdWdpbiBpcyBub3QgZm91bmQgZm9yIHNvbWUgcmVhc29uLiBQbGVhc2UgY3JlYXRlIGEgZGlzY3Vzc2lvbiBpbiBHaXRIdWIuXCIpO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoIXdvcmtzcGFjZXNfcGx1Z2luLmVuYWJsZWQpIHtcclxuICAgICAgICAgICAgdGhpcy50aHJvdyhcIldvcmtzcGFjZXMgY29yZSBwbHVnaW4gaXMgbm90IGVuYWJsZWQuXCIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc3Qgd29ya3NwYWNlX25hbWUgPSB3b3Jrc3BhY2VzX3BsdWdpbi5pbnN0YW5jZT8uYWN0aXZlV29ya3NwYWNlO1xyXG4gICAgICAgIGlmICghd29ya3NwYWNlX25hbWUpIHtcclxuICAgICAgICAgICAgdGhpcy50aHJvdyhcIkNvdWxkIG5vdCBmaWd1cmUgb3V0IHRoZSBjdXJyZW50IHdvcmtzcGFjZSdzIG5hbWUuIFByb2JhYmx5IHlvdSBoYXZlIG5vdCBsb2FkZWQgYSB3b3Jrc3BhY2UuIFlvdSBjYW4gZG8gaXQgZS5nLiB2aWEgXFxcIk1hbmFnZSB3b3Jrc3BhY2VzXFxcIiBmcm9tIHRoZSBsZWZ0IHNpZGUgcGFuZWwuXCIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQWxsIG9rXHJcbiAgICAgICAgcmV0dXJuIHdvcmtzcGFjZV9uYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRBdmFpbGFiaWxpdHlUZXh0KCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIFwiPHN0cm9uZz5Pbmx5IGF2YWlsYWJsZTwvc3Ryb25nPiB3aGVuIHRoZSBXb3Jrc3BhY2VzIGNvcmUgcGx1Z2luIGlzIGVuYWJsZWQuXCI7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7XHJcbiAgICBJUGFyYW1ldGVycyxcclxuICAgIFZhcmlhYmxlLFxyXG59IGZyb20gXCIuL1ZhcmlhYmxlXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfUGFzc3Rocm91Z2ggZXh0ZW5kcyBWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwicGFzc3Rocm91Z2hcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIHRoZSBzYW1lIHZhbHVlIHRoYXQgaXMgcGFzc2VkIGFzIGFuIGFyZ3VtZW50LiBVc2VkIGZvciB0ZXN0aW5nIHNwZWNpYWwgY2hhcmFjdGVycycgZXNjYXBpbmcuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBwYXJhbWV0ZXJzOiBJUGFyYW1ldGVycyA9IHtcclxuICAgICAgICB2YWx1ZToge1xyXG4gICAgICAgICAgICB0eXBlOiBcInN0cmluZ1wiLFxyXG4gICAgICAgICAgICByZXF1aXJlZDogdHJ1ZSxcclxuICAgICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKGNhc3RlZEFyZ3VtZW50czoge3ZhbHVlOiBzdHJpbmd9KTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICAvLyBTaW1wbHkgcmV0dXJuIHRoZSBhcmd1bWVudCB0aGF0IHdhcyByZWNlaXZlZC5cclxuICAgICAgICByZXR1cm4gY2FzdGVkQXJndW1lbnRzLnZhbHVlO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRBdmFpbGFiaWxpdHlUZXh0KCkge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+T25seSBhdmFpbGFibGU8L3N0cm9uZz4gaW4gZGVidWcgbW9kZS5cIjtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtJUGFyYW1ldGVyc30gZnJvbSBcIi4vVmFyaWFibGVcIjtcclxuaW1wb3J0IHtGaWxlVmFyaWFibGV9IGZyb20gXCIuL0ZpbGVWYXJpYWJsZVwiO1xyXG5pbXBvcnQge2dldEZpbGVZQU1MVmFsdWV9IGZyb20gXCIuL1ZhcmlhYmxlSGVscGVyc1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX1lBTUxWYWx1ZSBleHRlbmRzIEZpbGVWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwieWFtbF92YWx1ZVwiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiUmVhZHMgYSBzaW5nbGUgdmFsdWUgZnJvbSB0aGUgY3VycmVudCBmaWxlJ3MgZnJvbnRtYXR0ZXIuIFRha2VzIGEgcHJvcGVydHkgbmFtZSBhcyBhbiBhcmd1bWVudC4gWW91IGNhbiBhY2Nlc3MgbmVzdGVkIHByb3BlcnRpZXMgd2l0aCBkb3Qgbm90YXRpb246IHByb3BlcnR5MS5wcm9wZXJ0eTJcIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHBhcmFtZXRlcnM6IElQYXJhbWV0ZXJzID0ge1xyXG4gICAgICAgIHByb3BlcnR5X25hbWU6IHtcclxuICAgICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcclxuICAgICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXHJcbiAgICAgICAgfSxcclxuICAgIH07XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoY2FzdGVkQXJndW1lbnRzOiB7cHJvcGVydHlfbmFtZTogc3RyaW5nfSk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgLy8gV2UgZG8gaGF2ZSBhbiBhY3RpdmUgZmlsZVxyXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGdldEZpbGVZQU1MVmFsdWUodGhpcy5hcHAsIHRoaXMuZ2V0RmlsZU9yVGhyb3coKSwgY2FzdGVkQXJndW1lbnRzLnByb3BlcnR5X25hbWUpO1xyXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KHJlc3VsdCkpIHtcclxuICAgICAgICAgICAgLy8gVGhlIHJlc3VsdCBjb250YWlucyBlcnJvciBtZXNzYWdlKHMpLlxyXG4gICAgICAgICAgICB0aGlzLnRocm93KHJlc3VsdC5qb2luKFwiIFwiKSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gVGhlIHJlc3VsdCBpcyBvaywgaXQncyBhIHN0cmluZy5cclxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBwdWJsaWMgZ2V0QXZhaWxhYmlsaXR5VGV4dCgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBzdXBlci5nZXRBdmFpbGFiaWxpdHlUZXh0KCkgKyBcIiBBbHNvLCB0aGUgZ2l2ZW4gWUFNTCBwcm9wZXJ0eSBtdXN0IGV4aXN0IGluIHRoZSBmaWxlJ3MgZnJvbnRtYXR0ZXIuXCI7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEhlbHBOYW1lKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIFwiPHN0cm9uZz57e3lhbWxfdmFsdWU6cHJvcGVydHl9fTwvc3Ryb25nPlwiO1xyXG4gICAgfVxyXG5cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtcclxuICAgIFZhcmlhYmxlLFxyXG59IGZyb20gXCIuLi9WYXJpYWJsZVwiO1xyXG5pbXBvcnQge1NDX0V2ZW50fSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50XCI7XHJcblxyXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRXZlbnRWYXJpYWJsZSBleHRlbmRzIFZhcmlhYmxlIHtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYWx3YXlzX2F2YWlsYWJsZSA9IGZhbHNlO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICogQGFic3RyYWN0IFNob3VsZCBiZSBhYnN0cmFjdCwgYnV0IGNhbm5vdCBtYXJrIGlzIGFzIGFic3RyYWN0IGJlY2F1c2UgaXQncyBhbHNvIHN0YXRpYy5cclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHN1cHBvcnRlZF9zY19ldmVudHM6IHR5cGVvZiBTQ19FdmVudFtdO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogRXZlcnkgc3ViY2xhc3Mgc2hvdWxkIGNhbGwgdGhpcyBtZXRob2QgaW4gdGhlaXIgZ2VuZXJhdGVWYWx1ZSgpIGJlZm9yZSBnZW5lcmF0aW5nIGEgdmFsdWUuIFRoaXMgbWV0aG9kIHdpbGwgdGhyb3dcclxuICAgICAqIGEgVmFyaWFibGVFcnJvciBpZiBhbiBpbmNvbXBhdGlibGUgU0NfRXZlbnQgaXMgdHJpZWQgdG8gYmUgdXNlZCB3aXRoIHRoaXMge3t2YXJpYWJsZX19LlxyXG4gICAgICpcclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHJlcXVpcmVDb3JyZWN0RXZlbnQoc2NfZXZlbnQ6IFNDX0V2ZW50KTogdm9pZCB7XHJcbiAgICAgICAgLy8gMS4gQ2hlY2sgZ2VuZXJhbGx5IHRoYXQgYW4gZXZlbnQgaXMgaGFwcGVuaW5nLlxyXG4gICAgICAgIC8vIChNYXliZSB0aGlzIGNoZWNrIGlzIG5vdCBzbyBpbXBvcnRhbnQgYW55bW9yZSwgYXMgc2NfZXZlbnQgaXMgbm93IHJlY2VpdmVkIGFzIGEgcGFyYW1ldGVyIGluc3RlYWQgb2YgZnJvbSBhIHByb3BlcnR5LCBidXQgY2hlY2sganVzdCBpbiBjYXNlLilcclxuICAgICAgICBpZiAoIXNjX2V2ZW50KSB7XHJcbiAgICAgICAgICAgIHRoaXMudGhyb3coXCJUaGlzIHZhcmlhYmxlIGNhbiBvbmx5IGJlIHVzZWQgZHVyaW5nIGV2ZW50czogXCIgKyB0aGlzLmdldFN1bW1hcnlPZlN1cHBvcnRlZEV2ZW50cygpKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIDIuIENoZWNrIHBhcnRpY3VsYXJseSB3aGljaCBldmVudCBpdCBpcy5cclxuICAgICAgICBpZiAoIXRoaXMuc3VwcG9ydHNTQ19FdmVudChzY19ldmVudC5nZXRDbGFzcygpKSkge1xyXG4gICAgICAgICAgICB0aGlzLnRocm93KFwiVGhpcyB2YXJpYWJsZSBkb2VzIG5vdCBzdXBwb3J0IGV2ZW50ICdcIiArIHNjX2V2ZW50LnN0YXRpYygpLmdldFRpdGxlKCkgKyBcIicuIFN1cHBvcnRlZCBldmVudHM6IFwiICsgdGhpcy5nZXRTdW1tYXJ5T2ZTdXBwb3J0ZWRFdmVudHMoKSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBzdXBwb3J0c1NDX0V2ZW50KHNjX2V2ZW50X2NsYXNzOiB0eXBlb2YgU0NfRXZlbnQpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5zdXBwb3J0ZWRfc2NfZXZlbnRzLmNvbnRhaW5zKHNjX2V2ZW50X2NsYXNzKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGdldFN1bW1hcnlPZlN1cHBvcnRlZEV2ZW50cygpOiBzdHJpbmcge1xyXG4gICAgICAgIGNvbnN0IHNjX2V2ZW50X3RpdGxlczogc3RyaW5nW10gPSBbXTtcclxuICAgICAgICB0aGlzLnN1cHBvcnRlZF9zY19ldmVudHMuZm9yRWFjaCgoc2NfZXZlbnRfY2xhc3M6IHR5cGVvZiBTQ19FdmVudCkgPT4ge1xyXG4gICAgICAgICAgICBzY19ldmVudF90aXRsZXMucHVzaChzY19ldmVudF9jbGFzcy5nZXRUaXRsZSgpKTtcclxuICAgICAgICB9KTtcclxuICAgICAgICByZXR1cm4gc2NfZXZlbnRfdGl0bGVzLmpvaW4oXCIsIFwiKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QXZhaWxhYmlsaXR5VGV4dCgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+T25seSBhdmFpbGFibGU8L3N0cm9uZz4gaW4gZXZlbnRzOiBcIiArIHRoaXMuZ2V0U3VtbWFyeU9mU3VwcG9ydGVkRXZlbnRzKCkgKyBcIi5cIjtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi4vbWFpblwiO1xyXG5pbXBvcnQge0FwcCwgRXZlbnRSZWZ9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQge1xyXG4gICAgU2hlbGxDb21tYW5kUGFyc2luZ1Byb2Nlc3MsXHJcbiAgICBUU2hlbGxDb21tYW5kLFxyXG59IGZyb20gXCIuLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRDb25maWd1cmF0aW9ufSBmcm9tIFwiLi9TQ19FdmVudENvbmZpZ3VyYXRpb25cIjtcclxuaW1wb3J0IHtjbG9uZU9iamVjdH0gZnJvbSBcIi4uL0NvbW1vblwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlfSBmcm9tIFwiLi4vdmFyaWFibGVzL1ZhcmlhYmxlXCI7XHJcbmltcG9ydCB7RXZlbnRWYXJpYWJsZX0gZnJvbSBcIi4uL3ZhcmlhYmxlcy9ldmVudF92YXJpYWJsZXMvRXZlbnRWYXJpYWJsZVwiO1xyXG5pbXBvcnQge0RvY3VtZW50YXRpb25FdmVudHNGb2xkZXJMaW5rfSBmcm9tIFwiLi4vRG9jdW1lbnRhdGlvblwiO1xyXG5pbXBvcnQge1xyXG4gICAgU2hlbGxDb21tYW5kRXhlY3V0b3JcclxufSBmcm9tIFwiLi4vaW1wb3J0c1wiO1xyXG5cclxuLyoqXHJcbiAqIE5hbWVkIFNDX0V2ZW50IGluc3RlYWQgb2YganVzdCBFdmVudCwgYmVjYXVzZSBFdmVudCBpcyBhIGNsYXNzIGluIEphdmFTY3JpcHQuXHJcbiAqL1xyXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgU0NfRXZlbnQge1xyXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHBsdWdpbjogU0NfUGx1Z2luO1xyXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGFwcDogQXBwO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICogQGFic3RyYWN0IFNob3VsZCBiZSBhYnN0cmFjdCwgYnV0IGNhbm5vdCBtYXJrIGlzIGFzIGFic3RyYWN0IGJlY2F1c2UgaXQncyBhbHNvIHN0YXRpYy5cclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF9jb2RlOiBzdHJpbmc7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKiBAYWJzdHJhY3QgU2hvdWxkIGJlIGFic3RyYWN0LCBidXQgY2Fubm90IG1hcmsgaXMgYXMgYWJzdHJhY3QgYmVjYXVzZSBpdCdzIGFsc28gc3RhdGljLlxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X3RpdGxlOiBzdHJpbmc7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJZiB0cnVlLCBjaGFuZ2luZyB0aGUgZW5hYmxlZC9kaXNhYmxlZCBzdGF0dXMgb2YgdGhlIGV2ZW50IHBlcm1pdHMgcmVnaXN0ZXJpbmcgdGhlIGV2ZW50IGltbWVkaWF0ZWx5LCBzbyBpdCBjYW4gYWN0aXZhdGVcclxuICAgICAqIGFueXRpbWUuIFVzdWFsbHkgdHJ1ZSwgYnV0IGNhbiBiZSBzZXQgdG8gZmFsc2UgaWYgaW1tZWRpYXRlIHJlZ2lzdGVyaW5nIHRlbmRzIHRvIHRyaWdnZXIgdGhlIGV2ZW50IHVubmVjZXNzYXJpbHkuXHJcbiAgICAgKlxyXG4gICAgICogRXZlbnRzIGFyZSBhbHdheXMgcmVnaXN0ZXJlZCB3aGVuIGxvYWRpbmcgdGhlIHBsdWdpbiwgcmVnYXJkbGVzcyBvZiB0aGlzIHByb3BlcnR5LlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgcmVnaXN0ZXJfYWZ0ZXJfY2hhbmdpbmdfc2V0dGluZ3MgPSB0cnVlO1xyXG5cclxuICAgIHByaXZhdGUgZXZlbnRfcmVnaXN0cmF0aW9uczoge1xyXG4gICAgICAgIFtrZXk6IHN0cmluZ106IEV2ZW50UmVmLCAvLyBrZXk6IHRfc2hlbGxfY29tbWFuZCBpZFxyXG4gICAgfSA9IHt9O1xyXG4gICAgcHJvdGVjdGVkIGRlZmF1bHRfY29uZmlndXJhdGlvbjogU0NfRXZlbnRDb25maWd1cmF0aW9uID0ge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlLFxyXG4gICAgfTtcclxuXHJcbiAgICBwdWJsaWMgY29uc3RydWN0b3IocGx1Z2luOiBTQ19QbHVnaW4pIHtcclxuICAgICAgICB0aGlzLnBsdWdpbiA9IHBsdWdpbjtcclxuICAgICAgICB0aGlzLmFwcCA9IHBsdWdpbi5hcHA7XHJcblxyXG4gICAgICAgIHRoaXMuc3ViY2xhc3NfaW5zdGFuY2UgPSB0aGlzOyAvLyBTdG9yZXMgYSBzdWJjbGFzcyByZWZlcmVuY2UsIG5vdCBhIGJhc2UgY2xhc3MgcmVmZXJlbmNlLlxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ29udGFpbnMgYSB2ZXJzaW9uIG9mICd0aGlzJyB2YXJpYWJsZSB0aGF0IHJlZmVycyB0byB0aGUgYWN0dWFsIHN1YmNsYXNzLCBub3QgdGhpcyBiYXNlIGNsYXNzLlxyXG4gICAgICogVE9ETzogUGVyaGFwcyBtb3ZlIHRvIGEgbmV3IGNsYXNzIHRoYXQgd2lsbCBiZWNvbWUgYSBwYXJlbnQgb2YgdGhpcyBjbGFzcz9cclxuICAgICAqIEBwcml2YXRlXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgc3ViY2xhc3NfaW5zdGFuY2U6IHRoaXM7XHJcbiAgICBwdWJsaWMgZ2V0Q2xhc3MoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc3ViY2xhc3NfaW5zdGFuY2UuY29uc3RydWN0b3IgYXMgdHlwZW9mIFNDX0V2ZW50O1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBjYW5SZWdpc3RlckFmdGVyQ2hhbmdpbmdTZXR0aW5ncygpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5yZWdpc3Rlcl9hZnRlcl9jaGFuZ2luZ19zZXR0aW5ncztcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgcmVnaXN0ZXIodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKSB7XHJcbiAgICAgICAgY29uc3QgZXZlbnRfcmVmZXJlbmNlID0gdGhpcy5fcmVnaXN0ZXIodF9zaGVsbF9jb21tYW5kKTtcclxuICAgICAgICBpZiAoZXZlbnRfcmVmZXJlbmNlKSB7XHJcbiAgICAgICAgICAgIHRoaXMucGx1Z2luLnJlZ2lzdGVyRXZlbnQoZXZlbnRfcmVmZXJlbmNlKTtcclxuICAgICAgICAgICAgdGhpcy5ldmVudF9yZWdpc3RyYXRpb25zW3Rfc2hlbGxfY29tbWFuZC5nZXRJZCgpXSA9IGV2ZW50X3JlZmVyZW5jZTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIHVucmVnaXN0ZXIodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgYW4gRXZlbnRSZWYgaXMgYXZhaWxhYmxlLlxyXG4gICAgICAgIGlmICh1bmRlZmluZWQgPT09IHRoaXMuZXZlbnRfcmVnaXN0cmF0aW9uc1t0X3NoZWxsX2NvbW1hbmQuZ2V0SWQoKV0pIHtcclxuICAgICAgICAgICAgLy8gVGhlIGV2ZW50IHdhcyByZWdpc3RlcmVkIHdpdGhvdXQgYW4gRXZlbnRSZWYgb2JqZWN0LlxyXG4gICAgICAgICAgICAvLyBQcm92aWRlIGEgVFNoZWxsQ29tbWFuZCB0byBfdW5yZWdpc3RlcigpIHNvIGl0IGNhbiBkbyBhIGN1c3RvbSB1bnJlZ2lzdGVyaW5nLlxyXG4gICAgICAgICAgICB0aGlzLl91bnJlZ2lzdGVyKHRfc2hlbGxfY29tbWFuZCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gVGhlIGV2ZW50IHJlZ2lzdHJhdGlvbiBoYWQgY3JlYXRlZCBhbiBFdmVudFJlZiBvYmplY3QuXHJcbiAgICAgICAgICAgIC8vIFByb3ZpZGUgdGhlIEV2ZW50UmVmIHRvIF91bnJlZ2lzdGVyKCkgYW5kIGZvcmdldCBpdCBhZnRlcndhcmRzLlxyXG4gICAgICAgICAgICB0aGlzLl91bnJlZ2lzdGVyKHRoaXMuZXZlbnRfcmVnaXN0cmF0aW9uc1t0X3NoZWxsX2NvbW1hbmQuZ2V0SWQoKV0pO1xyXG4gICAgICAgICAgICBkZWxldGUgdGhpcy5ldmVudF9yZWdpc3RyYXRpb25zW3Rfc2hlbGxfY29tbWFuZC5nZXRJZCgpXTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IF9yZWdpc3Rlcih0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQpOiBmYWxzZSB8IEV2ZW50UmVmO1xyXG5cclxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCBfdW5yZWdpc3Rlcih0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQpOiB2b2lkO1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IF91bnJlZ2lzdGVyKGV2ZW50X3JlZmVyZW5jZTogRXZlbnRSZWYpOiB2b2lkO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogRXhlY3V0ZXMgYSBzaGVsbCBjb21tYW5kLlxyXG4gICAgICogQHBhcmFtIHRfc2hlbGxfY29tbWFuZFxyXG4gICAgICogQHBhcmFtIHBhcnNpbmdfcHJvY2VzcyBTQ19NZW51RXZlbnQgY2FuIHVzZSB0aGlzIHRvIHBhc3MgYW4gYWxyZWFkeSBzdGFydGVkIFBhcnNpbmdQcm9jZXNzIGluc3RhbmNlLiBJZiBvbWl0dGVkLCBhIG5ldyBQYXJzaW5nUHJvY2VzcyB3aWxsIGJlIGNyZWF0ZWQuXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBhc3luYyB0cmlnZ2VyKHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCwgcGFyc2luZ19wcm9jZXNzPzogU2hlbGxDb21tYW5kUGFyc2luZ1Byb2Nlc3MpIHtcclxuICAgICAgICAvLyBFeGVjdXRlIHRoZSBzaGVsbCBjb21tYW5kLlxyXG4gICAgICAgIGNvbnN0IGV4ZWN1dG9yID0gbmV3IFNoZWxsQ29tbWFuZEV4ZWN1dG9yKHRoaXMucGx1Z2luLCB0X3NoZWxsX2NvbW1hbmQsIHRoaXMpO1xyXG4gICAgICAgIGF3YWl0IGV4ZWN1dG9yLmRvUHJlYWN0aW9uc0FuZEV4ZWN1dGVTaGVsbENvbW1hbmQocGFyc2luZ19wcm9jZXNzKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgc3RhdGljIGdldENvZGUoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuZXZlbnRfY29kZTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgc3RhdGljIGdldFRpdGxlKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmV2ZW50X3RpdGxlO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIGxpc3Qgb2YgdmFyaWFibGVzIHRvIHRoZSBnaXZlbiBjb250YWluZXIgZWxlbWVudC4gRWFjaCB2YXJpYWJsZSBpcyBhIGxpbmsgdG8gaXRzIGRvY3VtZW50YXRpb24uXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIGNvbnRhaW5lclxyXG4gICAgICogQHJldHVybiBBIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIGFueXRoaW5nIHdhcyBjcmVhdGVkIG9yIG5vdC4gTm90IGFsbCBTQ19FdmVudHMgdXRpbGlzZSBldmVudCB2YXJpYWJsZXMuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBjcmVhdGVTdW1tYXJ5T2ZFdmVudFZhcmlhYmxlcyhjb250YWluZXI6IEhUTUxFbGVtZW50KTogYm9vbGVhbiB7XHJcbiAgICAgICAgbGV0IGhhc0NyZWF0ZWRFbGVtZW50cyA9IGZhbHNlO1xyXG4gICAgICAgIHRoaXMuZ2V0RXZlbnRWYXJpYWJsZXMoKS5mb3JFYWNoKCh2YXJpYWJsZTogVmFyaWFibGUpID0+IHtcclxuICAgICAgICAgICAgaWYgKGhhc0NyZWF0ZWRFbGVtZW50cykge1xyXG4gICAgICAgICAgICAgICAgY29udGFpbmVyLmluc2VydEFkamFjZW50VGV4dChcImJlZm9yZWVuZFwiLCBcIiwgXCIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGhhc0NyZWF0ZWRFbGVtZW50cyA9IHRydWU7XHJcbiAgICAgICAgICAgIHZhcmlhYmxlLmNyZWF0ZURvY3VtZW50YXRpb25MaW5rRWxlbWVudChjb250YWluZXIpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybiBoYXNDcmVhdGVkRWxlbWVudHM7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBnZXRFdmVudFZhcmlhYmxlcygpIHtcclxuICAgICAgICBjb25zdCBldmVudF92YXJpYWJsZXM6IEV2ZW50VmFyaWFibGVbXSA9IFtdO1xyXG4gICAgICAgIHRoaXMucGx1Z2luLmdldFZhcmlhYmxlcygpLmZvckVhY2goKHZhcmlhYmxlOiBWYXJpYWJsZSkgPT4ge1xyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgdmFyaWFibGUgaXMgYW4gRXZlbnRWYXJpYWJsZVxyXG4gICAgICAgICAgICBpZiAodmFyaWFibGUgaW5zdGFuY2VvZiBFdmVudFZhcmlhYmxlKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBZZXMgaXQgaXMuXHJcbiAgICAgICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgdmFyaWFibGUgc3VwcG9ydHMgdGhpcyBwYXJ0aWN1bGFyIGV2ZW50LlxyXG4gICAgICAgICAgICAgICAgaWYgKHZhcmlhYmxlLnN1cHBvcnRzU0NfRXZlbnQodGhpcy5nZXRDbGFzcygpKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFllcyBpdCBzdXBwb3J0cy5cclxuICAgICAgICAgICAgICAgICAgICBldmVudF92YXJpYWJsZXMucHVzaCh2YXJpYWJsZSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgICByZXR1cm4gZXZlbnRfdmFyaWFibGVzO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ2FuIGJlIG92ZXJyaWRkZW4gaW4gY2hpbGQgY2xhc3NlcyB0aGF0IG5lZWQgY3VzdG9tIHNldHRpbmdzIGZpZWxkcy5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gZW5hYmxlZFxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZ2V0RGVmYXVsdENvbmZpZ3VyYXRpb24oZW5hYmxlZDogYm9vbGVhbik6IFNDX0V2ZW50Q29uZmlndXJhdGlvbiB7XHJcbiAgICAgICAgY29uc3QgY29uZmlndXJhdGlvbiA9IGNsb25lT2JqZWN0PFNDX0V2ZW50Q29uZmlndXJhdGlvbj4odGhpcy5kZWZhdWx0X2NvbmZpZ3VyYXRpb24pO1xyXG4gICAgICAgIGNvbmZpZ3VyYXRpb24uZW5hYmxlZCA9IGVuYWJsZWQ7XHJcbiAgICAgICAgcmV0dXJuIGNvbmZpZ3VyYXRpb247XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGdldENvbmZpZ3VyYXRpb24odF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKSB7XHJcbiAgICAgICAgcmV0dXJuIHRfc2hlbGxfY29tbWFuZC5nZXRFdmVudENvbmZpZ3VyYXRpb24odGhpcyk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDYW4gYmUgb3ZlcnJpZGRlbiBpbiBjaGlsZCBjbGFzc2VzIHRvIHByb3ZpZGUgY3VzdG9tIGNvbmZpZ3VyYXRpb24gZmllbGRzIGZvciBTaGVsbENvbW1hbmRzRXh0cmFPcHRpb25zTW9kYWwuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIGV4dHJhX3NldHRpbmdzX2NvbnRhaW5lclxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgY3JlYXRlRXh0cmFTZXR0aW5nc0ZpZWxkcyhleHRyYV9zZXR0aW5nc19jb250YWluZXI6IEhUTUxEaXZFbGVtZW50LCB0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQpOiB2b2lkIHtcclxuICAgICAgICAvLyBNb3N0IGNsYXNzZXMgZG8gbm90IGRlZmluZSBjdXN0b20gc2V0dGluZ3MsIHNvIGZvciB0aG9zZSBjbGFzc2VzIHRoaXMgbWV0aG9kIGRvZXMgbm90IG5lZWQgdG8gZG8gYW55dGhpbmcuXHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIGFsbCB0aGUgVFNoZWxsQ29tbWFuZCBpbnN0YW5jZXMgdGhhdCBoYXZlIGVuYWJsZWQgdGhpcyBldmVudC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldFRTaGVsbENvbW1hbmRzKCk6IFRTaGVsbENvbW1hbmRbXSB7XHJcbiAgICAgICAgY29uc3QgZW5hYmxlZF90X3NoZWxsX2NvbW1hbmRzOiBUU2hlbGxDb21tYW5kW10gPSBbXTtcclxuICAgICAgICBPYmplY3QudmFsdWVzKHRoaXMucGx1Z2luLmdldFRTaGVsbENvbW1hbmRzKCkpLmZvckVhY2goKHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCkgPT4ge1xyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGlzIGV2ZW50IGhhcyBiZWVuIGVuYWJsZWQgZm9yIHRoZSBzaGVsbCBjb21tYW5kLlxyXG4gICAgICAgICAgICBpZiAodF9zaGVsbF9jb21tYW5kLmlzU0NfRXZlbnRFbmFibGVkKHRoaXMuc3RhdGljKCkuZXZlbnRfY29kZSkpIHtcclxuICAgICAgICAgICAgICAgIC8vIFllcywgaXQncyBlbmFibGVkLlxyXG4gICAgICAgICAgICAgICAgZW5hYmxlZF90X3NoZWxsX2NvbW1hbmRzLnB1c2godF9zaGVsbF9jb21tYW5kKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybiBlbmFibGVkX3Rfc2hlbGxfY29tbWFuZHM7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIHN0YXRpYygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb25zdHJ1Y3RvciBhcyB0eXBlb2YgU0NfRXZlbnQ7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDaGlsZCBjbGFzc2VzIGNhbiBvdmVycmlkZSB0aGlzIHRvIGhvb2sgaW50byBhIHNpdHVhdGlvbiB3aGVyZSBhIHVzZXIgaGFzIGVuYWJsZWQgYW4gZXZlbnQgaW4gc2V0dGluZ3MuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHRfc2hlbGxfY29tbWFuZCBUaGUgVFNoZWxsQ29tbWFuZCBpbnN0YW5jZSBmb3Igd2hpY2ggdGhpcyBTQ19FdmVudCB3YXMgZW5hYmxlZCBmb3IuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBvbkFmdGVyRW5hYmxpbmcodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKTogdm9pZCB7XHJcbiAgICAgICAgLy8gSWYgYW4gU0NfRXZlbnQgZG9lcyBub3Qgb3ZlcnJpZGUgdGhpcyBob29rIG1ldGhvZCwgZG8gbm90aGluZy5cclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgc3RhdGljIGdldERvY3VtZW50YXRpb25MaW5rKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIERvY3VtZW50YXRpb25FdmVudHNGb2xkZXJMaW5rICsgZW5jb2RlVVJJQ29tcG9uZW50KHRoaXMuZXZlbnRfdGl0bGUpO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX0V2ZW50fSBmcm9tIFwiLi9TQ19FdmVudFwiO1xyXG5pbXBvcnQge1RTaGVsbENvbW1hbmR9IGZyb20gXCIuLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7RXZlbnRSZWZ9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5cclxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFNDX1dvcmtzcGFjZUV2ZW50IGV4dGVuZHMgU0NfRXZlbnQge1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IHJlYWRvbmx5IHdvcmtzcGFjZV9ldmVudDpcclxuICAgICAgICAvLyBUT0RPOiBGaW5kIGEgd2F5IHRvIG1ha2UgdGhpcyBsaXN0IGR5bmFtaWMuXHJcbiAgICAgICAgLy8gVGhpcyBsaXN0IHJlZmxlY3RzIE9ic2lkaWFuIEFQSSB2ZXJzaW9uIDAuMTIuMTEuXHJcbiAgICAgICAgfCAncXVpY2stcHJldmlldydcclxuICAgICAgICB8ICdyZXNpemUnXHJcbiAgICAgICAgfCAnY2xpY2snXHJcbiAgICAgICAgfCAnYWN0aXZlLWxlYWYtY2hhbmdlJ1xyXG4gICAgICAgIHwgJ2ZpbGUtb3BlbidcclxuICAgICAgICB8ICdsYXlvdXQtY2hhbmdlJ1xyXG4gICAgICAgIHwgJ2Nzcy1jaGFuZ2UnXHJcbiAgICAgICAgfCAnZmlsZS1tZW51J1xyXG4gICAgICAgIHwgJ2VkaXRvci1tZW51J1xyXG4gICAgICAgIHwgJ2NvZGVtaXJyb3InXHJcbiAgICAgICAgfCAncXVpdCdcclxuICAgIDtcclxuXHJcbiAgICBwcm90ZWN0ZWQgX3JlZ2lzdGVyKHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCkge1xyXG4gICAgICAgIC8vIEB0cy1pZ25vcmUgVE9ETzogRmluZCBhIHdheSB0byBnZXQgYSBkeW5hbWljIHR5cGUgZm9yIHRoaXMud29ya3NwYWNlX2V2ZW50IC5cclxuICAgICAgICByZXR1cm4gdGhpcy5hcHAud29ya3NwYWNlLm9uKHRoaXMud29ya3NwYWNlX2V2ZW50LCB0aGlzLmdldFRyaWdnZXIodF9zaGVsbF9jb21tYW5kKSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIF91bnJlZ2lzdGVyKGV2ZW50X3JlZmVyZW5jZTogRXZlbnRSZWYpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLmFwcC53b3Jrc3BhY2Uub2ZmcmVmKGV2ZW50X3JlZmVyZW5jZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGdldFRyaWdnZXIodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKSB7XHJcbiAgICAgICAgcmV0dXJuIGFzeW5jICguLi5wYXJhbWV0ZXJzOiB1bmtub3duW10gLyogTmVlZCB0byBoYXZlIHRoaXMgdWdseSBwYXJhbWV0ZXIgdGhpbmcgc28gdGhhdCBzdWJjbGFzc2VzIGNhbiBkZWZpbmUgdGhlaXIgb3duIHBhcmFtZXRlcnMuICovKSA9PiBhd2FpdCB0aGlzLnRyaWdnZXIodF9zaGVsbF9jb21tYW5kKTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtTQ19Xb3Jrc3BhY2VFdmVudH0gZnJvbSBcIi4vU0NfV29ya3NwYWNlRXZlbnRcIjtcclxuaW1wb3J0IHtTaGVsbENvbW1hbmRQYXJzaW5nUHJvY2VzcywgVFNoZWxsQ29tbWFuZH0gZnJvbSBcIi4uL1RTaGVsbENvbW1hbmRcIjtcclxuaW1wb3J0IHtNZW51fSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHtQYXJzaW5nUmVzdWx0fSBmcm9tIFwiLi4vdmFyaWFibGVzL3BhcnNlVmFyaWFibGVzXCI7XHJcblxyXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgU0NfTWVudUV2ZW50IGV4dGVuZHMgU0NfV29ya3NwYWNlRXZlbnQge1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBhZGRUU2hlbGxDb21tYW5kVG9NZW51KHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCwgbWVudTogTWVudSkge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgbWVudSBpdGVtIGFzIHNvb24gYXMgcG9zc2libGUuIChJZiBpdCdzIGNyZWF0ZWQgYWZ0ZXIgJ2F3YWl0IHBhcnNpbmdfcHJvY2Vzcy5wcm9jZXNzKCknIGJlbG93LCBpdCB3b24ndCBiZSBzaG93biBpbiB0aGUgbWVudSBmb3Igc29tZSByZWFzb24sIGF0IGxlYXN0IGluIE9ic2lkaWFuIDAuMTYuMSkuXHJcbiAgICAgICAgbWVudS5hZGRJdGVtKGFzeW5jIG1lbnVJdGVtID0+IHtcclxuICAgICAgICAgICAgLy8gUGFyc2Ugc2hlbGwgY29tbWFuZCB2YXJpYWJsZXMgdG8gZ2V0IGEgdGl0bGVcclxuICAgICAgICAgICAgbGV0IHRpdGxlID0gdF9zaGVsbF9jb21tYW5kLmdldEFsaWFzT3JTaGVsbENvbW1hbmQoKTsgLy8gTWF5IGNvbnRhaW4gdW5wYXJzZWQgdmFyaWFibGVzLlxyXG4gICAgICAgICAgICBsZXQgcGFyc2luZ19wcm9jZXNzOiBTaGVsbENvbW1hbmRQYXJzaW5nUHJvY2VzcztcclxuICAgICAgICAgICAgaWYgKHRoaXMucGx1Z2luLnNldHRpbmdzLnByZXZpZXdfdmFyaWFibGVzX2luX2NvbW1hbmRfcGFsZXR0ZSkge1xyXG4gICAgICAgICAgICAgICAgLy8gU3RhcnQgYSBwYXJzaW5nIHByb2Nlc3NcclxuICAgICAgICAgICAgICAgIHBhcnNpbmdfcHJvY2VzcyA9IHRfc2hlbGxfY29tbWFuZC5jcmVhdGVQYXJzaW5nUHJvY2Vzcyh0aGlzKTtcclxuICAgICAgICAgICAgICAgIGlmIChhd2FpdCBwYXJzaW5nX3Byb2Nlc3MucHJvY2VzcygpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gUGFyc2luZyBzdWNjZWVkZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGFyc2luZ19yZXN1bHRzID0gcGFyc2luZ19wcm9jZXNzLmdldFBhcnNpbmdSZXN1bHRzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgYWxpYXNQYXJzaW5nUmVzdWx0OiBQYXJzaW5nUmVzdWx0ID0gcGFyc2luZ19yZXN1bHRzW1wiYWxpYXNcIl0gYXMgUGFyc2luZ1Jlc3VsdDsgLy8gYXMgUGFyc2luZ1Jlc3VsdDogVGVsbHMgVHlwZVNjcmlwdCB0aGF0IHRoZSBvYmplY3QgZXhpc3RzLlxyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQ6IFBhcnNpbmdSZXN1bHQgPSBwYXJzaW5nX3Jlc3VsdHNbXCJzaGVsbF9jb21tYW5kXCJdIGFzIFBhcnNpbmdSZXN1bHQ7IC8vIGFzIFBhcnNpbmdSZXN1bHQ6IFRlbGxzIFR5cGVTY3JpcHQgdGhhdCB0aGUgb2JqZWN0IGV4aXN0cy5cclxuICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IGFsaWFzUGFyc2luZ1Jlc3VsdC5wYXJzZWRfY29udGVudCB8fCBzaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0LnBhcnNlZF9jb250ZW50IGFzIHN0cmluZzsgLy8gVHJ5IHRvIHVzZSBhIHBhcnNlZCBhbGlhcywgYnV0IGlmIG5vIGFsaWFzIGlzIGF2YWlsYWJsZSwgdXNlIGEgcGFyc2VkIHNoZWxsIGNvbW1hbmQgaW5zdGVhZC4gYXMgc3RyaW5nID0gcGFyc2VkIHNoZWxsIGNvbW1hbmQgYWx3YXlzIGV4aXN0IHdoZW4gdGhlIHBhcnNpbmcgaXRzZWxmIGhhcyBzdWNjZWVkZWQuXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAvLyBJZiBwYXJzaW5nIHByb2Nlc3MgZmFpbHMsIHRoZSBmYWlsZWQgcHJvY2VzcyBjYW4gYmUgcGFzc2VkIHRvIHRoaXMudHJpZ2dlcigpLiBUaGUgZXhlY3V0aW9uIHdpbGwgZXZlbnR1YWxseSBiZSBjYW5jZWxsZWQgYW5kIGVycm9yIG1lc3NhZ2VzIGRpc3BsYXllZCAoaWYgZGlzcGxheWluZyBpcyBhbGxvd2VkKS5cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gU2V0IG1lbnUgaXRlbSB0aXRsZSAtIGJlIGl0IHBhcnNlZCBvciBub3QuXHJcbiAgICAgICAgICAgIG1lbnVJdGVtLnNldFRpdGxlKHRpdGxlKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEljb24gYW5kIG9uQ2xpY2sgaGFuZGxlci5cclxuICAgICAgICAgICAgbWVudUl0ZW1cclxuICAgICAgICAgICAgICAgIC5zZXRJY29uKHRfc2hlbGxfY29tbWFuZC5nZXRJY29uSWQoKSkgLy8gSWNvbiBpZCBjYW4gYmUgbnVsbC5cclxuICAgICAgICAgICAgICAgIC5vbkNsaWNrKGFzeW5jICgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnRyaWdnZXIoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRfc2hlbGxfY29tbWFuZCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyc2luZ19wcm9jZXNzLFxyXG4gICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICA7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7VFNoZWxsQ29tbWFuZH0gZnJvbSBcIi4uL1RTaGVsbENvbW1hbmRcIjtcclxuaW1wb3J0IHtNZW51LCBUQWJzdHJhY3RGaWxlLCBURmlsZSwgVEZvbGRlciwgV29ya3NwYWNlTGVhZn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7U0NfTWVudUV2ZW50fSBmcm9tIFwiLi9TQ19NZW51RXZlbnRcIjtcclxuXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBTQ19BYnN0cmFjdEZpbGVNZW51RXZlbnQgZXh0ZW5kcyBTQ19NZW51RXZlbnQge1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGZpbGVfb3JfZm9sZGVyOiBcImZpbGVcIiB8IFwiZm9sZGVyXCI7XHJcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgd29ya3NwYWNlX2V2ZW50ID0gXCJmaWxlLW1lbnVcIjtcclxuICAgIHByb3RlY3RlZCBmaWxlOiBURmlsZTtcclxuICAgIHByb3RlY3RlZCBmb2xkZXI6IFRGb2xkZXI7XHJcblxyXG4gICAgcHJvdGVjdGVkIGdldFRyaWdnZXIodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKSB7XHJcbiAgICAgICAgcmV0dXJuIGFzeW5jIChtZW51OiBNZW51LCBmaWxlOiBUQWJzdHJhY3RGaWxlLCBzb3VyY2U6IHN0cmluZywgbGVhZj86IFdvcmtzcGFjZUxlYWYpID0+IHtcclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhhdCBpdCdzIHRoZSBjb3JyZWN0IG1lbnU6IGlmIHRoZSBTQ19FdmVudCByZXF1aXJlcyBhIGZpbGUgbWVudSwgJ2ZpbGUnIG5lZWRzIHRvIGJlIGEgVEZpbGUsIG90aGVyd2lzZSBpdCBuZWVkcyB0byBiZSBhIFRGb2xkZXIuXHJcbiAgICAgICAgICAgIGlmICgodGhpcy5maWxlX29yX2ZvbGRlciA9PT0gXCJmb2xkZXJcIiAmJiBmaWxlIGluc3RhbmNlb2YgVEZvbGRlcikgfHwgKHRoaXMuZmlsZV9vcl9mb2xkZXIgPT09IFwiZmlsZVwiICYmIGZpbGUgaW5zdGFuY2VvZiBURmlsZSkpIHtcclxuICAgICAgICAgICAgICAgIC8vIFRoZSBtZW51IGlzIGNvcnJlY3QuXHJcblxyXG4gICAgICAgICAgICAgICAgLy8gRmlsZS9mb2xkZXIgZm9yIGRlY2xhcmVFeHRyYVZhcmlhYmxlcygpXHJcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKHRoaXMuZmlsZV9vcl9mb2xkZXIpIHtcclxuICAgICAgICAgICAgICAgICAgICBjYXNlIFwiZmlsZVwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbGUgPSBmaWxlIGFzIFRGaWxlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICBjYXNlIFwiZm9sZGVyXCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZm9sZGVyID0gZmlsZSBhcyBURm9sZGVyO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmFkZFRTaGVsbENvbW1hbmRUb01lbnUodF9zaGVsbF9jb21tYW5kLCBtZW51KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcbiAgICB9XHJcbn1cclxuIiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX0Fic3RyYWN0RmlsZU1lbnVFdmVudH0gZnJvbSBcIi4vU0NfQWJzdHJhY3RGaWxlTWVudUV2ZW50XCI7XHJcbmltcG9ydCB7VEZpbGUsIFRGb2xkZXJ9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNDX0V2ZW50X0ZpbGVNZW51IGV4dGVuZHMgU0NfQWJzdHJhY3RGaWxlTWVudUV2ZW50IHtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgZXZlbnRfY29kZSA9IFwiZmlsZS1tZW51XCI7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X3RpdGxlID0gXCJGaWxlIG1lbnVcIjtcclxuICAgIHByb3RlY3RlZCBmaWxlX29yX2ZvbGRlcjogXCJmaWxlXCIgPSBcImZpbGVcIjtcclxuXHJcbiAgICBwdWJsaWMgZ2V0RmlsZSgpOiBURmlsZSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsZTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0Rm9sZGVyKCk6IFRGb2xkZXIge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmZpbGUucGFyZW50O1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX0V2ZW50fSBmcm9tIFwiLi9TQ19FdmVudFwiO1xyXG5pbXBvcnQge1xyXG4gICAgRXZlbnRSZWYsXHJcbiAgICBUQWJzdHJhY3RGaWxlLFxyXG4gICAgVEZpbGUsXHJcbiAgICBURm9sZGVyLFxyXG59IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQge1RTaGVsbENvbW1hbmR9IGZyb20gXCIuLi9UU2hlbGxDb21tYW5kXCI7XHJcblxyXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgU0NfVmF1bHRFdmVudCBleHRlbmRzIFNDX0V2ZW50IHtcclxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCByZWFkb25seSB2YXVsdF9ldmVudDpcclxuICAgICAgICAvLyBUT0RPOiBGaW5kIGEgd2F5IHRvIG1ha2UgdGhpcyBsaXN0IGR5bmFtaWMuXHJcbiAgICAgICAgLy8gVGhpcyBsaXN0IHJlZmxlY3RzIE9ic2lkaWFuIEFQSSB2ZXJzaW9uIDAuMTIuMTEuXHJcbiAgICAgICAgfCBcImNyZWF0ZVwiXHJcbiAgICAgICAgfCBcIm1vZGlmeVwiXHJcbiAgICAgICAgfCBcImRlbGV0ZVwiXHJcbiAgICAgICAgfCBcInJlbmFtZVwiXHJcbiAgICAgICAgfCBcImNsb3NlZFwiIC8vIE5vdCBpbXBsZW1lbnQgYnkgYW55IFNDX0V2ZW50XyogY2xhc3MsIGJlY2F1c2UgSSdtIG5vdCBzdXJlIGlmIHRoaXMgZXZlbnQgaXMgbmVlZGVkLiBCdXQgY2FuIGJlIGltcGxlbWVudGVkIGlmIG5lZWQgYmUuXHJcbiAgICA7XHJcbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3QgZmlsZV9vcl9mb2xkZXI6IFwiZmlsZVwiIHwgXCJmb2xkZXJcIjtcclxuICAgIHByb3RlY3RlZCBmaWxlOiBURmlsZTtcclxuICAgIHByb3RlY3RlZCBmb2xkZXI6IFRGb2xkZXI7XHJcblxyXG4gICAgcHJvdGVjdGVkIF9yZWdpc3Rlcih0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQpOiBmYWxzZSB8IEV2ZW50UmVmIHtcclxuICAgICAgICAvLyBAdHMtaWdub3JlIFRPRE86IEZpbmQgYSB3YXkgdG8gZ2V0IGEgZHluYW1pYyB0eXBlIGZvciB0aGlzLnZhdWx0X2V2ZW50IC5cclxuICAgICAgICByZXR1cm4gdGhpcy5hcHAudmF1bHQub24odGhpcy52YXVsdF9ldmVudCwgdGhpcy5nZXRUcmlnZ2VyKHRfc2hlbGxfY29tbWFuZCkpO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBfdW5yZWdpc3RlcihldmVudF9yZWZlcmVuY2U6IEV2ZW50UmVmKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5hcHAudmF1bHQub2ZmcmVmKGV2ZW50X3JlZmVyZW5jZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGdldFRyaWdnZXIodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKSB7XHJcbiAgICAgICAgcmV0dXJuIGFzeW5jIChmaWxlOiBUQWJzdHJhY3RGaWxlLCAuLi5leHRyYV9hcmd1bWVudHM6IHVua25vd25bXSAvKiBOZWVkZWQgZm9yIFNDX0V2ZW50X0ZpbGVSZW5hbWVkIGFuZCBTQ19FdmVudF9Gb2xkZXJSZW5hbWVkIHRvIGJlIGFibGUgdG8gZGVmaW5lIGFuIGFkZGl0aW9uYWwgcGFyYW1ldGVyLiovKSA9PiB7XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayB0aGF0IGl0J3MgdGhlIGNvcnJlY3QgdHlwZSBvZiBmaWxlOiBpZiB0aGUgU0NfRXZlbnQgcmVxdWlyZXMgYSBmaWxlLCAnZmlsZScgbmVlZHMgdG8gYmUgYSBURmlsZSwgb3RoZXJ3aXNlIGl0IG5lZWRzIHRvIGJlIGEgVEZvbGRlci5cclxuICAgICAgICAgICAgaWYgKCh0aGlzLmZpbGVfb3JfZm9sZGVyID09PSBcImZvbGRlclwiICYmIGZpbGUgaW5zdGFuY2VvZiBURm9sZGVyKSB8fCAodGhpcy5maWxlX29yX2ZvbGRlciA9PT0gXCJmaWxlXCIgJiYgZmlsZSBpbnN0YW5jZW9mIFRGaWxlKSkge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhlIGZpbGUgdHlwZSBpcyBjb3JyZWN0LlxyXG5cclxuICAgICAgICAgICAgICAgIC8vIEZpbGUvZm9sZGVyIGZvciBkZWNsYXJlRXh0cmFWYXJpYWJsZXMoKVxyXG4gICAgICAgICAgICAgICAgc3dpdGNoICh0aGlzLmZpbGVfb3JfZm9sZGVyKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBcImZpbGVcIjpcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5maWxlID0gZmlsZSBhcyBURmlsZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBcImZvbGRlclwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZvbGRlciA9IGZpbGUgYXMgVEZvbGRlcjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy50cmlnZ2VyKHRfc2hlbGxfY29tbWFuZCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGhpcyBzaG91bGQgb25seSBiZSBjYWxsZWQgaWYgZmlsZV9vcl9mb2xkZXIgaXMgXCJmaWxlXCIhXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXRGaWxlKCk6IFRGaWxlIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5maWxlO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGhpcyBjYW4gYmUgY2FsbGVkIHdoZXRoZXIgZmlsZV9vcl9mb2xkZXIgaXMgXCJmaWxlXCIgb3IgXCJmb2xkZXJcIi5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldEZvbGRlcigpOiBURm9sZGVyIHtcclxuICAgICAgICBzd2l0Y2ggKHRoaXMuZmlsZV9vcl9mb2xkZXIpIHtcclxuICAgICAgICAgICAgY2FzZSBcImZpbGVcIjpcclxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmZpbGUucGFyZW50O1xyXG4gICAgICAgICAgICBjYXNlIFwiZm9sZGVyXCI6XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5mb2xkZXI7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtTQ19WYXVsdEV2ZW50fSBmcm9tIFwiLi9TQ19WYXVsdEV2ZW50XCI7XHJcblxyXG5leHBvcnQgY2xhc3MgU0NfRXZlbnRfRmlsZUNyZWF0ZWQgZXh0ZW5kcyBTQ19WYXVsdEV2ZW50IHtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgZXZlbnRfY29kZSA9IFwiZmlsZS1jcmVhdGVkXCI7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X3RpdGxlID0gXCJGaWxlIGNyZWF0ZWRcIjtcclxuICAgIHByb3RlY3RlZCByZWFkb25seSB2YXVsdF9ldmVudCA9IFwiY3JlYXRlXCI7XHJcbiAgICBwcm90ZWN0ZWQgZmlsZV9vcl9mb2xkZXI6IFwiZmlsZVwiID0gXCJmaWxlXCI7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U0NfVmF1bHRFdmVudH0gZnJvbSBcIi4vU0NfVmF1bHRFdmVudFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWQgZXh0ZW5kcyBTQ19WYXVsdEV2ZW50IHtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgZXZlbnRfY29kZSA9IFwiZmlsZS1jb250ZW50LW1vZGlmaWVkXCI7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X3RpdGxlID0gXCJGaWxlIGNvbnRlbnQgbW9kaWZpZWRcIjtcclxuICAgIHByb3RlY3RlZCByZWFkb25seSB2YXVsdF9ldmVudCA9IFwibW9kaWZ5XCI7XHJcbiAgICBwcm90ZWN0ZWQgZmlsZV9vcl9mb2xkZXI6IFwiZmlsZVwiID0gXCJmaWxlXCI7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U0NfVmF1bHRFdmVudH0gZnJvbSBcIi4vU0NfVmF1bHRFdmVudFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNDX0V2ZW50X0ZpbGVEZWxldGVkIGV4dGVuZHMgU0NfVmF1bHRFdmVudCB7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X2NvZGUgPSBcImZpbGUtZGVsZXRlZFwiO1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF90aXRsZSA9IFwiRmlsZSBkZWxldGVkXCI7XHJcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgdmF1bHRfZXZlbnQgPSBcImRlbGV0ZVwiO1xyXG4gICAgcHJvdGVjdGVkIGZpbGVfb3JfZm9sZGVyOiBcImZpbGVcIiA9IFwiZmlsZVwiO1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX1ZhdWx0RXZlbnR9IGZyb20gXCIuL1NDX1ZhdWx0RXZlbnRcIjtcclxuaW1wb3J0IHtUU2hlbGxDb21tYW5kfSBmcm9tIFwiLi4vVFNoZWxsQ29tbWFuZFwiO1xyXG5pbXBvcnQge1RBYnN0cmFjdEZpbGV9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQge1xyXG4gICAgZXh0cmFjdEZpbGVOYW1lLFxyXG4gICAgZXh0cmFjdEZpbGVQYXJlbnRQYXRoLFxyXG59IGZyb20gXCIuLi9Db21tb25cIjtcclxuXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBTQ19WYXVsdE1vdmVPclJlbmFtZUV2ZW50IGV4dGVuZHMgU0NfVmF1bHRFdmVudCB7XHJcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgdmF1bHRfZXZlbnQgPSBcInJlbmFtZVwiO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGVsbHMgd2hldGhlciB0aGlzIGV2ZW50IHNob3VsZCB0cmlnZ2VyIHdoZW4gYSBmaWxlL2ZvbGRlciBpcyBtb3ZlZCBPUiByZW5hbWVkLlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3QgbW92ZV9vcl9yZW5hbWU6IFwibW92ZVwiIHwgXCJyZW5hbWVcIjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZSBmaWxlJ3Mgb2xkIHBhdGgsIGdvdHRlbiBmcm9tIE9ic2lkaWFuJ3MgVmF1bHQub24oXCJyZW5hbWVcIikuIE9ubHkgcHJlc2VudCBpZiB0aGlzLmZpbGVfb3JfZm9sZGVyIGlzIFwiZmlsZVwiLlxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBmaWxlX29sZF9yZWxhdGl2ZV9wYXRoOiBzdHJpbmc7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJZiB0aGlzLmZpbGVfb3JfZm9sZGVyIGlzIFwiZmlsZVwiOiBUaGUgZmlsZSdzIHBhcmVudCBmb2xkZXIncyBvbGQgcGF0aC5cclxuICAgICAqIElmIHRoaXMuZmlsZV9vcl9mb2xkZXIgaXMgXCJmb2xkZXJcIjogVGhlIGZvbGRlcidzIG9sZCBwYXRoLlxyXG4gICAgICpcclxuICAgICAqIFJlbGF0aXZlIGZyb20gdGhlIHZhdWx0J3Mgcm9vdCBmb2xkZXIuIEdvdHRlbiBmcm9tIE9ic2lkaWFuJ3MgVmF1bHQub24oXCJyZW5hbWVcIikuXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGZvbGRlcl9vbGRfcmVsYXRpdmVfcGF0aDogc3RyaW5nO1xyXG5cclxuICAgIHByb3RlY3RlZCBnZXRUcmlnZ2VyKHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCkge1xyXG5cclxuICAgICAgICAvLyBHZXQgYSB0cmlnZ2VyIGZyb20gdGhlIHBhcmVudCBjbGFzcyAoU0NfVmF1bHRFdmVudCkuXHJcbiAgICAgICAgY29uc3QgdHJpZ2dlciA9IHN1cGVyLmdldFRyaWdnZXIodF9zaGVsbF9jb21tYW5kKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGFzeW5jIChhYnN0cmFjdF9maWxlOiBUQWJzdHJhY3RGaWxlLCBvbGRfcmVsYXRpdmVfcGF0aDogc3RyaW5nKSA9PiB7XHJcblxyXG4gICAgICAgICAgICAvLyBEZXRlY3QgaWYgdGhlIGZpbGUvZm9sZGVyIHdhcyBtb3ZlZCBvciByZW5hbWVkLlxyXG4gICAgICAgICAgICAvLyBJZiB0aGUgZmlsZS9mb2xkZXIgbmFtZSBoYXMgc3RheWVkIHRoZSBzYW1lLCBjb25jbHVkZSB0aGF0IHRoZSBmaWxlIGhhcyBiZWVuIE1PVkVELCBub3QgcmVuYW1lZC4gT3RoZXJ3aXNlLCBjb25jbHVkZSB0aGUgb3Bwb3NpdGUuXHJcbiAgICAgICAgICAgIGNvbnN0IG9sZF9maWxlX25hbWUgPSBleHRyYWN0RmlsZU5hbWUob2xkX3JlbGF0aXZlX3BhdGgpO1xyXG4gICAgICAgICAgICBjb25zdCBuZXdfZmlsZV9uYW1lID0gYWJzdHJhY3RfZmlsZS5uYW1lO1xyXG4gICAgICAgICAgICBjb25zdCBldmVudF90eXBlID0gKG9sZF9maWxlX25hbWUgPT09IG5ld19maWxlX25hbWUpID8gXCJtb3ZlXCIgOiBcInJlbmFtZVwiOyAvLyBUZWxscyB3aGF0IHJlYWxseSBoYXBwZW5lZC4gdGhpcy5tb3ZlX29yX3JlbmFtZSB0ZWxscyB3aGF0IGlzIHRoZSBjb25kaXRpb24gZm9yIHRoZSBldmVudCB0byB0cmlnZ2VyLlxyXG5cclxuICAgICAgICAgICAgLy8gT25seSBwcm9jZWVkIHRoZSB0cmlnZ2VyaW5nLCBpZiB0aGUgZGV0ZXJtaW5lZCB0eXBlIGVxdWFscyB0aGUgb25lIGRlZmluZWQgYnkgdGhlIGV2ZW50IGNsYXNzLlxyXG4gICAgICAgICAgICBpZiAoZXZlbnRfdHlwZSA9PT0gdGhpcy5tb3ZlX29yX3JlbmFtZSkge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhlIGV2ZW50IHR5cGUgaXMgY29ycmVjdC5cclxuXHJcbiAgICAgICAgICAgICAgICAvLyBGaWxlIGFuZCBmb2xkZXIgZm9yIGRlY2xhcmVFeHRyYVZhcmlhYmxlcygpXHJcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKHRoaXMuZmlsZV9vcl9mb2xkZXIpIHtcclxuICAgICAgICAgICAgICAgICAgICBjYXNlIFwiZmlsZVwiOlxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbGVfb2xkX3JlbGF0aXZlX3BhdGggPSBvbGRfcmVsYXRpdmVfcGF0aDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5mb2xkZXJfb2xkX3JlbGF0aXZlX3BhdGggPSBleHRyYWN0RmlsZVBhcmVudFBhdGgob2xkX3JlbGF0aXZlX3BhdGgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICBjYXNlIFwiZm9sZGVyXCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZm9sZGVyX29sZF9yZWxhdGl2ZV9wYXRoID0gb2xkX3JlbGF0aXZlX3BhdGg7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIC8vIENhbGwgdGhlIG5vcm1hbCB0cmlnZ2VyIGZ1bmN0aW9uLlxyXG4gICAgICAgICAgICAgICAgYXdhaXQgdHJpZ2dlcihhYnN0cmFjdF9maWxlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEZvbGRlck9sZFJlbGF0aXZlUGF0aCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5mb2xkZXJfb2xkX3JlbGF0aXZlX3BhdGg7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEZpbGVPbGRSZWxhdGl2ZVBhdGgoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuZmlsZV9vbGRfcmVsYXRpdmVfcGF0aDtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtTQ19WYXVsdE1vdmVPclJlbmFtZUV2ZW50fSBmcm9tIFwiLi9TQ19WYXVsdE1vdmVPclJlbmFtZUV2ZW50XCI7XHJcblxyXG5leHBvcnQgY2xhc3MgU0NfRXZlbnRfRmlsZVJlbmFtZWQgZXh0ZW5kcyBTQ19WYXVsdE1vdmVPclJlbmFtZUV2ZW50IHtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgZXZlbnRfY29kZSA9IFwiZmlsZS1yZW5hbWVkXCI7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X3RpdGxlID0gXCJGaWxlIHJlbmFtZWRcIjtcclxuICAgIHByb3RlY3RlZCBtb3ZlX29yX3JlbmFtZTogXCJyZW5hbWVcIiA9IFwicmVuYW1lXCI7XHJcbiAgICBwcm90ZWN0ZWQgZmlsZV9vcl9mb2xkZXI6IFwiZmlsZVwiID0gXCJmaWxlXCI7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U0NfVmF1bHRNb3ZlT3JSZW5hbWVFdmVudH0gZnJvbSBcIi4vU0NfVmF1bHRNb3ZlT3JSZW5hbWVFdmVudFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNDX0V2ZW50X0ZpbGVNb3ZlZCBleHRlbmRzIFNDX1ZhdWx0TW92ZU9yUmVuYW1lRXZlbnQge1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF9jb2RlID0gXCJmaWxlLW1vdmVkXCI7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X3RpdGxlID0gXCJGaWxlIG1vdmVkXCI7XHJcbiAgICBwcm90ZWN0ZWQgbW92ZV9vcl9yZW5hbWU6IFwibW92ZVwiID0gXCJtb3ZlXCI7XHJcbiAgICBwcm90ZWN0ZWQgZmlsZV9vcl9mb2xkZXI6IFwiZmlsZVwiID0gXCJmaWxlXCI7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7RXZlbnRWYXJpYWJsZX0gZnJvbSBcIi4vRXZlbnRWYXJpYWJsZVwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVNZW51fSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVNZW51XCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZUNyZWF0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZUNyZWF0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlRGVsZXRlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlRGVsZXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVSZW5hbWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVSZW5hbWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZU1vdmVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVNb3ZlZFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0V2ZW50RmlsZU5hbWUgZXh0ZW5kcyBFdmVudFZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJldmVudF9maWxlX25hbWVcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIHRoZSBldmVudCByZWxhdGVkIGZpbGUgbmFtZSB3aXRoIGEgZmlsZSBleHRlbnNpb24uIElmIHlvdSBuZWVkIGl0IHdpdGhvdXQgdGhlIGV4dGVuc2lvbiwgdXNlIHt7ZXZlbnRfdGl0bGV9fSBpbnN0ZWFkLlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBzdXBwb3J0ZWRfc2NfZXZlbnRzID0gW1xyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVNZW51LFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVDcmVhdGVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZURlbGV0ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZU1vdmVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVSZW5hbWVkLFxyXG4gICAgXTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZShcclxuICAgICAgICBhcmd1bWVudHNBcmVOb3RVc2VkOiBuZXZlcixcclxuICAgICAgICBzY19ldmVudDogU0NfRXZlbnRfRmlsZU1lbnUgfCBTQ19FdmVudF9GaWxlQ3JlYXRlZCB8IFNDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWQgfCBTQ19FdmVudF9GaWxlRGVsZXRlZCB8IFNDX0V2ZW50X0ZpbGVNb3ZlZCB8IFNDX0V2ZW50X0ZpbGVSZW5hbWVkLFxyXG4gICAgKTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICB0aGlzLnJlcXVpcmVDb3JyZWN0RXZlbnQoc2NfZXZlbnQpO1xyXG5cclxuICAgICAgICByZXR1cm4gc2NfZXZlbnQuZ2V0RmlsZSgpLm5hbWU7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7RXZlbnRWYXJpYWJsZX0gZnJvbSBcIi4vRXZlbnRWYXJpYWJsZVwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVNZW51fSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVNZW51XCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZUNyZWF0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZUNyZWF0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlRGVsZXRlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlRGVsZXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVSZW5hbWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVSZW5hbWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZU1vdmVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVNb3ZlZFwiO1xyXG5pbXBvcnQge2dldEZpbGVQYXRofSBmcm9tIFwiLi4vVmFyaWFibGVIZWxwZXJzXCI7XHJcbmltcG9ydCB7SVBhcmFtZXRlcnN9IGZyb20gXCIuLi9WYXJpYWJsZVwiO1xyXG5pbXBvcnQge0lBdXRvY29tcGxldGVJdGVtfSBmcm9tIFwiLi4vLi4vc2V0dGluZ3Mvc2V0dGluZ19lbGVtZW50cy9BdXRvY29tcGxldGVcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9FdmVudEZpbGVQYXRoIGV4dGVuZHMgRXZlbnRWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiZXZlbnRfZmlsZV9wYXRoXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyBwYXRoIHRvIHRoZSBldmVudCByZWxhdGVkIGZpbGUsIGVpdGhlciBhcyBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbSwgb3IgYXMgcmVsYXRpdmUgZnJvbSB0aGUgcm9vdCBvZiB0aGUgT2JzaWRpYW4gdmF1bHQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBwYXJhbWV0ZXJzOiBJUGFyYW1ldGVycyA9IHtcclxuICAgICAgICBtb2RlOiB7XHJcbiAgICAgICAgICAgIG9wdGlvbnM6IFtcImFic29sdXRlXCIsIFwicmVsYXRpdmVcIl0sXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH0sXHJcbiAgICB9O1xyXG5cclxuICAgIHByb3RlY3RlZCBzdXBwb3J0ZWRfc2NfZXZlbnRzID0gW1xyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVNZW51LFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVDcmVhdGVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZURlbGV0ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZU1vdmVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVSZW5hbWVkLFxyXG4gICAgXTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZShcclxuICAgICAgICBjYXN0ZWRBcmd1bWVudHM6IHttb2RlOiBcImFic29sdXRlXCIgfCBcInJlbGF0aXZlXCJ9LFxyXG4gICAgICAgIHNjX2V2ZW50OiBTQ19FdmVudF9GaWxlTWVudSB8IFNDX0V2ZW50X0ZpbGVDcmVhdGVkIHwgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCB8IFNDX0V2ZW50X0ZpbGVEZWxldGVkIHwgU0NfRXZlbnRfRmlsZU1vdmVkIHwgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICApOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHRoaXMucmVxdWlyZUNvcnJlY3RFdmVudChzY19ldmVudCk7XHJcblxyXG4gICAgICAgIHJldHVybiBnZXRGaWxlUGF0aCh0aGlzLmFwcCwgc2NfZXZlbnQuZ2V0RmlsZSgpLCBjYXN0ZWRBcmd1bWVudHMubW9kZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEF1dG9jb21wbGV0ZUl0ZW1zKCkge1xyXG4gICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgIC8vIE5vcm1hbCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7XCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjphYnNvbHV0ZX19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgcGF0aCB0byB0aGUgZXZlbnQgcmVsYXRlZCBmaWxlLCBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbS4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6cmVsYXRpdmV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHBhdGggdG8gdGhlIGV2ZW50IHJlbGF0ZWQgZmlsZSwgcmVsYXRpdmUgZnJvbSB0aGUgcm9vdCBvZiB0aGUgT2JzaWRpYW4gdmF1bHQuIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwibm9ybWFsLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG5cclxuICAgICAgICAgICAgLy8gVW5lc2NhcGVkIHZhcmlhYmxlc1xyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3shXCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjphYnNvbHV0ZX19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgcGF0aCB0byB0aGUgZXZlbnQgcmVsYXRlZCBmaWxlLCBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbS4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJ1bmVzY2FwZWQtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7eyFcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOnJlbGF0aXZlfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyBwYXRoIHRvIHRoZSBldmVudCByZWxhdGVkIGZpbGUsIHJlbGF0aXZlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIE9ic2lkaWFuIHZhdWx0LiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRIZWxwTmFtZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+e3tldmVudF9maWxlX3BhdGg6cmVsYXRpdmV9fTwvc3Ryb25nPiBvciA8c3Ryb25nPnt7ZXZlbnRfZmlsZV9wYXRoOmFic29sdXRlfX08L3N0cm9uZz5cIjtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtTQ19BYnN0cmFjdEZpbGVNZW51RXZlbnR9IGZyb20gXCIuL1NDX0Fic3RyYWN0RmlsZU1lbnVFdmVudFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNDX0V2ZW50X0ZvbGRlck1lbnUgZXh0ZW5kcyBTQ19BYnN0cmFjdEZpbGVNZW51RXZlbnQge1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF9jb2RlID0gXCJmb2xkZXItbWVudVwiO1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF90aXRsZSA9IFwiRm9sZGVyIG1lbnVcIjtcclxuICAgIHByb3RlY3RlZCBmaWxlX29yX2ZvbGRlcjogXCJmb2xkZXJcIiA9IFwiZm9sZGVyXCI7XHJcblxyXG4gICAgcHVibGljIGdldEZvbGRlcigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5mb2xkZXI7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U0NfVmF1bHRFdmVudH0gZnJvbSBcIi4vU0NfVmF1bHRFdmVudFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNDX0V2ZW50X0ZvbGRlckNyZWF0ZWQgZXh0ZW5kcyBTQ19WYXVsdEV2ZW50IHtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgZXZlbnRfY29kZSA9IFwiZm9sZGVyLWNyZWF0ZWRcIjtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgZXZlbnRfdGl0bGUgPSBcIkZvbGRlciBjcmVhdGVkXCI7XHJcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgdmF1bHRfZXZlbnQgPSBcImNyZWF0ZVwiO1xyXG4gICAgcHJvdGVjdGVkIGZpbGVfb3JfZm9sZGVyOiBcImZvbGRlclwiID0gXCJmb2xkZXJcIjtcclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtTQ19WYXVsdEV2ZW50fSBmcm9tIFwiLi9TQ19WYXVsdEV2ZW50XCI7XHJcblxyXG5leHBvcnQgY2xhc3MgU0NfRXZlbnRfRm9sZGVyRGVsZXRlZCBleHRlbmRzIFNDX1ZhdWx0RXZlbnQge1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF9jb2RlID0gXCJmb2xkZXItZGVsZXRlZFwiO1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF90aXRsZSA9IFwiRm9sZGVyIGRlbGV0ZWRcIjtcclxuICAgIHByb3RlY3RlZCByZWFkb25seSB2YXVsdF9ldmVudCA9IFwiZGVsZXRlXCI7XHJcbiAgICBwcm90ZWN0ZWQgZmlsZV9vcl9mb2xkZXI6IFwiZm9sZGVyXCIgPSBcImZvbGRlclwiO1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX1ZhdWx0TW92ZU9yUmVuYW1lRXZlbnR9IGZyb20gXCIuL1NDX1ZhdWx0TW92ZU9yUmVuYW1lRXZlbnRcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBTQ19FdmVudF9Gb2xkZXJSZW5hbWVkIGV4dGVuZHMgU0NfVmF1bHRNb3ZlT3JSZW5hbWVFdmVudCB7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X2NvZGUgPSBcImZvbGRlci1yZW5hbWVkXCI7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X3RpdGxlID0gXCJGb2xkZXIgcmVuYW1lZFwiO1xyXG4gICAgcHJvdGVjdGVkIG1vdmVfb3JfcmVuYW1lOiBcInJlbmFtZVwiID0gXCJyZW5hbWVcIjtcclxuICAgIHByb3RlY3RlZCBmaWxlX29yX2ZvbGRlcjogXCJmb2xkZXJcIiA9IFwiZm9sZGVyXCI7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U0NfVmF1bHRNb3ZlT3JSZW5hbWVFdmVudH0gZnJvbSBcIi4vU0NfVmF1bHRNb3ZlT3JSZW5hbWVFdmVudFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNDX0V2ZW50X0ZvbGRlck1vdmVkIGV4dGVuZHMgU0NfVmF1bHRNb3ZlT3JSZW5hbWVFdmVudCB7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X2NvZGUgPSBcImZvbGRlci1tb3ZlZFwiO1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF90aXRsZSA9IFwiRm9sZGVyIG1vdmVkXCI7XHJcbiAgICBwcm90ZWN0ZWQgbW92ZV9vcl9yZW5hbWU6IFwibW92ZVwiID0gXCJtb3ZlXCI7XHJcbiAgICBwcm90ZWN0ZWQgZmlsZV9vcl9mb2xkZXI6IFwiZm9sZGVyXCIgPSBcImZvbGRlclwiO1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVNZW51fSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVNZW51XCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRm9sZGVyTWVudX0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9Gb2xkZXJNZW51XCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZUNyZWF0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZUNyZWF0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9Gb2xkZXJDcmVhdGVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZvbGRlckNyZWF0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlRGVsZXRlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlRGVsZXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZvbGRlckRlbGV0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRm9sZGVyRGVsZXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVSZW5hbWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVSZW5hbWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRm9sZGVyUmVuYW1lZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9Gb2xkZXJSZW5hbWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRm9sZGVyTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRm9sZGVyTW92ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1vdmVkXCI7XHJcbmltcG9ydCB7RXZlbnRWYXJpYWJsZX0gZnJvbSBcIi4vRXZlbnRWYXJpYWJsZVwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0V2ZW50Rm9sZGVyTmFtZSBleHRlbmRzIEV2ZW50VmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcImV2ZW50X2ZvbGRlcl9uYW1lXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJGaWxlIGV2ZW50czogR2l2ZXMgdGhlIGV2ZW50IHJlbGF0ZWQgZmlsZSdzIHBhcmVudCBmb2xkZXIgbmFtZS4gRm9sZGVyIGV2ZW50czogR2l2ZXMgdGhlIHNlbGVjdGVkIGZvbGRlcidzIG5hbWUuIEdpdmVzIGEgZG90IGlmIHRoZSBmb2xkZXIgaXMgdGhlIHZhdWx0J3Mgcm9vdC4gTm8gYW5jZXN0b3IgZm9sZGVycyBhcmUgaW5jbHVkZWQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN1cHBvcnRlZF9zY19ldmVudHMgPSBbXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZU1lbnUsXHJcbiAgICAgICAgU0NfRXZlbnRfRm9sZGVyTWVudSxcclxuICAgICAgICBTQ19FdmVudF9GaWxlQ3JlYXRlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVEZWxldGVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVNb3ZlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlUmVuYW1lZCxcclxuICAgICAgICBTQ19FdmVudF9Gb2xkZXJDcmVhdGVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZvbGRlckRlbGV0ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRm9sZGVyTW92ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRm9sZGVyUmVuYW1lZCxcclxuICAgIF07XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoXHJcbiAgICAgICAgYXJndW1lbnRzQXJlTm90VXNlZDogbmV2ZXIsXHJcbiAgICAgICAgc2NfZXZlbnQ6IFNDX0V2ZW50X0ZpbGVNZW51IHwgU0NfRXZlbnRfRm9sZGVyTWVudSB8IFNDX0V2ZW50X0ZpbGVDcmVhdGVkIHwgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCB8IFNDX0V2ZW50X0ZpbGVEZWxldGVkIHwgU0NfRXZlbnRfRmlsZU1vdmVkIHwgU0NfRXZlbnRfRmlsZVJlbmFtZWQgfCBTQ19FdmVudF9Gb2xkZXJDcmVhdGVkIHwgU0NfRXZlbnRfRm9sZGVyRGVsZXRlZCB8IFNDX0V2ZW50X0ZvbGRlck1vdmVkIHwgU0NfRXZlbnRfRm9sZGVyUmVuYW1lZCxcclxuICAgICk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgdGhpcy5yZXF1aXJlQ29ycmVjdEV2ZW50KHNjX2V2ZW50KTtcclxuXHJcbiAgICAgICAgY29uc3QgZm9sZGVyID0gc2NfZXZlbnQuZ2V0Rm9sZGVyKCk7XHJcbiAgICAgICAgcmV0dXJuIGZvbGRlci5pc1Jvb3QoKVxyXG4gICAgICAgICAgICAgICAgPyBcIi5cIiAvLyBSZXR1cm4gYSBkb3QgaW5zdGVhZCBvZiBhbiBlbXB0eSBzdHJpbmcuXHJcbiAgICAgICAgICAgICAgICA6IGZvbGRlci5uYW1lXHJcbiAgICAgICAgO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVNZW51fSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVNZW51XCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRm9sZGVyTWVudX0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9Gb2xkZXJNZW51XCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZUNyZWF0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZUNyZWF0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9Gb2xkZXJDcmVhdGVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZvbGRlckNyZWF0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlRGVsZXRlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlRGVsZXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZvbGRlckRlbGV0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRm9sZGVyRGVsZXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVSZW5hbWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVSZW5hbWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRm9sZGVyUmVuYW1lZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9Gb2xkZXJSZW5hbWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRm9sZGVyTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRm9sZGVyTW92ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1vdmVkXCI7XHJcbmltcG9ydCB7RXZlbnRWYXJpYWJsZX0gZnJvbSBcIi4vRXZlbnRWYXJpYWJsZVwiO1xyXG5pbXBvcnQge2dldEZvbGRlclBhdGh9IGZyb20gXCIuLi9WYXJpYWJsZUhlbHBlcnNcIjtcclxuaW1wb3J0IHtJUGFyYW1ldGVyc30gZnJvbSBcIi4uL1ZhcmlhYmxlXCI7XHJcbmltcG9ydCB7SUF1dG9jb21wbGV0ZUl0ZW19IGZyb20gXCIuLi8uLi9zZXR0aW5ncy9zZXR0aW5nX2VsZW1lbnRzL0F1dG9jb21wbGV0ZVwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0V2ZW50Rm9sZGVyUGF0aCBleHRlbmRzIEV2ZW50VmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcImV2ZW50X2ZvbGRlcl9wYXRoXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJGaWxlIGV2ZW50czogR2l2ZXMgcGF0aCB0byB0aGUgZXZlbnQgcmVsYXRlZCBmaWxlJ3MgcGFyZW50IGZvbGRlci4gRm9sZGVyIGV2ZW50czogR2l2ZXMgcGF0aCB0byB0aGUgZXZlbnQgcmVsYXRlZCBmb2xkZXIuIFRoZSBwYXRoIGlzIGVpdGhlciBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbSwgb3IgcmVsYXRpdmUgZnJvbSB0aGUgcm9vdCBvZiB0aGUgT2JzaWRpYW4gdmF1bHQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBwYXJhbWV0ZXJzOiBJUGFyYW1ldGVycyA9IHtcclxuICAgICAgICBtb2RlOiB7XHJcbiAgICAgICAgICAgIG9wdGlvbnM6IFtcImFic29sdXRlXCIsIFwicmVsYXRpdmVcIl0sXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH0sXHJcbiAgICB9O1xyXG5cclxuICAgIHByb3RlY3RlZCBzdXBwb3J0ZWRfc2NfZXZlbnRzID0gW1xyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVNZW51LFxyXG4gICAgICAgIFNDX0V2ZW50X0ZvbGRlck1lbnUsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNyZWF0ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlRGVsZXRlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlTW92ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRm9sZGVyQ3JlYXRlZCxcclxuICAgICAgICBTQ19FdmVudF9Gb2xkZXJEZWxldGVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZvbGRlck1vdmVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZvbGRlclJlbmFtZWQsXHJcbiAgICBdO1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKFxyXG4gICAgICAgIGNhc3RlZEFyZ3VtZW50czoge21vZGU6IFwiYWJzb2x1dGVcIiB8IFwicmVsYXRpdmVcIn0sXHJcbiAgICAgICAgc2NfZXZlbnQ6IFNDX0V2ZW50X0ZpbGVNZW51IHwgU0NfRXZlbnRfRm9sZGVyTWVudSB8IFNDX0V2ZW50X0ZpbGVDcmVhdGVkIHwgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCB8IFNDX0V2ZW50X0ZpbGVEZWxldGVkIHwgU0NfRXZlbnRfRmlsZU1vdmVkIHwgU0NfRXZlbnRfRmlsZVJlbmFtZWQgfCBTQ19FdmVudF9Gb2xkZXJDcmVhdGVkIHwgU0NfRXZlbnRfRm9sZGVyRGVsZXRlZCB8IFNDX0V2ZW50X0ZvbGRlck1vdmVkIHwgU0NfRXZlbnRfRm9sZGVyUmVuYW1lZCxcclxuICAgICk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgdGhpcy5yZXF1aXJlQ29ycmVjdEV2ZW50KHNjX2V2ZW50KTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGdldEZvbGRlclBhdGgodGhpcy5hcHAsIHNjX2V2ZW50LmdldEZvbGRlcigpLCBjYXN0ZWRBcmd1bWVudHMubW9kZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEF1dG9jb21wbGV0ZUl0ZW1zKCkge1xyXG4gICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgIC8vIE5vcm1hbCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7XCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjphYnNvbHV0ZX19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiRmlsZSBldmVudHM6IEdpdmVzIHBhdGggdG8gdGhlIGV2ZW50IHJlbGF0ZWQgZmlsZSdzIHBhcmVudCBmb2xkZXIuIEZvbGRlciBldmVudHM6IEdpdmVzIHBhdGggdG8gdGhlIGV2ZW50IHJlbGF0ZWQgZm9sZGVyLiBUaGUgcGF0aCBpcyBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbS4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6cmVsYXRpdmV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkZpbGUgZXZlbnRzOiBHaXZlcyBwYXRoIHRvIHRoZSBldmVudCByZWxhdGVkIGZpbGUncyBwYXJlbnQgZm9sZGVyLiBGb2xkZXIgZXZlbnRzOiBHaXZlcyBwYXRoIHRvIHRoZSBldmVudCByZWxhdGVkIGZvbGRlci4gVGhlIHBhdGggaXMgcmVsYXRpdmUgZnJvbSB0aGUgcm9vdCBvZiB0aGUgT2JzaWRpYW4gdmF1bHQuIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwibm9ybWFsLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG5cclxuICAgICAgICAgICAgLy8gVW5lc2NhcGVkIHZhcmlhYmxlc1xyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3shXCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjphYnNvbHV0ZX19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiRmlsZSBldmVudHM6IEdpdmVzIHBhdGggdG8gdGhlIGV2ZW50IHJlbGF0ZWQgZmlsZSdzIHBhcmVudCBmb2xkZXIuIEZvbGRlciBldmVudHM6IEdpdmVzIHBhdGggdG8gdGhlIGV2ZW50IHJlbGF0ZWQgZm9sZGVyLiBUaGUgcGF0aCBpcyBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbS4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJ1bmVzY2FwZWQtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7eyFcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOnJlbGF0aXZlfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJGaWxlIGV2ZW50czogR2l2ZXMgcGF0aCB0byB0aGUgZXZlbnQgcmVsYXRlZCBmaWxlJ3MgcGFyZW50IGZvbGRlci4gRm9sZGVyIGV2ZW50czogR2l2ZXMgcGF0aCB0byB0aGUgZXZlbnQgcmVsYXRlZCBmb2xkZXIuIFRoZSBwYXRoIGlzIHJlbGF0aXZlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIE9ic2lkaWFuIHZhdWx0LiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRIZWxwTmFtZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+e3tldmVudF9mb2xkZXJfcGF0aDpyZWxhdGl2ZX19PC9zdHJvbmc+IG9yIDxzdHJvbmc+e3tldmVudF9mb2xkZXJfcGF0aDphYnNvbHV0ZX19PC9zdHJvbmc+XCI7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZU1lbnV9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1lbnVcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlQ3JlYXRlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlQ3JlYXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVEZWxldGVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVEZWxldGVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZVJlbmFtZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZVJlbmFtZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1vdmVkXCI7XHJcbmltcG9ydCB7RXZlbnRWYXJpYWJsZX0gZnJvbSBcIi4vRXZlbnRWYXJpYWJsZVwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0V2ZW50VGl0bGUgZXh0ZW5kcyBFdmVudFZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJldmVudF90aXRsZVwiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiR2l2ZXMgdGhlIGV2ZW50IHJlbGF0ZWQgZmlsZSBuYW1lIHdpdGhvdXQgYSBmaWxlIGV4dGVuc2lvbi4gSWYgeW91IG5lZWQgaXQgd2l0aCB0aGUgZXh0ZW5zaW9uLCB1c2Uge3tldmVudF9maWxlX25hbWV9fSBpbnN0ZWFkLlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBzdXBwb3J0ZWRfc2NfZXZlbnRzID0gW1xyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVNZW51LFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVDcmVhdGVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZURlbGV0ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZU1vdmVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVSZW5hbWVkLFxyXG4gICAgXTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZShcclxuICAgICAgICBhcmd1bWVudHNBcmVOb3RVc2VkOiBuZXZlcixcclxuICAgICAgICBzY19ldmVudDogU0NfRXZlbnRfRmlsZU1lbnUgfCBTQ19FdmVudF9GaWxlQ3JlYXRlZCB8IFNDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWQgfCBTQ19FdmVudF9GaWxlRGVsZXRlZCB8IFNDX0V2ZW50X0ZpbGVNb3ZlZCB8IFNDX0V2ZW50X0ZpbGVSZW5hbWVkLFxyXG4gICAgKTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICB0aGlzLnJlcXVpcmVDb3JyZWN0RXZlbnQoc2NfZXZlbnQpO1xyXG5cclxuICAgICAgICByZXR1cm4gc2NfZXZlbnQuZ2V0RmlsZSgpLmJhc2VuYW1lO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0V2ZW50VmFyaWFibGV9IGZyb20gXCIuL0V2ZW50VmFyaWFibGVcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTWVudX0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlTWVudVwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVDcmVhdGVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVDcmVhdGVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZURlbGV0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZURlbGV0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlUmVuYW1lZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlUmVuYW1lZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVNb3ZlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlTW92ZWRcIjtcclxuaW1wb3J0IHtnZXRGaWxlRXh0ZW5zaW9ufSBmcm9tIFwiLi4vVmFyaWFibGVIZWxwZXJzXCI7XHJcbmltcG9ydCB7SVBhcmFtZXRlcnN9IGZyb20gXCIuLi9WYXJpYWJsZVwiO1xyXG5pbXBvcnQge0lBdXRvY29tcGxldGVJdGVtfSBmcm9tIFwiLi4vLi4vc2V0dGluZ3Mvc2V0dGluZ19lbGVtZW50cy9BdXRvY29tcGxldGVcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9FdmVudEZpbGVFeHRlbnNpb24gZXh0ZW5kcyBFdmVudFZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJldmVudF9maWxlX2V4dGVuc2lvblwiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiR2l2ZXMgdGhlIGV2ZW50IHJlbGF0ZWQgZmlsZSBuYW1lJ3MgZW5kaW5nLiBVc2Uge3tldmVudF9maWxlX2V4dGVuc2lvbjp3aXRoLWRvdH19IHRvIGluY2x1ZGUgYSBwcmVjZWRpbmcgZG90LiBJZiB0aGUgZXh0ZW5zaW9uIGlzIGVtcHR5LCBubyBkb3QgaXMgYWRkZWQuIHt7ZXZlbnRfZmlsZV9leHRlbnNpb246bm8tZG90fX0gbmV2ZXIgaW5jbHVkZXMgYSBkb3QuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyBwYXJhbWV0ZXJzOiBJUGFyYW1ldGVycyA9IHtcclxuICAgICAgICBcImRvdFwiOiB7XHJcbiAgICAgICAgICAgIG9wdGlvbnM6IFtcIndpdGgtZG90XCIsIFwibm8tZG90XCJdLFxyXG4gICAgICAgICAgICByZXF1aXJlZDogdHJ1ZSxcclxuICAgICAgICB9LFxyXG4gICAgfTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3VwcG9ydGVkX3NjX2V2ZW50cyA9IFtcclxuICAgICAgICBTQ19FdmVudF9GaWxlTWVudSxcclxuICAgICAgICBTQ19FdmVudF9GaWxlQ3JlYXRlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVEZWxldGVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVNb3ZlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlUmVuYW1lZCxcclxuICAgIF07XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoXHJcbiAgICAgICAgY2FzdGVkQXJndW1lbnRzOiB7XCJkb3RcIjogXCJ3aXRoLWRvdFwiIHwgXCJuby1kb3RcIn0sXHJcbiAgICAgICAgc2NfZXZlbnQ6IFNDX0V2ZW50X0ZpbGVNZW51IHwgU0NfRXZlbnRfRmlsZUNyZWF0ZWQgfCBTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkIHwgU0NfRXZlbnRfRmlsZURlbGV0ZWQgfCBTQ19FdmVudF9GaWxlTW92ZWQgfCBTQ19FdmVudF9GaWxlUmVuYW1lZCxcclxuICAgICk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgdGhpcy5yZXF1aXJlQ29ycmVjdEV2ZW50KHNjX2V2ZW50KTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGdldEZpbGVFeHRlbnNpb24oc2NfZXZlbnQuZ2V0RmlsZSgpLCBjYXN0ZWRBcmd1bWVudHMuZG90ID09PSBcIndpdGgtZG90XCIpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRBdXRvY29tcGxldGVJdGVtcygpIHtcclxuICAgICAgICByZXR1cm4gW1xyXG4gICAgICAgICAgICAvLyBOb3JtYWwgdmFyaWFibGVzXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6bm8tZG90fX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyB0aGUgZXZlbnQgcmVsYXRlZCBmaWxlIG5hbWUncyBlbmRpbmcgd2l0aG91dCBhIHByZWNlZGluZyBkb3QuIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwibm9ybWFsLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3tcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOndpdGgtZG90fX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyB0aGUgZXZlbnQgcmVsYXRlZCBmaWxlIG5hbWUncyBlbmRpbmcgd2l0aCBhIHByZWNlZGluZyBkb3QuIElmIHRoZSBleHRlbnNpb24gaXMgZW1wdHksIG5vIGRvdCBpcyBpbmNsdWRlZC4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcblxyXG4gICAgICAgICAgICAvLyBVbmVzY2FwZWQgdmFyaWFibGVzXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7eyFcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOm5vLWRvdH19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgdGhlIGV2ZW50IHJlbGF0ZWQgZmlsZSBuYW1lJ3MgZW5kaW5nIHdpdGhvdXQgYSBwcmVjZWRpbmcgZG90LiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7IVwiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6d2l0aC1kb3R9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSBldmVudCByZWxhdGVkIGZpbGUgbmFtZSdzIGVuZGluZyB3aXRoIGEgcHJlY2VkaW5nIGRvdC4gSWYgdGhlIGV4dGVuc2lvbiBpcyBlbXB0eSwgbm8gZG90IGlzIGluY2x1ZGVkLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRIZWxwTmFtZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+e3tldmVudF9maWxlX2V4dGVuc2lvbjp3aXRoLWRvdH19PC9zdHJvbmc+IG9yIDxzdHJvbmc+e3tldmVudF9maWxlX2V4dGVuc2lvbjpuby1kb3R9fTwvc3Ryb25nPlwiO1xyXG4gICAgfVxyXG5cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTWVudX0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlTWVudVwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVDcmVhdGVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVDcmVhdGVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZURlbGV0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZURlbGV0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlUmVuYW1lZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlUmVuYW1lZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVNb3ZlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlTW92ZWRcIjtcclxuaW1wb3J0IHtFdmVudFZhcmlhYmxlfSBmcm9tIFwiLi9FdmVudFZhcmlhYmxlXCI7XHJcbmltcG9ydCB7SVBhcmFtZXRlcnN9IGZyb20gXCIuLi9WYXJpYWJsZVwiO1xyXG5pbXBvcnQge2dldEZpbGVUYWdzfSBmcm9tIFwiLi4vVmFyaWFibGVIZWxwZXJzXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfRXZlbnRUYWdzIGV4dGVuZHMgRXZlbnRWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiZXZlbnRfdGFnc1wiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiR2l2ZXMgYWxsIHRhZ3MgZGVmaW5lZCBpbiB0aGUgZXZlbnQgcmVsYXRlZCBub3RlLiBSZXBsYWNlIHRoZSBcXFwic2VwYXJhdG9yXFxcIiBwYXJ0IHdpdGggYSBjb21tYSwgc3BhY2Ugb3Igd2hhdGV2ZXIgY2hhcmFjdGVycyB5b3Ugd2FudCB0byB1c2UgYXMgYSBzZXBhcmF0b3IgYmV0d2VlbiB0YWdzLiBBIHNlcGFyYXRvciBpcyBhbHdheXMgbmVlZGVkIHRvIGJlIGRlZmluZWQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN1cHBvcnRlZF9zY19ldmVudHMgPSBbXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZU1lbnUsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNyZWF0ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlRGVsZXRlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlTW92ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICBdO1xyXG5cclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgcGFyYW1ldGVyczogSVBhcmFtZXRlcnMgPSB7XHJcbiAgICAgICAgc2VwYXJhdG9yOiB7XHJcbiAgICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoXHJcbiAgICAgICAgY2FzdGVkQXJndW1lbnRzOiB7c2VwYXJhdG9yOiBzdHJpbmd9LFxyXG4gICAgICAgIHNjX2V2ZW50OiBTQ19FdmVudF9GaWxlTWVudSB8IFNDX0V2ZW50X0ZpbGVDcmVhdGVkIHwgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCB8IFNDX0V2ZW50X0ZpbGVEZWxldGVkIHwgU0NfRXZlbnRfRmlsZU1vdmVkIHwgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICApOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHRoaXMucmVxdWlyZUNvcnJlY3RFdmVudChzY19ldmVudCk7XHJcblxyXG4gICAgICAgIGNvbnN0IGZpbGUgPSBzY19ldmVudC5nZXRGaWxlKCk7XHJcbiAgICAgICAgcmV0dXJuIGdldEZpbGVUYWdzKHRoaXMuYXBwLCBmaWxlKS5qb2luKGNhc3RlZEFyZ3VtZW50cy5zZXBhcmF0b3IpO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVNZW51fSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVNZW51XCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZUNyZWF0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZUNyZWF0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlRGVsZXRlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlRGVsZXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVSZW5hbWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVSZW5hbWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZU1vdmVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVNb3ZlZFwiO1xyXG5pbXBvcnQge0V2ZW50VmFyaWFibGV9IGZyb20gXCIuL0V2ZW50VmFyaWFibGVcIjtcclxuaW1wb3J0IHtnZXRGaWxlWUFNTFZhbHVlfSBmcm9tIFwiLi4vVmFyaWFibGVIZWxwZXJzXCI7XHJcbmltcG9ydCB7SVBhcmFtZXRlcnN9IGZyb20gXCIuLi9WYXJpYWJsZVwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0V2ZW50WUFNTFZhbHVlIGV4dGVuZHMgRXZlbnRWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiZXZlbnRfeWFtbF92YWx1ZVwiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiUmVhZHMgYSBzaW5nbGUgdmFsdWUgZnJvbSB0aGUgZXZlbnQgcmVsYXRlZCBmaWxlJ3MgZnJvbnRtYXR0ZXIuIFRha2VzIGEgcHJvcGVydHkgbmFtZSBhcyBhbiBhcmd1bWVudC4gWW91IGNhbiBhY2Nlc3MgbmVzdGVkIHByb3BlcnRpZXMgd2l0aCBkb3Qgbm90YXRpb246IHByb3BlcnR5MS5wcm9wZXJ0eTJcIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHBhcmFtZXRlcnM6IElQYXJhbWV0ZXJzID0ge1xyXG4gICAgICAgIHByb3BlcnR5X25hbWU6IHtcclxuICAgICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcclxuICAgICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXHJcbiAgICAgICAgfSxcclxuICAgIH07XHJcblxyXG4gICAgcHJvdGVjdGVkIHN1cHBvcnRlZF9zY19ldmVudHMgPSBbXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZU1lbnUsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNyZWF0ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlRGVsZXRlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlTW92ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICBdO1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKFxyXG4gICAgICAgIGNhc3RlZEFyZ3VtZW50czoge3Byb3BlcnR5X25hbWU6IHN0cmluZ30sXHJcbiAgICAgICAgc2NfZXZlbnQ6IFNDX0V2ZW50X0ZpbGVNZW51IHwgU0NfRXZlbnRfRmlsZUNyZWF0ZWQgfCBTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkIHwgU0NfRXZlbnRfRmlsZURlbGV0ZWQgfCBTQ19FdmVudF9GaWxlTW92ZWQgfCBTQ19FdmVudF9GaWxlUmVuYW1lZCxcclxuICAgICk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgdGhpcy5yZXF1aXJlQ29ycmVjdEV2ZW50KHNjX2V2ZW50KTtcclxuXHJcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gZ2V0RmlsZVlBTUxWYWx1ZSh0aGlzLmFwcCwgc2NfZXZlbnQuZ2V0RmlsZSgpLCBjYXN0ZWRBcmd1bWVudHMucHJvcGVydHlfbmFtZSk7XHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocmVzdWx0KSkge1xyXG4gICAgICAgICAgICAvLyBUaGUgcmVzdWx0IGNvbnRhaW5zIGVycm9yIG1lc3NhZ2UocykuXHJcbiAgICAgICAgICAgIHRoaXMudGhyb3cocmVzdWx0LmpvaW4oXCIgXCIpKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBUaGUgcmVzdWx0IGlzIG9rLCBpdCdzIGEgc3RyaW5nLlxyXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHB1YmxpYyBnZXRBdmFpbGFiaWxpdHlUZXh0KCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIHN1cGVyLmdldEF2YWlsYWJpbGl0eVRleHQoKSArIFwiIEFsc28sIHRoZSBnaXZlbiBZQU1MIHByb3BlcnR5IG11c3QgZXhpc3QgaW4gdGhlIGZpbGUncyBmcm9udG1hdHRlci5cIjtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0SGVscE5hbWUoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gXCI8c3Ryb25nPnt7ZXZlbnRfeWFtbF92YWx1ZTpwcm9wZXJ0eX19PC9zdHJvbmc+XCI7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7SVBhcmFtZXRlcnMsIFZhcmlhYmxlfSBmcm9tIFwiLi9WYXJpYWJsZVwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0Vudmlyb25tZW50IGV4dGVuZHMgVmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcImVudmlyb25tZW50XCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyBhbiBlbnZpcm9ubWVudCB2YXJpYWJsZSdzIHZhbHVlLiBJdCdzIGFuIG9yaWdpbmFsIHZhbHVlIHJlY2VpdmVkIHdoZW4gT2JzaWRpYW4gd2FzIHN0YXJ0ZWQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIGFsd2F5c19hdmFpbGFibGUgPSBmYWxzZTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHBhcmFtZXRlcnM6IElQYXJhbWV0ZXJzID0ge1xyXG4gICAgICAgIHZhcmlhYmxlOiB7XHJcbiAgICAgICAgICAgIHR5cGU6IFwic3RyaW5nXCIsXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH0sXHJcbiAgICB9O1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKGNhc3RlZEFyZ3VtZW50czoge3ZhcmlhYmxlOiBzdHJpbmd9KTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICAvLyBDaGVjayB0aGF0IHRoZSByZXF1ZXN0ZWQgZW52aXJvbm1lbnQgdmFyaWFibGUgZXhpc3RzLlxyXG4gICAgICAgIGlmICh1bmRlZmluZWQgIT09IHByb2Nlc3MuZW52W2Nhc3RlZEFyZ3VtZW50cy52YXJpYWJsZV0pIHtcclxuICAgICAgICAgICAgLy8gWWVzLCBpdCBleGlzdHMuXHJcbiAgICAgICAgICAgIHJldHVybiBwcm9jZXNzLmVudltjYXN0ZWRBcmd1bWVudHMudmFyaWFibGVdIGFzIHN0cmluZzsgLy8gYXMgc3RyaW5nOiB0ZWxscyBUeXBlU2NyaXB0IGNvbXBpbGVyIHRoYXQgdGhlIGl0ZW0gZXhpc3RzLCBpcyBub3QgdW5kZWZpbmVkLlxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIEl0IGRvZXMgbm90IGV4aXN0LlxyXG4gICAgICAgICAgICAvLyBGcmVhayBvdXQuXHJcbiAgICAgICAgICAgIHRoaXMudGhyb3coYEVudmlyb25tZW50IHZhcmlhYmxlIG5hbWVkICcke2Nhc3RlZEFyZ3VtZW50cy52YXJpYWJsZX0nIGRvZXMgbm90IGV4aXN0LmApO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0SGVscE5hbWUoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gXCI8c3Ryb25nPnt7ZW52aXJvbm1lbnQ6dmFyaWFibGV9fTwvc3Ryb25nPlwiO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRBdmFpbGFiaWxpdHlUZXh0KCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIFwiPHN0cm9uZz5Pbmx5IGF2YWlsYWJsZTwvc3Ryb25nPiBpZiB0aGUgcGFzc2VkIGVudmlyb25tZW50IHZhcmlhYmxlIG5hbWUgZXhpc3RzLlwiO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0V2ZW50VmFyaWFibGV9IGZyb20gXCIuL0V2ZW50VmFyaWFibGVcIjtcclxuaW1wb3J0IHtleHRyYWN0RmlsZU5hbWV9IGZyb20gXCIuLi8uLi9Db21tb25cIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlUmVuYW1lZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlUmVuYW1lZFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0V2ZW50T2xkRmlsZU5hbWUgZXh0ZW5kcyBFdmVudFZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJldmVudF9vbGRfZmlsZV9uYW1lXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyB0aGUgcmVuYW1lZCBmaWxlJ3Mgb2xkIG5hbWUgd2l0aCBhIGZpbGUgZXh0ZW5zaW9uLiBJZiB5b3UgbmVlZCBpdCB3aXRob3V0IHRoZSBleHRlbnNpb24sIHVzZSB7e2V2ZW50X29sZF90aXRsZX19IGluc3RlYWQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN1cHBvcnRlZF9zY19ldmVudHMgPSBbXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICBdO1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKFxyXG4gICAgICAgIGFyZ3VtZW50c0FyZU5vdFVzZWQ6IG5ldmVyLFxyXG4gICAgICAgIHNjX2V2ZW50OiBTQ19FdmVudF9GaWxlUmVuYW1lZCxcclxuICAgICk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgdGhpcy5yZXF1aXJlQ29ycmVjdEV2ZW50KHNjX2V2ZW50KTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGV4dHJhY3RGaWxlTmFtZShzY19ldmVudC5nZXRGaWxlT2xkUmVsYXRpdmVQYXRoKCksIHRydWUpO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0V2ZW50VmFyaWFibGV9IGZyb20gXCIuL0V2ZW50VmFyaWFibGVcIjtcclxuaW1wb3J0IHtcclxuICAgIGdldFZhdWx0QWJzb2x1dGVQYXRoLFxyXG4gICAgbm9ybWFsaXplUGF0aDIsXHJcbn0gZnJvbSBcIi4uLy4uL0NvbW1vblwiO1xyXG5pbXBvcnQge0lQYXJhbWV0ZXJzfSBmcm9tIFwiLi4vVmFyaWFibGVcIjtcclxuaW1wb3J0IHtJQXV0b2NvbXBsZXRlSXRlbX0gZnJvbSBcIi4uLy4uL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvQXV0b2NvbXBsZXRlXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZVJlbmFtZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZVJlbmFtZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1vdmVkXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfRXZlbnRPbGRGaWxlUGF0aCBleHRlbmRzIEV2ZW50VmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcImV2ZW50X29sZF9maWxlX3BhdGhcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIHRoZSByZW5hbWVkL21vdmVkIGZpbGUncyBvbGQgcGF0aCwgZWl0aGVyIGFzIGFic29sdXRlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIGZpbGUgc3lzdGVtLCBvciBhcyByZWxhdGl2ZSBmcm9tIHRoZSByb290IG9mIHRoZSBPYnNpZGlhbiB2YXVsdC5cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHBhcmFtZXRlcnM6IElQYXJhbWV0ZXJzID0ge1xyXG4gICAgICAgIG1vZGU6IHtcclxuICAgICAgICAgICAgb3B0aW9uczogW1wiYWJzb2x1dGVcIiwgXCJyZWxhdGl2ZVwiXSxcclxuICAgICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXHJcbiAgICAgICAgfSxcclxuICAgIH07XHJcblxyXG4gICAgcHJvdGVjdGVkIHN1cHBvcnRlZF9zY19ldmVudHMgPSBbXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZU1vdmVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVSZW5hbWVkLFxyXG4gICAgXTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZShcclxuICAgICAgICBjYXN0ZWRBcmd1bWVudHM6IHttb2RlOiBcImFic29sdXRlXCIgfCBcInJlbGF0aXZlXCJ9LFxyXG4gICAgICAgIHNjX2V2ZW50OiBTQ19FdmVudF9GaWxlTW92ZWQgfCBTQ19FdmVudF9GaWxlUmVuYW1lZCxcclxuICAgICk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgdGhpcy5yZXF1aXJlQ29ycmVjdEV2ZW50KHNjX2V2ZW50KTtcclxuXHJcbiAgICAgICAgY29uc3QgZmlsZV9vbGRfcmVsYXRpdmVfcGF0aCA9IHNjX2V2ZW50LmdldEZpbGVPbGRSZWxhdGl2ZVBhdGgoKTtcclxuICAgICAgICBzd2l0Y2ggKGNhc3RlZEFyZ3VtZW50cy5tb2RlLnRvTG93ZXJDYXNlKCkpIHtcclxuICAgICAgICAgICAgY2FzZSBcInJlbGF0aXZlXCI6XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gbm9ybWFsaXplUGF0aDIoZmlsZV9vbGRfcmVsYXRpdmVfcGF0aCk7XHJcbiAgICAgICAgICAgIGNhc2UgXCJhYnNvbHV0ZVwiOlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZVBhdGgyKGdldFZhdWx0QWJzb2x1dGVQYXRoKHRoaXMuYXBwKSArIFwiL1wiICsgZmlsZV9vbGRfcmVsYXRpdmVfcGF0aCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLnRocm93KFwiVW5yZWNvZ25pemVkIG1vZGUgcGFyYW1ldGVyOiBcIiArIGNhc3RlZEFyZ3VtZW50cy5tb2RlKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QXV0b2NvbXBsZXRlSXRlbXMoKSB7XHJcbiAgICAgICAgcmV0dXJuIFtcclxuICAgICAgICAgICAgLy8gTm9ybWFsIHZhcmlhYmxlc1xyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3tcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOmFic29sdXRlfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyB0aGUgcmVuYW1lZC9tb3ZlZCBmaWxlJ3Mgb2xkIHBhdGgsIGFic29sdXRlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIGZpbGUgc3lzdGVtLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5vcm1hbC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7XCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjpyZWxhdGl2ZX19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgdGhlIHJlbmFtZWQvbW92ZWQgZmlsZSdzIG9sZCBwYXRoLCByZWxhdGl2ZSBmcm9tIHRoZSByb290IG9mIHRoZSBPYnNpZGlhbiB2YXVsdC4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcblxyXG4gICAgICAgICAgICAvLyBVbmVzY2FwZWQgdmFyaWFibGVzXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7eyFcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOmFic29sdXRlfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyB0aGUgcmVuYW1lZC9tb3ZlZCBmaWxlJ3Mgb2xkIHBhdGgsIGFic29sdXRlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIGZpbGUgc3lzdGVtLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7IVwiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6cmVsYXRpdmV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSByZW5hbWVkL21vdmVkIGZpbGUncyBvbGQgcGF0aCwgcmVsYXRpdmUgZnJvbSB0aGUgcm9vdCBvZiB0aGUgT2JzaWRpYW4gdmF1bHQuIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwidW5lc2NhcGVkLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgIF07XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEhlbHBOYW1lKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIFwiPHN0cm9uZz57e2V2ZW50X2ZpbGVfcGF0aDpyZWxhdGl2ZX19PC9zdHJvbmc+IG9yIDxzdHJvbmc+e3tldmVudF9maWxlX3BhdGg6YWJzb2x1dGV9fTwvc3Ryb25nPlwiO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0V2ZW50VmFyaWFibGV9IGZyb20gXCIuL0V2ZW50VmFyaWFibGVcIjtcclxuaW1wb3J0IHtleHRyYWN0RmlsZU5hbWV9IGZyb20gXCIuLi8uLi9Db21tb25cIjtcclxuaW1wb3J0IHtTQ19FdmVudF9Gb2xkZXJSZW5hbWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZvbGRlclJlbmFtZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1vdmVkXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfRXZlbnRPbGRGb2xkZXJOYW1lIGV4dGVuZHMgRXZlbnRWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiZXZlbnRfb2xkX2ZvbGRlcl9uYW1lXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJGaWxlIGV2ZW50czogR2l2ZXMgdGhlIG1vdmVkIGZpbGUncyBvbGQgcGFyZW50IGZvbGRlcidzIG5hbWUuIEZvbGRlciBldmVudHM6IEdpdmVzIHRoZSByZW5hbWVkIGZvbGRlcidzIG9sZCBuYW1lLlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBzdXBwb3J0ZWRfc2NfZXZlbnRzID0gW1xyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVNb3ZlZCxcclxuICAgICAgICBTQ19FdmVudF9Gb2xkZXJSZW5hbWVkLFxyXG4gICAgXTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZShcclxuICAgICAgICBhcmd1bWVudHNBcmVOb3RVc2VkOiBuZXZlcixcclxuICAgICAgICBzY19ldmVudDogU0NfRXZlbnRfRmlsZU1vdmVkIHwgU0NfRXZlbnRfRm9sZGVyUmVuYW1lZCxcclxuICAgICk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgdGhpcy5yZXF1aXJlQ29ycmVjdEV2ZW50KHNjX2V2ZW50KTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGV4dHJhY3RGaWxlTmFtZShzY19ldmVudC5nZXRGb2xkZXJPbGRSZWxhdGl2ZVBhdGgoKSk7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7RXZlbnRWYXJpYWJsZX0gZnJvbSBcIi4vRXZlbnRWYXJpYWJsZVwiO1xyXG5pbXBvcnQge1xyXG4gICAgZ2V0VmF1bHRBYnNvbHV0ZVBhdGgsXHJcbiAgICBub3JtYWxpemVQYXRoMixcclxufSBmcm9tIFwiLi4vLi4vQ29tbW9uXCI7XHJcbmltcG9ydCB7SVBhcmFtZXRlcnN9IGZyb20gXCIuLi9WYXJpYWJsZVwiO1xyXG5pbXBvcnQge0lBdXRvY29tcGxldGVJdGVtfSBmcm9tIFwiLi4vLi4vc2V0dGluZ3Mvc2V0dGluZ19lbGVtZW50cy9BdXRvY29tcGxldGVcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9Gb2xkZXJSZW5hbWVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZvbGRlclJlbmFtZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1vdmVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRm9sZGVyTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRm9sZGVyTW92ZWRcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9FdmVudE9sZEZvbGRlclBhdGggZXh0ZW5kcyBFdmVudFZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJldmVudF9vbGRfZm9sZGVyX3BhdGhcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkZpbGUgZXZlbnRzOiBHaXZlcyB0aGUgbW92ZWQgZmlsZSdzIG9sZCBwYXJlbnQgZm9sZGVyJ3MgcGF0aC4gRm9sZGVyIGV2ZW50czogR2l2ZXMgdGhlIHJlbmFtZWQvbW92ZWQgZm9sZGVyJ3Mgb2xkIHBhdGguIFRoZSBwYXRoIGlzIGVpdGhlciBhcyBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbSwgb3IgYXMgcmVsYXRpdmUgZnJvbSB0aGUgcm9vdCBvZiB0aGUgT2JzaWRpYW4gdmF1bHQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBwYXJhbWV0ZXJzOiBJUGFyYW1ldGVycyA9IHtcclxuICAgICAgICBtb2RlOiB7XHJcbiAgICAgICAgICAgIG9wdGlvbnM6IFtcImFic29sdXRlXCIsIFwicmVsYXRpdmVcIl0sXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH0sXHJcbiAgICB9O1xyXG5cclxuICAgIHByb3RlY3RlZCBzdXBwb3J0ZWRfc2NfZXZlbnRzID0gW1xyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVNb3ZlZCxcclxuICAgICAgICBTQ19FdmVudF9Gb2xkZXJNb3ZlZCxcclxuICAgICAgICBTQ19FdmVudF9Gb2xkZXJSZW5hbWVkLFxyXG4gICAgXTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZShcclxuICAgICAgICBjYXN0ZWRBcmd1bWVudHM6IHttb2RlOiBcImFic29sdXRlXCIgfCBcInJlbGF0aXZlXCJ9LFxyXG4gICAgICAgIHNjX2V2ZW50OiBTQ19FdmVudF9GaWxlTW92ZWQgfCBTQ19FdmVudF9Gb2xkZXJSZW5hbWVkIHwgU0NfRXZlbnRfRm9sZGVyTW92ZWQsXHJcbiAgICApOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHRoaXMucmVxdWlyZUNvcnJlY3RFdmVudChzY19ldmVudCk7XHJcblxyXG4gICAgICAgIGNvbnN0IGZvbGRlcl9vbGRfcmVsYXRpdmVfcGF0aCA9IHNjX2V2ZW50LmdldEZvbGRlck9sZFJlbGF0aXZlUGF0aCgpO1xyXG4gICAgICAgIHN3aXRjaCAoY2FzdGVkQXJndW1lbnRzLm1vZGUudG9Mb3dlckNhc2UoKSkge1xyXG4gICAgICAgICAgICBjYXNlIFwicmVsYXRpdmVcIjpcclxuICAgICAgICAgICAgICAgIHJldHVybiBub3JtYWxpemVQYXRoMihmb2xkZXJfb2xkX3JlbGF0aXZlX3BhdGgpO1xyXG4gICAgICAgICAgICBjYXNlIFwiYWJzb2x1dGVcIjpcclxuICAgICAgICAgICAgICAgIHJldHVybiBub3JtYWxpemVQYXRoMihnZXRWYXVsdEFic29sdXRlUGF0aCh0aGlzLmFwcCkgKyBcIi9cIiArIGZvbGRlcl9vbGRfcmVsYXRpdmVfcGF0aCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLnRocm93KFwiVW5yZWNvZ25pemVkIG1vZGUgcGFyYW1ldGVyOiBcIiArIGNhc3RlZEFyZ3VtZW50cy5tb2RlKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QXV0b2NvbXBsZXRlSXRlbXMoKSB7XHJcbiAgICAgICAgcmV0dXJuIFtcclxuICAgICAgICAgICAgLy8gTm9ybWFsIHZhcmlhYmxlc1xyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3tcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOmFic29sdXRlfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJGaWxlIGV2ZW50czogR2l2ZXMgdGhlIG1vdmVkIGZpbGUncyBvbGQgcGFyZW50IGZvbGRlcidzIHBhdGguIEZvbGRlciBldmVudHM6IEdpdmVzIHRoZSByZW5hbWVkL21vdmVkIGZvbGRlcidzIG9sZCBwYXRoLiBUaGUgcGF0aCBpcyBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbS4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6cmVsYXRpdmV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkZpbGUgZXZlbnRzOiBHaXZlcyB0aGUgbW92ZWQgZmlsZSdzIG9sZCBwYXJlbnQgZm9sZGVyJ3MgcGF0aC4gRm9sZGVyIGV2ZW50czogR2l2ZXMgdGhlIHJlbmFtZWQvbW92ZWQgZm9sZGVyJ3Mgb2xkIHBhdGguIFRoZSBwYXRoIGlzIHJlbGF0aXZlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIE9ic2lkaWFuIHZhdWx0LiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5vcm1hbC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuXHJcbiAgICAgICAgICAgIC8vIFVuZXNjYXBlZCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7IVwiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6YWJzb2x1dGV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkZpbGUgZXZlbnRzOiBHaXZlcyB0aGUgbW92ZWQgZmlsZSdzIG9sZCBwYXJlbnQgZm9sZGVyJ3MgcGF0aC4gRm9sZGVyIGV2ZW50czogR2l2ZXMgdGhlIHJlbmFtZWQvbW92ZWQgZm9sZGVyJ3Mgb2xkIHBhdGguIFRoZSBwYXRoIGlzIGFic29sdXRlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIGZpbGUgc3lzdGVtLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7IVwiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6cmVsYXRpdmV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkZpbGUgZXZlbnRzOiBHaXZlcyB0aGUgbW92ZWQgZmlsZSdzIG9sZCBwYXJlbnQgZm9sZGVyJ3MgcGF0aC4gRm9sZGVyIGV2ZW50czogR2l2ZXMgdGhlIHJlbmFtZWQvbW92ZWQgZm9sZGVyJ3Mgb2xkIHBhdGguIFRoZSBwYXRoIGlzIHJlbGF0aXZlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIE9ic2lkaWFuIHZhdWx0LiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRIZWxwTmFtZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+e3tldmVudF9maWxlX3BhdGg6cmVsYXRpdmV9fTwvc3Ryb25nPiBvciA8c3Ryb25nPnt7ZXZlbnRfZmlsZV9wYXRoOmFic29sdXRlfX08L3N0cm9uZz5cIjtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtFdmVudFZhcmlhYmxlfSBmcm9tIFwiLi9FdmVudFZhcmlhYmxlXCI7XHJcbmltcG9ydCB7ZXh0cmFjdEZpbGVOYW1lfSBmcm9tIFwiLi4vLi4vQ29tbW9uXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZVJlbmFtZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZVJlbmFtZWRcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9FdmVudE9sZFRpdGxlIGV4dGVuZHMgRXZlbnRWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiZXZlbnRfb2xkX3RpdGxlXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyB0aGUgcmVuYW1lZCBmaWxlJ3Mgb2xkIG5hbWUgd2l0aG91dCBhIGZpbGUgZXh0ZW5zaW9uLiBJZiB5b3UgbmVlZCBpdCB3aXRoIHRoZSBleHRlbnNpb24sIHVzZSB7e2V2ZW50X29sZF9maWxlX25hbWV9fSBpbnN0ZWFkLlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBzdXBwb3J0ZWRfc2NfZXZlbnRzID0gW1xyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVSZW5hbWVkLFxyXG4gICAgXTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZShcclxuICAgICAgICBhcmd1bWVudHNBcmVOb3RVc2VkOiBuZXZlcixcclxuICAgICAgICBzY19ldmVudDogU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICApOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHRoaXMucmVxdWlyZUNvcnJlY3RFdmVudChzY19ldmVudCk7XHJcblxyXG4gICAgICAgIHJldHVybiBleHRyYWN0RmlsZU5hbWUoc2NfZXZlbnQuZ2V0RmlsZU9sZFJlbGF0aXZlUGF0aCgpLCBmYWxzZSk7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7VmFyaWFibGV9IGZyb20gXCIuL1ZhcmlhYmxlXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfTmV3Tm90ZUZvbGRlck5hbWUgZXh0ZW5kcyBWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwibmV3X25vdGVfZm9sZGVyX25hbWVcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIHRoZSBmb2xkZXIgbmFtZSBmb3IgXFxcIkRlZmF1bHQgbG9jYXRpb24gZm9yIG5ldyBub3Rlc1xcXCIgKGEgc2V0dGluZyBpbiBPYnNpZGlhbikuIE5vIGFuY2VzdG9yIGZvbGRlcnMgYXJlIGluY2x1ZGVkLlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKCk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgY29uc3QgY3VycmVudF9maWxlID0gdGhpcy5hcHAud29ya3NwYWNlLmdldEFjdGl2ZUZpbGUoKTsgLy8gTmVlZGVkIGp1c3QgaW4gY2FzZSBuZXcgbm90ZXMgc2hvdWxkIGJlIGNyZWF0ZWQgaW4gdGhlIHNhbWUgZm9sZGVyIGFzIHRoZSBjdXJyZW50bHkgb3BlbiBmaWxlLlxyXG4gICAgICAgIGNvbnN0IGZvbGRlciA9IHRoaXMuYXBwLmZpbGVNYW5hZ2VyLmdldE5ld0ZpbGVQYXJlbnQoY3VycmVudF9maWxlID8gY3VycmVudF9maWxlLnBhdGggOiBcIlwiKTsgLy8gSWYgbm8gZmlsZSBpcyBvcGVuLCB1c2UgYW4gZW1wdHkgc3RyaW5nIGFzIGluc3RydWN0ZWQgaW4gLmdldE5ld0ZpbGVQYXJlbnQoKSdzIGRvY3VtZW50YXRpb24uXHJcbiAgICAgICAgaWYgKCFmb2xkZXIpIHtcclxuICAgICAgICAgICAgdGhpcy50aHJvdyhcIkNhbm5vdCBkZXRlcm1pbmUgYSBmb2xkZXIgbmFtZSBmb3IgbmV3IG5vdGVzLiBQbGVhc2UgY3JlYXRlIGEgZGlzY3Vzc2lvbiBpbiBHaXRIdWIuXCIpOyAvLyBJIGd1ZXNzIHRoaXMgbmV2ZXIgaGFwcGVucy5cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIHRoZSBmb2xkZXIgaXMgdGhlIHZhdWx0J3Mgcm9vdCBmb2xkZXIsIHJldHVybiBcIi5cIiBpbnN0ZWFkIG9mIFwiIFwiIChhIHNwYWNlIGNoYXJhY3RlcikuIEkgZG9uJ3Qga25vdyB3aHkgdGhlIG5hbWUgaXMgXCIgXCIgd2hlbiB0aGUgZm9sZGVyIGlzIHJvb3QuXHJcbiAgICAgICAgcmV0dXJuIGZvbGRlci5pc1Jvb3QoKVxyXG4gICAgICAgICAgICA/IFwiLlwiXHJcbiAgICAgICAgICAgIDogZm9sZGVyLm5hbWVcclxuICAgICAgICA7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7XHJcbiAgICBJUGFyYW1ldGVycyxcclxuICAgIFZhcmlhYmxlLFxyXG59IGZyb20gXCIuL1ZhcmlhYmxlXCI7XHJcbmltcG9ydCB7SUF1dG9jb21wbGV0ZUl0ZW19IGZyb20gXCIuLi9zZXR0aW5ncy9zZXR0aW5nX2VsZW1lbnRzL0F1dG9jb21wbGV0ZVwiO1xyXG5pbXBvcnQge2dldEZvbGRlclBhdGh9IGZyb20gXCIuL1ZhcmlhYmxlSGVscGVyc1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX05ld05vdGVGb2xkZXJQYXRoIGV4dGVuZHMgVmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcIm5ld19ub3RlX2ZvbGRlcl9wYXRoXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyBwYXRoIHRvIHRoZSBcXFwiRGVmYXVsdCBsb2NhdGlvbiBmb3IgbmV3IG5vdGVzXFxcIiBmb2xkZXIgKGEgc2V0dGluZyBpbiBPYnNpZGlhbiksIGVpdGhlciBhcyBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbSwgb3IgYXMgcmVsYXRpdmUgZnJvbSB0aGUgcm9vdCBvZiB0aGUgT2JzaWRpYW4gdmF1bHQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBwYXJhbWV0ZXJzOiBJUGFyYW1ldGVycyA9IHtcclxuICAgICAgICBtb2RlOiB7XHJcbiAgICAgICAgICAgIG9wdGlvbnM6IFtcImFic29sdXRlXCIsIFwicmVsYXRpdmVcIl0sXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoY2FzdGVkQXJndW1lbnRzOiB7bW9kZTogXCJhYnNvbHV0ZVwiIHwgXCJyZWxhdGl2ZVwifSk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgY29uc3QgY3VycmVudF9maWxlID0gdGhpcy5hcHAud29ya3NwYWNlLmdldEFjdGl2ZUZpbGUoKTsgLy8gTmVlZGVkIGp1c3QgaW4gY2FzZSBuZXcgbm90ZXMgc2hvdWxkIGJlIGNyZWF0ZWQgaW4gdGhlIHNhbWUgZm9sZGVyIGFzIHRoZSBjdXJyZW50bHkgb3BlbiBmaWxlLlxyXG4gICAgICAgIGNvbnN0IGZvbGRlciA9IHRoaXMuYXBwLmZpbGVNYW5hZ2VyLmdldE5ld0ZpbGVQYXJlbnQoY3VycmVudF9maWxlID8gY3VycmVudF9maWxlLnBhdGggOiBcIlwiKTsgLy8gSWYgbm8gZmlsZSBpcyBvcGVuLCB1c2UgYW4gZW1wdHkgc3RyaW5nIGFzIGluc3RydWN0ZWQgaW4gLmdldE5ld0ZpbGVQYXJlbnQoKSdzIGRvY3VtZW50YXRpb24uXHJcbiAgICAgICAgaWYgKGZvbGRlcikge1xyXG4gICAgICAgICAgICByZXR1cm4gZ2V0Rm9sZGVyUGF0aCh0aGlzLmFwcCwgZm9sZGVyLCBjYXN0ZWRBcmd1bWVudHMubW9kZSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy50aHJvdyhcIkNhbm5vdCBkZXRlcm1pbmUgYSBmb2xkZXIgcGF0aCBmb3IgbmV3IG5vdGVzLiBQbGVhc2UgY3JlYXRlIGEgZGlzY3Vzc2lvbiBpbiBHaXRIdWIuXCIpOyAvLyBJIGd1ZXNzIHRoaXMgbmV2ZXIgaGFwcGVucy5cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEF1dG9jb21wbGV0ZUl0ZW1zKCkge1xyXG4gICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgIC8vIE5vcm1hbCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7XCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjphYnNvbHV0ZX19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgcGF0aCB0byB0aGUgXFxcIkRlZmF1bHQgbG9jYXRpb24gZm9yIG5ldyBub3Rlc1xcXCIgZm9sZGVyIChhIHNldHRpbmcgaW4gT2JzaWRpYW4pLCBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbS4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6cmVsYXRpdmV9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHBhdGggdG8gdGhlIFxcXCJEZWZhdWx0IGxvY2F0aW9uIGZvciBuZXcgbm90ZXNcXFwiIGZvbGRlciAoYSBzZXR0aW5nIGluIE9ic2lkaWFuKSwgcmVsYXRpdmUgZnJvbSB0aGUgcm9vdCBvZiB0aGUgT2JzaWRpYW4gdmF1bHQuIFwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwibm9ybWFsLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG5cclxuICAgICAgICAgICAgLy8gVW5lc2NhcGVkIHZhcmlhYmxlc1xyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3shXCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjphYnNvbHV0ZX19XCIsXHJcbiAgICAgICAgICAgICAgICBoZWxwX3RleHQ6IFwiR2l2ZXMgcGF0aCB0byB0aGUgXFxcIkRlZmF1bHQgbG9jYXRpb24gZm9yIG5ldyBub3Rlc1xcXCIgZm9sZGVyIChhIHNldHRpbmcgaW4gT2JzaWRpYW4pLCBhYnNvbHV0ZSBmcm9tIHRoZSByb290IG9mIHRoZSBmaWxlIHN5c3RlbS4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJ1bmVzY2FwZWQtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7eyFcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOnJlbGF0aXZlfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyBwYXRoIHRvIHRoZSBcXFwiRGVmYXVsdCBsb2NhdGlvbiBmb3IgbmV3IG5vdGVzXFxcIiBmb2xkZXIgKGEgc2V0dGluZyBpbiBPYnNpZGlhbiksIHJlbGF0aXZlIGZyb20gdGhlIHJvb3Qgb2YgdGhlIE9ic2lkaWFuIHZhdWx0LiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRIZWxwTmFtZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+e3tmb2xkZXJfcGF0aDpyZWxhdGl2ZX19PC9zdHJvbmc+IG9yIDxzdHJvbmc+e3tmb2xkZXJfcGF0aDphYnNvbHV0ZX19PC9zdHJvbmc+XCI7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7RmlsZVZhcmlhYmxlfSBmcm9tIFwiLi9GaWxlVmFyaWFibGVcIjtcclxuaW1wb3J0IHtub3JtYWxpemVQYXRofSBmcm9tIFwib2JzaWRpYW5cIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9GaWxlVVJJIGV4dGVuZHMgRmlsZVZhcmlhYmxle1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcImZpbGVfdXJpXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyBhbiBPYnNpZGlhbiBVUkkgdGhhdCBvcGVucyB0aGUgY3VycmVudCBmaWxlLlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKCk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMucGx1Z2luLmdldE9ic2lkaWFuVVJJKFwib3BlblwiLCB7XHJcbiAgICAgICAgICAgIGZpbGU6IG5vcm1hbGl6ZVBhdGgodGhpcy5nZXRGaWxlT3JUaHJvdygpLnBhdGgpLCAvLyBVc2Ugbm9ybWFsaXplUGF0aCgpIGluc3RlYWQgb2Ygbm9ybWFsaXplUGF0aDIoKSBiZWNhdXNlIC8gc2hvdWxkIG5vdCBiZSBjb252ZXJ0ZWQgdG8gXFwgb24gV2luZG93cyBiZWNhdXNlIHRoaXMgaXMgdXNlZCBhcyBhIFVSSSwgbm90IGFzIGEgZmlsZSBzeXN0ZW0gcGF0aC5cclxuICAgICAgICB9KTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtFdmVudFZhcmlhYmxlfSBmcm9tIFwiLi9FdmVudFZhcmlhYmxlXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZU1lbnV9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1lbnVcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlQ3JlYXRlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlQ3JlYXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVEZWxldGVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVEZWxldGVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZVJlbmFtZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZVJlbmFtZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1vdmVkXCI7XHJcbmltcG9ydCB7XHJcbiAgICBub3JtYWxpemVQYXRoLFxyXG4gICAgVEZpbGUsXHJcbn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfRXZlbnRGaWxlVVJJIGV4dGVuZHMgRXZlbnRWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiZXZlbnRfZmlsZV91cmlcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIGFuIE9ic2lkaWFuIFVSSSB0aGF0IG9wZW5zIHRoZSBldmVudCByZWxhdGVkIGZpbGUuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN1cHBvcnRlZF9zY19ldmVudHMgPSBbXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZU1lbnUsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNyZWF0ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlRGVsZXRlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlTW92ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICBdO1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKFxyXG4gICAgICAgIGFyZ3VtZW50c0FyZU5vdFVzZWQ6IG5ldmVyLFxyXG4gICAgICAgIHNjX2V2ZW50OiBTQ19FdmVudF9GaWxlTWVudSB8IFNDX0V2ZW50X0ZpbGVDcmVhdGVkIHwgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCB8IFNDX0V2ZW50X0ZpbGVEZWxldGVkIHwgU0NfRXZlbnRfRmlsZU1vdmVkIHwgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICApOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHRoaXMucmVxdWlyZUNvcnJlY3RFdmVudChzY19ldmVudCk7XHJcblxyXG4gICAgICAgIGNvbnN0IGZpbGU6IFRGaWxlID0gc2NfZXZlbnQuZ2V0RmlsZSgpO1xyXG4gICAgICAgIHJldHVybiB0aGlzLnBsdWdpbi5nZXRPYnNpZGlhblVSSShcIm9wZW5cIiwge1xyXG4gICAgICAgICAgICBmaWxlOiBub3JtYWxpemVQYXRoKGZpbGUucGF0aCksIC8vIFVzZSBub3JtYWxpemVQYXRoKCkgaW5zdGVhZCBvZiBub3JtYWxpemVQYXRoMigpIGJlY2F1c2UgLyBzaG91bGQgbm90IGJlIGNvbnZlcnRlZCB0byBcXCBvbiBXaW5kb3dzIGJlY2F1c2UgdGhpcyBpcyB1c2VkIGFzIGEgVVJJLCBub3QgYXMgYSBmaWxlIHN5c3RlbSBwYXRoLlxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtGaWxlVmFyaWFibGV9IGZyb20gXCIuL0ZpbGVWYXJpYWJsZVwiO1xyXG5pbXBvcnQge2dldEZpbGVDb250ZW50V2l0aG91dFlBTUx9IGZyb20gXCIuLi9Db21tb25cIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9Ob3RlQ29udGVudCBleHRlbmRzIEZpbGVWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwibm90ZV9jb250ZW50XCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyB0aGUgY3VycmVudCBub3RlJ3MgY29udGVudCB3aXRob3V0IFlBTUwgZnJvbnRtYXR0ZXIuIElmIHlvdSBuZWVkIFlBTUwgaW5jbHVkZWQsIHVzZSB7e2ZpbGVfY29udGVudH19IGluc3RlYWQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoKTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICByZXR1cm4gYXdhaXQgZ2V0RmlsZUNvbnRlbnRXaXRob3V0WUFNTCh0aGlzLmFwcCwgdGhpcy5nZXRGaWxlT3JUaHJvdygpKTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtFdmVudFZhcmlhYmxlfSBmcm9tIFwiLi9FdmVudFZhcmlhYmxlXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZU1lbnV9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1lbnVcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlQ3JlYXRlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlQ3JlYXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVDb250ZW50TW9kaWZpZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVEZWxldGVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVEZWxldGVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZVJlbmFtZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZVJlbmFtZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTW92ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZU1vdmVkXCI7XHJcbmltcG9ydCB7Z2V0RmlsZUNvbnRlbnRXaXRob3V0WUFNTH0gZnJvbSBcIi4uLy4uL0NvbW1vblwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX0V2ZW50Tm90ZUNvbnRlbnQgZXh0ZW5kcyBFdmVudFZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJldmVudF9ub3RlX2NvbnRlbnRcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIHRoZSBldmVudCByZWxhdGVkIGZpbGUncyBjb250ZW50IHdpdGhvdXQgWUFNTCBmcm9udG1hdHRlci4gSWYgeW91IG5lZWQgWUFNTCBpbmNsdWRlZCwgdXNlIHt7ZXZlbnRfZmlsZV9jb250ZW50fX0gaW5zdGVhZC5cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3VwcG9ydGVkX3NjX2V2ZW50cyA9IFtcclxuICAgICAgICBTQ19FdmVudF9GaWxlTWVudSxcclxuICAgICAgICBTQ19FdmVudF9GaWxlQ3JlYXRlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVEZWxldGVkLFxyXG4gICAgICAgIFNDX0V2ZW50X0ZpbGVNb3ZlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlUmVuYW1lZCxcclxuICAgIF07XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGdlbmVyYXRlVmFsdWUoXHJcbiAgICAgICAgYXJndW1lbnRzQXJlTm90VXNlZDogbmV2ZXIsXHJcbiAgICAgICAgc2NfZXZlbnQ6IFNDX0V2ZW50X0ZpbGVNZW51IHwgU0NfRXZlbnRfRmlsZUNyZWF0ZWQgfCBTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkIHwgU0NfRXZlbnRfRmlsZURlbGV0ZWQgfCBTQ19FdmVudF9GaWxlTW92ZWQgfCBTQ19FdmVudF9GaWxlUmVuYW1lZCxcclxuICAgICk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgdGhpcy5yZXF1aXJlQ29ycmVjdEV2ZW50KHNjX2V2ZW50KTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGF3YWl0IGdldEZpbGVDb250ZW50V2l0aG91dFlBTUwodGhpcy5hcHAsIHNjX2V2ZW50LmdldEZpbGUoKSk7XHJcbiAgICB9XHJcblxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0ZpbGVWYXJpYWJsZX0gZnJvbSBcIi4vRmlsZVZhcmlhYmxlXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfRmlsZUNvbnRlbnQgZXh0ZW5kcyBGaWxlVmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcImZpbGVfY29udGVudFwiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiR2l2ZXMgdGhlIGN1cnJlbnQgZmlsZSdzIGNvbnRlbnQsIGluY2x1ZGluZyBZQU1MIGZyb250bWF0dGVyLiBJZiB5b3UgbmVlZCBZQU1MIGV4Y2x1ZGVkLCB1c2Uge3tub3RlX2NvbnRlbnR9fSBpbnN0ZWFkLlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKCk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAgICAgLy8gUmV0cmlldmUgZmlsZSBjb250ZW50LlxyXG4gICAgICAgIHJldHVybiBhd2FpdCBhcHAudmF1bHQucmVhZCh0aGlzLmdldEZpbGVPclRocm93KCkpO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0V2ZW50VmFyaWFibGV9IGZyb20gXCIuL0V2ZW50VmFyaWFibGVcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTWVudX0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlTWVudVwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVDcmVhdGVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVDcmVhdGVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZURlbGV0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZURlbGV0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlUmVuYW1lZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlUmVuYW1lZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVNb3ZlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlTW92ZWRcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9FdmVudEZpbGVDb250ZW50IGV4dGVuZHMgRXZlbnRWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiZXZlbnRfZmlsZV9jb250ZW50XCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyB0aGUgZXZlbnQgcmVsYXRlZCBmaWxlJ3MgY29udGVudCwgaW5jbHVkaW5nIFlBTUwgZnJvbnRtYXR0ZXIuIElmIHlvdSBuZWVkIFlBTUwgZXhjbHVkZWQsIHVzZSB7e2V2ZW50X25vdGVfY29udGVudH19IGluc3RlYWQuXCI7XHJcblxyXG4gICAgcHJvdGVjdGVkIHN1cHBvcnRlZF9zY19ldmVudHMgPSBbXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZU1lbnUsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNyZWF0ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlRGVsZXRlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlTW92ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICBdO1xyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBnZW5lcmF0ZVZhbHVlKFxyXG4gICAgICAgIGFyZ3VtZW50c0FyZU5vdFVzZWQ6IG5ldmVyLFxyXG4gICAgICAgIHNjX2V2ZW50OiBTQ19FdmVudF9GaWxlTWVudSB8IFNDX0V2ZW50X0ZpbGVDcmVhdGVkIHwgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCB8IFNDX0V2ZW50X0ZpbGVEZWxldGVkIHwgU0NfRXZlbnRfRmlsZU1vdmVkIHwgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICApOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHRoaXMucmVxdWlyZUNvcnJlY3RFdmVudChzY19ldmVudCk7XHJcblxyXG4gICAgICAgIC8vIFJldHJpZXZlIGZpbGUgY29udGVudC5cclxuICAgICAgICByZXR1cm4gYXdhaXQgYXBwLnZhdWx0LnJlYWQoc2NfZXZlbnQuZ2V0RmlsZSgpKTtcclxuICAgIH1cclxuXHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7RWRpdG9yVmFyaWFibGV9IGZyb20gXCIuL0VkaXRvclZhcmlhYmxlXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfQ2FyZXRQYXJhZ3JhcGggZXh0ZW5kcyBFZGl0b3JWYXJpYWJsZSB7XHJcbiAgICBwdWJsaWMgdmFyaWFibGVfbmFtZSA9IFwiY2FyZXRfcGFyYWdyYXBoXCI7XHJcbiAgICBwdWJsaWMgaGVscF90ZXh0ID0gXCJHaXZlcyBhIHRleHQgbGluZSBhdCB0aGUgY3VycmVudCBjYXJldCBwb3NpdGlvbi5cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZSgpOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIGNvbnN0IGVkaXRvciA9IHRoaXMuZ2V0RWRpdG9yT3JUaHJvdygpO1xyXG4gICAgICAgIHRoaXMucmVxdWlyZVZpZXdNb2RlU291cmNlKCk7XHJcblxyXG4gICAgICAgIGNvbnN0IGNhcmV0UG9zaXRpb24gPSBlZGl0b3IuZ2V0Q3Vyc29yKCd0bycpO1xyXG4gICAgICAgIHJldHVybiBlZGl0b3IuZ2V0TGluZShjYXJldFBvc2l0aW9uLmxpbmUpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRBdmFpbGFiaWxpdHlUZXh0KCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIHN1cGVyLmdldEF2YWlsYWJpbGl0eVRleHQoKSArIFwiIE5vdCBhdmFpbGFibGUgaW4gcHJldmlldyBtb2RlLlwiO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0lQYXJhbWV0ZXJzLCBWYXJpYWJsZX0gZnJvbSBcIi4vVmFyaWFibGVcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBWYXJpYWJsZV9OZXdsaW5lIGV4dGVuZHMgVmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcIm5ld2xpbmVcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIGEgXFxcXG4gY2hhcmFjdGVyLiBVc2VkIGZvciB0ZXN0aW5nIGxpbmUgYnJlYWsgZXNjYXBpbmcuIEFuIG9wdGlvbmFsIGFyZ3VtZW50IGNhbiBiZSB1c2VkIHRvIHRlbGwgaG93IG1hbnkgbmV3bGluZXMgYXJlIG5lZWRlZC5cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHBhcmFtZXRlcnM6IElQYXJhbWV0ZXJzID0ge1xyXG4gICAgICAgIGNvdW50OiB7XHJcbiAgICAgICAgICAgIHR5cGU6IFwiaW50ZWdlclwiLFxyXG4gICAgICAgICAgICByZXF1aXJlZDogZmFsc2UsXHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgZ2VuZXJhdGVWYWx1ZShjYXN0ZWRBcmd1bWVudHM6IHtjb3VudD86IG51bWJlcn0pOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIC8vIFJldHVybiBcXG4sIHBvc3NpYmx5IHJlcGVhdGluZyBpdFxyXG4gICAgICAgIHJldHVybiBcIlxcblwiLnJlcGVhdChjYXN0ZWRBcmd1bWVudHMuY291bnQgPz8gMSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEF2YWlsYWJpbGl0eVRleHQoKSB7XHJcbiAgICAgICAgcmV0dXJuIFwiPHN0cm9uZz5Pbmx5IGF2YWlsYWJsZTwvc3Ryb25nPiBpbiBkZWJ1ZyBtb2RlLlwiO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0ZpbGVWYXJpYWJsZX0gZnJvbSBcIi4vRmlsZVZhcmlhYmxlXCI7XHJcbmltcG9ydCB7Z2V0RmlsZVlBTUx9IGZyb20gXCIuLi9Db21tb25cIjtcclxuaW1wb3J0IHtJUGFyYW1ldGVyc30gZnJvbSBcIi4vVmFyaWFibGVcIjtcclxuaW1wb3J0IHtJQXV0b2NvbXBsZXRlSXRlbX0gZnJvbSBcIi4uL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvQXV0b2NvbXBsZXRlXCI7XHJcbmltcG9ydCB7VEZpbGV9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlX1lBTUxDb250ZW50IGV4dGVuZHMgRmlsZVZhcmlhYmxlIHtcclxuICAgIHB1YmxpYyB2YXJpYWJsZV9uYW1lID0gXCJ5YW1sX2NvbnRlbnRcIjtcclxuICAgIHB1YmxpYyBoZWxwX3RleHQgPSBcIkdpdmVzIHRoZSBjdXJyZW50IG5vdGUncyBZQU1MIGZyb250bWF0dGVyLiBEYXNoZXMgLS0tIGNhbiBiZSBpbmNsdWRlZCBvciBleGNsdWRlZC5cIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHBhcmFtZXRlcnM6IElQYXJhbWV0ZXJzID0ge1xyXG4gICAgICAgIHdpdGhEYXNoZXM6IHtcclxuICAgICAgICAgICAgb3B0aW9uczogW1wid2l0aC1kYXNoZXNcIiwgXCJuby1kYXNoZXNcIl0sXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH0sXHJcbiAgICB9O1xyXG5cclxuICAgIHByb3RlY3RlZCBnZW5lcmF0ZVZhbHVlKGNhc3RlZEFyZ3VtZW50czoge3dpdGhEYXNoZXM6IFwid2l0aC1kYXNoZXNcIiB8IFwibm8tZGFzaGVzXCJ9KTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgICAgICAgICBsZXQgZmlsZTogVEZpbGU7XHJcbiAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBmaWxlID0gdGhpcy5nZXRGaWxlT3JUaHJvdygpO1xyXG4gICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgLy8gTmVlZCB0byBjYXRjaCBoZXJlLCBiZWNhdXNlIFZhcmlhYmxlLmdldFZhbHVlKCkncyAuY2F0Y2goKSBibG9jayB3b24ndCBiZSBhYmxlIHRvIGNhdGNoIHRocm93biBlcnJvcnMsXHJcbiAgICAgICAgICAgICAgICAvLyBpdCBjYW4gb25seSBjYXRjaCBlcnJvcnMgdGhhdCB3ZXJlIHBhc3NlZCB0byByZWplY3QoKS5cclxuICAgICAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGdldEZpbGVZQU1MKHRoaXMuYXBwLCBmaWxlLCBcIndpdGgtZGFzaGVzXCIgPT09IGNhc3RlZEFyZ3VtZW50cy53aXRoRGFzaGVzKS50aGVuKCh5YW1sQ29udGVudDogc3RyaW5nKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBpZiAobnVsbCA9PT0geWFtbENvbnRlbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBObyBZQU1MIGZyb250bWF0dGVyLlxyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVqZWN0KFwiVGhlIGN1cnJlbnQgZmlsZSBkb2VzIG5vdCBjb250YWluIGEgWUFNTCBmcm9udG1hdHRlci5cIiwgcmVqZWN0KTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gR290IGEgWUFNTCBmcm9udG1hdHRlci5cclxuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHlhbWxDb250ZW50KTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEF2YWlsYWJpbGl0eVRleHQoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gc3VwZXIuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpICsgXCIgQWxzbywgYSBZQU1MIGZyb250bWF0dGVyIHNlY3Rpb24gbmVlZHMgdG8gYmUgcHJlc2VudC5cIjtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QXV0b2NvbXBsZXRlSXRlbXMoKSB7XHJcbiAgICAgICAgcmV0dXJuIFtcclxuICAgICAgICAgICAgLy8gTm9ybWFsIHZhcmlhYmxlc1xyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3tcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOndpdGgtZGFzaGVzfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyB0aGUgY3VycmVudCBub3RlJ3MgWUFNTCBmcm9udG1hdHRlciwgd3JhcHBlZCBiZXR3ZWVuIC0tLSBsaW5lcy4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6bm8tZGFzaGVzfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyB0aGUgY3VycmVudCBub3RlJ3MgWUFNTCBmcm9udG1hdHRlciwgZXhjbHVkaW5nIHRvcCBhbmQgYm90dG9tIC0tLSBsaW5lcy4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJub3JtYWwtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcblxyXG4gICAgICAgICAgICAvLyBVbmVzY2FwZWQgdmFyaWFibGVzXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7eyFcIiArIHRoaXMudmFyaWFibGVfbmFtZSArIFwiOndpdGgtZGFzaGVzfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyB0aGUgY3VycmVudCBub3RlJ3MgWUFNTCBmcm9udG1hdHRlciwgd3JhcHBlZCBiZXR3ZWVuIC0tLSBsaW5lcy5cIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7IVwiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6bm8tZGFzaGVzfX1cIixcclxuICAgICAgICAgICAgICAgIGhlbHBfdGV4dDogXCJHaXZlcyB0aGUgY3VycmVudCBub3RlJ3MgWUFNTCBmcm9udG1hdHRlciwgZXhjbHVkaW5nIHRvcCBhbmQgYm90dG9tIC0tLSBsaW5lcy4gXCIgKyB0aGlzLmdldEF2YWlsYWJpbGl0eVRleHQoKSxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCJ1bmVzY2FwZWQtdmFyaWFibGVcIixcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rOiB0aGlzLmdldERvY3VtZW50YXRpb25MaW5rKCksXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgXTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0SGVscE5hbWUoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gXCI8c3Ryb25nPnt7eWFtbF9jb250ZW50OndpdGgtZGFzaGVzfX08L3N0cm9uZz4gb3IgPHN0cm9uZz57e3lhbWxfY29udGVudDpuby1kYXNoZXN9fTwvc3Ryb25nPlwiO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0V2ZW50VmFyaWFibGV9IGZyb20gXCIuL0V2ZW50VmFyaWFibGVcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlTWVudX0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlTWVudVwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVDcmVhdGVkfSBmcm9tIFwiLi4vLi4vZXZlbnRzL1NDX0V2ZW50X0ZpbGVDcmVhdGVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZURlbGV0ZWR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRfRmlsZURlbGV0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlUmVuYW1lZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlUmVuYW1lZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZpbGVNb3ZlZH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudF9GaWxlTW92ZWRcIjtcclxuaW1wb3J0IHtnZXRGaWxlWUFNTH0gZnJvbSBcIi4uLy4uL0NvbW1vblwiO1xyXG5pbXBvcnQge0lBdXRvY29tcGxldGVJdGVtfSBmcm9tIFwiLi4vLi4vc2V0dGluZ3Mvc2V0dGluZ19lbGVtZW50cy9BdXRvY29tcGxldGVcIjtcclxuaW1wb3J0IHtJUGFyYW1ldGVyc30gZnJvbSBcIi4uL1ZhcmlhYmxlXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVmFyaWFibGVfRXZlbnRZQU1MQ29udGVudCBleHRlbmRzIEV2ZW50VmFyaWFibGUge1xyXG4gICAgcHVibGljIHZhcmlhYmxlX25hbWUgPSBcImV2ZW50X3lhbWxfY29udGVudFwiO1xyXG4gICAgcHVibGljIGhlbHBfdGV4dCA9IFwiR2l2ZXMgdGhlIGV2ZW50IHJlbGF0ZWQgbm90ZSdzIFlBTUwgZnJvbnRtYXR0ZXIuIERhc2hlcyAtLS0gY2FuIGJlIGluY2x1ZGVkIG9yIGV4Y2x1ZGVkLlwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgcGFyYW1ldGVyczogSVBhcmFtZXRlcnMgPSB7XHJcbiAgICAgICAgd2l0aERhc2hlczoge1xyXG4gICAgICAgICAgICBvcHRpb25zOiBbXCJ3aXRoLWRhc2hlc1wiLCBcIm5vLWRhc2hlc1wiXSxcclxuICAgICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXHJcbiAgICAgICAgfSxcclxuICAgIH07XHJcblxyXG4gICAgcHJvdGVjdGVkIHN1cHBvcnRlZF9zY19ldmVudHMgPSBbXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZU1lbnUsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNyZWF0ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlRGVsZXRlZCxcclxuICAgICAgICBTQ19FdmVudF9GaWxlTW92ZWQsXHJcbiAgICAgICAgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICBdO1xyXG5cclxuICAgIHByb3RlY3RlZCBnZW5lcmF0ZVZhbHVlKFxyXG4gICAgICAgIGNhc3RlZEFyZ3VtZW50czoge3dpdGhEYXNoZXM6IFwid2l0aC1kYXNoZXNcIiB8IFwibm8tZGFzaGVzXCJ9LFxyXG4gICAgICAgIHNjX2V2ZW50OiBTQ19FdmVudF9GaWxlTWVudSB8IFNDX0V2ZW50X0ZpbGVDcmVhdGVkIHwgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZCB8IFNDX0V2ZW50X0ZpbGVEZWxldGVkIHwgU0NfRXZlbnRfRmlsZU1vdmVkIHwgU0NfRXZlbnRfRmlsZVJlbmFtZWQsXHJcbiAgICApOiBQcm9taXNlPHN0cmluZz4ge1xyXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnJlcXVpcmVDb3JyZWN0RXZlbnQoc2NfZXZlbnQpO1xyXG4gICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgLy8gTmVlZCB0byBjYXRjaCBoZXJlLCBiZWNhdXNlIFZhcmlhYmxlLmdldFZhbHVlKCkncyAuY2F0Y2goKSBibG9jayB3b24ndCBiZSBhYmxlIHRvIGNhdGNoIHRocm93biBlcnJvcnMsXHJcbiAgICAgICAgICAgICAgICAvLyBpdCBjYW4gb25seSBjYXRjaCBlcnJvcnMgdGhhdCB3ZXJlIHBhc3NlZCB0byByZWplY3QoKS5cclxuICAgICAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGdldEZpbGVZQU1MKHRoaXMuYXBwLCBzY19ldmVudC5nZXRGaWxlKCksIGNhc3RlZEFyZ3VtZW50cy53aXRoRGFzaGVzID09PSBcIndpdGgtZGFzaGVzXCIpLnRoZW4oKHlhbWxDb250ZW50OiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgICAgIGlmIChudWxsID09PSB5YW1sQ29udGVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIE5vIFlBTUwgZnJvbnRtYXR0ZXIuXHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWplY3QoXCJUaGUgZXZlbnQgcmVsYXRlZCBmaWxlIGRvZXMgbm90IGNvbnRhaW4gYSBZQU1MIGZyb250bWF0dGVyLlwiLCByZWplY3QpO1xyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBHb3QgYSBZQU1MIGZyb250bWF0dGVyLlxyXG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoeWFtbENvbnRlbnQpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QXZhaWxhYmlsaXR5VGV4dCgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBzdXBlci5nZXRBdmFpbGFiaWxpdHlUZXh0KCkgKyBcIiBBbHNvLCBhIFlBTUwgZnJvbnRtYXR0ZXIgc2VjdGlvbiBuZWVkcyB0byBiZSBwcmVzZW50LlwiO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRBdXRvY29tcGxldGVJdGVtcygpIHtcclxuICAgICAgICByZXR1cm4gW1xyXG4gICAgICAgICAgICAvLyBOb3JtYWwgdmFyaWFibGVzXHJcbiAgICAgICAgICAgIDxJQXV0b2NvbXBsZXRlSXRlbT57XHJcbiAgICAgICAgICAgICAgICB2YWx1ZTogXCJ7e1wiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6d2l0aC1kYXNoZXN9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSBldmVudCByZWxhdGVkIG5vdGUncyBZQU1MIGZyb250bWF0dGVyLCB3cmFwcGVkIGJldHdlZW4gLS0tIGxpbmVzLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5vcm1hbC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7XCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjpuby1kYXNoZXN9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSBldmVudCByZWxhdGVkIG5vdGUncyBZQU1MIGZyb250bWF0dGVyLCBleGNsdWRpbmcgdG9wIGFuZCBib3R0b20gLS0tIGxpbmVzLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5vcm1hbC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuXHJcbiAgICAgICAgICAgIC8vIFVuZXNjYXBlZCB2YXJpYWJsZXNcclxuICAgICAgICAgICAgPElBdXRvY29tcGxldGVJdGVtPntcclxuICAgICAgICAgICAgICAgIHZhbHVlOiBcInt7IVwiICsgdGhpcy52YXJpYWJsZV9uYW1lICsgXCI6d2l0aC1kYXNoZXN9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSBldmVudCByZWxhdGVkIG5vdGUncyBZQU1MIGZyb250bWF0dGVyLCB3cmFwcGVkIGJldHdlZW4gLS0tIGxpbmVzLlwiICsgdGhpcy5nZXRBdmFpbGFiaWxpdHlUZXh0KCksXHJcbiAgICAgICAgICAgICAgICBncm91cDogXCJWYXJpYWJsZXNcIixcclxuICAgICAgICAgICAgICAgIHR5cGU6IFwidW5lc2NhcGVkLXZhcmlhYmxlXCIsXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGluazogdGhpcy5nZXREb2N1bWVudGF0aW9uTGluaygpLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICA8SUF1dG9jb21wbGV0ZUl0ZW0+e1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IFwie3shXCIgKyB0aGlzLnZhcmlhYmxlX25hbWUgKyBcIjpuby1kYXNoZXN9fVwiLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBcIkdpdmVzIHRoZSBldmVudCByZWxhdGVkIG5vdGUncyBZQU1MIGZyb250bWF0dGVyLCBleGNsdWRpbmcgdG9wIGFuZCBib3R0b20gLS0tIGxpbmVzLiBcIiArIHRoaXMuZ2V0QXZhaWxhYmlsaXR5VGV4dCgpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXA6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgZG9jdW1lbnRhdGlvbkxpbms6IHRoaXMuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRIZWxwTmFtZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBcIjxzdHJvbmc+e3tldmVudF95YW1sX2NvbnRlbnQ6d2l0aC1kYXNoZXN9fTwvc3Ryb25nPiBvciA8c3Ryb25nPnt7ZXZlbnRfeWFtbF9jb250ZW50Om5vLWRhc2hlc319PC9zdHJvbmc+XCI7XHJcbiAgICB9XHJcblxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1ZhcmlhYmxlfSBmcm9tIFwiLi9WYXJpYWJsZVwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX0NsaXBib2FyZH0gZnJvbSBcIi4vVmFyaWFibGVfQ2xpcGJvYXJkXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfQ2FyZXRQb3NpdGlvbn0gZnJvbSBcIi4vVmFyaWFibGVfQ2FyZXRQb3NpdGlvblwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX0RhdGV9IGZyb20gXCIuL1ZhcmlhYmxlX0RhdGVcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9GaWxlRXh0ZW5zaW9ufSBmcm9tIFwiLi9WYXJpYWJsZV9GaWxlRXh0ZW5zaW9uXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfRmlsZU5hbWV9IGZyb20gXCIuL1ZhcmlhYmxlX0ZpbGVOYW1lXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfRmlsZVBhdGh9IGZyb20gXCIuL1ZhcmlhYmxlX0ZpbGVQYXRoXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfRm9sZGVyTmFtZX0gZnJvbSBcIi4vVmFyaWFibGVfRm9sZGVyTmFtZVwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX0ZvbGRlclBhdGh9IGZyb20gXCIuL1ZhcmlhYmxlX0ZvbGRlclBhdGhcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9TZWxlY3Rpb259IGZyb20gXCIuL1ZhcmlhYmxlX1NlbGVjdGlvblwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX1RhZ3N9IGZyb20gXCIuL1ZhcmlhYmxlX1RhZ3NcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9UaXRsZX0gZnJvbSBcIi4vVmFyaWFibGVfVGl0bGVcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9WYXVsdFBhdGh9IGZyb20gXCIuL1ZhcmlhYmxlX1ZhdWx0UGF0aFwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX1dvcmtzcGFjZX0gZnJvbSBcIi4vVmFyaWFibGVfV29ya3NwYWNlXCI7XHJcbmltcG9ydCB7REVCVUdfT059IGZyb20gXCIuLi9EZWJ1Z1wiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX1Bhc3N0aHJvdWdofSBmcm9tIFwiLi9WYXJpYWJsZV9QYXNzdGhyb3VnaFwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi9tYWluXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfWUFNTFZhbHVlfSBmcm9tIFwiLi9WYXJpYWJsZV9ZQU1MVmFsdWVcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9FdmVudEZpbGVOYW1lfSBmcm9tIFwiLi9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnRGaWxlTmFtZVwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX0V2ZW50RmlsZVBhdGh9IGZyb20gXCIuL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudEZpbGVQYXRoXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfRXZlbnRGb2xkZXJOYW1lfSBmcm9tIFwiLi9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnRGb2xkZXJOYW1lXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfRXZlbnRGb2xkZXJQYXRofSBmcm9tIFwiLi9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnRGb2xkZXJQYXRoXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfRXZlbnRUaXRsZX0gZnJvbSBcIi4vZXZlbnRfdmFyaWFibGVzL1ZhcmlhYmxlX0V2ZW50VGl0bGVcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9FdmVudEZpbGVFeHRlbnNpb259IGZyb20gXCIuL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudEZpbGVFeHRlbnNpb25cIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9FdmVudFRhZ3N9IGZyb20gXCIuL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudFRhZ3NcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9FdmVudFlBTUxWYWx1ZX0gZnJvbSBcIi4vZXZlbnRfdmFyaWFibGVzL1ZhcmlhYmxlX0V2ZW50WUFNTFZhbHVlXCI7XHJcbmltcG9ydCB7Q3VzdG9tVmFyaWFibGVJbnN0YW5jZX0gZnJvbSBcIi4uL21vZGVscy9jdXN0b21fdmFyaWFibGUvQ3VzdG9tVmFyaWFibGVJbnN0YW5jZVwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX0Vudmlyb25tZW50fSBmcm9tIFwiLi9WYXJpYWJsZV9FbnZpcm9ubWVudFwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX0V2ZW50T2xkRmlsZU5hbWV9IGZyb20gXCIuL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudE9sZEZpbGVOYW1lXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfRXZlbnRPbGRGaWxlUGF0aH0gZnJvbSBcIi4vZXZlbnRfdmFyaWFibGVzL1ZhcmlhYmxlX0V2ZW50T2xkRmlsZVBhdGhcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9FdmVudE9sZEZvbGRlck5hbWV9IGZyb20gXCIuL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudE9sZEZvbGRlck5hbWVcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9FdmVudE9sZEZvbGRlclBhdGh9IGZyb20gXCIuL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudE9sZEZvbGRlclBhdGhcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9FdmVudE9sZFRpdGxlfSBmcm9tIFwiLi9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnRPbGRUaXRsZVwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX05ld05vdGVGb2xkZXJOYW1lfSBmcm9tIFwiLi9WYXJpYWJsZV9OZXdOb3RlRm9sZGVyTmFtZVwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX05ld05vdGVGb2xkZXJQYXRofSBmcm9tIFwiLi9WYXJpYWJsZV9OZXdOb3RlRm9sZGVyUGF0aFwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX0ZpbGVVUkl9IGZyb20gXCIuL1ZhcmlhYmxlX0ZpbGVVUklcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9FdmVudEZpbGVVUkl9IGZyb20gXCIuL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudEZpbGVVUklcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9Ob3RlQ29udGVudH0gZnJvbSBcIi4vVmFyaWFibGVfTm90ZUNvbnRlbnRcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9FdmVudE5vdGVDb250ZW50fSBmcm9tIFwiLi9ldmVudF92YXJpYWJsZXMvVmFyaWFibGVfRXZlbnROb3RlQ29udGVudFwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX0ZpbGVDb250ZW50fSBmcm9tIFwiLi9WYXJpYWJsZV9GaWxlQ29udGVudFwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX0V2ZW50RmlsZUNvbnRlbnR9IGZyb20gXCIuL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudEZpbGVDb250ZW50XCI7XHJcbmltcG9ydCB7VmFyaWFibGVfQ2FyZXRQYXJhZ3JhcGh9IGZyb20gXCIuL1ZhcmlhYmxlX0NhcmV0UGFyYWdyYXBoXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfTmV3bGluZX0gZnJvbSBcIi4vVmFyaWFibGVfTmV3bGluZVwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX1lBTUxDb250ZW50fSBmcm9tIFwiLi9WYXJpYWJsZV9ZQU1MQ29udGVudFwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlX0V2ZW50WUFNTENvbnRlbnR9IGZyb20gXCIuL2V2ZW50X3ZhcmlhYmxlcy9WYXJpYWJsZV9FdmVudFlBTUxDb250ZW50XCI7XHJcblxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGxvYWRWYXJpYWJsZXMocGx1Z2luOiBTQ19QbHVnaW4pOiBWYXJpYWJsZVNldCB7XHJcblxyXG4gICAgY29uc3QgdmFyaWFibGVzID0gbmV3IFZhcmlhYmxlU2V0KFtdKTtcclxuXHJcbiAgICAvLyBMb2FkIEN1c3RvbVZhcmlhYmxlc1xyXG4gICAgLy8gRG8gdGhpcyBiZWZvcmUgbG9hZGluZyBidWlsdC1pbiB2YXJpYWJsZXMgc28gdGhhdCB0aGVzZSB1c2VyLWRlZmluZWQgdmFyaWFibGVzIHdpbGwgYXBwZWFyIGZpcnN0IGluIGFsbCBsaXN0cyBjb250YWluaW5nIHZhcmlhYmxlcy5cclxuICAgIHBsdWdpbi5nZXRDdXN0b21WYXJpYWJsZUluc3RhbmNlcygpLmZvckVhY2goKGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZTogQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSkgPT4ge1xyXG4gICAgICAgIHZhcmlhYmxlcy5hZGQoY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlLmNyZWF0ZUN1c3RvbVZhcmlhYmxlKCkpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gTG9hZCBidWlsdC1pbiB2YXJpYWJsZXMuXHJcbiAgICBjb25zdCBidWlsdF9pbl92YXJpYWJsZXM6IFZhcmlhYmxlW10gPSBbXHJcbiAgICAgICAgLy8gTm9ybWFsIHZhcmlhYmxlc1xyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9DYXJldFBhcmFncmFwaChwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9DYXJldFBvc2l0aW9uKHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX0NsaXBib2FyZChwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9EYXRlKHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX0Vudmlyb25tZW50KHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX0ZpbGVDb250ZW50KHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX0ZpbGVFeHRlbnNpb24ocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfRmlsZU5hbWUocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfRmlsZVBhdGgocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfRmlsZVVSSShwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9Gb2xkZXJOYW1lKHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX0ZvbGRlclBhdGgocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfTmV3Tm90ZUZvbGRlck5hbWUocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfTmV3Tm90ZUZvbGRlclBhdGgocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfTm90ZUNvbnRlbnQocGx1Z2luKSxcclxuICAgICAgICAvLyBWYXJpYWJsZV9PdXRwdXQgaXMgbm90IGxvYWRlZCBoZXJlLCBiZWNhdXNlIGl0J3Mgb25seSB1c2VkIGluIE91dHB1dFdyYXBwZXJzLlxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9TZWxlY3Rpb24ocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfVGFncyhwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9UaXRsZShwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9WYXVsdFBhdGgocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfV29ya3NwYWNlKHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX1lBTUxDb250ZW50KHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX1lBTUxWYWx1ZShwbHVnaW4pLFxyXG5cclxuICAgICAgICAvLyBFdmVudCB2YXJpYWJsZXNcclxuICAgICAgICBuZXcgVmFyaWFibGVfRXZlbnRGaWxlQ29udGVudChwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9FdmVudEZpbGVFeHRlbnNpb24ocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfRXZlbnRGaWxlTmFtZShwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9FdmVudEZpbGVQYXRoKHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX0V2ZW50RmlsZVVSSShwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9FdmVudEZvbGRlck5hbWUocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfRXZlbnRGb2xkZXJQYXRoKHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX0V2ZW50Tm90ZUNvbnRlbnQocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfRXZlbnRPbGRGaWxlTmFtZShwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9FdmVudE9sZEZpbGVQYXRoKHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX0V2ZW50T2xkRm9sZGVyTmFtZShwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9FdmVudE9sZEZvbGRlclBhdGgocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfRXZlbnRPbGRUaXRsZShwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9FdmVudFRhZ3MocGx1Z2luKSxcclxuICAgICAgICBuZXcgVmFyaWFibGVfRXZlbnRUaXRsZShwbHVnaW4pLFxyXG4gICAgICAgIG5ldyBWYXJpYWJsZV9FdmVudFlBTUxDb250ZW50KHBsdWdpbiksXHJcbiAgICAgICAgbmV3IFZhcmlhYmxlX0V2ZW50WUFNTFZhbHVlKHBsdWdpbiksXHJcbiAgICBdO1xyXG4gICAgaWYgKERFQlVHX09OKSB7XHJcbiAgICAgICAgLy8gVmFyaWFibGVzIHRoYXQgYXJlIG9ubHkgZGVzaWduZWQgZm9yICdTaGVsbCBjb21tYW5kcyB0ZXN0IHN1aXRlJy5cclxuICAgICAgICBidWlsdF9pbl92YXJpYWJsZXMucHVzaChcclxuICAgICAgICAgICAgbmV3IFZhcmlhYmxlX05ld2xpbmUocGx1Z2luKSxcclxuICAgICAgICAgICAgbmV3IFZhcmlhYmxlX1Bhc3N0aHJvdWdoKHBsdWdpbiksXHJcbiAgICAgICAgKTtcclxuICAgIH1cclxuICAgIGZvciAoY29uc3QgYnVpbHRfaW5fdmFyaWFibGUgb2YgYnVpbHRfaW5fdmFyaWFibGVzKSB7XHJcbiAgICAgICAgLy8gSmF2YVNjcmlwdCdzIFNldCBkb2VzIG5vdCBoYXZlIGEgbWV0aG9kIHRvIGFkZCBtdWx0aXBsZSBpdGVtcyBhdCBvbmNlLCBzbyBuZWVkIHRvIGl0ZXJhdGUgdGhlbSBhbmQgYWRkIG9uZS1ieS1vbmUuXHJcbiAgICAgICAgdmFyaWFibGVzLmFkZChidWlsdF9pbl92YXJpYWJsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHZhcmlhYmxlcztcclxufVxyXG5cclxuZXhwb3J0IGNsYXNzIFZhcmlhYmxlU2V0IGV4dGVuZHMgU2V0PFZhcmlhYmxlPiB7fSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi4vbWFpblwiO1xyXG5pbXBvcnQge2RlYnVnTG9nfSBmcm9tIFwiLi4vRGVidWdcIjtcclxuaW1wb3J0IHtTQ19FdmVudH0gZnJvbSBcIi4uL2V2ZW50cy9TQ19FdmVudFwiO1xyXG5pbXBvcnQge2VzY2FwZVZhbHVlfSBmcm9tIFwiLi9lc2NhcGVycy9Fc2NhcGVWYWx1ZVwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlU2V0fSBmcm9tIFwiLi9sb2FkVmFyaWFibGVzXCI7XHJcbmltcG9ydCB7XHJcbiAgICBJUmF3QXJndW1lbnRzLFxyXG4gICAgVmFyaWFibGUsXHJcbiAgICBWYXJpYWJsZVZhbHVlUmVzdWx0LFxyXG59IGZyb20gXCIuL1ZhcmlhYmxlXCI7XHJcbmltcG9ydCB7VFNoZWxsQ29tbWFuZH0gZnJvbSBcIi4uL1RTaGVsbENvbW1hbmRcIjtcclxuaW1wb3J0IHtyZW1vdmVGcm9tU2V0fSBmcm9tIFwiLi4vQ29tbW9uXCI7XHJcblxyXG4vKipcclxuICogQHBhcmFtIHBsdWdpblxyXG4gKiBAcGFyYW0gY29udGVudFxyXG4gKiBAcGFyYW0gc2hlbGwgVXNlZCB0byBkZXRlcm1pbmUgaG93IHRvIGVzY2FwZSBzcGVjaWFsIGNoYXJhY3RlcnMgaW4gdmFyaWFibGUgdmFsdWVzLiBDYW4gYmUgbnVsbCwgaWYgbm8gZXNjYXBpbmcgaXMgd2FudGVkLlxyXG4gKiBAcGFyYW0gdF9zaGVsbF9jb21tYW5kIFdpbGwgb25seSBiZSB1c2VkIHRvIHJlYWQgZGVmYXVsdCB2YWx1ZSBjb25maWd1cmF0aW9ucy4gQ2FuIGJlIG51bGwgaWYgbm8gVFNoZWxsQ29tbWFuZCBpcyBhdmFpbGFibGUsIGJ1dCB0aGVuIG5vIGRlZmF1bHQgdmFsdWVzIGNhbiBiZSBhY2Nlc3NlZC5cclxuICogQHBhcmFtIHNjX2V2ZW50IFVzZSB1bmRlZmluZWQsIGlmIHBhcnNpbmcgaXMgbm90IGhhcHBlbmluZyBkdXJpbmcgYW4gZXZlbnQuXHJcbiAqIEBwYXJhbSB2YXJpYWJsZXMgSWYgeW91IHdhbnQgdG8gcGFyc2Ugb25seSBhIGNlcnRhaW4gc2V0IG9mIHZhcmlhYmxlcywgZGVmaW5lIHRoZW0gaW4gdGhpcyBwYXJhbWV0ZXIuIElmIHRoaXMgaXMgb21pdHRlZCwgYWxsIHZhcmlhYmxlcyB3aWxsIGJlIHBhcnNlZC5cclxuICogQHBhcmFtIHJhd192YWx1ZV9hdWdtZW50ZXIgQSBjYWxsYmFjayB0aGF0IHdpbGwgYmUgY2FsbGVkIGJlZm9yZSBldmVyeSBzdWJzdGl0dXRpb24uIEFsbG93cyBtb2RpZnlpbmcgb3IgY29tcGxldGVseSBjaGFuZ2luZyB0aGUgcmVzdWx0ZWQgdmFyaWFibGUgdmFsdWVzLlxyXG4gKiBAcGFyYW0gZXNjYXBlZF92YWx1ZV9hdWdtZW50ZXIgU2FtZSBhcyByYXdfdmFsdWVfYXVnbWVudGVyLCBidXQgY2FsbGVkIGFmdGVyIGVzY2FwaW5nIHRoZSB2YWx1ZS4gQ2FuIGJlIHVzZWQgdG8gZm9yIGV4YW1wbGUgd3JhcCB2YWx1ZXMgaW4gaHRtbCBlbGVtZW50cyBmb3IgZGlzcGxheWluZyBwdXJwb3Nlcy5cclxuICogQHJldHVybiBQYXJzaW5nUmVzdWx0XHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcGFyc2VWYXJpYWJsZXMoXHJcbiAgICAgICAgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgY29udGVudDogc3RyaW5nLFxyXG4gICAgICAgIHNoZWxsOiBzdHJpbmcgfCBudWxsLFxyXG4gICAgICAgIHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCB8IG51bGwsXHJcbiAgICAgICAgc2NfZXZlbnQ/OiBTQ19FdmVudCB8IG51bGwsXHJcbiAgICAgICAgdmFyaWFibGVzOiBWYXJpYWJsZVNldCA9IHBsdWdpbi5nZXRWYXJpYWJsZXMoKSxcclxuICAgICAgICByYXdfdmFsdWVfYXVnbWVudGVyOiAoKHZhcmlhYmxlOiBWYXJpYWJsZSwgcmF3X3ZhbHVlOiBWYXJpYWJsZVZhbHVlUmVzdWx0KSA9PiB2b2lkKSB8IG51bGwgPSBudWxsLFxyXG4gICAgICAgIGVzY2FwZWRfdmFsdWVfYXVnbWVudGVyOiAoKHZhcmlhYmxlOiBWYXJpYWJsZSwgZXNjYXBlZF92YWx1ZTogc3RyaW5nKSA9PiBzdHJpbmcpIHwgbnVsbCA9IG51bGwsXHJcbiAgICApOiBQcm9taXNlPFBhcnNpbmdSZXN1bHQ+IHtcclxuXHJcbiAgICBkZWJ1Z0xvZyhcInBhcnNlVmFyaWFibGVzKCk6IFN0YXJ0aW5nIHRvIHBhcnNlIFwiICsgY29udGVudCArIFwiIHdpdGggXCIgKyB2YXJpYWJsZXMuc2l6ZSArIFwiIHZhcmlhYmxlcy5cIik7XHJcblxyXG4gICAgLy8gSW5pdGlhbGl6ZSBhIHBhcnNpbmcgcmVzdWx0IG9iamVjdFxyXG4gICAgY29uc3QgcGFyc2luZ19yZXN1bHQ6IFBhcnNpbmdSZXN1bHQgPSB7XHJcbiAgICAgICAgb3JpZ2luYWxfY29udGVudDogY29udGVudCxcclxuICAgICAgICBwYXJzZWRfY29udGVudDogY29udGVudCwgLy8gQ3JlYXRlIGEgY29weSBvZiB0aGUgdmFyaWFibGUgYmVjYXVzZSB3ZSBkb24ndCB3YW50IHRvIGFsdGVyIHRoZSBvcmlnaW5hbCB2YWx1ZSBvZiAnY29udGVudCcgZHVyaW5nIGl0ZXJhdGluZyBpdHMgcmVnZXggbWF0Y2hlcy4gT3JpZ2luYWxseSB0aGlzIGNvcHkgd2FzIGp1c3QgYW5vdGhlciBsb2NhbCB2YXJpYWJsZSwgYnV0IG5vdyBpdCdzIGNoYW5nZWQgdG8gYmUgYSBwcm9wZXJ0eSBpbiBhbiBvYmplY3QuXHJcbiAgICAgICAgc3VjY2VlZGVkOiBmYWxzZSxcclxuICAgICAgICBlcnJvcl9tZXNzYWdlczogW10sXHJcbiAgICAgICAgY291bnRfcGFyc2VkX3ZhcmlhYmxlczogMCxcclxuICAgIH07XHJcblxyXG4gICAgZm9yIChjb25zdCB2YXJpYWJsZSBvZiB2YXJpYWJsZXMpXHJcbiAgICB7XHJcbiAgICAgICAgY29uc3QgcGF0dGVybiA9IG5ldyBSZWdFeHAodmFyaWFibGUuZ2V0UGF0dGVybigpLCBcImlndVwiKTsgLy8gaTogY2FzZS1pbnNlbnNpdGl2ZTsgZzogbWF0Y2ggYWxsIG9jY3VycmVuY2VzIGluc3RlYWQgb2YganVzdCB0aGUgZmlyc3Qgb25lLiB1OiBzdXBwb3J0IDQtYnl0ZSB1bmljb2RlIGNoYXJhY3RlcnMgdG9vLlxyXG4gICAgICAgIGNvbnN0IHBhcmFtZXRlcl9uYW1lcyA9IHZhcmlhYmxlLmdldFBhcmFtZXRlck5hbWVzKCk7XHJcbiAgICAgICAgbGV0IGFyZ3VtZW50X21hdGNoZXM6IFJlZ0V4cEV4ZWNBcnJheSB8IG51bGw7XHJcbiAgICAgICAgd2hpbGUgKChhcmd1bWVudF9tYXRjaGVzID0gcGF0dGVybi5leGVjKGNvbnRlbnQpKSAhPT0gbnVsbCkge1xyXG4gICAgICAgICAgICAvLyBDb3VudCBob3cgbWFueSB0aW1lcyBhbnkgdmFyaWFibGVzIGhhdmUgYXBwZWFyZWQuXHJcbiAgICAgICAgICAgIHBhcnNpbmdfcmVzdWx0LmNvdW50X3BhcnNlZF92YXJpYWJsZXMrKztcclxuXHJcbiAgICAgICAgICAgIC8vIFJlbW92ZSBzdHVmZiB0aGF0IHNob3VsZCBub3QgYmUgaXRlcmF0ZWQgaW4gYSBsYXRlciBsb29wLlxyXG4gICAgICAgICAgICAvKiogTmVlZCB0byBwcmVmaXggd2l0aCBfIGJlY2F1c2UgSmF2YVNjcmlwdCByZXNlcnZlcyB0aGUgdmFyaWFibGUgbmFtZSAnYXJndW1lbnRzJy4gKi9cclxuICAgICAgICAgICAgY29uc3QgX2FyZ3VtZW50cyA9IGFyZ3VtZW50X21hdGNoZXMuZmlsdGVyKCh2YWx1ZTogdW5rbm93biAvKiBXb24ndCBiZSB1c2VkICovLCBrZXk6IHVua25vd24pID0+IHtcclxuICAgICAgICAgICAgICAgIHJldHVybiBcIm51bWJlclwiID09PSB0eXBlb2Yga2V5O1xyXG4gICAgICAgICAgICAgICAgLy8gVGhpcyBsZWF2ZXMgb3V0IGZvciBleGFtcGxlIHRoZSBmb2xsb3dpbmcgbm9uLW51bWVyaWMga2V5cyAoYW5kIHRoZWlyIHZhbHVlcyk6XHJcbiAgICAgICAgICAgICAgICAvLyAtIFwiZ3JvdXBzXCJcclxuICAgICAgICAgICAgICAgIC8vIC0gXCJpbmRleFwiXHJcbiAgICAgICAgICAgICAgICAvLyAtIFwiaW5wdXRcIlxyXG4gICAgICAgICAgICAgICAgLy8gSW4gdGhlIGZ1dHVyZSwgdGhlcmUgY2FuIGFsc28gY29tZSBtb3JlIGVsZW1lbnRzIHRoYXQgd2lsbCBiZSBza2lwcGVkLiBFLmcuIFwiaW5kaWNlc1wiLiBTZWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9ub3RoaW5naXNsb3N0L29ic2lkaWFuLWR5bmFtaWMtaGlnaGxpZ2h0cy9pc3N1ZXMvMjUjaXNzdWVjb21tZW50LTEwMzg1NjM5OTAgKHJlZmVyZW5jZWQgMjAyMi0wMi0yMikuXHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgLy8gR2V0IHRoZSB7e3ZhcmlhYmxlfX0gc3RyaW5nIHRoYXQgd2lsbCBiZSBzdWJzdGl0dXRlZCAoPSByZXBsYWNlZCB3aXRoIHRoZSBhY3R1YWwgdmFsdWUgb2YgdGhlIHZhcmlhYmxlKS5cclxuICAgICAgICAgICAgY29uc3Qgc3Vic3RpdHV0ZTogc3RyaW5nID0gX2FyZ3VtZW50cy5zaGlmdCgpIGFzIHN0cmluZzsgLy8gJ19hcmd1bWVudHNbMF0nIGNvbnRhaW5zIHRoZSB3aG9sZSBtYXRjaCwgbm90IGp1c3QgYW4gYXJndW1lbnQuIEdldCBpdCBhbmQgcmVtb3ZlIGl0IGZyb20gJ19hcmd1bWVudHMnLiAnYXMgc3RyaW5nJyBpcyB1c2VkIHRvIHRlbGwgVHlwZVNjcmlwdCB0aGF0IF9hcmd1bWVudHNbMF0gaXMgYWx3YXlzIGRlZmluZWQuXHJcblxyXG4gICAgICAgICAgICAvLyBJdGVyYXRlIGFsbCBhcmd1bWVudHNcclxuICAgICAgICAgICAgY29uc3QgcHJlc2VudEFyZ3VtZW50czogSVJhd0FyZ3VtZW50cyA9IHt9O1xyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGkgaW4gX2FyZ3VtZW50cykge1xyXG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgdGhhdCB0aGUgYXJndW1lbnQgaXMgbm90IG9taXR0ZWQuIEl0IGNhbiBiZSBvbWl0dGVkICg9IHVuZGVmaW5lZCksIGlmIHRoZSBwYXJhbWV0ZXIgaXMgb3B0aW9uYWwuXHJcbiAgICAgICAgICAgICAgICBpZiAodW5kZWZpbmVkICE9PSBfYXJndW1lbnRzW2ldKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGFyZ3VtZW50IGlzIHByZXNlbnQuXHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgYXJndW1lbnQgPSBfYXJndW1lbnRzW2ldLnNsaWNlKDEpOyAvLyAuc2xpY2UoMSk6IFJlbW92ZSBhIHByZWNlZGluZyA6XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcGFyYW1ldGVyX25hbWUgPSBwYXJhbWV0ZXJfbmFtZXNbaV07XHJcbiAgICAgICAgICAgICAgICAgICAgcHJlc2VudEFyZ3VtZW50c1twYXJhbWV0ZXJfbmFtZV0gPSBhcmd1bWVudDtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gU2hvdWxkIHRoZSB2YXJpYWJsZSdzIHZhbHVlIGJlIGVzY2FwZWQ/IChVc3VhbGx5IHllcykuXHJcbiAgICAgICAgICAgIGxldCBlc2NhcGUgPSB0cnVlO1xyXG4gICAgICAgICAgICBpZiAoXCJ7eyFcIiA9PT0gc3Vic3RpdHV0ZS5zbGljZSgwLCAzKSkgeyAvLyAuc2xpY2UoMCwgMykgPSBnZXQgY2hhcmFjdGVycyAwLi4uMiwgc28gc3RvcCBiZWZvcmUgMy4gVGhlICdlbmQnIHBhcmFtZXRlciBpcyBjb25mdXNpbmcuXHJcbiAgICAgICAgICAgICAgICAvLyBUaGUgdmFyaWFibGUgdXNhZ2UgYmVnaW5zIHdpdGgge3shIGluc3RlYWQgb2Yge3tcclxuICAgICAgICAgICAgICAgIC8vIFRoaXMgbWVhbnMgdGhlIHZhcmlhYmxlJ3MgdmFsdWUgc2hvdWxkIE5PVCBiZSBlc2NhcGVkLlxyXG4gICAgICAgICAgICAgICAgZXNjYXBlID0gZmFsc2U7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgaWYgKCFzaGVsbCkge1xyXG4gICAgICAgICAgICAgICAgLy8gRXNjYXBpbmcgaXMgZm9yY2VkIE9GRi5cclxuICAgICAgICAgICAgICAgIGVzY2FwZSA9IGZhbHNlO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBSZW5kZXIgdGhlIHZhcmlhYmxlXHJcbiAgICAgICAgICAgIGNvbnN0IHZhcmlhYmxlX3ZhbHVlX3Jlc3VsdCA9IGF3YWl0IHZhcmlhYmxlLmdldFZhbHVlKFxyXG4gICAgICAgICAgICAgICAgdF9zaGVsbF9jb21tYW5kLFxyXG4gICAgICAgICAgICAgICAgc2NfZXZlbnQsXHJcbiAgICAgICAgICAgICAgICBwcmVzZW50QXJndW1lbnRzLFxyXG5cclxuICAgICAgICAgICAgICAgIC8vIERlZmluZSBhIHJlY3Vyc2l2ZSBjYWxsYmFjayB0aGF0IGNhbiBiZSB1c2VkIHRvIHBhcnNlIHBvc3NpYmxlIHZhcmlhYmxlcyBpbiBhIGRlZmF1bHQgdmFsdWUgb2YgdGhlIGN1cnJlbnQgdmFyaWFibGUuXHJcbiAgICAgICAgICAgICAgICAocmF3X2RlZmF1bHRfdmFsdWUpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBBdm9pZCBjaXJjdWxhciByZWZlcmVuY2VzIGJ5IHJlbW92aW5nIHRoZSBjdXJyZW50IHZhcmlhYmxlIGZyb20gdGhlIHNldCBvZiBwYXJzZWFibGUgdmFyaWFibGVzLlxyXG4gICAgICAgICAgICAgICAgICAgIC8vIFRoaXMgd2lsbCBjdW11bGF0ZSBpbiBkZWVwIG5lc3RlZCBwYXJzaW5nOiBQb3NzaWJsZSBkZWVwZXIgcGFyc2luZyByb3VuZHMgd2lsbCBhbHdheXMgaGF2ZSBuYXJyb3dlclxyXG4gICAgICAgICAgICAgICAgICAgIC8vIGFuZCBuYXJyb3dlciBzZXRzIG9mIHZhcmlhYmxlcyB0byBwYXJzZS5cclxuICAgICAgICAgICAgICAgICAgICBjb25zdCByZWR1Y2VkX3ZhcmlhYmxlcyA9IHJlbW92ZUZyb21TZXQodmFyaWFibGVzLCB2YXJpYWJsZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHBhcnNlVmFyaWFibGVzKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBwbHVnaW4sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJhd19kZWZhdWx0X3ZhbHVlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBudWxsLCAvLyBEaXNhYmxlIGVzY2FwaW5nIHNwZWNpYWwgY2hhcmFjdGVycyBhdCB0aGlzIHBoYXNlIHRvIGF2b2lkIGRvdWJsZSBlc2NhcGluZywgYXMgZXNjYXBpbmcgd2lsbCBiZSBkb25lIGxhdGVyLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0X3NoZWxsX2NvbW1hbmQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjX2V2ZW50LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICByZWR1Y2VkX3ZhcmlhYmxlcyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgcmF3X3ZhbHVlX2F1Z21lbnRlcixcclxuICAgICAgICAgICAgICAgICAgICAgICAgZXNjYXBlZF92YWx1ZV9hdWdtZW50ZXIsXHJcbiAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgICAvLyBBbGxvdyBjdXN0b20gbW9kaWZpY2F0aW9uIG9mIHRoZSByYXcgdmFsdWUuXHJcbiAgICAgICAgICAgIGlmIChyYXdfdmFsdWVfYXVnbWVudGVyKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGUgYXVnbWVudGVyIGNhbiBtb2RpZnkgdGhlIGNvbnRlbnQgb2YgdGhlIHZhcmlhYmxlX3ZhbHVlX3Jlc3VsdCBvYmplY3QuXHJcbiAgICAgICAgICAgICAgICByYXdfdmFsdWVfYXVnbWVudGVyKHZhcmlhYmxlLCB2YXJpYWJsZV92YWx1ZV9yZXN1bHQpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGNvbnN0IHJhd192YXJpYWJsZV92YWx1ZSA9IHZhcmlhYmxlX3ZhbHVlX3Jlc3VsdC52YWx1ZTtcclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIHBvc3NpYmxlIGVycm9yIG1lc3NhZ2VzIHRoYXQgbWlnaHQgaGF2ZSBjb21lIGZyb20gcmVuZGVyaW5nLlxyXG4gICAgICAgICAgICBpZiAodmFyaWFibGVfdmFsdWVfcmVzdWx0LnN1Y2NlZWRlZCkge1xyXG4gICAgICAgICAgICAgICAgLy8gUGFyc2luZyB3YXMgb2suXHJcblxyXG4gICAgICAgICAgICAgICAgLy8gRXNjYXBlIHRoZSB2YWx1ZSBpZiBuZWVkZWQuXHJcbiAgICAgICAgICAgICAgICBsZXQgdXNlX3ZhcmlhYmxlX3ZhbHVlOiBzdHJpbmc7XHJcbiAgICAgICAgICAgICAgICBpZiAoZXNjYXBlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVXNlIGFuIGVzY2FwZWQgdmFsdWUuXHJcbiAgICAgICAgICAgICAgICAgICAgdXNlX3ZhcmlhYmxlX3ZhbHVlID0gZXNjYXBlVmFsdWUoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNoZWxsIGFzIHN0cmluZywgLy8gc2hlbGwgaXMgYWx3YXlzIGEgc3RyaW5nIHdoZW4gZXNjYXBlIGlzIHRydWUuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJhd192YXJpYWJsZV92YWx1ZSBhcyBzdHJpbmcsIC8vIHJhd192YXJpYWJsZV92YWx1ZSBpcyBhbHdheXMgYSBzdHJpbmcgd2hlbiB2YXJpYWJsZV92YWx1ZV9yZXN1bHQuc3VjY2VlZGVkIGlzIHRydWUuXHJcbiAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gTm8gZXNjYXBpbmcgaXMgd2FudGVkLCBzbyB1c2UgdGhlIHJhdyB2YWx1ZS5cclxuICAgICAgICAgICAgICAgICAgICB1c2VfdmFyaWFibGVfdmFsdWUgPSByYXdfdmFyaWFibGVfdmFsdWUgYXMgc3RyaW5nOyAvLyByYXdfdmFyaWFibGVfdmFsdWUgaXMgYWx3YXlzIGEgc3RyaW5nIHdoZW4gdmFyaWFibGVfdmFsdWVfcmVzdWx0LnN1Y2NlZWRlZCBpcyB0cnVlLlxyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIC8vIEF1Z21lbnQgdGhlIGVzY2FwZWQgdmFsdWUsIGlmIHdhbnRlZC5cclxuICAgICAgICAgICAgICAgIGlmIChlc2NhcGVkX3ZhbHVlX2F1Z21lbnRlcikge1xyXG4gICAgICAgICAgICAgICAgICAgIHVzZV92YXJpYWJsZV92YWx1ZSA9IGVzY2FwZWRfdmFsdWVfYXVnbWVudGVyKHZhcmlhYmxlLCB1c2VfdmFyaWFibGVfdmFsdWUpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIC8vIFJlcGxhY2UgdGhlIHZhcmlhYmxlIG5hbWUgd2l0aCB0aGUgdmFyaWFibGUgdmFsdWUuXHJcbiAgICAgICAgICAgICAgICBwYXJzaW5nX3Jlc3VsdC5wYXJzZWRfY29udGVudCA9IChwYXJzaW5nX3Jlc3VsdC5wYXJzZWRfY29udGVudCBhcyBzdHJpbmcgLyogbm90IG51bGwgKi8pLnJlcGxhY2Uoc3Vic3RpdHV0ZSwgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIERvIHRoZSByZXBsYWNpbmcgaW4gYSBmdW5jdGlvbiBpbiBvcmRlciB0byBhdm9pZCBhIHBvc3NpYmxlICQgY2hhcmFjdGVyIHRvIGJlIGludGVycHJldGVkIGJ5IEphdmFTY3JpcHQgdG8gaW50ZXJhY3Qgd2l0aCB0aGUgcmVnZXguXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gTW9yZSBpbmZvcm1hdGlvbjogaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvU3RyaW5nL3JlcGxhY2Ujc3BlY2lmeWluZ19hX3N0cmluZ19hc19hX3BhcmFtZXRlciAocmVmZXJlbmNlZCAyMDIxLTExLTAyLilcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdXNlX3ZhcmlhYmxlX3ZhbHVlO1xyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGVyZSBoYXMgYmVlbiBwcm9ibGVtKHMpIHdpdGggdGhpcyB2YXJpYWJsZS5cclxuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwicGFyc2VWYXJpYWJsZXMoKTogUGFyc2luZyBjb250ZW50IFwiICsgY29udGVudCArIFwiIGZhaWxlZC5cIik7XHJcbiAgICAgICAgICAgICAgICBwYXJzaW5nX3Jlc3VsdC5zdWNjZWVkZWQgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgIHBhcnNpbmdfcmVzdWx0LnBhcnNlZF9jb250ZW50ID0gbnVsbDtcclxuICAgICAgICAgICAgICAgIHBhcnNpbmdfcmVzdWx0LmVycm9yX21lc3NhZ2VzID0gdmFyaWFibGVfdmFsdWVfcmVzdWx0LmVycm9yX21lc3NhZ2VzOyAvLyBSZXR1cm5pbmcgbm93IHByZXZlbnRzIHBhcnNpbmcgcmVzdCBvZiB0aGUgdmFyaWFibGVzLlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHBhcnNpbmdfcmVzdWx0O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgZGVidWdMb2coXCJwYXJzZVZhcmlhYmxlcygpOiBQYXJzaW5nIGNvbnRlbnQgXCIgKyBjb250ZW50ICsgXCIgc3VjY2VlZGVkLlwiKTtcclxuICAgIHBhcnNpbmdfcmVzdWx0LnN1Y2NlZWRlZCA9IHRydWU7XHJcbiAgICByZXR1cm4gcGFyc2luZ19yZXN1bHQ7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWFkcyBhbGwgdmFyaWFibGVzIGZyb20gdGhlIGNvbnRlbnQgc3RyaW5nLCBhbmQgcmV0dXJucyBhIFZhcmlhYmxlU2V0IGNvbnRhaW5pbmcgYWxsIHRoZSBmb3VuZCB2YXJpYWJsZXMuXHJcbiAqXHJcbiAqIFRoaXMgaXMgbmVlZGVkIGluIHNpdHVhdGlvbnMgd2hlcmUgdmFyaWFibGVzIHdpbGwgbm90IGJlIHBhcnNlZCAoPSB2YXJpYWJsZSB2YWx1ZXMgYXJlIG5vdCBuZWVkZWQpLCBidXQgd2hlcmUgaXQncyBqdXN0XHJcbiAqIG5lZWRlZCB0byBrbm93IHdoYXQgdmFyaWFibGVzIGUuZy4gYSBzaGVsbCBjb21tYW5kIHJlbGllcyBvbi5cclxuICpcclxuICogQHBhcmFtIHBsdWdpblxyXG4gKiBAcGFyYW0gY29udGVudFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFVzZWRWYXJpYWJsZXMoXHJcbiAgICAgICAgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgY29udGVudDogc3RyaW5nLFxyXG4gICAgKTogVmFyaWFibGVTZXQge1xyXG4gICAgY29uc3Qgc2VhcmNoX2Zvcl92YXJpYWJsZXM6IFZhcmlhYmxlU2V0ID0gcGx1Z2luLmdldFZhcmlhYmxlcygpO1xyXG4gICAgY29uc3QgZm91bmRfdmFyaWFibGVzID0gbmV3IFZhcmlhYmxlU2V0KCk7XHJcbiAgICBcclxuICAgIGZvciAoY29uc3QgdmFyaWFibGUgb2Ygc2VhcmNoX2Zvcl92YXJpYWJsZXMpXHJcbiAgICB7XHJcbiAgICAgICAgY29uc3QgcGF0dGVybiA9IG5ldyBSZWdFeHAodmFyaWFibGUuZ2V0UGF0dGVybigpLCBcImlndVwiKTsgLy8gaTogY2FzZS1pbnNlbnNpdGl2ZTsgZzogbWF0Y2ggYWxsIG9jY3VycmVuY2VzIGluc3RlYWQgb2YganVzdCB0aGUgZmlyc3Qgb25lLiB1OiBzdXBwb3J0IDQtYnl0ZSB1bmljb2RlIGNoYXJhY3RlcnMgdG9vLlxyXG4gICAgICAgIGlmIChwYXR0ZXJuLmV4ZWMoY29udGVudCkgIT09IG51bGwpIHtcclxuICAgICAgICAgICAgLy8gVGhpcyB2YXJpYWJsZSB3YXMgZm91bmQuXHJcbiAgICAgICAgICAgIGZvdW5kX3ZhcmlhYmxlcy5hZGQodmFyaWFibGUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gZm91bmRfdmFyaWFibGVzO1xyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFBhcnNpbmdSZXN1bHQge1xyXG4gICAgb3JpZ2luYWxfY29udGVudDogc3RyaW5nO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGhpcyBpcyBudWxsIGlmIHN1Y2NlZWRlZCBpcyBmYWxzZS5cclxuICAgICAqICovXHJcbiAgICBwYXJzZWRfY29udGVudDogc3RyaW5nIHwgbnVsbDtcclxuXHJcbiAgICBzdWNjZWVkZWQ6IGJvb2xlYW47XHJcbiAgICBlcnJvcl9tZXNzYWdlczogc3RyaW5nW107XHJcbiAgICBjb3VudF9wYXJzZWRfdmFyaWFibGVzOiBudW1iZXI7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uL21haW5cIjtcclxuaW1wb3J0IHtBcHB9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQge091dHB1dFN0cmVhbXN9IGZyb20gXCIuL091dHB1dENoYW5uZWxGdW5jdGlvbnNcIjtcclxuaW1wb3J0IHtcclxuICAgIE91dHB1dEhhbmRsaW5nTW9kZSxcclxuICAgIE91dHB1dFN0cmVhbSxcclxufSBmcm9tIFwiLi9PdXRwdXRDaGFubmVsQ29kZVwiO1xyXG5pbXBvcnQge2RlYnVnTG9nfSBmcm9tIFwiLi4vRGVidWdcIjtcclxuaW1wb3J0IHtTaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0LCBUU2hlbGxDb21tYW5kfSBmcm9tIFwiLi4vVFNoZWxsQ29tbWFuZFwiO1xyXG5pbXBvcnQge2pvaW5PYmplY3RQcm9wZXJ0aWVzfSBmcm9tIFwiLi4vQ29tbW9uXCI7XHJcbmltcG9ydCB7VmFyaWFibGVfT3V0cHV0fSBmcm9tIFwiLi4vdmFyaWFibGVzL1ZhcmlhYmxlX091dHB1dFwiO1xyXG5pbXBvcnQge3BhcnNlVmFyaWFibGVzfSBmcm9tIFwiLi4vdmFyaWFibGVzL3BhcnNlVmFyaWFibGVzXCI7XHJcbmltcG9ydCB7VmFyaWFibGVTZXR9IGZyb20gXCIuLi92YXJpYWJsZXMvbG9hZFZhcmlhYmxlc1wiO1xyXG5cclxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIE91dHB1dENoYW5uZWwge1xyXG5cclxuICAgIC8vIENsYXNzIHNwZWNpZmljIHByb3BlcnRpZXNcclxuICAgIC8qKlxyXG4gICAgICogSHVtYW4gcmVhZGFibGUgbmFtZSwgdXNlZCBpbiBzZXR0aW5ncy5cclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSB0aXRsZTogc3RyaW5nO1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBhY2NlcHRlZF9vdXRwdXRfc3RyZWFtczogT3V0cHV0U3RyZWFtW10gPSBbXCJzdGRvdXRcIiwgXCJzdGRlcnJcIl07XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGFjY2VwdHNfZW1wdHlfb3V0cHV0OiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEZXRlcm1pbmVzIGlmIHRoZSBvdXRwdXQgY2hhbm5lbCB3YW50cyB0byBoYW5kbGUgYSB1bmlmaWVkIG91dHB1dCBvciBub3QuIElmIHllcywgdGhpcyBwcm9wZXJ0eSBzaG91bGQgZGVmaW5lIGFcclxuICAgICAqIGRlbGltaXRlciBzdHJpbmcgdGhhdCB3aWxsIGJlIHVzZWQgYXMgYSBnbHVlIGJldHdlZW4gZGlmZmVyZW50IG91dHB1dCBzdHJlYW1zLlxyXG4gICAgICpcclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBjb21iaW5lX291dHB1dF9zdHJlYW1zOiBmYWxzZSB8IHN0cmluZyA9IGZhbHNlO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogVXNlZCBpbiBPdXRwdXRNb2RhbCB0byByZWRpcmVjdCBvdXRwdXQgYmFzZWQgb24gaG90a2V5cy4gSWYgdGhpcyBpcyB1bmRlZmluZWQsIHRoZW4gdGhlIG91dHB1dCBjaGFubmVsIGlzIGNvbXBsZXRlbHlcclxuICAgICAqIGV4Y2x1ZGVkIGZyb20gT3V0cHV0TW9kYWwuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgaG90a2V5X2xldHRlcjogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ2FuIGJlIG92ZXJyaWRkZW4gaW4gY2hpbGQgY2xhc3NlcyBpbiBvcmRlciB0byB2YXJ5IHRoZSB0aXRsZSBkZXBlbmRpbmcgb24gb3V0cHV0X3N0cmVhbS5cclxuICAgICAqIEBwYXJhbSBvdXRwdXRfc3RyZWFtXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzdGF0aWMgZ2V0VGl0bGUob3V0cHV0X3N0cmVhbTogT3V0cHV0U3RyZWFtKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMudGl0bGU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSW5zdGFuY2Ugc3BlY2lmaWMgcHJvcGVydGllc1xyXG4gICAgcHJvdGVjdGVkIGFwcDogQXBwO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHBsdWdpblxyXG4gICAgICogQHBhcmFtIHRfc2hlbGxfY29tbWFuZFxyXG4gICAgICogQHBhcmFtIHNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHRcclxuICAgICAqIEBwYXJhbSBvdXRwdXRIYW5kbGluZ01vZGVcclxuICAgICAqIEBwYXJhbSBwcm9jZXNzVGVybWluYXRvciBXaWxsIGJlIGNhbGxlZCBpZiB1c2VyIGRlY2lkZXMgdG8gZW5kIHRoZSBwcm9jZXNzLiBTZXQgdG8gbnVsbCBpZiB0aGUgcHJvY2VzcyBoYXMgYWxyZWFkeSBlbmRlZC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIHByb3RlY3RlZCBwbHVnaW46IFNDX1BsdWdpbixcclxuICAgICAgICBwcm90ZWN0ZWQgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kLFxyXG4gICAgICAgIHByb3RlY3RlZCBzaGVsbF9jb21tYW5kX3BhcnNpbmdfcmVzdWx0OiBTaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0LFxyXG4gICAgICAgIHByb3RlY3RlZCBvdXRwdXRIYW5kbGluZ01vZGU6IE91dHB1dEhhbmRsaW5nTW9kZSxcclxuICAgICAgICBwcm90ZWN0ZWQgcHJvY2Vzc1Rlcm1pbmF0b3I6ICgoKSA9PiB2b2lkKSB8IG51bGwsXHJcbiAgICApIHtcclxuICAgICAgICB0aGlzLmFwcCA9IHBsdWdpbi5hcHA7XHJcbiAgICAgICAgdGhpcy5pbml0aWFsaXplKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTdWIgY2xhc3NlcyBjYW4gZG8gaGVyZSBpbml0aWFsaXphdGlvbnMgdGhhdCBhcmUgY29tbW9uIHRvIGJvdGggaGFuZGxlQnVmZmVyZWQoKSBhbmQgaGFuZGxlUmVhbHRpbWUoKS5cclxuICAgICAqXHJcbiAgICAgKiBJbml0cyBjb3VsZCBiZSBkb25lIGluIGNvbnRydWN0b3IoKSwgdG9vLCBidXQgdGhpcyBpcyBjbGVhbmVyIC0gbm8gbmVlZCB0byBkZWFsIHdpdGggcGFyYW1ldGVycyBhbmQgbm8gbmVlZCBmb3IgYSBzdXBlcigpXHJcbiAgICAgKiBjYWxsLlxyXG4gICAgICpcclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGluaXRpYWxpemUoKSB7XHJcbiAgICAgICAgLy8gRG8gbm90aGluZyBieSBkZWZhdWx0LlxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIG91dHB1dCBTdWJjbGFzc2VzIHNob3VsZCBkZWZpbmUgdGhpcyBhcyBzdHJpbmcsIGlmIHRoZXkgZW5hYmxlICdjb21iaW5lX291dHB1dF9zdHJlYW1zJy4gT3RoZXJ3aXNlLCB0aGV5IHNob3VsZCBkZWZpbmUgdGhpcyBhcyBPdXRwdXRTdHJlYW1zLlxyXG4gICAgICogQHBhcmFtIGVycm9yX2NvZGVcclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IF9oYW5kbGVCdWZmZXJlZChvdXRwdXQ6IE91dHB1dFN0cmVhbXMgfCBzdHJpbmcsIGVycm9yX2NvZGU6IG51bWJlciB8IG51bGwpOiBQcm9taXNlPHZvaWQ+O1xyXG5cclxuICAgIHB1YmxpYyBhc3luYyBoYW5kbGVCdWZmZXJlZChvdXRwdXQ6IE91dHB1dFN0cmVhbXMsIGVycm9yX2NvZGU6IG51bWJlciB8IG51bGwsIGVuYWJsZU91dHB1dFdyYXBwaW5nID0gdHJ1ZSk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICAgIHRoaXMucmVxdWlyZUhhbmRsaW5nTW9kZShcImJ1ZmZlcmVkXCIpO1xyXG5cclxuICAgICAgICAvLyBRdWFsaWZ5IG91dHB1dFxyXG4gICAgICAgIGlmIChPdXRwdXRDaGFubmVsLmlzT3V0cHV0RW1wdHkob3V0cHV0KSkge1xyXG4gICAgICAgICAgICAvLyBUaGUgb3V0cHV0IGlzIGVtcHR5XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5zdGF0aWMoKS5hY2NlcHRzX2VtcHR5X291dHB1dCkge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhpcyBPdXRwdXRDaGFubmVsIGRvZXMgbm90IGFjY2VwdCBlbXB0eSBvdXRwdXQsIGkuZS4gZW1wdHkgb3V0cHV0IHNob3VsZCBiZSBqdXN0IGlnbm9yZWQuXHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyh0aGlzLmNvbnN0cnVjdG9yLm5hbWUgKyBcIi5oYW5kbGVCdWZmZXJlZCgpOiBJZ25vcmluZyBlbXB0eSBvdXRwdXQuXCIpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlYnVnTG9nKHRoaXMuY29uc3RydWN0b3IubmFtZSArIFwiLmhhbmRsZUJ1ZmZlcmVkKCk6IEhhbmRsaW5nIG91dHB1dC4uLlwiKTtcclxuXHJcbiAgICAgICAgLy8gT3V0cHV0IGlzIG9rLlxyXG4gICAgICAgIC8vIEhhbmRsZSBpdC5cclxuICAgICAgICBhd2FpdCB0aGlzLl9oYW5kbGVCdWZmZXJlZChhd2FpdCB0aGlzLnByZXBhcmVfb3V0cHV0KG91dHB1dCwgZW5hYmxlT3V0cHV0V3JhcHBpbmcpLCBlcnJvcl9jb2RlKTtcclxuICAgICAgICBkZWJ1Z0xvZyhcIk91dHB1dCBoYW5kbGluZyBpcyBkb25lLlwiKTtcclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3QgX2hhbmRsZVJlYWx0aW1lKG91dHB1dENvbnRlbnQ6IHN0cmluZywgb3V0cHV0U3RyZWFtTmFtZTogT3V0cHV0U3RyZWFtKTogUHJvbWlzZTx2b2lkPjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSBvdXRwdXRTdHJlYW1OYW1lXHJcbiAgICAgKiBAcGFyYW0gb3V0cHV0Q29udGVudFxyXG4gICAgICogQHBhcmFtIGVuYWJsZU91dHB1dFdyYXBwaW5nIE5vIGNhbGxlciBhY3R1YWxseSBzZXRzIHRoaXMgdG8gZmFsc2UgYXQgdGhlIG1vbWVudCwgdW5saWtlIHRoZSBoYW5kbGVCdWZmZXJlZCgpIG1ldGhvZCdzIGNvdW50ZXJwYXJ0LiBCdXQgaGF2ZSB0aGlzIGp1c3QgaW4gY2FzZS5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGFzeW5jIGhhbmRsZVJlYWx0aW1lKG91dHB1dFN0cmVhbU5hbWU6IE91dHB1dFN0cmVhbSwgb3V0cHV0Q29udGVudDogc3RyaW5nLCBlbmFibGVPdXRwdXRXcmFwcGluZyA9IHRydWUpIHtcclxuICAgICAgICB0aGlzLnJlcXVpcmVIYW5kbGluZ01vZGUoXCJyZWFsdGltZVwiKTtcclxuXHJcbiAgICAgICAgLy8gUXVhbGlmeSBvdXRwdXRcclxuICAgICAgICBpZiAoXCJcIiA9PT0gb3V0cHV0Q29udGVudCkge1xyXG4gICAgICAgICAgICAvLyBUaGUgb3V0cHV0IGlzIGVtcHR5XHJcbiAgICAgICAgICAgIGlmICghdGhpcy5zdGF0aWMoKS5hY2NlcHRzX2VtcHR5X291dHB1dCkge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhpcyBPdXRwdXRDaGFubmVsIGRvZXMgbm90IGFjY2VwdCBlbXB0eSBvdXRwdXQsIGkuZS4gZW1wdHkgb3V0cHV0IHNob3VsZCBiZSBqdXN0IGlnbm9yZWQuXHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyh0aGlzLmNvbnN0cnVjdG9yLm5hbWUgKyBcIi5oYW5kbGVSZWFsdGltZSgpOiBJZ25vcmluZyBlbXB0eSBvdXRwdXQuXCIpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRlYnVnTG9nKHRoaXMuY29uc3RydWN0b3IubmFtZSArIFwiLmhhbmRsZVJlYWx0aW1lKCk6IEhhbmRsaW5nIG91dHB1dC4uLlwiKTtcclxuXHJcbiAgICAgICAgLy8gT3V0cHV0IGlzIG9rLlxyXG5cclxuICAgICAgICAvLyBJZiBhbGxvd2VkLCB3cmFwIHRoZSBvdXRwdXQgd2l0aCBvdXRwdXQgd3JhcHBlciB0ZXh0LlxyXG4gICAgICAgIGlmIChlbmFibGVPdXRwdXRXcmFwcGluZykge1xyXG4gICAgICAgICAgICAvLyBXcmFwIG91dHB1dCAoYnV0IG9ubHkgaWYgYSB3cmFwcGVyIGlzIGRlZmluZWQpXHJcbiAgICAgICAgICAgIG91dHB1dENvbnRlbnQgPSBhd2FpdCB0aGlzLndyYXBPdXRwdXQob3V0cHV0U3RyZWFtTmFtZSwgb3V0cHV0Q29udGVudCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBIYW5kbGUgaXQuXHJcbiAgICAgICAgYXdhaXQgdGhpcy5faGFuZGxlUmVhbHRpbWUob3V0cHV0Q29udGVudCwgb3V0cHV0U3RyZWFtTmFtZSk7XHJcblxyXG4gICAgICAgIGRlYnVnTG9nKFwiT3V0cHV0IGhhbmRsaW5nIGlzIGRvbmUuXCIpO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBfZW5kUmVhbHRpbWUoZXhpdENvZGU6IG51bWJlcik6IHZvaWQge1xyXG4gICAgICAgIC8vIERvIG5vdGhpbmcgYnkgZGVmYXVsdC5cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFdoZW4gYSBzaGVsbCBjb21tYW5kIGlzIGV4ZWN1dGVkIGluIFwicmVhbHRpbWVcIiBtb2RlLCBhIHNlcGFyYXRlIGVuZGluZyBjYWxsIHNob3VsZCBiZSBtYWRlIGluIG9yZGVyIHRvIHBhc3MgYW5cclxuICAgICAqIGV4aXQgY29kZSB0byB0aGUgT3V0cHV0Q2hhbm5lbC4gU29tZSBPdXRwdXRDaGFubmVscyBkaXNwbGF5IHRoZSBjb2RlIHRvIHVzZXIsIGJ1dCBtb3N0IGRvIG5vdC5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gZXhpdENvZGVcclxuICAgICAqL1xyXG4gICAgcHVibGljIGVuZFJlYWx0aW1lKGV4aXRDb2RlOiBudW1iZXIpIHtcclxuICAgICAgICB0aGlzLnJlcXVpcmVIYW5kbGluZ01vZGUoXCJyZWFsdGltZVwiKTtcclxuXHJcbiAgICAgICAgdGhpcy5fZW5kUmVhbHRpbWUoZXhpdENvZGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgcmVxdWlyZUhhbmRsaW5nTW9kZShyZXF1aXJlZE1vZGU6IE91dHB1dEhhbmRsaW5nTW9kZSkge1xyXG4gICAgICAgIGlmICh0aGlzLm91dHB1dEhhbmRsaW5nTW9kZSAhPT0gcmVxdWlyZWRNb2RlKSB7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcInRoaXMub3V0cHV0SGFuZGxpbmdNb2RlIG11c3QgYmUgJ1wiK3JlcXVpcmVkTW9kZStcIicuXCIpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgc3RhdGljIGFjY2VwdHNPdXRwdXRTdHJlYW0ob3V0cHV0X3N0cmVhbTogT3V0cHV0U3RyZWFtKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuYWNjZXB0ZWRfb3V0cHV0X3N0cmVhbXMuY29udGFpbnMob3V0cHV0X3N0cmVhbSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEb2VzIHRoZSBmb2xsb3dpbmcgcHJlcGFyYXRpb25zOlxyXG4gICAgICogIC0gQ29tYmluZXMgb3V0cHV0IHN0cmVhbXMgKGlmIHdhbnRlZCBieSB0aGUgT3V0cHV0Q2hhbm5lbCkuXHJcbiAgICAgKiAgLSBXcmFwcyBvdXRwdXQgKGlmIGRlZmluZWQgaW4gc2hlbGwgY29tbWFuZCBjb25maWd1cmF0aW9uKS5cclxuICAgICAqIEBwYXJhbSBvdXRwdXRfc3RyZWFtc1xyXG4gICAgICogQHBhcmFtIGVuYWJsZU91dHB1dFdyYXBwaW5nXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGFzeW5jIHByZXBhcmVfb3V0cHV0KG91dHB1dF9zdHJlYW1zOiBPdXRwdXRTdHJlYW1zLCBlbmFibGVPdXRwdXRXcmFwcGluZzogYm9vbGVhbik6IFByb21pc2U8T3V0cHV0U3RyZWFtcyB8IHN0cmluZz4ge1xyXG4gICAgICAgIGNvbnN0IHdyYXBPdXRwdXRJZkVuYWJsZWQgPSBhc3luYyAob3V0cHV0U3RyZWFtTmFtZTogT3V0cHV0U3RyZWFtLCBvdXRwdXRDb250ZW50OiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgaWYgKGVuYWJsZU91dHB1dFdyYXBwaW5nKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBXcmFwIG91dHB1dCBjb250ZW50LlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMud3JhcE91dHB1dChvdXRwdXRTdHJlYW1OYW1lLCBvdXRwdXRDb250ZW50KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIFdyYXBwaW5nIGlzIGRpc2FibGVkLCByZXR1cm4gdW5tb2RpZmllZCBvdXRwdXQgY29udGVudC5cclxuICAgICAgICAgICAgICAgIHJldHVybiBvdXRwdXRDb250ZW50O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgY29uc3Qgd3JhcF9vdXRwdXRzX3NlcGFyYXRlbHkgPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IHdyYXBwZWRfb3V0cHV0X3N0cmVhbXM6IE91dHB1dFN0cmVhbXMgPSB7fTtcclxuICAgICAgICAgICAgbGV0IG91dHB1dF9zdHJlYW1fbmFtZTogT3V0cHV0U3RyZWFtO1xyXG4gICAgICAgICAgICBmb3IgKG91dHB1dF9zdHJlYW1fbmFtZSBpbiBvdXRwdXRfc3RyZWFtcykge1xyXG4gICAgICAgICAgICAgICAgd3JhcHBlZF9vdXRwdXRfc3RyZWFtc1tvdXRwdXRfc3RyZWFtX25hbWVdID0gYXdhaXQgd3JhcE91dHB1dElmRW5hYmxlZChcclxuICAgICAgICAgICAgICAgICAgICBvdXRwdXRfc3RyZWFtX25hbWUsXHJcbiAgICAgICAgICAgICAgICAgICAgb3V0cHV0X3N0cmVhbXNbb3V0cHV0X3N0cmVhbV9uYW1lXSBhcyBzdHJpbmcsIC8vIGFzIHN0cmluZyA9IG91dHB1dCBjb250ZW50IGFsd2F5cyBleGlzdHMgYmVjYXVzZSB0aGUga2V5IGNhbWUgZnJvbSBmb3IuLi5pbi5cclxuICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgcmV0dXJuIHdyYXBwZWRfb3V0cHV0X3N0cmVhbXM7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgb3V0cHV0cyBzaG91bGQgYmUgY29tYmluZWQuXHJcbiAgICAgICAgY29uc3QgY29tYmluZU91dHB1dFN0cmVhbXMgPSB0aGlzLnN0YXRpYygpLmNvbWJpbmVfb3V0cHV0X3N0cmVhbXM7XHJcbiAgICAgICAgaWYgKGNvbWJpbmVPdXRwdXRTdHJlYW1zKSB7XHJcbiAgICAgICAgICAgIC8vIENvbWJpbmUgb3V0cHV0IHN0cmluZ3MgaW50byBhIHNpbmdsZSBzdHJpbmcuXHJcblxyXG4gICAgICAgICAgICAvLyBDYW4gb3V0cHV0IHdyYXBwaW5nIGJlIGNvbWJpbmVkP1xyXG4gICAgICAgICAgICBpZiAodGhpcy50X3NoZWxsX2NvbW1hbmQuaXNPdXRwdXRXcmFwcGVyU3Rkb3V0U2FtZUFzU3RkZXJyKCkpIHtcclxuICAgICAgICAgICAgICAgIC8vIE91dHB1dCB3cmFwcGluZyBjYW4gYmUgY29tYmluZWQuXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gYXdhaXQgd3JhcE91dHB1dElmRW5hYmxlZChcclxuICAgICAgICAgICAgICAgICAgICBcInN0ZG91dFwiLFxyXG4gICAgICAgICAgICAgICAgICAgIGpvaW5PYmplY3RQcm9wZXJ0aWVzKG91dHB1dF9zdHJlYW1zLCBjb21iaW5lT3V0cHV0U3RyZWFtcyksIC8vIFVzZSBjb21iaW5lT3V0cHV0U3RyZWFtcyBhcyBhIGdsdWUgc3RyaW5nLlxyXG4gICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIE91dHB1dCB3cmFwcGluZyBuZWVkcyB0byBiZSBkb25lIHNlcGFyYXRlbHkuXHJcbiAgICAgICAgICAgICAgICBjb25zdCB3cmFwcGVkX291dHB1dF9zdHJlYW1zID0gYXdhaXQgd3JhcF9vdXRwdXRzX3NlcGFyYXRlbHkoKTtcclxuICAgICAgICAgICAgICAgIHJldHVybiBqb2luT2JqZWN0UHJvcGVydGllcyh3cmFwcGVkX291dHB1dF9zdHJlYW1zLCBjb21iaW5lT3V0cHV0U3RyZWFtcyk7IC8vIFVzZSBjb21iaW5lT3V0cHV0U3RyZWFtcyBhcyBhIGdsdWUgc3RyaW5nLlxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIERvIG5vdCBjb21iaW5lLCBoYW5kbGUgZWFjaCBzdHJlYW0gc2VwYXJhdGVseVxyXG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgd3JhcF9vdXRwdXRzX3NlcGFyYXRlbHkoKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTdXJyb3VuZHMgdGhlIGdpdmVuIG91dHB1dCB0ZXh0IHdpdGggYW4gb3V0cHV0IHdyYXBwZXIuIElmIG5vIG91dHB1dCB3cmFwcGVyIGlzIGRlZmluZWQsIHJldHVybnMgdGhlIG9yaWdpbmFsXHJcbiAgICAgKiBvdXRwdXQgdGV4dCB3aXRob3V0IGFueSBtb2RpZmljYXRpb25zLlxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGFzeW5jIHdyYXBPdXRwdXQob3V0cHV0X3N0cmVhbTogT3V0cHV0U3RyZWFtLCBvdXRwdXRfY29udGVudDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcclxuXHJcbiAgICAgICAgLy8gR2V0IHByZXBhcnNlZCBvdXRwdXQgd3JhcHBlciBjb250ZW50LiBJdCBoYXMgYWxsIG90aGVyIHZhcmlhYmxlcyBwYXJzZWQsIGV4Y2VwdCB7e291dHB1dH19LlxyXG4gICAgICAgIGNvbnN0IHBhcnNpbmdfcmVzdWx0X2tleToga2V5b2YgU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdCA9IFwib3V0cHV0X3dyYXBwZXJfXCIrb3V0cHV0X3N0cmVhbSBhcyBrZXlvZiBTaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0O1xyXG4gICAgICAgIGNvbnN0IG91dHB1dF93cmFwcGVyX2NvbnRlbnQgPSB0aGlzLnNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHRbcGFyc2luZ19yZXN1bHRfa2V5XSBhcyBzdHJpbmcgfCB1bmRlZmluZWQ7XHJcblxyXG4gICAgICAgIC8vIENoZWNrIGlmIG91dHB1dCB3cmFwcGVyIGNvbnRlbnQgZXhpc3RzLlxyXG4gICAgICAgIGlmICh1bmRlZmluZWQgPT09IG91dHB1dF93cmFwcGVyX2NvbnRlbnQpIHtcclxuICAgICAgICAgICAgLy8gTm8gT3V0cHV0V3JhcHBlciBpcyBkZWZpbmVkIGZvciB0aGlzIHNoZWxsIGNvbW1hbmQuXHJcbiAgICAgICAgICAgIC8vIFJldHVybiB0aGUgb3V0cHV0IHRleHQgd2l0aG91dCBtb2RpZmljYXRpb25zLlxyXG4gICAgICAgICAgICBkZWJ1Z0xvZyhcIk91dHB1dCB3cmFwcGluZzogTm8gd3JhcHBlciBpcyBkZWZpbmVkIGZvciAnXCIgKyBvdXRwdXRfc3RyZWFtICsgXCInLlwiKTtcclxuICAgICAgICAgICAgcmV0dXJuIG91dHB1dF9jb250ZW50O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gUGFyc2UgdGhlIHt7b3V0cHV0fX0gdmFyaWFibGVcclxuICAgICAgICBjb25zdCBvdXRwdXRfdmFyaWFibGUgPSBuZXcgVmFyaWFibGVfT3V0cHV0KHRoaXMucGx1Z2luLCBvdXRwdXRfY29udGVudCk7XHJcbiAgICAgICAgY29uc3QgcGFyc2luZ19yZXN1bHQgPSBhd2FpdCBwYXJzZVZhcmlhYmxlcyhcclxuICAgICAgICAgICAgdGhpcy5wbHVnaW4sXHJcbiAgICAgICAgICAgIG91dHB1dF93cmFwcGVyX2NvbnRlbnQsXHJcbiAgICAgICAgICAgIG51bGwsIC8vIE5vIHNoZWxsIGFueW1vcmUsIHNvIG5vIG5lZWQgZm9yIGVzY2FwaW5nLlxyXG4gICAgICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZCxcclxuICAgICAgICAgICAgbnVsbCwgLy8gTm8gc3VwcG9ydCBmb3Ige3tldmVudF8qfX0gdmFyaWFibGVzIGlzIG5lZWRlZCwgYmVjYXVzZSB0aGV5IGFyZSBhbHJlYWR5IHBhcnNlZCBpbiBvdXRwdXRfd3JhcHBlcl9jb250ZW50LiBUaGlzIHBoYXNlIG9ubHkgcGFyc2VzIHt7b3V0cHV0fX0gdmFyaWFibGUsIG5vdGhpbmcgZWxzZS5cclxuICAgICAgICAgICAgbmV3IFZhcmlhYmxlU2V0KFtvdXRwdXRfdmFyaWFibGVdKSwgLy8gT25seSBwYXJzZSB0aGUge3tvdXRwdXR9fSB2YXJpYWJsZS5cclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBJbnNwZWN0IHRoZSBwYXJzaW5nIHJlc3VsdC4gSXQgc2hvdWxkIGFsd2F5cyBzdWNjZWVkLCBhcyB0aGUge3tvdXRwdXR9fSB2YXJpYWJsZSBzaG91bGQgbm90IGdpdmUgYW55IGVycm9ycy5cclxuICAgICAgICBpZiAocGFyc2luZ19yZXN1bHQuc3VjY2VlZGVkKSB7XHJcbiAgICAgICAgICAgIC8vIFN1Y2NlZWRlZC5cclxuICAgICAgICAgICAgZGVidWdMb2coXCJPdXRwdXQgd3JhcHBpbmc6IFdyYXBwaW5nIFwiICsgb3V0cHV0X3N0cmVhbSArIFwiIHN1Y2NlZWRlZC5cIik7XHJcbiAgICAgICAgICAgIHJldHVybiBwYXJzaW5nX3Jlc3VsdC5wYXJzZWRfY29udGVudCBhcyBzdHJpbmc7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gRmFpbGVkIGZvciBzb21lIHJlYXNvbi5cclxuICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3RXJyb3IoXCJPdXRwdXQgd3JhcHBpbmcgZmFpbGVkLCBzZWUgZXJyb3IocykgYmVsb3cuXCIpO1xyXG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5uZXdFcnJvcnMocGFyc2luZ19yZXN1bHQuZXJyb3JfbWVzc2FnZXMpO1xyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJPdXRwdXQgd3JhcHBpbmcgZmFpbGVkOiBQYXJzaW5nIHt7b3V0cHV0fX0gcmVzdWx0ZWQgaW4gZXJyb3Iocyk6IFwiICsgcGFyc2luZ19yZXN1bHQuZXJyb3JfbWVzc2FnZXMuam9pbihcIiBcIikpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENhbiBiZSBtb3ZlZCB0byBhIGdsb2JhbCBmdW5jdGlvbiBpc091dHB1dFN0cmVhbUVtcHR5KCkgaWYgbmVlZGVkLlxyXG4gICAgICogQHBhcmFtIG91dHB1dFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBzdGF0aWMgaXNPdXRwdXRFbXB0eShvdXRwdXQ6IE91dHB1dFN0cmVhbXMpIHtcclxuICAgICAgICBpZiAodW5kZWZpbmVkICE9PSBvdXRwdXQuc3RkZXJyKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZCA9PT0gb3V0cHV0LnN0ZG91dCB8fCBcIlwiID09PSBvdXRwdXQuc3Rkb3V0O1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBzdGF0aWMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uc3RydWN0b3IgYXMgdHlwZW9mIE91dHB1dENoYW5uZWw7XHJcbiAgICB9XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgT3V0cHV0Q2hhbm5lbHMge1xyXG4gICAgc3Rkb3V0PzogT3V0cHV0Q2hhbm5lbCxcclxuICAgIHN0ZGVycj86IE91dHB1dENoYW5uZWwsXHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7T3V0cHV0Q2hhbm5lbH0gZnJvbSBcIi4vT3V0cHV0Q2hhbm5lbFwiO1xyXG5pbXBvcnQge091dHB1dFN0cmVhbXN9IGZyb20gXCIuL091dHB1dENoYW5uZWxGdW5jdGlvbnNcIjtcclxuaW1wb3J0IHtPdXRwdXRTdHJlYW19IGZyb20gXCIuL091dHB1dENoYW5uZWxDb2RlXCI7XHJcbmltcG9ydCB7Tm90aWNlfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuXHJcblxyXG5leHBvcnQgY2xhc3MgT3V0cHV0Q2hhbm5lbF9Ob3RpZmljYXRpb24gZXh0ZW5kcyBPdXRwdXRDaGFubmVsIHtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEFsbCByZWNlaXZlZCBvdXRwdXQgY3VtdWxhdGl2ZWx5LiBTdWJzZXF1ZW50IGhhbmRsaW5ncyB3aWxsIHRoZW4gdXNlIHRoZSB3aG9sZSBvdXRwdXQsIG5vdCBqdXN0IG5ldyBwYXJ0cy5cclxuICAgICAqIE9ubHkgdXNlZCBpbiBcInJlYWx0aW1lXCIgbW9kZS5cclxuICAgICAqXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIHJlYWx0aW1lQ29udGVudEJ1ZmZlciA9IFwiXCI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBIb2xkcyBhIE5vdGljZSBpbnN0YW5jZSBzbyB0aGF0IHRoZSBtZXNzYWdlIGNhbiBiZSB1cGRhdGVkIGR1cmluZyBzdWJzZXF1ZW50IGhhbmRsaW5ncy5cclxuICAgICAqIE9ubHkgdXNlZCBpbiBcInJlYWx0aW1lXCIgbW9kZS5cclxuICAgICAqXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIHJlYWx0aW1lTm90aWNlOiBOb3RpY2UgfCB1bmRlZmluZWQ7XHJcblxyXG4gICAgcHJpdmF0ZSByZWFsdGltZU5vdGljZVRpbWVvdXQ6IG51bWJlciB8IHVuZGVmaW5lZDtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEEgZmxhZyBmb3IgaW5kaWNhdGluZyB0aGF0IGlmIGFueSBzdGRlcnIgb3V0cHV0IGhhcyBoYXBwZW5lZCwgYWxsIHN1YnNlcXVlbnQgaGFuZGxpbmdzIHNob3VsZCBmb3JtYXQgdGhlIG91dHB1dFxyXG4gICAgICogTm90aWNlIG1lc3NhZ2Ugd2l0aCBlcnJvciBmb3JtYXR0aW5nIChpLmUuIHNob3cgWy4uLl0gYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgbWVzc2FnZSkuXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIHJlYWx0aW1lSGFzU3RkZXJyT2NjdXJyZWQgPSBmYWxzZTtcclxuXHJcbiAgICBwdWJsaWMgc3RhdGljIGdldFRpdGxlKG91dHB1dF9zdHJlYW06IE91dHB1dFN0cmVhbSk6IHN0cmluZyB7XHJcbiAgICAgICAgc3dpdGNoIChvdXRwdXRfc3RyZWFtKSB7XHJcbiAgICAgICAgICAgIGNhc2UgXCJzdGRvdXRcIjpcclxuICAgICAgICAgICAgICAgIHJldHVybiBcIk5vdGlmaWNhdGlvbiBiYWxsb29uXCI7XHJcbiAgICAgICAgICAgIGNhc2UgXCJzdGRlcnJcIjpcclxuICAgICAgICAgICAgICAgIHJldHVybiBcIkVycm9yIGJhbGxvb25cIjtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIF9oYW5kbGVCdWZmZXJlZChvdXRwdXQ6IE91dHB1dFN0cmVhbXMsIGVycm9yX2NvZGU6IG51bWJlciB8IG51bGwpOiBQcm9taXNlPHZvaWQ+IHtcclxuXHJcbiAgICAgICAgLy8gSXRlcmF0ZSBvdXRwdXQgc3RyZWFtcy5cclxuICAgICAgICAvLyBUaGVyZSBjYW4gYmUgYm90aCBcInN0ZG91dFwiIGFuZCBcInN0ZGVyclwiIHByZXNlbnQgYXQgdGhlIHNhbWUgdGltZSwgb3IganVzdCBvbmUgb2YgdGhlbS4gSWYgYm90aCBhcmUgcHJlc2VudCwgdHdvXHJcbiAgICAgICAgLy8gbm90aWZpY2F0aW9ucyB3aWxsIGJlIGNyZWF0ZWQuXHJcbiAgICAgICAgbGV0IG91dHB1dF9zdHJlYW1fbmFtZTogT3V0cHV0U3RyZWFtO1xyXG4gICAgICAgIGZvciAob3V0cHV0X3N0cmVhbV9uYW1lIGluIG91dHB1dCkge1xyXG4gICAgICAgICAgICBjb25zdCBvdXRwdXRfbWVzc2FnZTogc3RyaW5nID0gb3V0cHV0W291dHB1dF9zdHJlYW1fbmFtZV0gYXMgc3RyaW5nOyAvLyBhcyBzdHJpbmcgPSBvdXRwdXQgbWVzc2FnZSBpcyBub3QgdW5kZWZpbmVkIGJlY2F1c2Ugb2YgdGhlIGZvciBsb29wLlxyXG4gICAgICAgICAgICB0aGlzLm5vdGlmeShvdXRwdXRfc3RyZWFtX25hbWUsIG91dHB1dF9tZXNzYWdlLCBlcnJvcl9jb2RlKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIF9oYW5kbGVSZWFsdGltZShvdXRwdXRDb250ZW50OiBzdHJpbmcsIG91dHB1dFN0cmVhbU5hbWU6IE91dHB1dFN0cmVhbSk6IFByb21pc2U8dm9pZD4ge1xyXG5cclxuICAgICAgICAvLyBBcHBlbmQgbmV3IGNvbnRlbnRcclxuICAgICAgICB0aGlzLnJlYWx0aW1lQ29udGVudEJ1ZmZlciArPSBvdXRwdXRDb250ZW50O1xyXG5cclxuICAgICAgICAvLyBSYWlzZSBhIGZsYWcgaWYgc2VlaW5nICdzdGRlcnInIG91dHB1dC5cclxuICAgICAgICBpZiAoXCJzdGRlcnJcIiA9PT0gb3V0cHV0U3RyZWFtTmFtZSkge1xyXG4gICAgICAgICAgICB0aGlzLnJlYWx0aW1lSGFzU3RkZXJyT2NjdXJyZWQgPSB0cnVlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRG9lcyBhIE5vdGljZSBleGlzdCBhbHJlYWR5P1xyXG4gICAgICAgIGlmICh0aGlzLnJlYWx0aW1lTm90aWNlKSB7XHJcbiAgICAgICAgICAgIC8vIFJldXNlIGFuIGV4aXN0aW5nIE5vdGljZS5cclxuXHJcbiAgICAgICAgICAgIC8vIFNob3VsZCBvdXRwdXQgYmUgZm9ybWF0dGVkIGFzIGFuIGVycm9yIG1lc3NhZ2U/XHJcbiAgICAgICAgICAgIGxldCB1cGRhdGVkTWVzc2FnZTogc3RyaW5nO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5yZWFsdGltZUhhc1N0ZGVyck9jY3VycmVkKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBBcHBseSBlcnJvciBmb3JtYXR0aW5nIHRvIG91dHB1dFxyXG4gICAgICAgICAgICAgICAgdXBkYXRlZE1lc3NhZ2UgPSBPdXRwdXRDaGFubmVsX05vdGlmaWNhdGlvbi5mb3JtYXRFcnJvck1lc3NhZ2UodGhpcy5yZWFsdGltZUNvbnRlbnRCdWZmZXIsIG51bGwpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgLy8gVXNlIG91dHB1dCBhcy1pc1xyXG4gICAgICAgICAgICAgICAgdXBkYXRlZE1lc3NhZ2UgPSB0aGlzLnJlYWx0aW1lQ29udGVudEJ1ZmZlcjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gVXNlIHRoZSB1cGRhdGVkIG91dHB1dFxyXG4gICAgICAgICAgICB0aGlzLnJlYWx0aW1lTm90aWNlLnNldE1lc3NhZ2UodXBkYXRlZE1lc3NhZ2UpO1xyXG5cclxuICAgICAgICAgICAgLy8gVXBkYXRlIG5vdGljZSBoaWRpbmcgdGltZW91dFxyXG4gICAgICAgICAgICB3aW5kb3cuY2xlYXJUaW1lb3V0KHRoaXMucmVhbHRpbWVOb3RpY2VUaW1lb3V0KTsgLy8gUmVtb3ZlIG9sZCB0aW1lb3V0XHJcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uSGlkaW5nKG91dHB1dFN0cmVhbU5hbWUpOyAvLyBBZGQgbmV3IHRpbWVvdXRcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBDcmVhdGUgYSBuZXcgTm90aWNlLlxyXG4gICAgICAgICAgICB0aGlzLnJlYWx0aW1lTm90aWNlID0gdGhpcy5ub3RpZnkoXHJcbiAgICAgICAgICAgICAgICB0aGlzLnJlYWx0aW1lSGFzU3RkZXJyT2NjdXJyZWQgPyBcInN0ZGVyclwiIDogXCJzdGRvdXRcIixcclxuICAgICAgICAgICAgICAgIHRoaXMucmVhbHRpbWVDb250ZW50QnVmZmVyLFxyXG4gICAgICAgICAgICAgICAgbnVsbCxcclxuICAgICAgICAgICAgICAgIDAsIC8vIFVzZSAwIHRpbWVvdXQgc28gdGhhdCB0aGUgTm90aWNlIHdvbid0IGhpZGUgYXV0b21hdGljYWxseS5cclxuICAgICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAgIC8vIENyZWF0ZSBhIHRpbWVvdXQgZm9yIGhpZGluZyB0aGUgTm90aWNlXHJcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlTm90aWZpY2F0aW9uSGlkaW5nKG91dHB1dFN0cmVhbU5hbWUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGVybWluYXRpbmcgYnV0dG9uXHJcbiAgICAgICAgLy8gQHRzLWlnbm9yZSBOb3RpY2Uubm90aWNlRWwgYmVsb25ncyB0byBPYnNpZGlhbidzIFBSSVZBVEUgQVBJLCBhbmQgaXQgbWF5IGNoYW5nZSB3aXRob3V0IGEgcHJpb3Igbm90aWNlLiBPbmx5XHJcbiAgICAgICAgLy8gY3JlYXRlIHRoZSBidXR0b24gaWYgbm90aWNlRWwgZXhpc3RzIGFuZCBpcyBhbiBIVE1MRWxlbWVudC5cclxuICAgICAgICBjb25zdCBub3RpY2VFbCA9IHRoaXMucmVhbHRpbWVOb3RpY2Uubm90aWNlRWw7XHJcbiAgICAgICAgaWYgKG51bGwgPT09IHRoaXMucHJvY2Vzc1Rlcm1pbmF0b3IpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUHJvY2VzcyB0ZXJtaW5hdG9yIGlzIG5vdCBzZXQsIGFsdGhvdWdoIGl0IHNob3VsZCBiZSBzZXQgd2hlbiBoYW5kbGluZyBvdXRwdXQgaW4gcmVhbHRpbWUgbW9kZS5cIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICh1bmRlZmluZWQgIT09IG5vdGljZUVsICYmIG5vdGljZUVsIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcclxuICAgICAgICAgICAgdGhpcy5wbHVnaW4uY3JlYXRlUmVxdWVzdFRlcm1pbmF0aW5nQnV0dG9uKG5vdGljZUVsLCB0aGlzLnByb2Nlc3NUZXJtaW5hdG9yKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIF9lbmRSZWFsdGltZShleGl0Q29kZTogbnVtYmVyIHwgbnVsbCk6IHZvaWQge1xyXG4gICAgICAgIGlmIChleGl0Q29kZSAhPT0gMCB8fCB0aGlzLnJlYWx0aW1lSGFzU3RkZXJyT2NjdXJyZWQpIHtcclxuICAgICAgICAgICAgLy8gSWYgYSBOb3RpY2UgZXhpc3RzLCB1cGRhdGUgaXQgd2l0aCB0aGUgZXhpdENvZGVcclxuICAgICAgICAgICAgdGhpcy5yZWFsdGltZU5vdGljZT8uc2V0TWVzc2FnZShPdXRwdXRDaGFubmVsX05vdGlmaWNhdGlvbi5mb3JtYXRFcnJvck1lc3NhZ2UoXHJcbiAgICAgICAgICAgICAgICB0aGlzLnJlYWx0aW1lQ29udGVudEJ1ZmZlcixcclxuICAgICAgICAgICAgICAgIGV4aXRDb2RlLCAvLyBJZiBleGl0Q29kZSBpcyBudWxsLCBpdCBtZWFucyB1c2VyIHRlcm1pbmF0ZWQgdGhlIHByb2Nlc3MsIGFuZCBpdCB3aWxsIHNob3cgdXAgYXMgXCJbLi4uXVwiLiBJdCdzIG9rLCBpdCBpbmRpY2F0ZXMgdGhhdCBubyBleGl0IGNvZGUgd2FzIHJlY2VpdmVkLlxyXG4gICAgICAgICAgICApKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFJlbW92ZSB0ZXJtaW5hdGluZyBidXR0b25cclxuICAgICAgICAvLyBAdHMtaWdub3JlIE5vdGljZS5ub3RpY2VFbCBiZWxvbmdzIHRvIE9ic2lkaWFuJ3MgUFJJVkFURSBBUEksIGFuZCBpdCBtYXkgY2hhbmdlIHdpdGhvdXQgYSBwcmlvciBub3RpY2UuIE9ubHlcclxuICAgICAgICAvLyBjcmVhdGUgdGhlIGJ1dHRvbiBpZiBub3RpY2VFbCBleGlzdHMgYW5kIGlzIGFuIEhUTUxFbGVtZW50LlxyXG4gICAgICAgIGNvbnN0IG5vdGljZUVsID0gdGhpcy5yZWFsdGltZU5vdGljZT8ubm90aWNlRWw7XHJcbiAgICAgICAgaWYgKHVuZGVmaW5lZCAhPT0gbm90aWNlRWwgJiYgbm90aWNlRWwgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCkge1xyXG4gICAgICAgICAgICBub3RpY2VFbC5maW5kKFwiLlNDLWljb24tdGVybWluYXRlLXByb2Nlc3NcIik/LnJlbW92ZSgpOyAvLyA/ID0gT25seSB0cnkgdG8gcmVtb3ZlIGlmIHRoZSBidXR0b24gZXhpc3RzLiBJdCBkb2VzIG5vdCBleGlzdCBpZiAuc2V0TWVzc2FnZSgpIHdhcyBjYWxsZWQgYWJvdmUgYXMgaXQgb3ZlcndyaXRlcyBhbGwgY29udGVudCBpbiB0aGUgTm90aWNlLlxyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gb3V0cHV0U3RyZWFtTmFtZVxyXG4gICAgICogQHBhcmFtIG91dHB1dENvbnRlbnRcclxuICAgICAqIEBwYXJhbSBleGl0Q29kZVxyXG4gICAgICogQHBhcmFtIG5vdGljZVRpbWVvdXQgQWxsb3dzIG92ZXJyaWRpbmcgdGhlIG5vdGljZS9lcnJvciB0aW1lb3V0IHNldHRpbmcuXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIG5vdGlmeShvdXRwdXRTdHJlYW1OYW1lOiBPdXRwdXRTdHJlYW0sIG91dHB1dENvbnRlbnQ6IHN0cmluZywgZXhpdENvZGU6IG51bWJlciB8IG51bGwsIG5vdGljZVRpbWVvdXQ/OiBudW1iZXIpOiBOb3RpY2Uge1xyXG4gICAgICAgIHN3aXRjaCAob3V0cHV0U3RyZWFtTmFtZSkge1xyXG4gICAgICAgICAgICBjYXNlIFwic3Rkb3V0XCI6XHJcbiAgICAgICAgICAgICAgICAvLyBOb3JtYWwgb3V0cHV0XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5wbHVnaW4ubmV3Tm90aWZpY2F0aW9uKG91dHB1dENvbnRlbnQsIG5vdGljZVRpbWVvdXQgPz8gdW5kZWZpbmVkKTtcclxuICAgICAgICAgICAgY2FzZSBcInN0ZGVyclwiOlxyXG4gICAgICAgICAgICAgICAgLy8gRXJyb3Igb3V0cHV0XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5wbHVnaW4ubmV3RXJyb3IoT3V0cHV0Q2hhbm5lbF9Ob3RpZmljYXRpb24uZm9ybWF0RXJyb3JNZXNzYWdlKG91dHB1dENvbnRlbnQsIGV4aXRDb2RlKSwgbm90aWNlVGltZW91dCA/PyB1bmRlZmluZWQpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHN0YXRpYyBmb3JtYXRFcnJvck1lc3NhZ2Uob3V0cHV0Q29udGVudDogc3RyaW5nLCBleGl0Q29kZTogbnVtYmVyIHwgbnVsbCk6IHN0cmluZyB7XHJcbiAgICAgICAgaWYgKG51bGwgPT09IGV4aXRDb2RlKSB7XHJcbiAgICAgICAgICAgIC8vIElmIGEgXCJyZWFsdGltZVwiIHByb2Nlc3MgaXMgbm90IGZpbmlzaGVkLCB0aGVyZSBpcyBubyBleGl0IGNvZGUgeWV0LlxyXG4gICAgICAgICAgICAvLyBAdHMtaWdub3JlIFllYSBJIGtub3cgXCIuLi5cIiBpcyBub3QgYSBudW1iZXIgbm9yIG51bGwuIDopXHJcbiAgICAgICAgICAgIGV4aXRDb2RlID0gXCIuLi5cIjtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIFwiW1wiICsgZXhpdENvZGUgKyBcIl06IFwiICsgb3V0cHV0Q29udGVudDtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGhhbmRsZU5vdGlmaWNhdGlvbkhpZGluZyhvdXRwdXRTdHJlYW1OYW1lOiBPdXRwdXRTdHJlYW0pIHtcclxuXHJcbiAgICAgICAgLy8gSGlkZSBieSB0aW1lb3V0XHJcbiAgICAgICAgbGV0IG5vcm1hbFRpbWVvdXQ6IG51bWJlcjtcclxuICAgICAgICBzd2l0Y2ggKG91dHB1dFN0cmVhbU5hbWUpIHtcclxuICAgICAgICAgICAgY2FzZSBcInN0ZG91dFwiOlxyXG4gICAgICAgICAgICAgICAgbm9ybWFsVGltZW91dCA9IHRoaXMucGx1Z2luLmdldE5vdGlmaWNhdGlvbk1lc3NhZ2VEdXJhdGlvbk1zKCk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgY2FzZSBcInN0ZGVyclwiOlxyXG4gICAgICAgICAgICAgICAgbm9ybWFsVGltZW91dCA9IHRoaXMucGx1Z2luLmdldEVycm9yTWVzc2FnZUR1cmF0aW9uTXMoKTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnJlYWx0aW1lTm90aWNlVGltZW91dCA9IHdpbmRvdy5zZXRUaW1lb3V0KFxyXG4gICAgICAgICAgICAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAvLyBIaWRlIHRoZSBOb3RpY2VcclxuICAgICAgICAgICAgICAgIHRoaXMucmVhbHRpbWVOb3RpY2U/LmhpZGUoKTsgLy8gPyA9IERvbid0IHRyeSB0byBoaWRlIGlmIGEgdXNlciBoYXMgY2xvc2VkIHRoZSBub3RpZmljYXRpb24gYnkgY2xpY2tpbmcuIFNlZSB0aGUgJ3RoaXMucmVhbHRpbWVOb3RpY2UgPSB1bmRlZmluZWQ7JyBsaW5lIGluIHRoZSBiZWxvdyBjbGljayBoYW5kbGVyLlxyXG4gICAgICAgICAgICAgICAgdGhpcy5yZWFsdGltZU5vdGljZSA9IHVuZGVmaW5lZDtcclxuICAgICAgICAgICAgICAgIHRoaXMucmVhbHRpbWVOb3RpY2VUaW1lb3V0ID0gdW5kZWZpbmVkO1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBub3JtYWxUaW1lb3V0LFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFN1YnNjcmliZSB0byBOb3RpY2UncyBjbGljayBldmVudC5cclxuICAgICAgICAvLyBAdHMtaWdub3JlIE5vdGljZS5ub3RpY2VFbCBiZWxvbmdzIHRvIE9ic2lkaWFuJ3MgUFJJVkFURSBBUEksIGFuZCBpdCBtYXkgY2hhbmdlIHdpdGhvdXQgYSBwcmlvciBub3RpY2UuIE9ubHlcclxuICAgICAgICAvLyBkZWZpbmUgdGhlIGNsaWNrIGxpc3RlbmVyIGlmIG5vdGljZUVsIGV4aXN0cyBhbmQgaXMgYW4gSFRNTEVsZW1lbnQuXHJcbiAgICAgICAgY29uc3Qgbm90aWNlRWwgPSB0aGlzLnJlYWx0aW1lTm90aWNlLm5vdGljZUVsO1xyXG4gICAgICAgIGlmICh1bmRlZmluZWQgIT09IG5vdGljZUVsICYmIG5vdGljZUVsIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcclxuICAgICAgICAgICAgbm90aWNlRWwub25DbGlja0V2ZW50KCgpID0+IHtcclxuICAgICAgICAgICAgICAgIHdpbmRvdy5jbGVhclRpbWVvdXQodGhpcy5yZWFsdGltZU5vdGljZVRpbWVvdXQpOyAvLyBNYWtlIHN1cmUgdGltZW91dCB3aWxsIG5vdCBhY2NpZGVudGFsbHkgdHJ5IHRvIGxhdGVyIGhpZGUgYW4gYWxyZWFkeSBoaWRkZW4gTm90aWZpY2F0aW9uLlxyXG4gICAgICAgICAgICAgICAgdGhpcy5yZWFsdGltZU5vdGljZVRpbWVvdXQgPSB1bmRlZmluZWQ7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnJlYWx0aW1lTm90aWNlID0gdW5kZWZpbmVkOyAvLyBHaXZlIGEgc2lnbmFsIHRvIF9oYW5kbGVSZWFsdGltZSgpIHRoYXQgaWYgbmV3IG91dHB1dCBjb21lcywgYSBuZXcgTm90aWNlIHNob3VsZCBiZSBjcmVhdGVkLlxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7T3V0cHV0Q2hhbm5lbH0gZnJvbSBcIi4vT3V0cHV0Q2hhbm5lbFwiO1xyXG5pbXBvcnQge2dldEVkaXRvciwgZ2V0Vmlld30gZnJvbSBcIi4uL0NvbW1vblwiO1xyXG5pbXBvcnQge0VkaXRvcn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7ZGVidWdMb2d9IGZyb20gXCIuLi9EZWJ1Z1wiO1xyXG5cclxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIE91dHB1dENoYW5uZWxfQ3VycmVudEZpbGUgZXh0ZW5kcyBPdXRwdXRDaGFubmVsIHtcclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoZXJlIGNhbiBiZSBib3RoIFwic3Rkb3V0XCIgYW5kIFwic3RkZXJyXCIgcHJlc2VudCBhdCB0aGUgc2FtZSB0aW1lLCBvciBqdXN0IG9uZSBvZiB0aGVtLiBJZiBib3RoIGFyZSBwcmVzZW50LCB0aGV5XHJcbiAgICAgKiB3aWxsIGJlIGpvaW5lZCB0b2dldGhlciB3aXRoIFwiIFwiIGFzIGEgc2VwYXJhdG9yLlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGNvbWJpbmVfb3V0cHV0X3N0cmVhbXMgPSBcIiBcIjtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgX2hhbmRsZUJ1ZmZlcmVkKG91dHB1dENvbnRlbnQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICAgIHRoaXMuaGFuZGxlKG91dHB1dENvbnRlbnQpO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBfaGFuZGxlUmVhbHRpbWUob3V0cHV0Q29udGVudDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgdGhpcy5oYW5kbGUob3V0cHV0Q29udGVudCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBoYW5kbGUob3V0cHV0X21lc3NhZ2U6IHN0cmluZykge1xyXG4gICAgICAgIGNvbnN0IGVkaXRvciA9IGdldEVkaXRvcih0aGlzLmFwcCk7XHJcbiAgICAgICAgY29uc3QgdmlldyA9IGdldFZpZXcodGhpcy5hcHApO1xyXG5cclxuICAgICAgICBpZiAobnVsbCA9PT0gZWRpdG9yKSB7XHJcbiAgICAgICAgICAgIC8vIEZvciBzb21lIHJlYXNvbiBpdCdzIG5vdCBwb3NzaWJsZSB0byBnZXQgYW4gZWRpdG9yLlxyXG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5uZXdFcnJvcihcIkNvdWxkIG5vdCBnZXQgYW4gZWRpdG9yIGluc3RhbmNlISBQbGVhc2UgY3JlYXRlIGEgZGlzY3Vzc2lvbiBpbiBHaXRIdWIuIFRoZSBjb21tYW5kIG91dHB1dCBpcyBpbiB0aGUgbmV4dCBlcnJvciBib3g6XCIpO1xyXG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5uZXdFcnJvcihvdXRwdXRfbWVzc2FnZSk7IC8vIEdvb2QgdG8gb3V0cHV0IGl0IGF0IGxlYXN0IHNvbWUgd2F5LlxyXG4gICAgICAgICAgICBkZWJ1Z0xvZyhcIk91dHB1dENoYW5uZWxfQ3VycmVudEZpbGU6IENvdWxkIG5vdCBnZXQgYW4gZWRpdG9yIGluc3RhbmNlLlwiKTtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIHZpZXcgaXMgaW4gc291cmNlIG1vZGVcclxuICAgICAgICBpZiAobnVsbCA9PT0gdmlldykge1xyXG4gICAgICAgICAgICAvLyBGb3Igc29tZSByZWFzb24gaXQncyBub3QgcG9zc2libGUgdG8gZ2V0IGFuIGVkaXRvciwgYnV0IGl0J3Mgbm90IGEgYmlnIHByb2JsZW0uXHJcbiAgICAgICAgICAgIGRlYnVnTG9nKFwiT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZTogQ291bGQgbm90IGdldCBhIHZpZXcgaW5zdGFuY2UuXCIpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIFdlIGRvIGhhdmUgYSB2aWV3XHJcbiAgICAgICAgICAgIGlmIChcInNvdXJjZVwiICE9PSB2aWV3LmdldE1vZGUoKSkge1xyXG4gICAgICAgICAgICAgICAgLy8gV2FybiB0aGF0IHRoZSBvdXRwdXQgbWlnaHQgZ28gdG8gYW4gdW5leHBlY3RlZCBwbGFjZSBpbiB0aGUgbm90ZSBmaWxlLlxyXG4gICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3Tm90aWZpY2F0aW9uKFwiTm90ZSB0aGF0IHlvdXIgYWN0aXZlIG5vdGUgaXMgbm90IGluICdFZGl0JyBtb2RlISBUaGUgb3V0cHV0IGNvbWVzIHZpc2libGUgd2hlbiB5b3Ugc3dpdGNoIHRvICdFZGl0JyBtb2RlIGFnYWluIVwiKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSW5zZXJ0IGludG8gdGhlIGN1cnJlbnQgZmlsZVxyXG4gICAgICAgIHRoaXMuaW5zZXJ0SW50b0VkaXRvcihlZGl0b3IsIG91dHB1dF9tZXNzYWdlKTtcclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3QgaW5zZXJ0SW50b0VkaXRvcihlZGl0b3I6IEVkaXRvciwgb3V0cHV0X21lc3NhZ2U6IHN0cmluZyk6IHZvaWQ7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7T3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZX0gZnJvbSBcIi4vT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZVwiO1xyXG5pbXBvcnQge0VkaXRvcn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZUNhcmV0IGV4dGVuZHMgT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZSB7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHRpdGxlID0gXCJDdXJyZW50IGZpbGU6IGNhcmV0IHBvc2l0aW9uXCI7XHJcblxyXG4gICAgcHVibGljIHN0YXRpYyByZWFkb25seSBob3RrZXlfbGV0dGVyID0gXCJSXCI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbnNlcnRzIHRleHQgaW50byB0aGUgZ2l2ZW4gZWRpdG9yLCBhdCBjYXJldCBwb3NpdGlvbi5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gZWRpdG9yXHJcbiAgICAgKiBAcGFyYW0gb3V0cHV0X21lc3NhZ2VcclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGluc2VydEludG9FZGl0b3IoZWRpdG9yOiBFZGl0b3IsIG91dHB1dF9tZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgICAgICBlZGl0b3IucmVwbGFjZVNlbGVjdGlvbihvdXRwdXRfbWVzc2FnZSk7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7T3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZX0gZnJvbSBcIi4vT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZVwiO1xyXG5pbXBvcnQge0VkaXRvcn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZVRvcCBleHRlbmRzIE91dHB1dENoYW5uZWxfQ3VycmVudEZpbGUge1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSB0aXRsZSA9IFwiQ3VycmVudCBmaWxlOiB0b3BcIjtcclxuXHJcbiAgICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IGhvdGtleV9sZXR0ZXIgPSBcIlRcIjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEluc2VydHMgdGV4dCBpbnRvIHRoZSBnaXZlbiBlZGl0b3IsIGF0IHRvcC5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gZWRpdG9yXHJcbiAgICAgKiBAcGFyYW0gb3V0cHV0X21lc3NhZ2VcclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGluc2VydEludG9FZGl0b3IoZWRpdG9yOiBFZGl0b3IsIG91dHB1dF9tZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgICAgICBjb25zdCB0b3BfcG9zaXRpb24gPSBlZGl0b3Iub2Zmc2V0VG9Qb3MoMCk7XHJcbiAgICAgICAgZWRpdG9yLnJlcGxhY2VSYW5nZShvdXRwdXRfbWVzc2FnZSwgdG9wX3Bvc2l0aW9uKTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtPdXRwdXRDaGFubmVsfSBmcm9tIFwiLi9PdXRwdXRDaGFubmVsXCI7XHJcbmltcG9ydCB7RU9MfSBmcm9tIFwib3NcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBPdXRwdXRDaGFubmVsX1N0YXR1c0JhciBleHRlbmRzIE91dHB1dENoYW5uZWwge1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSB0aXRsZSA9IFwiU3RhdHVzIGJhclwiO1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBhY2NlcHRzX2VtcHR5X291dHB1dCA9IHRydWU7XHJcblxyXG4gICAgcHVibGljIHN0YXRpYyByZWFkb25seSBob3RrZXlfbGV0dGVyID0gXCJTXCI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBBbGwgcmVjZWl2ZWQgb3V0cHV0IGN1bXVsYXRpdmVseS4gU3Vic2VxdWVudCBoYW5kbGluZ3Mgd2lsbCB0aGVuIHVzZSB0aGUgd2hvbGUgb3V0cHV0LCBub3QganVzdCBuZXcgcGFydHMuXHJcbiAgICAgKiBPbmx5IHVzZWQgaW4gXCJyZWFsdGltZVwiIG1vZGUuXHJcbiAgICAgKlxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSByZWFsdGltZUNvbnRlbnRCdWZmZXIgPSBcIlwiO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ29tYmluZSBzdGRvdXQgYW5kIHN0ZGVyciAoaW4gY2FzZSBib3RoIG9mIHRoZW0gaGFwcGVuIHRvIGJlIHByZXNlbnQpLlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGNvbWJpbmVfb3V0cHV0X3N0cmVhbXMgPSBFT0wgKyBFT0w7XHJcblxyXG4gICAgcHVibGljIGFzeW5jIF9oYW5kbGVCdWZmZXJlZChvdXRwdXRDb250ZW50OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICB0aGlzLnNldFN0YXR1c0JhckNvbnRlbnQob3V0cHV0Q29udGVudCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGFzeW5jIF9oYW5kbGVSZWFsdGltZShvdXRwdXRDb250ZW50OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICB0aGlzLnJlYWx0aW1lQ29udGVudEJ1ZmZlciArPSBvdXRwdXRDb250ZW50O1xyXG4gICAgICAgIHRoaXMuc2V0U3RhdHVzQmFyQ29udGVudCh0aGlzLnJlYWx0aW1lQ29udGVudEJ1ZmZlcik7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBzZXRTdGF0dXNCYXJDb250ZW50KG91dHB1dENvbnRlbnQ6IHN0cmluZykge1xyXG4gICAgICAgIGNvbnN0IHN0YXR1c19iYXJfZWxlbWVudCA9IHRoaXMucGx1Z2luLmdldE91dHB1dFN0YXR1c0JhckVsZW1lbnQoKTtcclxuXHJcbiAgICAgICAgb3V0cHV0Q29udGVudCA9IG91dHB1dENvbnRlbnQudHJpbSgpO1xyXG5cclxuICAgICAgICAvLyBGdWxsIG91dHB1dCAoc2hvd24gd2hlbiBob3ZlcmluZyB3aXRoIG1vdXNlKVxyXG4gICAgICAgIHN0YXR1c19iYXJfZWxlbWVudC5zZXRBdHRyKFwiYXJpYS1sYWJlbFwiLCBvdXRwdXRDb250ZW50KTtcclxuXHJcbiAgICAgICAgLy8gU2hvdyBsYXN0IGxpbmUgcGVybWFuZW50bHkuXHJcbiAgICAgICAgY29uc3Qgb3V0cHV0X21lc3NhZ2VfbGluZXMgPSBvdXRwdXRDb250ZW50LnNwbGl0KC8oXFxyXFxufFxccnxcXG4pL3UpO1xyXG4gICAgICAgIGNvbnN0IGxhc3Rfb3V0cHV0X2xpbmUgPSBvdXRwdXRfbWVzc2FnZV9saW5lc1tvdXRwdXRfbWVzc2FnZV9saW5lcy5sZW5ndGggLSAxXTtcclxuICAgICAgICBzdGF0dXNfYmFyX2VsZW1lbnQuc2V0VGV4dChsYXN0X291dHB1dF9saW5lKTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtPdXRwdXRDaGFubmVsX0N1cnJlbnRGaWxlfSBmcm9tIFwiLi9PdXRwdXRDaGFubmVsX0N1cnJlbnRGaWxlXCI7XHJcbmltcG9ydCB7RWRpdG9yLCBFZGl0b3JQb3NpdGlvbn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZUJvdHRvbSBleHRlbmRzIE91dHB1dENoYW5uZWxfQ3VycmVudEZpbGUge1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSB0aXRsZSA9IFwiQ3VycmVudCBmaWxlOiBib3R0b21cIjtcclxuXHJcbiAgICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IGhvdGtleV9sZXR0ZXIgPSBcIkJcIjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEluc2VydHMgdGV4dCBpbnRvIHRoZSBnaXZlbiBlZGl0b3IsIGF0IGJvdHRvbS5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gZWRpdG9yXHJcbiAgICAgKiBAcGFyYW0gb3V0cHV0X21lc3NhZ2VcclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGluc2VydEludG9FZGl0b3IoZWRpdG9yOiBFZGl0b3IsIG91dHB1dF9tZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgICAgICBjb25zdCBib3R0b21fcG9zaXRpb246IEVkaXRvclBvc2l0aW9uID0ge1xyXG4gICAgICAgICAgICBjaDogZWRpdG9yLmdldExpbmUoZWRpdG9yLmxhc3RMaW5lKCkpLmxlbmd0aCwgICAvLyBUaGUgbGFzdCBjaGFyYWN0ZXIqIG9mIC4uLlxyXG4gICAgICAgICAgICBsaW5lOiBlZGl0b3IubGFzdExpbmUoKSwgICAgICAgICAgICAgICAgICAgICAgICAvLyAuLi4gdGhlIGxhc3QgbGluZS5cclxuICAgICAgICB9OyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gKikgQnV0IGRvIG5vdCBzdWJ0cmFjdCAxLCBiZWNhdXNlIGNoIGlzIHplcm8tYmFzZWQsIHNvIHdoZW4gLmxlbmd0aCBpcyB1c2VkIHdpdGhvdXQgLTEsIHdlIGFyZSBwb2ludGluZyBBRlRFUiB0aGUgbGFzdCBjaGFyYWN0ZXIuXHJcbiAgICAgICAgZWRpdG9yLnJlcGxhY2VSYW5nZShvdXRwdXRfbWVzc2FnZSwgYm90dG9tX3Bvc2l0aW9uKTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtPdXRwdXRDaGFubmVsfSBmcm9tIFwiLi9PdXRwdXRDaGFubmVsXCI7XHJcbmltcG9ydCB7Y29weVRvQ2xpcGJvYXJkfSBmcm9tIFwiLi4vQ29tbW9uXCI7XHJcbmltcG9ydCB7RU9MfSBmcm9tIFwib3NcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBPdXRwdXRDaGFubmVsX0NsaXBib2FyZCBleHRlbmRzIE91dHB1dENoYW5uZWwge1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSB0aXRsZSA9IFwiQ2xpcGJvYXJkXCI7XHJcblxyXG4gICAgcHVibGljIHN0YXRpYyByZWFkb25seSBob3RrZXlfbGV0dGVyID0gXCJMXCI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBBbGwgcmVjZWl2ZWQgb3V0cHV0IGN1bXVsYXRpdmVseS4gU3Vic2VxdWVudCBoYW5kbGluZ3Mgd2lsbCB0aGVuIHVzZSB0aGUgd2hvbGUgb3V0cHV0LCBub3QganVzdCBuZXcgcGFydHMuXHJcbiAgICAgKiBPbmx5IHVzZWQgaW4gXCJyZWFsdGltZVwiIG1vZGUuXHJcbiAgICAgKlxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSByZWFsdGltZUNvbnRlbnRCdWZmZXIgPSBcIlwiO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGhlcmUgY2FuIGJlIGJvdGggXCJzdGRvdXRcIiBhbmQgXCJzdGRlcnJcIiBwcmVzZW50IGF0IHRoZSBzYW1lIHRpbWUsIG9yIGp1c3Qgb25lIG9mIHRoZW0uIElmIGJvdGggYXJlIHByZXNlbnQsIHRoZXlcclxuICAgICAqIHdpbGwgYmUgam9pbmVkIHRvZ2V0aGVyIHdpdGggXCIgXCIgYXMgYSBzZXBhcmF0b3IuXHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgY29tYmluZV9vdXRwdXRfc3RyZWFtcyA9IFwiIFwiOyAvLyBUT0RPOiBDaGFuZ2UgdG8gXCJcIiBhcyB0aGVyZSBzaG91bGQgYmUgbm8gZXh0cmEgc3BhY2UgYmV0d2VlbiBzdGRvdXQgYW5kIHN0ZGVyci4gQ29tcGFyZSBpdCB0byB0aGUgdGVybWluYWw6IEFGQUlLIHRoZXJlIGlzIG5vIHNlcGFyYXRpb24gYmV0d2VlbiBzdGRvdXQgYW5kIHN0ZGVyciBvdXRwdXRzLCBqdXN0IHRoYXQgdHlwaWNhbGx5IGVhY2ggb3V0cHV0IGVuZHMgd2l0aCBhIG5ld2xpbmUuXHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIF9oYW5kbGVCdWZmZXJlZChvdXRwdXRDb250ZW50OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICBhd2FpdCBjb3B5VG9DbGlwYm9hcmQob3V0cHV0Q29udGVudCk7XHJcbiAgICAgICAgdGhpcy5ub3RpZnkob3V0cHV0Q29udGVudCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIF9oYW5kbGVSZWFsdGltZShvdXRwdXRDb250ZW50OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICB0aGlzLnJlYWx0aW1lQ29udGVudEJ1ZmZlciArPSBvdXRwdXRDb250ZW50O1xyXG4gICAgICAgIGF3YWl0IGNvcHlUb0NsaXBib2FyZCh0aGlzLnJlYWx0aW1lQ29udGVudEJ1ZmZlcik7XHJcbiAgICAgICAgdGhpcy5ub3RpZnkodGhpcy5yZWFsdGltZUNvbnRlbnRCdWZmZXIpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgbm90aWZ5KG91dHB1dF9tZXNzYWdlOiBzdHJpbmcpIHtcclxuICAgICAgICBpZiAodGhpcy5wbHVnaW4uc2V0dGluZ3Mub3V0cHV0X2NoYW5uZWxfY2xpcGJvYXJkX2Fsc29fb3V0cHV0c190b19ub3RpZmljYXRpb24pIHtcclxuICAgICAgICAgICAgLy8gTm90aWZ5IHRoZSB1c2VyIHNvIHRoZXkga25vdyBhKSB3aGF0IHdhcyBjb3BpZWQgdG8gY2xpcGJvYXJkLCBhbmQgYikgdGhhdCB0aGVpciBjb21tYW5kIGhhcyBmaW5pc2hlZCBleGVjdXRpb24uXHJcbiAgICAgICAgICAgIHRoaXMucGx1Z2luLm5ld05vdGlmaWNhdGlvbihcIkNvcGllZCB0byBjbGlwYm9hcmQ6IFwiICsgRU9MICsgb3V0cHV0X21lc3NhZ2UgKyBFT0wgKyBFT0wgKyBcIihOb3RpZmljYXRpb24gY2FuIGJlIHR1cm5lZCBvZmYgaW4gc2V0dGluZ3MuKVwiKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7SG90a2V5LCBNb2RpZmllciwgUGxhdGZvcm19IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuL21haW5cIjtcclxuaW1wb3J0IHtkZWJ1Z0xvZ30gZnJvbSBcIi4vRGVidWdcIjtcclxuXHJcbi8qKlxyXG4gKiBUT0RPOiBNb3ZlIHRoaXMgdG8gVFNoZWxsQ29tbWFuZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRIb3RrZXlzRm9yU2hlbGxDb21tYW5kKHBsdWdpbjogU0NfUGx1Z2luLCBzaGVsbF9jb21tYW5kX2lkOiBzdHJpbmcpOiBIb3RrZXlbXSB7XHJcbiAgICAvLyBSZXRyaWV2ZSBhbGwgaG90a2V5cyBzZXQgYnkgdXNlci5cclxuICAgIC8vIEB0cy1pZ25vcmVcclxuICAgIGNvbnN0IGFwcF9jdXN0b21faG90a2V5cyA9IHBsdWdpbi5hcHAuaG90a2V5TWFuYWdlcj8uY3VzdG9tS2V5cztcclxuICAgIGlmICghYXBwX2N1c3RvbV9ob3RrZXlzKSB7XHJcbiAgICAgICAgZGVidWdMb2coXCJnZXRIb3RrZXlzRm9yU2hlbGxDb21tYW5kKCkgZmFpbGVkLCB3aWxsIHJldHVybiBhbiBlbXB0eSBhcnJheS5cIik7XHJcbiAgICAgICAgcmV0dXJuIFtdO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCBvbmx5IG91ciBob3RrZXlzLlxyXG4gICAgY29uc3QgaG90a2V5X2luZGV4ID0gcGx1Z2luLmdldFBsdWdpbklkKCkgKyBcIjpcIiArIHBsdWdpbi5nZW5lcmF0ZU9ic2lkaWFuQ29tbWFuZElkKHNoZWxsX2NvbW1hbmRfaWQpOyAvLyBFLmcuIFwib2JzaWRpYW4tc2hlbGxjb21tYW5kczpzaGVsbC1jb21tYW5kLTBcIlxyXG4gICAgZGVidWdMb2coXCJnZXRIb3RrZXlzRm9yU2hlbGxDb21tYW5kKCkgc3VjY2VlZGVkLlwiKTtcclxuICAgIHJldHVybiBhcHBfY3VzdG9tX2hvdGtleXNbaG90a2V5X2luZGV4XSA/PyBbXTsgLy8gSWYgbm8gaG90a2V5IGFycmF5IGlzIHNldCBmb3IgdGhpcyBjb21tYW5kLCByZXR1cm4gYW4gZW1wdHkgYXJyYXkuIEFsdGhvdWdoIEkgZG8gYmVsaWV2ZSB0aGF0IGFsbCBjb21tYW5kcyBkbyBoYXZlIGFuIGFycmF5IGFueXdheSwgYnV0IGhhdmUgdGhpcyBjaGVjayBqdXN0IGluIGNhc2UuXHJcbn1cclxuXHJcbi8qKlxyXG4gKiBUT0RPOiBJcyB0aGVyZSBhIHdheSB0byBtYWtlIE9ic2lkaWFuIGRvIHRoaXMgY29udmVyc2lvbiBmb3IgdXM/IENoZWNrIHRoaXM6IGh0dHBzOi8vZ2l0aHViLmNvbS9wamVieS9ob3RrZXktaGVscGVyL2Jsb2IvYzhhMDMyZTRjNTJiZDljZTA4Y2I5MDljZWMxNWQxZWQ5ZDBhMzQzOS9zcmMvcGx1Z2luLmpzI0w0LUw2XHJcbiAqXHJcbiAqIEBwYXJhbSBob3RrZXlcclxuICogQGNvbnN0cnVjdG9yXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gSG90a2V5VG9TdHJpbmcoaG90a2V5OiBIb3RrZXkpIHtcclxuICAgIGNvbnN0IGtleXM6IHN0cmluZ1tdID0gW107XHJcbiAgICBob3RrZXkubW9kaWZpZXJzLmZvckVhY2goKG1vZGlmaWVyOiBNb2RpZmllcikgPT4ge1xyXG4gICAgICAgIGxldCBtb2RpZmllcl9rZXkgPSBtb2RpZmllci50b1N0cmluZygpOyAvLyBUaGlzIGlzIG9uZSBvZiAnTW9kJyB8ICdDdHJsJyB8ICdNZXRhJyB8ICdTaGlmdCcgfCAnQWx0J1xyXG4gICAgICAgIGlmIChcIk1vZFwiID09PSBtb2RpZmllcl9rZXkpIHtcclxuICAgICAgICAgICAgLy8gQ2hhbmdlIFwiTW9kXCIgdG8gc29tZXRoaW5nIG1vcmUgbWVhbmluZ2Z1bC5cclxuICAgICAgICAgICAgbW9kaWZpZXJfa2V5ID0gQ21kT3JDdHJsKCk7IC8vIGlzTWFjT1Mgc2hvdWxkIGFsc28gYmUgdHJ1ZSBpZiB0aGUgZGV2aWNlIGlzIGlQaG9uZS9pUGFkLiBDYW4gYmUgaGFuZHkgaWYgdGhpcyBwbHVnaW4gZ2V0cyBtb2JpbGUgc3VwcG9ydCBzb21lIGRheS5cclxuICAgICAgICB9XHJcbiAgICAgICAga2V5cy5wdXNoKG1vZGlmaWVyX2tleSk7XHJcbiAgICB9KTtcclxuICAgIGtleXMucHVzaChob3RrZXkua2V5KTsgLy8gVGhpcyBpcyBzb21ldGhpbmcgbGlrZSBhIGxldHRlciAoJ0EnLCAnQicgZXRjKSBvciBzcGFjZS9lbnRlci93aGF0ZXZlci5cclxuICAgIHJldHVybiBrZXlzLmpvaW4oXCIgKyBcIik7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBDbWRPckN0cmwoKTogXCJDbWRcIiB8IFwiQ3RybFwiIHtcclxuICAgIHJldHVybiBQbGF0Zm9ybS5pc01hY09TID8gXCJDbWRcIiA6IFwiQ3RybFwiO1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge091dHB1dENoYW5uZWx9IGZyb20gXCIuL091dHB1dENoYW5uZWxcIjtcclxuaW1wb3J0IHtcclxuICAgIGdldE91dHB1dENoYW5uZWxDbGFzc2VzLFxyXG4gICAgaW5pdGlhbGl6ZU91dHB1dENoYW5uZWwsXHJcbiAgICBPdXRwdXRTdHJlYW1zLFxyXG59IGZyb20gXCIuL091dHB1dENoYW5uZWxGdW5jdGlvbnNcIjtcclxuaW1wb3J0IHtTZXR0aW5nLCBUZXh0QXJlYUNvbXBvbmVudH0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7T3V0cHV0Q2hhbm5lbENvZGUsIE91dHB1dFN0cmVhbX0gZnJvbSBcIi4vT3V0cHV0Q2hhbm5lbENvZGVcIjtcclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi4vbWFpblwiO1xyXG5pbXBvcnQge1NoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQsIFRTaGVsbENvbW1hbmR9IGZyb20gXCIuLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7U0NfTW9kYWx9IGZyb20gXCIuLi9TQ19Nb2RhbFwiO1xyXG5pbXBvcnQge2dldFNlbGVjdGlvbkZyb21UZXh0YXJlYX0gZnJvbSBcIi4uL0NvbW1vblwiO1xyXG5pbXBvcnQge0NtZE9yQ3RybH0gZnJvbSBcIi4uL0hvdGtleXNcIjtcclxuaW1wb3J0IHtFT0x9IGZyb20gXCJvc1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIE91dHB1dENoYW5uZWxfTW9kYWwgZXh0ZW5kcyBPdXRwdXRDaGFubmVsIHtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgdGl0bGUgPSBcIkFzayBhZnRlciBleGVjdXRpb25cIjtcclxuXHJcbiAgICBwcml2YXRlIG1vZGFsOiBPdXRwdXRNb2RhbDtcclxuXHJcbiAgICBwcm90ZWN0ZWQgaW5pdGlhbGl6ZSgpOiB2b2lkIHtcclxuICAgICAgICAvLyBJbml0aWFsaXplIGEgbW9kYWwgKGJ1dCBkb24ndCBvcGVuIHlldClcclxuICAgICAgICB0aGlzLm1vZGFsID0gbmV3IE91dHB1dE1vZGFsKFxyXG4gICAgICAgICAgICB0aGlzLnBsdWdpbixcclxuICAgICAgICAgICAgdGhpcy50X3NoZWxsX2NvbW1hbmQsXHJcbiAgICAgICAgICAgIHRoaXMuc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdCxcclxuICAgICAgICAgICAgdGhpcy5wcm9jZXNzVGVybWluYXRvcixcclxuICAgICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBfaGFuZGxlQnVmZmVyZWQob3V0cHV0czogT3V0cHV0U3RyZWFtcywgZXJyb3JfY29kZTogbnVtYmVyIHwgbnVsbCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICAgIC8vIFBhc3Mgb3V0cHV0cyB0byBtb2RhbFxyXG4gICAgICAgIHRoaXMubW9kYWwuc2V0T3V0cHV0Q29udGVudHMob3V0cHV0cyk7XHJcblxyXG4gICAgICAgIC8vIERlZmluZSBhIHBvc3NpYmxlIGVycm9yIGNvZGUgdG8gYmUgc2hvd24gb24gdGhlIG1vZGFsLlxyXG4gICAgICAgIGlmIChlcnJvcl9jb2RlICE9PSBudWxsKSB7XHJcbiAgICAgICAgICAgIHRoaXMubW9kYWwuc2V0RXhpdENvZGUoZXJyb3JfY29kZSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBEb25lXHJcbiAgICAgICAgdGhpcy5tb2RhbC5vcGVuKCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIF9oYW5kbGVSZWFsdGltZShvdXRwdXRDb250ZW50OiBzdHJpbmcsIG91dHB1dFN0cmVhbU5hbWU6IE91dHB1dFN0cmVhbSk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICAgIHRoaXMubW9kYWwuYWRkT3V0cHV0Q29udGVudChvdXRwdXRTdHJlYW1OYW1lLCBvdXRwdXRDb250ZW50KTtcclxuICAgICAgICBpZiAoIXRoaXMubW9kYWwuaXNPcGVuKCkpIHtcclxuICAgICAgICAgICAgdGhpcy5tb2RhbC5vcGVuKCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIGV4aXRDb2RlIENhbiBiZSBudWxsIGlmIHVzZXIgdGVybWluYXRlZCB0aGUgcHJvY2VzcyBieSBjbGlja2luZyBhIGJ1dHRvbi4gSW4gb3RoZXIgcGxhY2VzIGV4aXRDb2RlIGNhbiBiZSBudWxsIGlmIHByb2Nlc3MgaXMgc3RpbGwgcnVubmluZywgYnV0IGhlcmUgdGhhdCBjYW5ub3QgYmUgdGhlIGNhc2UuXHJcbiAgICAgKlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgX2VuZFJlYWx0aW1lKGV4aXRDb2RlOiBudW1iZXIgfCBudWxsKSB7XHJcbiAgICAgICAgLy8gRGVsZXRlIHRlcm1pbmF0b3IgYnV0dG9uIGFzIHRoZSBwcm9jZXNzIGlzIGFscmVhZHkgZW5kZWQuXHJcbiAgICAgICAgdGhpcy5tb2RhbC5yZW1vdmVQcm9jZXNzVGVybWluYXRvckJ1dHRvbigpO1xyXG5cclxuICAgICAgICAvLyBQYXNzIGV4aXRDb2RlIHRvIHRoZSBtb2RhbFxyXG4gICAgICAgIHRoaXMubW9kYWwuc2V0RXhpdENvZGUoZXhpdENvZGUpO1xyXG4gICAgfVxyXG5cclxufVxyXG5cclxuY2xhc3MgT3V0cHV0TW9kYWwgZXh0ZW5kcyBTQ19Nb2RhbCB7XHJcblxyXG4gICAgcHJpdmF0ZSByZWFkb25seSB0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQ7XHJcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHQ6IFNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQ7XHJcbiAgICBwcml2YXRlIGV4aXRfY29kZTogbnVtYmVyIHwgbnVsbCA9IG51bGw7IC8vIFRPRE86IFRoaW5rIGFib3V0IGNoYW5naW5nIHRoZSBsb2dpYzogZXhpdCBjb2RlIGNvdWxkIGJlIHVuZGVmaW5lZCB3aGVuIGl0J3Mgbm90IHJlY2VpdmVkLCBhbmQgbnVsbCB3aGVuIGEgdXNlciBoYXMgdGVybWluYXRlZCB0aGUgZXhlY3V0aW9uLiBUaGUgY2hhbmdlIG5lZWRzIHRvIGJlIGRvbmUgaW4gdGhlIHdob2xlIHBsdWdpbiwgYWx0aG91Z2ggSSBvbmx5IHdyb3RlIGFib3V0IGl0IGluIHRoaXMgT3V0cHV0TW9kYWwgY2xhc3MuXHJcblxyXG4gICAgLy8gRmllbGRzIGFuZCBIVE1MIGVsZW1lbnRzXHJcbiAgICBwcml2YXRlIG91dHB1dEZpZWxkc0NvbnRhaW5lcjogSFRNTEVsZW1lbnQ7XHJcbiAgICBwcml2YXRlIHJlYWRvbmx5IG91dHB1dEZpZWxkczoge1trZXk6IHN0cmluZ106IFNldHRpbmd9ID0ge307XHJcbiAgICBwcml2YXRlIGV4aXRDb2RlRWxlbWVudDogSFRNTEVsZW1lbnQ7XHJcbiAgICBwcml2YXRlIHByb2Nlc3NUZXJtaW5hdG9yQnV0dG9uQ29udGFpbmVyOiBIVE1MRWxlbWVudDtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBwbHVnaW46IFNDX1BsdWdpbixcclxuICAgICAgICB0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQsXHJcbiAgICAgICAgc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdDogU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdCxcclxuICAgICAgICBwcml2YXRlIHByb2Nlc3NUZXJtaW5hdG9yOiAoKCkgPT4gdm9pZCkgfCBudWxsLFxyXG4gICAgKSB7XHJcbiAgICAgICAgc3VwZXIocGx1Z2luKTtcclxuXHJcbiAgICAgICAgdGhpcy50X3NoZWxsX2NvbW1hbmQgPSB0X3NoZWxsX2NvbW1hbmQ7XHJcbiAgICAgICAgdGhpcy5zaGVsbF9jb21tYW5kX3BhcnNpbmdfcmVzdWx0ID0gc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdDtcclxuXHJcbiAgICAgICAgdGhpcy5jcmVhdGVPdXRwdXRGaWVsZHMoKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENhbGxlZCB3aGVuIGRvaW5nIFwiYnVmZmVyZWRcIiBvdXRwdXQgaGFuZGxpbmcuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIG91dHB1dHNcclxuICAgICAqL1xyXG4gICAgcHVibGljIHNldE91dHB1dENvbnRlbnRzKG91dHB1dHM6IE91dHB1dFN0cmVhbXMpIHtcclxuICAgICAgICBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhvdXRwdXRzKS5mb3JFYWNoKChvdXRwdXRTdHJlYW1OYW1lOiBPdXRwdXRTdHJlYW0pID0+IHtcclxuICAgICAgICAgICAgY29uc3Qgb3V0cHV0RmllbGQ6IFNldHRpbmcgPSB0aGlzLm91dHB1dEZpZWxkc1tvdXRwdXRTdHJlYW1OYW1lXTtcclxuXHJcbiAgICAgICAgICAgIC8vIFNldCBmaWVsZCB2YWx1ZVxyXG4gICAgICAgICAgICBjb25zdCB0ZXh0YXJlYUNvbXBvbmVudCA9IG91dHB1dEZpZWxkLmNvbXBvbmVudHMuZmlyc3QoKSBhcyBUZXh0QXJlYUNvbXBvbmVudDtcclxuICAgICAgICAgICAgY29uc3Qgb3V0cHV0Q29udGVudCA9IG91dHB1dHNbb3V0cHV0U3RyZWFtTmFtZV07XHJcbiAgICAgICAgICAgIHRleHRhcmVhQ29tcG9uZW50LnNldFZhbHVlKG91dHB1dENvbnRlbnQgYXMgc3RyaW5nKTsgLy8gYXMgc3RyaW5nID0gb3V0cHV0Q29udGVudCBpcyBub3QgdW5kZWZpbmVkIGJlY2F1c2Ugb2YgdGhlIC5mb3JFYWNoKCkgbG9vcC5cclxuXHJcbiAgICAgICAgICAgIC8vIE1ha2UgZmllbGQgdmlzaWJsZSAoaWYgaXQncyBub3QgYWxyZWFkeSlcclxuICAgICAgICAgICAgb3V0cHV0RmllbGQuc2V0dGluZ0VsLm1hdGNoUGFyZW50KFwiLlNDLWhpZGVcIik/LnJlbW92ZUNsYXNzKFwiU0MtaGlkZVwiKTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENhbGxlZCB3aGVuIGRvaW5nIFwicmVhbHRpbWVcIiBvdXRwdXQgaGFuZGxpbmcuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIG91dHB1dFN0cmVhbU5hbWVcclxuICAgICAqIEBwYXJhbSBvdXRwdXRDb250ZW50XHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBhZGRPdXRwdXRDb250ZW50KG91dHB1dFN0cmVhbU5hbWU6IE91dHB1dFN0cmVhbSwgb3V0cHV0Q29udGVudDogc3RyaW5nKSB7XHJcbiAgICAgICAgY29uc3Qgb3V0cHV0RmllbGQ6IFNldHRpbmcgPSB0aGlzLm91dHB1dEZpZWxkc1tvdXRwdXRTdHJlYW1OYW1lXTtcclxuXHJcbiAgICAgICAgLy8gVXBkYXRlIGZpZWxkIHZhbHVlXHJcbiAgICAgICAgY29uc3QgdGV4dGFyZWFDb21wb25lbnQgPSBvdXRwdXRGaWVsZC5jb21wb25lbnRzLmZpcnN0KCkgYXMgVGV4dEFyZWFDb21wb25lbnQ7XHJcbiAgICAgICAgdGV4dGFyZWFDb21wb25lbnQuc2V0VmFsdWUodGV4dGFyZWFDb21wb25lbnQuZ2V0VmFsdWUoKSArIG91dHB1dENvbnRlbnQpO1xyXG5cclxuICAgICAgICAvLyBNYWtlIGZpZWxkIHZpc2libGUgKGlmIGl0J3Mgbm90IGFscmVhZHkpXHJcbiAgICAgICAgb3V0cHV0RmllbGQuc2V0dGluZ0VsLm1hdGNoUGFyZW50KFwiLlNDLWhpZGVcIik/LnJlbW92ZUNsYXNzKFwiU0MtaGlkZVwiKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgb25PcGVuKCk6IHZvaWQge1xyXG4gICAgICAgIHN1cGVyLm9uT3BlbigpO1xyXG4gICAgICAgIHRoaXMubW9kYWxFbC5hZGRDbGFzcyhcIlNDLW1vZGFsLW91dHB1dFwiKTtcclxuXHJcbiAgICAgICAgLy8gSGVhZGluZ1xyXG4gICAgICAgIGNvbnN0IGhlYWRpbmcgPSB0aGlzLnNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHQuYWxpYXM7XHJcbiAgICAgICAgdGhpcy50aXRsZUVsLmlubmVyVGV4dCA9IGhlYWRpbmcgPyBoZWFkaW5nIDogXCJTaGVsbCBjb21tYW5kIG91dHB1dFwiOyAgLy8gVE9ETzogVXNlIHRoaXMuc2V0VGl0bGUoKSBpbnN0ZWFkLlxyXG5cclxuICAgICAgICAvLyBTaGVsbCBjb21tYW5kIHByZXZpZXdcclxuICAgICAgICB0aGlzLm1vZGFsRWwuY3JlYXRlRWwoXCJwcmVcIiwge3RleHQ6IHRoaXMuc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdC5zaGVsbF9jb21tYW5kLCBhdHRyOiB7Y2xhc3M6IFwiU0Mtbm8tbWFyZ2luIFNDLXdyYXBwYWJsZVwifX0pOyAvLyBubyBtYXJnaW4gc28gdGhhdCBleGl0IGNvZGUgd2lsbCBiZSBjbG9zZS5cclxuXHJcbiAgICAgICAgLy8gQ29udGFpbmVyIGZvciB0ZXJtaW5hdGluZyBidXR0b24gYW5kIGV4aXQgY29kZVxyXG4gICAgICAgIGNvbnN0IHByb2Nlc3NSZXN1bHRDb250YWluZXIgPSB0aGlzLm1vZGFsRWwuY3JlYXRlRGl2KCk7XHJcblxyXG4gICAgICAgIC8vICdSZXF1ZXN0IHRvIHRlcm1pbmF0ZSB0aGUgcHJvY2VzcycgaWNvbiBidXR0b25cclxuICAgICAgICBpZiAodGhpcy5wcm9jZXNzVGVybWluYXRvcikge1xyXG4gICAgICAgICAgICB0aGlzLnByb2Nlc3NUZXJtaW5hdG9yQnV0dG9uQ29udGFpbmVyID0gcHJvY2Vzc1Jlc3VsdENvbnRhaW5lci5jcmVhdGVFbCgnc3BhbicpO1xyXG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5jcmVhdGVSZXF1ZXN0VGVybWluYXRpbmdCdXR0b24odGhpcy5wcm9jZXNzVGVybWluYXRvckJ1dHRvbkNvbnRhaW5lciwgdGhpcy5wcm9jZXNzVGVybWluYXRvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBFeGl0IGNvZGUgKHB1dCBvbiBzYW1lIGxpbmUgd2l0aCBwcm9jZXNzIHRlcm1pbmF0b3IgYnV0dG9uLCBpZiBleGlzdHMpXHJcbiAgICAgICAgdGhpcy5leGl0Q29kZUVsZW1lbnQgPSBwcm9jZXNzUmVzdWx0Q29udGFpbmVyLmNyZWF0ZUVsKFwic21hbGxcIiwge3RleHQ6IFwiRXhlY3V0aW5nLi4uXCIsIGF0dHI6IHtzdHlsZTogXCJmb250LXdlaWdodDogYm9sZDtcIn19KTsgLy8gU2hvdyBcIkV4ZWN1dGluZy4uLlwiIGJlZm9yZSBhbiBhY3R1YWwgZXhpdCBjb2RlIGlzIHJlY2VpdmVkLlxyXG4gICAgICAgIGlmICh0aGlzLmV4aXRfY29kZSAhPT0gbnVsbCkge1xyXG4gICAgICAgICAgICB0aGlzLmRpc3BsYXlFeGl0Q29kZSgpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gT3V0cHV0IGZpZWxkc1xyXG4gICAgICAgIHRoaXMubW9kYWxFbC5pbnNlcnRBZGphY2VudEVsZW1lbnQoXCJiZWZvcmVlbmRcIix0aGlzLm91dHB1dEZpZWxkc0NvbnRhaW5lcik7XHJcblxyXG4gICAgICAgIC8vIEZvY3VzIG9uIHRoZSBmaXJzdCBvdXRwdXQgZmllbGRcclxuICAgICAgICB0aGlzLmZvY3VzRmlyc3RGaWVsZCgpO1xyXG5cclxuICAgICAgICAvLyBBIHRpcCBhYm91dCBzZWxlY3RpbmcgdGV4dC5cclxuICAgICAgICB0aGlzLm1vZGFsRWwuY3JlYXRlRGl2KHtcclxuICAgICAgICAgICAgdGV4dDogXCJUaXAhIElmIHlvdSBzZWxlY3Qgc29tZXRoaW5nLCBvbmx5IHRoZSBzZWxlY3RlZCB0ZXh0IHdpbGwgYmUgdXNlZC5cIixcclxuICAgICAgICAgICAgYXR0cjoge2NsYXNzOiBcInNldHRpbmctaXRlbS1kZXNjcmlwdGlvblwiIC8qIEEgQ1NTIGNsYXNzIGRlZmluZWQgYnkgT2JzaWRpYW4uICovfSxcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGNyZWF0ZU91dHB1dEZpZWxkcygpIHtcclxuICAgICAgICAvLyBDcmVhdGUgYSBwYXJlbnQtbGVzcyBjb250YWluZXIuIG9uT3BlbigpIHdpbGwgcGxhY2UgaXQgaW4gdGhlIGNvcnJlY3QgcGxhY2UuXHJcbiAgICAgICAgdGhpcy5vdXRwdXRGaWVsZHNDb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGZpZWxkIGNvbnRhaW5lcnMgaW4gY29ycmVjdCBvcmRlclxyXG4gICAgICAgIGxldCBzdGRvdXRGaWVsZENvbnRhaW5lcjogSFRNTERpdkVsZW1lbnQ7XHJcbiAgICAgICAgbGV0IHN0ZGVyckZpZWxkQ29udGFpbmVyOiBIVE1MRGl2RWxlbWVudDtcclxuICAgICAgICBzd2l0Y2ggKHRoaXMudF9zaGVsbF9jb21tYW5kLmdldE91dHB1dENoYW5uZWxPcmRlcigpKSB7XHJcbiAgICAgICAgICAgIGNhc2UgXCJzdGRvdXQtZmlyc3RcIjoge1xyXG4gICAgICAgICAgICAgICAgc3Rkb3V0RmllbGRDb250YWluZXIgPSB0aGlzLm91dHB1dEZpZWxkc0NvbnRhaW5lci5jcmVhdGVEaXYoKTtcclxuICAgICAgICAgICAgICAgIHN0ZGVyckZpZWxkQ29udGFpbmVyID0gdGhpcy5vdXRwdXRGaWVsZHNDb250YWluZXIuY3JlYXRlRGl2KCk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBjYXNlIFwic3RkZXJyLWZpcnN0XCI6IHtcclxuICAgICAgICAgICAgICAgIHN0ZGVyckZpZWxkQ29udGFpbmVyID0gdGhpcy5vdXRwdXRGaWVsZHNDb250YWluZXIuY3JlYXRlRGl2KCk7XHJcbiAgICAgICAgICAgICAgICBzdGRvdXRGaWVsZENvbnRhaW5lciA9IHRoaXMub3V0cHV0RmllbGRzQ29udGFpbmVyLmNyZWF0ZURpdigpO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIENyZWF0ZSBmaWVsZHNcclxuICAgICAgICB0aGlzLm91dHB1dEZpZWxkcy5zdGRvdXQgPSB0aGlzLmNyZWF0ZU91dHB1dEZpZWxkKFwic3Rkb3V0XCIsIHN0ZG91dEZpZWxkQ29udGFpbmVyKTtcclxuICAgICAgICB0aGlzLm91dHB1dEZpZWxkcy5zdGRlcnIgPSB0aGlzLmNyZWF0ZU91dHB1dEZpZWxkKFwic3RkZXJyXCIsIHN0ZGVyckZpZWxkQ29udGFpbmVyKTtcclxuXHJcbiAgICAgICAgLy8gSGlkZSB0aGUgZmllbGRzJyBjb250YWluZXJzIGF0IHRoZSBiZWdpbm5pbmcuIFRoZXkgd2lsbCBiZSBzaG93biB3aGVuIGNvbnRlbnQgaXMgYWRkZWQuXHJcbiAgICAgICAgc3Rkb3V0RmllbGRDb250YWluZXIuYWRkQ2xhc3MoXCJTQy1oaWRlXCIpO1xyXG4gICAgICAgIHN0ZGVyckZpZWxkQ29udGFpbmVyLmFkZENsYXNzKFwiU0MtaGlkZVwiKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGNyZWF0ZU91dHB1dEZpZWxkKG91dHB1dF9zdHJlYW06IE91dHB1dFN0cmVhbSwgY29udGFpbmVyRWxlbWVudDogSFRNTEVsZW1lbnQpIHtcclxuICAgICAgICBsZXQgb3V0cHV0X3RleHRhcmVhOiBUZXh0QXJlYUNvbXBvbmVudDtcclxuXHJcbiAgICAgICAgY29udGFpbmVyRWxlbWVudC5jcmVhdGVFbChcImhyXCIsIHthdHRyOiB7Y2xhc3M6IFwiU0Mtbm8tbWFyZ2luXCJ9fSk7XHJcblxyXG4gICAgICAgIC8vIE91dHB1dCBzdHJlYW0gbmFtZVxyXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lckVsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKG91dHB1dF9zdHJlYW0pXHJcbiAgICAgICAgICAgIC5zZXRIZWFkaW5nKClcclxuICAgICAgICAgICAgLnNldENsYXNzKFwiU0Mtbm8tYm90dG9tLWJvcmRlclwiKVxyXG4gICAgICAgIDtcclxuXHJcbiAgICAgICAgLy8gVGV4dGFyZWFcclxuICAgICAgICBjb25zdCB0ZXh0YXJlYV9zZXR0aW5nID0gbmV3IFNldHRpbmcoY29udGFpbmVyRWxlbWVudClcclxuICAgICAgICAgICAgLmFkZFRleHRBcmVhKHRleHRhcmVhID0+IG91dHB1dF90ZXh0YXJlYSA9IHRleHRhcmVhKVxyXG4gICAgICAgIDtcclxuICAgICAgICB0ZXh0YXJlYV9zZXR0aW5nLmluZm9FbC5hZGRDbGFzcyhcIlNDLWhpZGVcIik7IC8vIE1ha2Ugcm9vbSBmb3IgdGhlIHRleHRhcmVhIGJ5IGhpZGluZyB0aGUgbGVmdCBjb2x1bW4uXHJcbiAgICAgICAgdGV4dGFyZWFfc2V0dGluZy5zZXR0aW5nRWwuYWRkQ2xhc3MoXCJTQy1vdXRwdXQtY2hhbm5lbC1tb2RhbC10ZXh0YXJlYS1jb250YWluZXJcIiwgXCJTQy1uby10b3AtYm9yZGVyXCIpO1xyXG5cclxuICAgICAgICAvLyBBZGQgY29udHJvbHMgZm9yIHJlZGlyZWN0aW5nIHRoZSBvdXRwdXQgdG8gYW5vdGhlciBjaGFubmVsLlxyXG4gICAgICAgIGNvbnN0IHJlZGlyZWN0X3NldHRpbmcgPSBuZXcgU2V0dGluZyhjb250YWluZXJFbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIlJlZGlyZWN0OlwiKVxyXG4gICAgICAgICAgICAuc2V0Q2xhc3MoXCJTQy1uby10b3AtYm9yZGVyXCIpXHJcbiAgICAgICAgICAgIC5zZXRDbGFzcyhcIlNDLW91dHB1dC1jaGFubmVsLW1vZGFsLXJlZGlyZWN0aW9uLWJ1dHRvbnMtY29udGFpbmVyXCIpIC8vIEkgdGhpbmsgdGhpcyBjYWxscyBhY3R1YWxseSBIVE1MRGl2RWxlbWVudC5hZGRDbGFzcygpLCBzbyBpdCBzaG91bGQgbm90IG92ZXJyaWRlIHRoZSBwcmV2aW91cyAuc2V0Q2xhc3MoKS5cclxuICAgICAgICA7XHJcbiAgICAgICAgY29uc3Qgb3V0cHV0Q2hhbm5lbHMgPSBnZXRPdXRwdXRDaGFubmVsQ2xhc3NlcygpO1xyXG4gICAgICAgIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKG91dHB1dENoYW5uZWxzKS5mb3JFYWNoKChvdXRwdXRfY2hhbm5lbF9uYW1lOiBPdXRwdXRDaGFubmVsQ29kZSkgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCBvdXRwdXRDaGFubmVsQ2xhc3MgPSBvdXRwdXRDaGFubmVsc1tvdXRwdXRfY2hhbm5lbF9uYW1lXTtcclxuXHJcbiAgICAgICAgICAgIC8vIEVuc3VyZSB0aGlzIGNoYW5uZWwgaXMgbm90IGV4Y2x1ZGVkIGJ5IGNoZWNraW5nIHRoYXQgaXMgaGFzIGEgaG90a2V5IGRlZmluZWQuXHJcbiAgICAgICAgICAgIGlmIChvdXRwdXRDaGFubmVsQ2xhc3MuaG90a2V5X2xldHRlcikge1xyXG4gICAgICAgICAgICAgICAgLy8gRW5zdXJlIHRoZSBvdXRwdXQgY2hhbm5lbCBhY2NlcHRzIHRoaXMgb3V0cHV0IHN0cmVhbS4gRS5nLiBPdXRwdXRDaGFubmVsX09wZW5GaWxlcyBkb2VzIG5vdCBhY2NlcHQgXCJzdGRlcnJcIi5cclxuICAgICAgICAgICAgICAgIGlmIChvdXRwdXRDaGFubmVsQ2xhc3MuYWNjZXB0c091dHB1dFN0cmVhbShvdXRwdXRfc3RyZWFtKSkge1xyXG5cclxuICAgICAgICAgICAgICAgICAgICBjb25zdCB0ZXh0YXJlYV9lbGVtZW50ID0gdGV4dGFyZWFfc2V0dGluZy5zZXR0aW5nRWwuZmluZChcInRleHRhcmVhXCIpIGFzIEhUTUxUZXh0QXJlYUVsZW1lbnQ7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vIERlZmluZSBhbiBvdXRwdXQgaGFuZGxlclxyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGhhbmRsZV9vdXRwdXQgPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlZGlyZWN0IG91dHB1dCB0byB0aGUgc2VsZWN0ZWQgY2hhbm5lbFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBvdXRwdXRfc3RyZWFtczogT3V0cHV0U3RyZWFtcyA9IHt9O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBvdXRwdXRfc3RyZWFtc1tvdXRwdXRfc3RyZWFtXSA9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZXRTZWxlY3Rpb25Gcm9tVGV4dGFyZWEodGV4dGFyZWFfZWxlbWVudCwgdHJ1ZSkgLy8gVXNlIHRoZSBzZWxlY3Rpb24sIG9yLi4uXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA/PyBvdXRwdXRfdGV4dGFyZWEuZ2V0VmFsdWUoKSAvLyAuLi51c2UgdGhlIHdob2xlIHRleHQsIGlmIG5vdGhpbmcgaXMgc2VsZWN0ZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgb3V0cHV0Q2hhbm5lbCA9IGluaXRpYWxpemVPdXRwdXRDaGFubmVsKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0X2NoYW5uZWxfbmFtZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy50X3NoZWxsX2NvbW1hbmQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImJ1ZmZlcmVkXCIsIC8vIFVzZSBcImJ1ZmZlcmVkXCIgbW9kZSBldmVuIGlmIHRoaXMgbW9kYWwgd2FzIG9wZW5lZCBpbiBcInJlYWx0aW1lXCIgbW9kZSwgYmVjYXVzZSBhdCB0aGlzIHBvaW50IHRoZSBvdXRwdXQgcmVkaXJlY3Rpb24gaXMgYSBzaW5nbGUtdGltZSBqb2IsIG5vdCByZWN1cnJpbmcuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnByb2Nlc3NUZXJtaW5hdG9yLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBvdXRwdXRDaGFubmVsLmhhbmRsZUJ1ZmZlcmVkKG91dHB1dF9zdHJlYW1zLCB0aGlzLmV4aXRfY29kZSwgZmFsc2UpOyAvLyBmYWxzZTogRGlzYWJsZSBvdXRwdXQgd3JhcHBpbmcgYXMgaXQncyBhbHJlYWR5IHdyYXBwZWQgYmVmb3JlIHRoZSBvdXRwdXQgY29udGVudCB3YXMgcGFzc2VkIHRvIHRoaXMgbW9kYWwuXHJcbiAgICAgICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gQ3JlYXRlIHRoZSBidXR0b25cclxuICAgICAgICAgICAgICAgICAgICByZWRpcmVjdF9zZXR0aW5nLmFkZEJ1dHRvbigoYnV0dG9uKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b24ub25DbGljayhhc3luYyAoZXZlbnQ6IE1vdXNlRXZlbnQpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgb3V0cHV0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgaGFuZGxlX291dHB1dCgpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGaW5pc2hcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZXZlbnQuY3RybEtleSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTcGVjaWFsIGNsaWNrLCBjb250cm9sL2NvbW1hbmQga2V5IGlzIHByZXNzZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENsb3NlIHRoZSBtb2RhbC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jbG9zZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5vcm1hbCBjbGljaywgY29udHJvbCBrZXkgaXMgbm90IHByZXNzZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERvIG5vdCBjbG9zZSB0aGUgbW9kYWwuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHRhcmVhX2VsZW1lbnQuZm9jdXMoKTsgLy8gQnJpbmcgdGhlIGZvY3VzIGJhY2sgdG8gdGhlIHRleHRhcmVhIGluIG9yZGVyIHRvIHNob3cgYSBwb3NzaWJsZSBoaWdobGlnaHQgKD1zZWxlY3Rpb24pIGFnYWluLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERlZmluZSBidXR0b24gdGV4dHMgYW5kIGFzc2lnbiBob3RrZXlzXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBvdXRwdXRfY2hhbm5lbF90aXRsZTogc3RyaW5nID0gb3V0cHV0Q2hhbm5lbENsYXNzLmdldFRpdGxlKG91dHB1dF9zdHJlYW0pO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEJ1dHRvbiB0ZXh0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b24uc2V0QnV0dG9uVGV4dChvdXRwdXRfY2hhbm5lbF90aXRsZSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGlwcyBhYm91dCBob3RrZXlzXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b24uc2V0VG9vbHRpcChcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgUmVkaXJlY3Q6IE5vcm1hbCBjbGljayBPUiAke0NtZE9yQ3RybCgpfSArICR7b3V0cHV0Q2hhbm5lbENsYXNzLmhvdGtleV9sZXR0ZXJ9LmBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICArIEVPTCArIEVPTCArXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFJlZGlyZWN0IGFuZCBjbG9zZSB0aGUgbW9kYWw6ICR7Q21kT3JDdHJsKCl9ICsgY2xpY2sgT1IgJHtDbWRPckN0cmwoKX0gKyBTaGlmdCArICR7b3V0cHV0Q2hhbm5lbENsYXNzLmhvdGtleV9sZXR0ZXJ9LmBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gMS4gaG90a2V5OiBDdHJsL0NtZCArIG51bWJlcjogaGFuZGxlIG91dHB1dFxyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2NvcGUucmVnaXN0ZXIoW1wiQ3RybFwiXSwgb3V0cHV0Q2hhbm5lbENsYXNzLmhvdGtleV9sZXR0ZXIsIGhhbmRsZV9vdXRwdXQpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyAyLiBob3RrZXk6IEN0cmwvQ21kICsgU2hpZnQgKyBudW1iZXI6IGhhbmRsZSBvdXRwdXQgYW5kIGNsb3NlIHRoZSBtb2RhbC5cclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnNjb3BlLnJlZ2lzdGVyKFtcIkN0cmxcIiwgXCJTaGlmdFwiXSwgb3V0cHV0Q2hhbm5lbENsYXNzLmhvdGtleV9sZXR0ZXIsICgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlX291dHB1dCgpLnRoZW4oKTsgLy8gdGhlbigpOiBObyBuZWVkIHRvIHdhaXQgZm9yIG91dHB1dCBoYW5kbGluZyB0byBmaW5pc2ggYmVmb3JlIGNsb3NpbmcgdGhlIG1vZGFsLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNsb3NlKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgcmV0dXJuIHRleHRhcmVhX3NldHRpbmc7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIHJlbW92ZVByb2Nlc3NUZXJtaW5hdG9yQnV0dG9uKCkge1xyXG4gICAgICAgIGlmICh0aGlzLnByb2Nlc3NUZXJtaW5hdG9yQnV0dG9uQ29udGFpbmVyKSB7XHJcbiAgICAgICAgICAgIHRoaXMucHJvY2Vzc1Rlcm1pbmF0b3JCdXR0b25Db250YWluZXIucmVtb3ZlKCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogU2hvdWxkIGJlIGNhbGxlZCBvbmx5IGlmIGFuIGV4aXQgY29kZSB3YXMgcmVjZWl2ZWQuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIGV4aXRfY29kZSBDYW4gYmUgbnVsbCBpZiB1c2VyIHRlcm1pbmF0ZWQgdGhlIHByb2Nlc3MgYnkgY2xpY2tpbmcgYSBidXR0b24uXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBzZXRFeGl0Q29kZShleGl0X2NvZGU6IG51bWJlciB8IG51bGwpIHtcclxuICAgICAgICB0aGlzLmV4aXRfY29kZSA9IGV4aXRfY29kZTtcclxuXHJcbiAgICAgICAgLy8gVHJ5IHRvIHNob3cgdGhlIGV4aXQgY29kZS5cclxuICAgICAgICBpZiAodGhpcy5pc09wZW4oKSkge1xyXG4gICAgICAgICAgICBpZiAobnVsbCA9PT0gdGhpcy5leGl0X2NvZGUpIHtcclxuICAgICAgICAgICAgICAgIC8vIFVzZXIgaGFzIHRlcm1pbmF0ZWQgdGhlIHByb2Nlc3MsIHNvIHRoZXJlJ3Mgbm8gZXhpdCBjb2RlIGV2ZW4gdGhvdWdoIHRoZSBwcm9jZXNzIGhhcyBlbmRlZC5cclxuICAgICAgICAgICAgICAgIHRoaXMuZXhpdENvZGVFbGVtZW50LmlubmVyVGV4dCA9IFwiVXNlciB0ZXJtaW5hdGVkXCI7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBkaXNwbGF5RXhpc3RDb2RlKCkgY2FuIG9ubHkgYmUgY2FsbGVkIGlmIG9uT3BlbigpIGhhcyBiZWVuIGNhbGxlZCBiZWZvcmUuXHJcbiAgICAgICAgICAgICAgICAvLyBJZiBvbk9wZW4oKSB3aWxsIGJlIGNhbGxlZCBsYXRlciwgaXQgd2lsbCBjYWxsIGRpc3BsYXlFeGl0Q29kZSgpIGl0c2VsZiB3aGVuIGl0IHNlZXMgdGhhdCB0aGlzLmV4aXRfY29kZSBpcyBkZWZpbmVkLlxyXG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwbGF5RXhpdENvZGUoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGRpc3BsYXlFeGl0Q29kZSgpIHtcclxuICAgICAgICBpZiAobnVsbCA9PT0gdGhpcy5leGl0X2NvZGUpIHtcclxuICAgICAgICAgICAgLy8gQ3VycmVudGx5IHRoZXJlIGFyZSB0d28gY2FsbGVycyBmb3IgdGhpcyBtZXRob2QsIGFuZCBib3RoIG9mIHRoZW0gZG9lcyBhIG51bGwgY2hlY2sgb24gdGhlIGV4aXQgY29kZSBiZWZvcmUnXHJcbiAgICAgICAgICAgIC8vIHRoZSBjYWxsLCBzbyB3ZSdsbCBuZXZlciBnZXQgaGVyZSBpbiBwcmFjdGlzZS5cclxuICAgICAgICAgICAgLy8gVE9ETzogUmVtb3ZlIHRoaXMgY2hlY2tpbmcvdGhyb3dpbmcgYW5kIG1ha2UgdGhpcyBtZXRob2QgYWJsZSB0byBkaXNwbGF5IHRocmVlIHRleHRzOiBhKSBhbiBleGl0IGNvZGUsIGIpIEV4ZWN1dGluZy4uLiwgb3IgYykgVXNlciB0ZXJtaW5hdGVkLlxyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgZGlzcGxheSBleGl0IGNvZGUgYmVjYXVzZSBpdCdzIG51bGxcIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuZXhpdENvZGVFbGVtZW50LmlubmVyVGV4dCA9IFwiRXhpdCBjb2RlOiBcIiArIHRoaXMuZXhpdF9jb2RlLnRvU3RyaW5nKCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBmb2N1c0ZpcnN0RmllbGQoKSB7XHJcbiAgICAgICAgc3dpdGNoICh0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRPdXRwdXRDaGFubmVsT3JkZXIoKSkge1xyXG4gICAgICAgICAgICBjYXNlIFwic3Rkb3V0LWZpcnN0XCI6IHtcclxuICAgICAgICAgICAgICAgIHRoaXMub3V0cHV0RmllbGRzLnN0ZG91dC5jb250cm9sRWwuZmluZChcInRleHRhcmVhXCIpLmZvY3VzKCk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBjYXNlIFwic3RkZXJyLWZpcnN0XCI6IHtcclxuICAgICAgICAgICAgICAgIHRoaXMub3V0cHV0RmllbGRzLnN0ZGVyci5jb250cm9sRWwuZmluZChcInRleHRhcmVhXCIpLmZvY3VzKCk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgYXBwcm92ZSgpOiB2b2lkIHtcclxuICAgICAgICAvLyBObyBuZWVkIHRvIHBlcmZvcm0gYW55IGFjdGlvbiwganVzdCBjbG9zZSB0aGUgbW9kYWwuXHJcbiAgICAgICAgdGhpcy5jbG9zZSgpO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge091dHB1dENoYW5uZWx9IGZyb20gXCIuL091dHB1dENoYW5uZWxcIjtcclxuaW1wb3J0IHtPdXRwdXRTdHJlYW1zfSBmcm9tIFwiLi9PdXRwdXRDaGFubmVsRnVuY3Rpb25zXCI7XHJcbmltcG9ydCB7T3V0cHV0U3RyZWFtfSBmcm9tIFwiLi9PdXRwdXRDaGFubmVsQ29kZVwiO1xyXG5pbXBvcnQge1xyXG4gICAgRWRpdG9yU2VsZWN0aW9uT3JDYXJldCxcclxuICAgIG5vcm1hbGl6ZVBhdGgsXHJcbiAgICBQYW5lVHlwZSxcclxufSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHtcclxuICAgIGdldEVkaXRvcixcclxuICAgIGdldFZhdWx0QWJzb2x1dGVQYXRoLFxyXG4gICAgaXNJbnRlZ2VyLFxyXG4gICAgaXNXaW5kb3dzLFxyXG4gICAgcHJlcGFyZUVkaXRvclBvc2l0aW9uLFxyXG59IGZyb20gXCIuLi9Db21tb25cIjtcclxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwicGF0aFwiO1xyXG5pbXBvcnQge0VPTH0gZnJvbSBcIm9zXCI7XHJcbmltcG9ydCB7ZGVidWdMb2d9IGZyb20gXCIuLi9EZWJ1Z1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIE91dHB1dENoYW5uZWxfT3BlbkZpbGVzIGV4dGVuZHMgT3V0cHV0Q2hhbm5lbCB7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IHRpdGxlID0gXCJPcGVuIGZpbGVzXCI7XHJcblxyXG4gICAgcHVibGljIHN0YXRpYyByZWFkb25seSBob3RrZXlfbGV0dGVyID0gXCJPXCI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUaGlzIG91dHB1dCBjaGFubmVsIGlzIG5vdCBzdWl0YWJsZSBmb3Igc3RkZXJyLCBhcyBzdGRlcnIgY2FuIGNvbnRhaW4gdW5leHBlY3RlZCBtZXNzYWdlcy5cclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBhY2NlcHRlZF9vdXRwdXRfc3RyZWFtczogT3V0cHV0U3RyZWFtW10gPSBbXCJzdGRvdXRcIl07XHJcblxyXG4gICAgcHJvdGVjdGVkIF9oYW5kbGVCdWZmZXJlZChvdXRwdXQ6IE91dHB1dFN0cmVhbXMsIGVycm9yX2NvZGU6IG51bWJlciB8IG51bGwpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICBsZXQgaGFuZGxpbmdQaXBlbGluZSA9IFByb21pc2UucmVzb2x2ZSgpO1xyXG4gICAgICAgIGxldCBvdXRwdXRfc3RyZWFtX25hbWU6IE91dHB1dFN0cmVhbTtcclxuICAgICAgICBmb3IgKG91dHB1dF9zdHJlYW1fbmFtZSBpbiBvdXRwdXQpIHtcclxuICAgICAgICAgICAgaGFuZGxpbmdQaXBlbGluZSA9IGhhbmRsaW5nUGlwZWxpbmUuZmluYWxseSgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5oYW5kbGUob3V0cHV0W291dHB1dF9zdHJlYW1fbmFtZV0gYXMgc3RyaW5nKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBoYW5kbGluZ1BpcGVsaW5lO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBfaGFuZGxlUmVhbHRpbWUob3V0cHV0Q29udGVudDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuaGFuZGxlKG91dHB1dENvbnRlbnQpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgaGFuZGxlKG91dHB1dENvbnRlbnQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xyXG4gICAgICAgICAgICAvLyBSZWFkIGZpbGUgZGVmaW5pdGlvbnMuIFVzdWFsbHkgdGhlcmUncyBqdXN0IG9uZSwgYnV0IHRoZXJlIGNhbiBiZSBtYW55LiBEZWZpbml0aW9ucyBhcmUgc2VwYXJhdGVkIGJ5IG5ld2xpbmVcclxuICAgICAgICAgICAgLy8gY2hhcmFjdGVycy4gRWFjaCBmaWxlIGRlZmluaXRpb24gZGVmaW5lcyBvbmUgZmlsZSB0byBiZSBvcGVuZWQuXHJcbiAgICAgICAgICAgIGNvbnN0IGZpbGVfZGVmaW5pdGlvbnNfc3RyaW5nID0gb3V0cHV0Q29udGVudC50cmltKCk7IC8vIENvbnRhaW5zIGF0IGxlYXN0IGZpbGUgbmFtZShzKSwgYW5kIE1BWUJFOiBhIGNhcmV0IHBvc2l0aW9uLCBuZXcgcGFuZSBvcHRpb24sIGFuZCB2aWV3IHN0YXRlXHJcbiAgICAgICAgICAgIGNvbnN0IGZpbGVfZGVmaW5pdGlvbnMgPSBmaWxlX2RlZmluaXRpb25zX3N0cmluZy5zcGxpdCgvW1xcclxcbl0rL3UpO1xyXG5cclxuICAgICAgICAgICAgLy8gSXRlcmF0ZSBhbGwgZmlsZSBkZWZpbml0aW9ucyB0aGF0IHNob3VsZCBiZSBvcGVuZWQuXHJcbiAgICAgICAgICAgIGxldCBvcGVuaW5nX3BpcGVsaW5lID0gUHJvbWlzZS5yZXNvbHZlKCk7XHJcbiAgICAgICAgICAgIGZvciAoY29uc3QgZmlsZV9kZWZpbml0aW9uIG9mIGZpbGVfZGVmaW5pdGlvbnMpIHtcclxuICAgICAgICAgICAgICAgIC8vIENoYWluIGVhY2ggZmlsZSBvcGVuaW5nIHRvIGhhcHBlbiBvbmUgYWZ0ZXIgYW5vdGhlci4gSWYgb25lIGZpbGUgb3BlbmluZyBmYWlscyBmb3Igd2hhdGV2ZXIgcmVhc29uLCBpdFxyXG4gICAgICAgICAgICAgICAgLy8gaXMgb2sgdG8gY29udGludWUgdG8gb3BlbiB0aGUgbmV4dCBmaWxlLiBUaGlzIGlzIHdoeSAuZmluYWxseSgpIGlzIHVzZWQgaW5zdGVhZCBvZiAudGhlbigpLlxyXG4gICAgICAgICAgICAgICAgb3BlbmluZ19waXBlbGluZSA9IG9wZW5pbmdfcGlwZWxpbmUuZmluYWxseSgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuaW50ZXJwcmV0RmlsZU9wZW5pbmdEZWZpbml0aW9uKGZpbGVfZGVmaW5pdGlvbik7XHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgb3BlbmluZ19waXBlbGluZS5maW5hbGx5KCgpID0+IHJlc29sdmUoKSAvKiBUZWxsIHRoYXQgYWxsIG9wZW5pbmdzIGhhdmUgYmVlbiBwcm9jZXNzZWQuICovKTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGludGVycHJldEZpbGVPcGVuaW5nRGVmaW5pdGlvbihmaWxlX2RlZmluaXRpb246IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAgICAgICAgIGRlYnVnTG9nKFwiT3V0cHV0Q2hhbm5lbF9PcGVuRmlsZXM6IEludGVycHJldGluZyBmaWxlIG9wZW5pbmcgZGVmaW5pdGlvbjogXCIgKyBmaWxlX2RlZmluaXRpb24pO1xyXG4gICAgICAgICAgICAvLyBHZXQgcGFydHMgdGhhdCBkZWZpbmUgZGlmZmVyZW50IGRldGFpbHMgYWJvdXQgaG93IHRoZSBmaWxlIHNob3VsZCBiZSBvcGVuZWRcclxuICAgICAgICAgICAgY29uc3QgZmlsZV9kZWZpbml0aW9uX3BhcnRzOiBzdHJpbmdbXSA9IGZpbGVfZGVmaW5pdGlvbi5zcGxpdChcIjpcIik7IC8vIElmIGZpbGVfZGVmaW5pdGlvbiBpcyBcIlwiLCBpLmUuIGFuIGVtcHR5IHN0cmluZywgdGhlIHJlc3VsdCB3aWxsIGJlIFtcIlwiXSwgaS5lLiBhbiBhcnJheSB3aXRoIGFuIGVtcHR5IHN0cmluZyBhcyBpdHMgb25seSBpdGVtLlxyXG5cclxuICAgICAgICAgICAgLy8gVGhlIGZpcnN0IHBhcnQgaXMgYWx3YXlzIHRoZSBmaWxlIHBhdGhcclxuICAgICAgICAgICAgbGV0IG9wZW5fZmlsZV9wYXRoOiBzdHJpbmcgPSBmaWxlX2RlZmluaXRpb25fcGFydHMuc2hpZnQoKSBhcyBzdHJpbmc7IC8vIElmIGZpbGVfZGVmaW5pdGlvbiBpcyBcIlwiLCB0aGlzIHdpbGwgYmUgXCJcIiwgdG9vLiAnYXMgc3RyaW5nJyBpcyB1c2VkIGJlY2F1c2UgZmlsZV9kZWZpbml0aW9uX3BhcnRzIGlzIG5ldmVyIGVtcHR5IChpdCBhbHdheXMgY29udGFpbnMgYXQgbGVhc3Qgb25lIGl0ZW0pLCBzbyAuc2hpZnQoKSB3aWxsIG5ldmVyIHJldHVybiB1bmRlZmluZWQgaGVyZS5cclxuXHJcbiAgICAgICAgICAgIC8vIE9uIFdpbmRvd3M6IENoZWNrIGlmIGFuIGFic29sdXRlIHBhdGggd2FzIHNwbGl0IGluY29ycmVjdGx5LiAoRS5nLiBhIHBhdGggc3RhcnRpbmcgd2l0aCBcIkM6XFwuLi5cIikuXHJcbiAgICAgICAgICAgIGlmIChpc1dpbmRvd3MoKSAmJiBmaWxlX2RlZmluaXRpb25fcGFydHMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgY29tYmluZWRfcGF0aDogc3RyaW5nID0gb3Blbl9maWxlX3BhdGggKyBcIjpcIiArIGZpbGVfZGVmaW5pdGlvbl9wYXJ0c1swXTtcclxuICAgICAgICAgICAgICAgIGlmIChwYXRoLmlzQWJzb2x1dGUoY29tYmluZWRfcGF0aCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBZZXMsIHRoZSBmaXJzdCB0d28gcGFydHMgZG8gZm9ybSBhbiBhYnNvbHV0ZSBwYXRoIHRvZ2V0aGVyLCBzbyB0aGV5IHNob3VsZCBub3QgYmUgc3BsaXQuXHJcbiAgICAgICAgICAgICAgICAgICAgb3Blbl9maWxlX3BhdGggPSBjb21iaW5lZF9wYXRoO1xyXG4gICAgICAgICAgICAgICAgICAgIGZpbGVfZGVmaW5pdGlvbl9wYXJ0cy5zaGlmdCgpOyAvLyBSZW1vdmUgdGhlIHNlY29uZCBwYXJ0IHNvIHRoYXQgaXQgd29uJ3QgYmUgYWNjaWRlbnRhbGx5IHByb2Nlc3NlZCBpbiB0aGUgJ1NwZWNpYWwgZmVhdHVyZXMnIHBhcnQuXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIFRyaW0gdGhlIGZpbGUgcGF0aCwgZm9yIGJlaW5nIGFibGUgdG8gdXNlIGNsZWFuZXIgc2VwYXJhdGlvbiBiZXR3ZWVuIGZpbGUgbmFtZSBhbmQgb3RoZXIgcGFydHMsIGUuZzogTXlGaWxlLm1kIDogbmV3LXBhbmVcclxuICAgICAgICAgICAgb3Blbl9maWxlX3BhdGggPSBvcGVuX2ZpbGVfcGF0aC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBTcGVjaWFsIGZlYXR1cmVzXHJcbiAgICAgICAgICAgIGNvbnN0IGNhcmV0X3BhcnRzOiBudW1iZXJbXSA9IFtdOyAvLyBJZiBjYXJldCBwb3NpdGlvbiBpcyBwcmVzZW50IGluIGZpbGVfZGVmaW5pdGlvbl9wYXJ0cywgdGhlIGZpcnN0IGl0ZW0gaW4gdGhpcyBhcnJheSB3aWxsIGJlIHRoZSBjYXJldCBsaW5lLCB0aGUgc2Vjb25kIHdpbGwgYmUgdGhlIGNvbHVtbi4gSWYgbW9yZSBwYXJ0cyBhcmUgcHJlc2VudCwgdGhleSB3aWxsIGJlIHVzZWQgZm9yIG1ha2luZyBzZWxlY3Rpb25zLlxyXG4gICAgICAgICAgICBsZXQgbmV3TGVhZjogUGFuZVR5cGUgfCBmYWxzZSA9IGZhbHNlO1xyXG4gICAgICAgICAgICBsZXQgY2FuX2NyZWF0ZV9maWxlID0gZmFsc2U7XHJcbiAgICAgICAgICAgIGxldCBmaWxlX2RlZmluaXRpb25faW50ZXJwcmV0aW5nX2ZhaWxlZCA9IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgZmlsZV9kZWZpbml0aW9uX3BhcnRzLmZvckVhY2goKGZpbGVfZGVmaW5pdGlvbl9wYXJ0OiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgICAgIGZpbGVfZGVmaW5pdGlvbl9wYXJ0ID0gZmlsZV9kZWZpbml0aW9uX3BhcnQudG9Mb2NhbGVMb3dlckNhc2UoKS50cmltKCk7IC8vIC50cmltKCkgaXMgZm9yIGJlaW5nIGFibGUgdG8gdXNlIGNsZWFuZXIgc2VwYXJhdGlvbiBiZXR3ZWVuIGUuZy4gZGlmZmVyZW50IHNlbGVjdGlvbnM6IE15RmlsZS5tZDoxOjE6MTotMSA6IDU6MTo1Oi0xXHJcblxyXG4gICAgICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIHRoZSBwYXJ0IHR5cGVcclxuICAgICAgICAgICAgICAgIGlmIChpc0ludGVnZXIoZmlsZV9kZWZpbml0aW9uX3BhcnQsIHRydWUpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyBpcyBhIG51bWJlciwgc28gY29uc2lkZXIgaXQgYXMgYSBjYXJldCBwb3NpdGlvbiBwYXJ0LlxyXG4gICAgICAgICAgICAgICAgICAgIGNhcmV0X3BhcnRzLnB1c2gocGFyc2VJbnQoZmlsZV9kZWZpbml0aW9uX3BhcnQpKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbXVsdGlwbGVOZXdQYXJ0c0Vycm9yTWVzc2FnZSA9IFwiQ2Fubm90IG9wZW4gZmlsZTogT25seSBvbmUgb2YgdGhlIGZvbGxvd2luZyBjYW4gYmUgZGVmaW5lZDogbmV3LXBhbmUsIG5ldy10YWIsIG9yIG5ldy13aW5kb3cuXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChmaWxlX2RlZmluaXRpb25fcGFydCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwibmV3LXBhbmVcIjpcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEVuc3VyZSBubyBuZXctKiBkZWZpbml0aW9uIGlzIHVzZWQgYmVmb3JlLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5ld0xlYWYgPT09IGZhbHNlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3TGVhZiA9IFwic3BsaXRcIjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3RXJyb3IobXVsdGlwbGVOZXdQYXJ0c0Vycm9yTWVzc2FnZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZV9kZWZpbml0aW9uX2ludGVycHJldGluZ19mYWlsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJuZXctdGFiXCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBFbnN1cmUgbm8gbmV3LSogZGVmaW5pdGlvbiBpcyB1c2VkIGJlZm9yZS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChuZXdMZWFmID09PSBmYWxzZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld0xlYWYgPSBcInRhYlwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5uZXdFcnJvcihtdWx0aXBsZU5ld1BhcnRzRXJyb3JNZXNzYWdlKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2RlZmluaXRpb25faW50ZXJwcmV0aW5nX2ZhaWxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSBcIm5ldy13aW5kb3dcIjpcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEVuc3VyZSBubyBuZXctKiBkZWZpbml0aW9uIGlzIHVzZWQgYmVmb3JlLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5ld0xlYWYgPT09IGZhbHNlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3TGVhZiA9IFwid2luZG93XCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLm5ld0Vycm9yKG11bHRpcGxlTmV3UGFydHNFcnJvck1lc3NhZ2UpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGVfZGVmaW5pdGlvbl9pbnRlcnByZXRpbmdfZmFpbGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiY2FuLWNyZWF0ZS1maWxlXCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYW5fY3JlYXRlX2ZpbGUgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5uZXdFcnJvcihcIkNhbm5vdCBvcGVuIGZpbGU6IFVucmVjb2duaXNlZCBkZWZpbml0aW9uIHBhcnQ6IFwiICsgZmlsZV9kZWZpbml0aW9uX3BhcnQgKyBcIiBpbiBcIiArIGZpbGVfZGVmaW5pdGlvbik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2RlZmluaXRpb25faW50ZXJwcmV0aW5nX2ZhaWxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgaWYgKGZpbGVfZGVmaW5pdGlvbl9pbnRlcnByZXRpbmdfZmFpbGVkKSB7XHJcbiAgICAgICAgICAgICAgICByZWplY3QoKTtcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gRW5zdXJlIHRoZSBwYXRoIGlzIHJlbGF0aXZlXHJcbiAgICAgICAgICAgIGlmIChwYXRoLmlzQWJzb2x1dGUob3Blbl9maWxlX3BhdGgpKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGUgcGF0aCBpcyBhYnNvbHV0ZS5cclxuICAgICAgICAgICAgICAgIC8vIENoZWNrIGlmIGl0IGNhbiBiZSBjb252ZXJ0ZWQgdG8gcmVsYXRpdmUuXHJcbiAgICAgICAgICAgICAgICBjb25zdCB2YXVsdF9hYnNvbHV0ZV9wYXRoOiBzdHJpbmcgPSBnZXRWYXVsdEFic29sdXRlUGF0aCh0aGlzLmFwcCk7XHJcbiAgICAgICAgICAgICAgICBpZiAob3Blbl9maWxlX3BhdGgudG9Mb2NhbGVMb3dlckNhc2UoKS5zdGFydHNXaXRoKHZhdWx0X2Fic29sdXRlX3BhdGgudG9Mb2NhbGVMb3dlckNhc2UoKSkpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBDb252ZXJ0aW5nIHRvIHJlbGF0aXZlIGlzIHBvc3NpYmxlXHJcbiAgICAgICAgICAgICAgICAgICAgb3Blbl9maWxlX3BhdGggPSBvcGVuX2ZpbGVfcGF0aC5zdWJzdHIodmF1bHRfYWJzb2x1dGVfcGF0aC5sZW5ndGgpOyAvLyBHZXQgZXZlcnl0aGluZyBhZnRlciB0aGUgcG9pbnQgd2hlcmUgdGhlIHZhdWx0IHBhdGggZW5kcy5cclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gQ2Fubm90IGNvbnZlcnQgdG8gcmVsYXRpdmUsIGJlY2F1c2UgdGhlIGZpbGUgZG9lcyBub3QgcmVzaWRlIGluIHRoZSB2YXVsdFxyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLm5ld0Vycm9yKFwiQ2Fubm90IG9wZW4gZmlsZSAnXCIgKyBvcGVuX2ZpbGVfcGF0aCArIFwiJyBhcyB0aGUgcGF0aCBpcyBvdXRzaWRlIHRoaXMgdmF1bHQuXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIHJlamVjdCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ2xlYW4gdXAgdGhlIGZpbGUgcGF0aFxyXG4gICAgICAgICAgICBvcGVuX2ZpbGVfcGF0aCA9IG5vcm1hbGl6ZVBhdGgob3Blbl9maWxlX3BhdGgpOyAvLyBub3JtYWxpemVQYXRoKCkgaXMgdXNlZCBvbiBwdXJwb3NlLCBpbnN0ZWFkIG9mIG5vcm1hbGl6ZVBhdGgyKCksIGJlY2F1c2UgYmFja3NsYXNoZXMgXFwgc2hvdWxkIGJlIGNvbnZlcnRlZCB0byBmb3J3YXJkIHNsYXNoZXMgL1xyXG5cclxuICAgICAgICAgICAgdGhpcy5vcGVuRmlsZUluVGFiKG9wZW5fZmlsZV9wYXRoLCBuZXdMZWFmLCBjYW5fY3JlYXRlX2ZpbGUpLnRoZW4oKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhlIGZpbGUgaXMgbm93IG9wZW5cclxuICAgICAgICAgICAgICAgIC8vIENoZWNrLCBkaWQgd2UgaGF2ZSBhIGNhcmV0IHBvc2l0aW9uIGF2YWlsYWJsZS4gSWYgbm90LCBkbyBub3RoaW5nLlxyXG4gICAgICAgICAgICAgICAgY29uc3QgY291bnRfY2FyZXRfcGFydHM6IG51bWJlciA9IGNhcmV0X3BhcnRzLmxlbmd0aDtcclxuICAgICAgICAgICAgICAgIGlmIChjb3VudF9jYXJldF9wYXJ0cyA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBZZXMsIGEgY2FyZXQgcG9zaXRpb24gd2FzIGRlZmluZWQgaW4gdGhlIG91dHB1dC5cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gRW5zdXJlIHRoZSBjb3JyZWN0IGFtb3VudCBvZiBjYXJldCBwb3NpdGlvbiBwYXJ0cy5cclxuICAgICAgICAgICAgICAgICAgICAvLyAwIHBhcnRzOiBubyBjYXJldCBwb3NpdGlvbmluZyBuZWVkcyB0byBiZSBkb25lIChidXQgaW4gdGhpcyBwYXJ0IG9mIGNvZGUgdGhlIGFtb3VudCBvZiBwYXJ0cyBpcyBhbHdheXMgZ3JlYXRlciB0aGFuIDApLlxyXG4gICAgICAgICAgICAgICAgICAgIC8vIDEgcGFydDogY2FyZXQgbGluZSBpcyBkZWZpbmVkLCBubyBjb2x1bW4uXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gMiBwYXJ0czogY2FyZXQgbGluZSBhbmQgY29sdW1uIGFyZSBkZWZpbmVkLlxyXG4gICAgICAgICAgICAgICAgICAgIC8vIDMgcGFydHM6IE5PVCBBTExPV0VELlxyXG4gICAgICAgICAgICAgICAgICAgIC8vIDQgcGFydHM6IHNlbGVjdGlvbiBzdGFydGluZyBwb3NpdGlvbiAobGluZSwgY29sdW1uKSBhbmQgc2VsZWN0aW9uIGVuZCBwb3NpdGlvbiAobGluZSwgY29sdW1uKSBhcmUgZGVmaW5lZC5cclxuICAgICAgICAgICAgICAgICAgICAvLyA1IHBhcnRzIG9yIG1vcmU6IE5PVCBBTExPV0VELiBFeGNlcHRpb246IGFueSBudW1iZXIgb2Ygc2V0cyBvZiBmb3VyIHBhcnRzIGlzIGFsbG93ZWQsIGkuZS4gOCBwYXJ0cywgMTIgcGFydHMsIDE2IHBhcnRzIGV0Yy4gYXJlIGFsbG93ZWQgYXMgdGhleSBjYW4gZGVmaW5lIG11bHRpcGxlIHNlbGVjdGlvbnMuXHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3JfbWVzc2FnZV9iYXNlOiBzdHJpbmcgPSBcIkZpbGUgb3BlbmVkLCBidXQgY2FyZXQgY2Fubm90IGJlIHBvc2l0aW9uZWQgZHVlIHRvIGFuIGluY29ycmVjdCBhbW91bnQgKFwiICsgY291bnRfY2FyZXRfcGFydHMgKyBcIikgb2YgbnVtZXJpYyB2YWx1ZXMgaW4gdGhlIG91dHB1dDogXCIgKyBmaWxlX2RlZmluaXRpb24gKyBFT0wgKyBFT0w7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvdW50X2NhcmV0X3BhcnRzID09IDMpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW5jb3JyZWN0IGFtb3VudCBvZiBjYXJldCBwYXJ0c1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5uZXdFcnJvcihlcnJvcl9tZXNzYWdlX2Jhc2UgKyBcIlRocmVlIG51bWVyaWMgcGFydHMgaXMgYW4gaW5jb3JyZWN0IGFtb3VudCwgY29ycmVjdCB3b3VsZCBiZSAxLDIgb3IgNCBwYXJ0cy5cIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChjb3VudF9jYXJldF9wYXJ0cyA+IDQgJiYgY291bnRfY2FyZXRfcGFydHMgJSA0ICE9PSAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEluY29ycmVjdCBhbW91bnQgb2YgY2FyZXQgcGFydHNcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3RXJyb3IoZXJyb3JfbWVzc2FnZV9iYXNlICsgXCJQZXJoYXBzIHRvbyBtYW55IG51bWVyaWMgcGFydHMgYXJlIGRlZmluZWQ/IElmIG1vcmUgdGhhbiBmb3VyIHBhcnRzIGFyZSBkZWZpbmVkLCBtYWtlIHN1cmUgdG8gZGVmaW5lIGNvbXBsZXRlIHNldHMgb2YgZm91ciBwYXJ0cy4gVGhlIGFtb3VudCBvZiBudW1lcmljIHBhcnRzIG5lZWRzIHRvIGJlIGRpdmlkYWJsZSBieSA0LlwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vIEV2ZW4gdGhvdWdoIHRoZSBmaWxlIGlzIGFscmVhZHkgbG9hZGVkLCByZW5kZXJpbmcgaXQgbWF5IHRha2Ugc29tZSB0aW1lLCB0aHVzIHRoZSBoZWlnaHQgb2YgdGhlIGNvbnRlbnQgbWF5IGluY3JlYXNlLlxyXG4gICAgICAgICAgICAgICAgICAgIC8vIEZvciB0aGlzIHJlYXNvbiwgdGhlcmUgbmVlZHMgdG8gYmUgYSB0aW55IGRlbGF5IGJlZm9yZSBzZXR0aW5nIHRoZSBjYXJldCBwb3NpdGlvbi4gSWYgdGhlIGNhcmV0IHBvc2l0aW9uIGlzIHNldCBpbW1lZGlhdGVseSxcclxuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgY2FyZXQgd2lsbCBiZSBwbGFjZWQgaW4gYSBjb3JyZWN0IHBvc2l0aW9uLCBidXQgaXQgbWlnaHQgYmUgdGhhdCB0aGUgZWRpdG9yIGRvZXMgbm90IHNjcm9sbCBpbnRvIGNvcnJlY3QgcG9zaXRpb24sIHNvIHRoZVxyXG4gICAgICAgICAgICAgICAgICAgIC8vIGNhcmV0IG1pZ2h0IGJlIG91dCBvZiB0aGUgdmlldywgZXZlbiB3aGVuIGl0J3MgaW4gYSBjb3JyZWN0IHBsYWNlLiAoT2JzaWRpYW4gdmVyc2lvbiAwLjEzLjIzKS5cclxuICAgICAgICAgICAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGVkaXRvciA9IGdldEVkaXRvcih0aGlzLmFwcCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlZGl0b3IpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjb3VudF9jYXJldF9wYXJ0cyA+PSA0KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2VsZWN0aW9uIG1vZGVcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGVyZSBjYW4gYmUgbXVsdGlwbGUgc2VsZWN0aW9ucyBkZWZpbmVkXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2VsZWN0aW9uczogRWRpdG9yU2VsZWN0aW9uT3JDYXJldFtdID0gW107XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKGNhcmV0X3BhcnRzLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmcm9tTGluZTogbnVtYmVyIHwgdW5kZWZpbmVkID0gY2FyZXRfcGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZnJvbUNvbHVtbjogbnVtYmVyIHwgdW5kZWZpbmVkID0gY2FyZXRfcGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdG9MaW5lOiBudW1iZXIgfCB1bmRlZmluZWQgPSBjYXJldF9wYXJ0cy5zaGlmdCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB0b0NvbHVtbjogbnVtYmVyIHwgdW5kZWZpbmVkID0gY2FyZXRfcGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHVuZGVmaW5lZCA9PT0gZnJvbUxpbmUgfHwgdW5kZWZpbmVkID09PSBmcm9tQ29sdW1uIHx8IHVuZGVmaW5lZCA9PT0gdG9MaW5lIHx8IHVuZGVmaW5lZCA9PT0gdG9Db2x1bW4pIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoaXMgc2hvdWxkIG5ldmVyIGhhcHBlbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkVuY291bnRlcmVkIHVuZGVmaW5lZCB2YWx1ZXMgaW4gZnJvbUxpbmUsIGZyb21Db2x1bW4sIHRvTGluZSwgYW5kL29yIHRvQ29sdW1uLiBTdHJhbmdlLCBiZWNhdXNlIHRoZSBjb3JyZWN0IGFtb3VudCBvZiBwYXJ0cyBpbiBjYXJldF9wYXJ0cyB3YXMgY2hlY2tlZCBiZWZvcmVoYW5kLlwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Rpb25zLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5jaG9yOiBwcmVwYXJlRWRpdG9yUG9zaXRpb24oZWRpdG9yLCBmcm9tTGluZSwgZnJvbUNvbHVtbiksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkOiBwcmVwYXJlRWRpdG9yUG9zaXRpb24oZWRpdG9yLCB0b0xpbmUsIHRvQ29sdW1uKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkaXRvci5zZXRTZWxlY3Rpb25zKHNlbGVjdGlvbnMpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaW1wbGUgY2FyZXQgbW9kZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNhcmV0X2xpbmU6IG51bWJlciA9IGNhcmV0X3BhcnRzWzBdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNhcmV0X2NvbHVtbjogbnVtYmVyID0gY2FyZXRfcGFydHNbMV0gPz8gMTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZGl0b3Iuc2V0Q3Vyc29yKHByZXBhcmVFZGl0b3JQb3NpdGlvbihlZGl0b3IsIGNhcmV0X2xpbmUsIGNhcmV0X2NvbHVtbikpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFmdGVyIHBsYWNpbmcgY2FyZXRzIC8gc2VsZWN0aW5nIHRleHQsIGhhdmUgYSBzbWFsbCBkZWxheSBhZnRlciBhbGxvd2luZyB0byBvcGVuIGFub3RoZXIgZmlsZSAoaW4gY2FzZSBtdWx0aXBsZSBmaWxlcyBhcmUgb3BlbmVkIGluIGEgcm93KS4gVGhpcyBhbGxvd3MgdGhlIHNlbGVjdGlvbiB0byBiZSByZW1lbWJlcmVkIGluIHRoZSBwYW5lJ3MgaGlzdG9yeS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KHJlc29sdmUsIDMwMCk7IC8vIElmIHlvdSBjaGFuZ2UgdGhpcyBBRERJVElPTkFMIGRlbGF5LCByZW1lbWJlciB0byBjaGFuZ2UgaXQgaW4gdGhlIGRvY3VtZW50YXRpb24sIHRvby5cclxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5vIGVkaXRvclxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3RXJyb3IoXCJGaWxlIG9wZW5lZCwgYnV0IGNhcmV0IGNhbm5vdCBiZSBwb3NpdGlvbmVkIGJlY2F1c2Ugbm8gZWRpdG9yIHdhcyBmb3VuZC5cIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH0sIDUwMCk7IC8vIDUwMG1zIGlzIHByb2JhYmx5IGxvbmcgZW5vdWdoIGV2ZW4gaWYgYSBuZXcgdGFiIGlzIG9wZW5lZCAodGFrZXMgbW9yZSB0aW1lIHRoYW4gb3BlbmluZyBhIGZpbGUgaW50byBhbiBleGlzdGluZyB0YWIpLiBUaGlzIGNhbiBiZSBtYWRlIGludG8gYSBzZXR0aW5nIHNvbWV0aW1lLiBJZiB5b3UgY2hhbmdlIHRoaXMsIHJlbWVtYmVyIHRvIGNoYW5nZSBpdCBpbiB0aGUgZG9jdW1lbnRhdGlvbiwgdG9vLlxyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBObyBjYXJldCBwYXJ0cyBleGlzdC4gQWxsIGlzIGRvbmUgbm93LlxyXG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSwgKGVycm9yX21lc3NhZ2U6IHN0cmluZyB8IHVua25vd24pID0+IHtcclxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZXJyb3JfbWVzc2FnZSA9PT0gXCJzdHJpbmdcIikge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIE9wZW5pbmcgdGhlIGZpbGUgaGFzIGZhaWxlZC5cclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5uZXdFcnJvcihlcnJvcl9tZXNzYWdlKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gU29tZSBvdGhlciBydW50aW1lIGVycm9yIGhhcyBvY2N1cnJlZC5cclxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnJvcl9tZXNzYWdlO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgcmVqZWN0KCk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgb3BlbkZpbGVJblRhYihmaWxlX3BhdGg6IHN0cmluZywgbmV3TGVhZjogUGFuZVR5cGUgfCBmYWxzZSwgY2FuX2NyZWF0ZV9maWxlOiBib29sZWFuKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgLy8gRW5zdXJlIHRoYXQgdGhlIGZpbGUgZXhpc3RzIChvciBjYW4gYmUgY3JlYXRlZClcclxuICAgICAgICBjb25zdCBzb3VyY2VfcGF0aCA9IFwiXCI7IC8vIFRPRE86IFdoZW4gYWRkaW5nIGFuIG9wdGlvbiBmb3IgY3JlYXRpbmcgbmV3IGZpbGVzLCByZWFkIHRoaXMgZG9jdW1lbnRhdGlvbiBmcm9tIE9ic2lkaWFuIEFQSSdzIGdldE5ld0ZpbGVQYXJlbnQoKTogXCJzb3VyY2VQYXRoIOKAkyBUaGUgcGF0aCB0byB0aGUgY3VycmVudCBvcGVuL2ZvY3VzZWQgZmlsZSwgdXNlZCB3aGVuIHRoZSB1c2VyIHdhbnRzIG5ldyBmaWxlcyB0byBiZSBjcmVhdGVkIOKAnGluIHRoZSBzYW1lIGZvbGRlcuKAnS4gVXNlIGFuIGVtcHR5IHN0cmluZyBpZiB0aGVyZSBpcyBubyBhY3RpdmUgZmlsZS5cIlxyXG4gICAgICAgIGNvbnN0IGZpbGVfZXhpc3RzX29yX2Nhbl9iZV9jcmVhdGVkID0gY2FuX2NyZWF0ZV9maWxlIHx8IG51bGwgIT09IHRoaXMuYXBwLm1ldGFkYXRhQ2FjaGUuZ2V0Rmlyc3RMaW5rcGF0aERlc3QoZmlsZV9wYXRoLCBzb3VyY2VfcGF0aCk7XHJcbiAgICAgICAgaWYgKGZpbGVfZXhpc3RzX29yX2Nhbl9iZV9jcmVhdGVkKSB7XHJcbiAgICAgICAgICAgIC8vIFllcywgdGhlIGZpbGUgZXhpc3RzIChvciBjYW4gYmUgY3JlYXRlZClcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuYXBwLndvcmtzcGFjZS5vcGVuTGlua1RleHQoZmlsZV9wYXRoLCBzb3VyY2VfcGF0aCwgbmV3TGVhZik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gTm8sIHRoZSBmaWxlIGRvZXMgbm90IGV4aXN0LCBhbmQgaXQgbWF5IG5vdCBiZSBjcmVhdGVkLlxyXG4gICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoXCJDYW5ub3Qgb3BlbiBmaWxlICdcIiArIGZpbGVfcGF0aCArIFwiJywgYXMgaXQgZG9lcyBub3QgZXhpc3QuIChJZiB5b3Ugd2FudCB0byBhbGxvdyBmaWxlIGNyZWF0aW9uLCBhZGQgOmNhbi1jcmVhdGUtZmlsZSB0byB0aGUgc2hlbGwgY29tbWFuZCBvdXRwdXQuKVwiKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi9tYWluXCI7XHJcbmltcG9ydCB7T3V0cHV0Q2hhbm5lbF9Ob3RpZmljYXRpb259IGZyb20gXCIuL091dHB1dENoYW5uZWxfTm90aWZpY2F0aW9uXCI7XHJcbmltcG9ydCB7T3V0cHV0Q2hhbm5lbCwgT3V0cHV0Q2hhbm5lbHN9IGZyb20gXCIuL091dHB1dENoYW5uZWxcIjtcclxuaW1wb3J0IHtPdXRwdXRDaGFubmVsX0N1cnJlbnRGaWxlQ2FyZXR9IGZyb20gXCIuL091dHB1dENoYW5uZWxfQ3VycmVudEZpbGVDYXJldFwiO1xyXG5pbXBvcnQge091dHB1dENoYW5uZWxfQ3VycmVudEZpbGVUb3B9IGZyb20gXCIuL091dHB1dENoYW5uZWxfQ3VycmVudEZpbGVUb3BcIjtcclxuaW1wb3J0IHtcclxuICAgIE91dHB1dENoYW5uZWxDb2RlLFxyXG4gICAgT3V0cHV0Q2hhbm5lbENvZGVzLFxyXG4gICAgT3V0cHV0SGFuZGxpbmdNb2RlLFxyXG4gICAgT3V0cHV0U3RyZWFtLFxyXG59IGZyb20gXCIuL091dHB1dENoYW5uZWxDb2RlXCI7XHJcbmltcG9ydCB7T3V0cHV0Q2hhbm5lbF9TdGF0dXNCYXJ9IGZyb20gXCIuL091dHB1dENoYW5uZWxfU3RhdHVzQmFyXCI7XHJcbmltcG9ydCB7T3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZUJvdHRvbX0gZnJvbSBcIi4vT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZUJvdHRvbVwiO1xyXG5pbXBvcnQge091dHB1dENoYW5uZWxfQ2xpcGJvYXJkfSBmcm9tIFwiLi9PdXRwdXRDaGFubmVsX0NsaXBib2FyZFwiO1xyXG5pbXBvcnQge1NoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQsIFRTaGVsbENvbW1hbmR9IGZyb20gXCIuLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7T3V0cHV0Q2hhbm5lbF9Nb2RhbH0gZnJvbSBcIi4vT3V0cHV0Q2hhbm5lbF9Nb2RhbFwiO1xyXG5pbXBvcnQge091dHB1dENoYW5uZWxfT3BlbkZpbGVzfSBmcm9tIFwiLi9PdXRwdXRDaGFubmVsX09wZW5GaWxlc1wiO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBPdXRwdXRTdHJlYW1zIHtcclxuICAgIHN0ZG91dD86IHN0cmluZztcclxuICAgIHN0ZGVycj86IHN0cmluZztcclxufVxyXG5cclxuY29uc3Qgb3V0cHV0Q2hhbm5lbENsYXNzZXM6IHtcclxuICAgIFtrZXk6IHN0cmluZ106IHR5cGVvZiBPdXRwdXRDaGFubmVsO1xyXG59ID0ge307XHJcblxyXG4vLyBSZWdpc3RlciBvdXRwdXQgY2hhbm5lbHNcclxucmVnaXN0ZXJPdXRwdXRDaGFubmVsKFwibm90aWZpY2F0aW9uXCIsIE91dHB1dENoYW5uZWxfTm90aWZpY2F0aW9uKTtcclxucmVnaXN0ZXJPdXRwdXRDaGFubmVsKFwiY3VycmVudC1maWxlLWNhcmV0XCIsIE91dHB1dENoYW5uZWxfQ3VycmVudEZpbGVDYXJldCk7XHJcbnJlZ2lzdGVyT3V0cHV0Q2hhbm5lbChcImN1cnJlbnQtZmlsZS10b3BcIiwgT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZVRvcCk7XHJcbnJlZ2lzdGVyT3V0cHV0Q2hhbm5lbChcImN1cnJlbnQtZmlsZS1ib3R0b21cIiwgT3V0cHV0Q2hhbm5lbF9DdXJyZW50RmlsZUJvdHRvbSk7XHJcbnJlZ2lzdGVyT3V0cHV0Q2hhbm5lbChcIm9wZW4tZmlsZXNcIiwgT3V0cHV0Q2hhbm5lbF9PcGVuRmlsZXMpO1xyXG5yZWdpc3Rlck91dHB1dENoYW5uZWwoXCJzdGF0dXMtYmFyXCIsIE91dHB1dENoYW5uZWxfU3RhdHVzQmFyKTtcclxucmVnaXN0ZXJPdXRwdXRDaGFubmVsKFwiY2xpcGJvYXJkXCIsIE91dHB1dENoYW5uZWxfQ2xpcGJvYXJkKTtcclxucmVnaXN0ZXJPdXRwdXRDaGFubmVsKFwibW9kYWxcIiwgT3V0cHV0Q2hhbm5lbF9Nb2RhbCk7XHJcblxyXG4vKipcclxuICogVGhpcyBmdW5jdGlvbiBpcyBkZXNpZ25lZCB0byBiZSBjYWxsZWQgYWZ0ZXIgYSAnV2FpdCB1bnRpbCBmaW5pc2hlZCcgdHlwZSBvZiBzaGVsbCBjb21tYW5kIGZpbmlzaGVzIGl0cyBleGVjdXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSBwbHVnaW5cclxuICogQHBhcmFtIHRfc2hlbGxfY29tbWFuZFxyXG4gKiBAcGFyYW0gc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdFxyXG4gKiBAcGFyYW0gc3Rkb3V0XHJcbiAqIEBwYXJhbSBzdGRlcnJcclxuICogQHBhcmFtIGVycm9yX2NvZGUgVE9ETzogUmVuYW1lIHRvIGV4aXRDb2RlIGV2ZXJ5d2hlcmUgaW4gdGhlIGNvZGViYXNlLlxyXG4gKiBAcGFyYW0gb3V0cHV0X2NoYW5uZWxzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaGFuZGxlQnVmZmVyZWRPdXRwdXQoXHJcbiAgICAgICAgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kLFxyXG4gICAgICAgIHNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHQ6IFNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQsXHJcbiAgICAgICAgc3Rkb3V0OiBzdHJpbmcsXHJcbiAgICAgICAgc3RkZXJyOiBzdHJpbmcsXHJcbiAgICAgICAgZXJyb3JfY29kZTogbnVtYmVyIHwgbnVsbCxcclxuICAgICAgICBvdXRwdXRfY2hhbm5lbHM6IE91dHB1dENoYW5uZWxDb2Rlc1xyXG4gICAgKTogdm9pZCB7XHJcbiAgICAvLyBUZXJtaW5vbG9neTogU3RyZWFtID0gb3V0cHV0cyBzdHJlYW0gZnJvbSBhIGNvbW1hbmQsIGNhbiBiZSBcInN0ZG91dFwiIG9yIFwic3RkZXJyXCIuIENoYW5uZWwgPSBhIG1ldGhvZCBmb3IgdGhpcyBhcHBsaWNhdGlvbiB0byBwcmVzZW50IHRoZSBvdXRwdXQgb3QgdXNlciwgZS5nLiBcIm5vdGlmaWNhdGlvblwiLlxyXG5cclxuICAgIGNvbnN0IHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbiA9IHRfc2hlbGxfY29tbWFuZC5nZXRDb25maWd1cmF0aW9uKCk7IC8vIFRPRE86IFJlZmFjdG9yIE91dHB1dENoYW5uZWxzIHRvIHVzZSBUU2hlbGxDb21tYW5kIGluc3RlYWQgb2YgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0cyBkaXJlY3RseS5cclxuXHJcbiAgICAvLyBJbnNlcnQgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gYW4gb2JqZWN0IGluIGEgY29ycmVjdCBvcmRlclxyXG4gICAgbGV0IG91dHB1dDogT3V0cHV0U3RyZWFtcyA9IHt9O1xyXG4gICAgaWYgKHN0ZG91dC5sZW5ndGggJiYgc3RkZXJyLmxlbmd0aCkge1xyXG4gICAgICAgIC8vIEJvdGggc3Rkb3V0IGFuZCBzdGRlcnIgaGF2ZSBjb250ZW50XHJcbiAgICAgICAgLy8gRGVjaWRlIHRoZSBvdXRwdXQgb3JkZXIgPT0gRmluZCBvdXQgd2hpY2ggZGF0YSBzdHJlYW0gc2hvdWxkIGJlIHByb2Nlc3NlZCBmaXJzdCwgc3Rkb3V0IG9yIHN0ZGVyci5cclxuICAgICAgICBzd2l0Y2ggKHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbi5vdXRwdXRfY2hhbm5lbF9vcmRlcikge1xyXG4gICAgICAgICAgICBjYXNlIFwic3Rkb3V0LWZpcnN0XCI6XHJcbiAgICAgICAgICAgICAgICBvdXRwdXQgPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgc3Rkb3V0OiBzdGRvdXQsXHJcbiAgICAgICAgICAgICAgICAgICAgc3RkZXJyOiBzdGRlcnIsXHJcbiAgICAgICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGNhc2UgXCJzdGRlcnItZmlyc3RcIjpcclxuICAgICAgICAgICAgICAgIG91dHB1dCA9IHtcclxuICAgICAgICAgICAgICAgICAgICBzdGRlcnI6IHN0ZGVycixcclxuICAgICAgICAgICAgICAgICAgICBzdGRvdXQ6IHN0ZG91dCxcclxuICAgICAgICAgICAgICAgIH07XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICB9IGVsc2UgaWYgKHN0ZG91dC5sZW5ndGgpIHtcclxuICAgICAgICAvLyBPbmx5IHN0ZG91dCBoYXMgY29udGVudFxyXG4gICAgICAgIG91dHB1dCA9IHtcclxuICAgICAgICAgICAgc3Rkb3V0OiBzdGRvdXQsXHJcbiAgICAgICAgfTtcclxuICAgIH0gZWxzZSBpZiAoc3RkZXJyLmxlbmd0aCkge1xyXG4gICAgICAgIC8vIE9ubHkgc3RkZXJyIGhhcyBjb250ZW50XHJcbiAgICAgICAgb3V0cHV0ID0ge1xyXG4gICAgICAgICAgICBzdGRlcnI6IHN0ZGVycixcclxuICAgICAgICB9O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBOZWl0aGVyIHN0ZG91dCBub3Igc3RkZXJyIGhhdmUgY29udGVudFxyXG4gICAgICAgIC8vIFByb3ZpZGUgZW1wdHkgb3V0cHV0LCBzb21lIG91dHB1dCBjaGFubmVscyB3aWxsIHByb2Nlc3MgaXQsIHdoaWxlIG90aGVyIHdpbGwganVzdCBpZ25vcmUgaXQuXHJcbiAgICAgICAgb3V0cHV0ID0ge1xyXG4gICAgICAgICAgICBcInN0ZG91dFwiOiBcIlwiLFxyXG4gICAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2hvdWxkIHN0ZGVyciBiZSBwcm9jZXNzZWQgc2FtZSB0aW1lIHdpdGggc3Rkb3V0P1xyXG4gICAgaWYgKG91dHB1dF9jaGFubmVscy5zdGRvdXQgPT09IG91dHB1dF9jaGFubmVscy5zdGRlcnIpIHtcclxuICAgICAgICAvLyBTdGRvdXQgYW5kIHN0ZGVyciB1c2UgdGhlIHNhbWUgY2hhbm5lbC5cclxuICAgICAgICAvLyBNYWtlIG9uZSBoYW5kbGluZyBjYWxsLlxyXG4gICAgICAgIGhhbmRsZV9zdHJlYW0oXHJcbiAgICAgICAgICAgIHBsdWdpbixcclxuICAgICAgICAgICAgdF9zaGVsbF9jb21tYW5kLFxyXG4gICAgICAgICAgICBzaGVsbF9jb21tYW5kX3BhcnNpbmdfcmVzdWx0LFxyXG4gICAgICAgICAgICBvdXRwdXRfY2hhbm5lbHMuc3Rkb3V0LFxyXG4gICAgICAgICAgICBvdXRwdXQsXHJcbiAgICAgICAgICAgIGVycm9yX2NvZGUsXHJcbiAgICAgICAgKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gU3Rkb3V0IGFuZCBzdGRlcnIgdXNlIGRpZmZlcmVudCBjaGFubmVscy5cclxuICAgICAgICAvLyBNYWtlIHR3byBoYW5kbGluZyBjYWxscy5cclxuICAgICAgICBsZXQgb3V0cHV0X3N0cmVhbV9uYW1lOiBPdXRwdXRTdHJlYW07XHJcbiAgICAgICAgZm9yIChvdXRwdXRfc3RyZWFtX25hbWUgaW4gb3V0cHV0KSB7XHJcbiAgICAgICAgICAgIGNvbnN0IG91dHB1dF9jaGFubmVsX25hbWUgPSBvdXRwdXRfY2hhbm5lbHNbb3V0cHV0X3N0cmVhbV9uYW1lXTtcclxuICAgICAgICAgICAgY29uc3Qgb3V0cHV0X21lc3NhZ2UgPSBvdXRwdXRbb3V0cHV0X3N0cmVhbV9uYW1lXTtcclxuICAgICAgICAgICAgY29uc3Qgc2VwYXJhdGVkX291dHB1dDogT3V0cHV0U3RyZWFtcyA9IHt9O1xyXG4gICAgICAgICAgICBzZXBhcmF0ZWRfb3V0cHV0W291dHB1dF9zdHJlYW1fbmFtZV0gPSBvdXRwdXRfbWVzc2FnZTtcclxuICAgICAgICAgICAgaGFuZGxlX3N0cmVhbShcclxuICAgICAgICAgICAgICAgIHBsdWdpbixcclxuICAgICAgICAgICAgICAgIHRfc2hlbGxfY29tbWFuZCxcclxuICAgICAgICAgICAgICAgIHNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHQsXHJcbiAgICAgICAgICAgICAgICBvdXRwdXRfY2hhbm5lbF9uYW1lLFxyXG4gICAgICAgICAgICAgICAgc2VwYXJhdGVkX291dHB1dCxcclxuICAgICAgICAgICAgICAgIGVycm9yX2NvZGUsXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgIH1cclxufVxyXG5cclxuYXN5bmMgZnVuY3Rpb24gaGFuZGxlX3N0cmVhbShcclxuICAgICAgICBwbHVnaW46IFNDX1BsdWdpbixcclxuICAgICAgICB0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQsXHJcbiAgICAgICAgc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdDogU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdCxcclxuICAgICAgICBvdXRwdXRfY2hhbm5lbF9uYW1lOiBPdXRwdXRDaGFubmVsQ29kZSxcclxuICAgICAgICBvdXRwdXQ6IE91dHB1dFN0cmVhbXMsXHJcbiAgICAgICAgZXJyb3JfY29kZTogbnVtYmVyfG51bGxcclxuICAgICk6IFByb21pc2U8dm9pZD4ge1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZSBvdXRwdXQgc2hvdWxkIGJlIGlnbm9yZWRcclxuICAgIGlmIChcImlnbm9yZVwiICE9PSBvdXRwdXRfY2hhbm5lbF9uYW1lKSB7XHJcbiAgICAgICAgLy8gVGhlIG91dHB1dCBzaG91bGQgbm90IGJlIGlnbm9yZWQuXHJcblxyXG4gICAgICAgIC8vIENoZWNrIHRoYXQgYW4gb3V0cHV0IGNoYW5uZWwgY2xhc3MgZXhpc3RzXHJcbiAgICAgICAgaWYgKHVuZGVmaW5lZCA9PT0gb3V0cHV0Q2hhbm5lbENsYXNzZXNbb3V0cHV0X2NoYW5uZWxfbmFtZV0pIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gb3V0cHV0IGNoYW5uZWwgY2xhc3MgZm91bmQgZm9yIGNoYW5uZWwgJ1wiICsgb3V0cHV0X2NoYW5uZWxfbmFtZSArIFwiJy5cIik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJbnN0YW50aWF0ZSB0aGUgY2hhbm5lbFxyXG4gICAgICAgIGNvbnN0IG91dHB1dENoYW5uZWw6IE91dHB1dENoYW5uZWwgPSBpbml0aWFsaXplT3V0cHV0Q2hhbm5lbChcclxuICAgICAgICAgICAgb3V0cHV0X2NoYW5uZWxfbmFtZSxcclxuICAgICAgICAgICAgcGx1Z2luLFxyXG4gICAgICAgICAgICB0X3NoZWxsX2NvbW1hbmQsXHJcbiAgICAgICAgICAgIHNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHQsXHJcbiAgICAgICAgICAgIFwiYnVmZmVyZWRcIixcclxuICAgICAgICAgICAgbnVsbCwgLy8gXCJCdWZmZXJlZFwiIG91dHB1dCBoYW5kbGluZyBkb2VzIG5vdCB1c2UgYSB0ZXJtaW5hdG9yLCBhcyB0aGUgcHJvY2VzcyBoYXMgYWxyZWFkeSBlbmRlZC5cclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBQZXJmb3JtIGhhbmRsaW5nIHRoZSBvdXRwdXRcclxuICAgICAgICBhd2FpdCBvdXRwdXRDaGFubmVsLmhhbmRsZUJ1ZmZlcmVkKG91dHB1dCwgZXJyb3JfY29kZSk7XHJcbiAgICB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBzdGFydFJlYWx0aW1lT3V0cHV0SGFuZGxpbmcoXHJcbiAgICAgICAgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgdFNoZWxsQ29tbWFuZDogVFNoZWxsQ29tbWFuZCxcclxuICAgICAgICBzaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0OiBTaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0LFxyXG4gICAgICAgIG91dHB1dENoYW5uZWxDb2RlczogT3V0cHV0Q2hhbm5lbENvZGVzLFxyXG4gICAgICAgIHByb2Nlc3NUZXJtaW5hdG9yOiAoKCkgPT4gdm9pZCkgfCBudWxsLFxyXG4gICAgKTogT3V0cHV0Q2hhbm5lbHMge1xyXG5cclxuICAgIGNvbnN0IG91dHB1dENoYW5uZWxzOiBPdXRwdXRDaGFubmVscyA9IHt9O1xyXG5cclxuICAgIC8vIHN0ZG91dFxyXG4gICAgaWYgKFwiaWdub3JlXCIgIT09IG91dHB1dENoYW5uZWxDb2Rlcy5zdGRvdXQpIHtcclxuICAgICAgICBvdXRwdXRDaGFubmVscy5zdGRvdXQgPSBpbml0aWFsaXplT3V0cHV0Q2hhbm5lbChcclxuICAgICAgICAgICAgb3V0cHV0Q2hhbm5lbENvZGVzLnN0ZG91dCxcclxuICAgICAgICAgICAgcGx1Z2luLFxyXG4gICAgICAgICAgICB0U2hlbGxDb21tYW5kLFxyXG4gICAgICAgICAgICBzaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0LFxyXG4gICAgICAgICAgICBcInJlYWx0aW1lXCIsXHJcbiAgICAgICAgICAgIHByb2Nlc3NUZXJtaW5hdG9yLFxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gc3RkZXJyXHJcbiAgICBpZiAoXCJpZ25vcmVcIiAhPT0gb3V0cHV0Q2hhbm5lbENvZGVzLnN0ZGVycikge1xyXG4gICAgICAgIGlmIChvdXRwdXRDaGFubmVsQ29kZXMuc3RkZXJyID09PSBvdXRwdXRDaGFubmVsQ29kZXMuc3Rkb3V0KSB7XHJcbiAgICAgICAgICAgIC8vIHN0ZGVyciBzaG91bGQgdXNlIHRoZSBzYW1lIGNoYW5uZWwgaW5zdGFuY2UgYXMgc3Rkb3V0LlxyXG4gICAgICAgICAgICBvdXRwdXRDaGFubmVscy5zdGRlcnIgPSBvdXRwdXRDaGFubmVscy5zdGRvdXQ7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gc3RkZXJyIHVzZXMgYSBkaWZmZXJlbnQgY2hhbm5lbCB0aGFuIHN0ZG91dC5cclxuICAgICAgICAgICAgb3V0cHV0Q2hhbm5lbHMuc3RkZXJyID0gaW5pdGlhbGl6ZU91dHB1dENoYW5uZWwoXHJcbiAgICAgICAgICAgICAgICBvdXRwdXRDaGFubmVsQ29kZXMuc3RkZXJyLFxyXG4gICAgICAgICAgICAgICAgcGx1Z2luLFxyXG4gICAgICAgICAgICAgICAgdFNoZWxsQ29tbWFuZCxcclxuICAgICAgICAgICAgICAgIHNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQsXHJcbiAgICAgICAgICAgICAgICBcInJlYWx0aW1lXCIsXHJcbiAgICAgICAgICAgICAgICBwcm9jZXNzVGVybWluYXRvcixcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIG91dHB1dENoYW5uZWxzO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZ2V0T3V0cHV0Q2hhbm5lbHNPcHRpb25MaXN0KG91dHB1dF9zdHJlYW06IE91dHB1dFN0cmVhbSkge1xyXG4gICAgY29uc3QgbGlzdDoge1xyXG4gICAgICAgIFtrZXk6IHN0cmluZ106IHN0cmluZztcclxuICAgIH0gPSB7aWdub3JlOiBcIklnbm9yZVwifTtcclxuICAgIGZvciAoY29uc3QgbmFtZSBpbiBvdXRwdXRDaGFubmVsQ2xhc3Nlcykge1xyXG4gICAgICAgIGNvbnN0IGNoYW5uZWxDbGFzczogdHlwZW9mIE91dHB1dENoYW5uZWwgPSBvdXRwdXRDaGFubmVsQ2xhc3Nlc1tuYW1lXTtcclxuICAgICAgICAvLyBDaGVjayB0aGF0IHRoZSBzdHJlYW0gaXMgc3VpdGFibGUgZm9yIHRoZSBjaGFubmVsXHJcbiAgICAgICAgaWYgKGNoYW5uZWxDbGFzcy5hY2NlcHRzT3V0cHV0U3RyZWFtKG91dHB1dF9zdHJlYW0pKSB7XHJcbiAgICAgICAgICAgIGxpc3RbbmFtZV0gPSBjaGFubmVsQ2xhc3MuZ2V0VGl0bGUob3V0cHV0X3N0cmVhbSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGxpc3Q7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRPdXRwdXRDaGFubmVsQ2xhc3NlcygpIHtcclxuICAgIHJldHVybiBvdXRwdXRDaGFubmVsQ2xhc3NlcztcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGluaXRpYWxpemVPdXRwdXRDaGFubmVsKFxyXG4gICAgICAgIGNoYW5uZWxDb2RlOiBPdXRwdXRDaGFubmVsQ29kZSxcclxuICAgICAgICBwbHVnaW46IFNDX1BsdWdpbixcclxuICAgICAgICB0U2hlbGxDb21tYW5kOiBUU2hlbGxDb21tYW5kLFxyXG4gICAgICAgIHNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQ6IFNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQsXHJcbiAgICAgICAgb3V0cHV0SGFuZGxpbmdNb2RlOiBPdXRwdXRIYW5kbGluZ01vZGUsXHJcbiAgICAgICAgcHJvY2Vzc1Rlcm1pbmF0b3I6ICgoKSA9PiB2b2lkKSB8IG51bGwsXHJcbiAgICApOiBPdXRwdXRDaGFubmVsIHtcclxuICAgIC8vIEB0cy1pZ25vcmUgVE9ETzogRmluZCBvdXQgaG93IHRvIHRlbGwgVHlwZVNjcmlwdCB0aGF0IGEgc3ViY2xhc3MgaXMgYmVpbmcgaW5zdGF0aWF0ZWQgaW5zdGVhZCBvZiB0aGUgYWJzdHJhY3QgYmFzZSBjbGFzczpcclxuICAgIHJldHVybiBuZXcgb3V0cHV0Q2hhbm5lbENsYXNzZXNbY2hhbm5lbENvZGVdKFxyXG4gICAgICAgIHBsdWdpbixcclxuICAgICAgICB0U2hlbGxDb21tYW5kLFxyXG4gICAgICAgIHNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQsXHJcbiAgICAgICAgb3V0cHV0SGFuZGxpbmdNb2RlLFxyXG4gICAgICAgIHByb2Nlc3NUZXJtaW5hdG9yLFxyXG4gICAgKTtcclxufVxyXG5cclxuZnVuY3Rpb24gcmVnaXN0ZXJPdXRwdXRDaGFubmVsKGNoYW5uZWxDb2RlOiBPdXRwdXRDaGFubmVsQ29kZSwgY2hhbm5lbENsYXNzOiB0eXBlb2YgT3V0cHV0Q2hhbm5lbCkge1xyXG4gICAgaWYgKHVuZGVmaW5lZCAhPT0gb3V0cHV0Q2hhbm5lbENsYXNzZXNbY2hhbm5lbENvZGVdKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiT3V0cHV0Q2hhbm5lbCBuYW1lZCAnXCIgKyBjaGFubmVsQ29kZSArIFwiJyBpcyBhbHJlYWR5IHJlZ2lzdGVyZWQhXCIpO1xyXG4gICAgfVxyXG4gICAgb3V0cHV0Q2hhbm5lbENsYXNzZXNbY2hhbm5lbENvZGVdID0gY2hhbm5lbENsYXNzO1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge2V4dHJhY3RGaWxlTmFtZSwgZ2V0T3BlcmF0aW5nU3lzdGVtLCBpc1dpbmRvd3N9IGZyb20gXCIuL0NvbW1vblwiO1xyXG5cclxuZXhwb3J0IGNvbnN0IFBsYXRmb3JtU2hlbGxzID0ge1xyXG4gICAgZGFyd2luOiB7XHJcbiAgICAgICAgXCIvYmluL2Jhc2hcIjogXCJCYXNoXCIsXHJcbiAgICAgICAgXCIvYmluL2Rhc2hcIjogXCJEYXNoXCIsXHJcbiAgICAgICAgXCIvYmluL3pzaFwiOiBcIlpzaCAoWiBzaGVsbClcIixcclxuICAgIH0sXHJcbiAgICBsaW51eDoge1xyXG4gICAgICAgIFwiL2Jpbi9iYXNoXCI6IFwiQmFzaFwiLFxyXG4gICAgICAgIFwiL2Jpbi9kYXNoXCI6IFwiRGFzaFwiLFxyXG4gICAgICAgIFwiL2Jpbi96c2hcIjogXCJac2ggKFogc2hlbGwpXCIsXHJcbiAgICB9LFxyXG4gICAgd2luMzI6IHtcclxuICAgICAgICBcInB3c2guZXhlXCI6IFwiUG93ZXJTaGVsbCBDb3JlXCIsXHJcbiAgICAgICAgXCJQb3dlclNoZWxsLmV4ZVwiOiBcIlBvd2VyU2hlbGwgNVwiLFxyXG4gICAgICAgIFwiQ01ELkVYRVwiOiBcImNtZC5leGVcIixcclxuICAgIH0sXHJcbn07XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZ2V0VXNlcnNEZWZhdWx0U2hlbGwoKTogc3RyaW5nIHtcclxuICAgIGlmIChpc1dpbmRvd3MoKSkge1xyXG4gICAgICAgIGlmICh1bmRlZmluZWQgPT09IHByb2Nlc3MuZW52LkNvbVNwZWMpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwicHJvY2Vzcy5lbnYuQ29tU3BlYyBpcyBub3QgYSBzdHJpbmcuXCIpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gcHJvY2Vzcy5lbnYuQ29tU3BlYztcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgICAgaWYgKHVuZGVmaW5lZCA9PT0gcHJvY2Vzcy5lbnYuU0hFTEwpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwicHJvY2Vzcy5lbnYuU0hFTEwgaXMgbm90IGEgc3RyaW5nLlwiKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHByb2Nlc3MuZW52LlNIRUxMO1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gaXNTaGVsbFN1cHBvcnRlZChzaGVsbDogc3RyaW5nKSB7XHJcbiAgICBjb25zdCBzaGVsbF9maWxlX25hbWUgPSBleHRyYWN0RmlsZU5hbWUoc2hlbGwpO1xyXG4gICAgY29uc3Qgc3VwcG9ydGVkX3NoZWxscyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKFBsYXRmb3JtU2hlbGxzW2dldE9wZXJhdGluZ1N5c3RlbSgpXSk7XHJcblxyXG4gICAgLy8gTGludXggYW5kIG1hY09TOiBBZGQgdGhlIGFtYmlndW91cyAnc2gnIGFzIGEgc3VwcG9ydGVkIHNoZWxsLiBJdCdzIG5vdCBwcmVzZW50IGluIFBsYXRmb3JtU2hlbGxzLCBiZWNhdXNlIGl0J3NcclxuICAgIC8vIG5vdCBkZXNpcmVkIHRvIGJlIGFuIGV4cGxpY2l0bHkgc2VsZWN0YWJsZSBzaGVsbCBhcyBpdCdzIHVuY2VydGFpbiwgd2hpY2ggc2hlbGwgaXQgYWN0dWFsbHkgcG9pbnRzIHRvLiBCdXQgaGF2ZVxyXG4gICAgLy8gaXQgc3VwcG9ydGVkIHdoZW4gaXQgY29tZXMgZnJvbSB0aGUgXCJVc2Ugc3lzdGVtIGRlZmF1bHQgKHNoKVwiIG9wdGlvbi5cclxuICAgIGlmICghaXNXaW5kb3dzKCkpIHtcclxuICAgICAgICAvLyBUaGUgcGxhdGZvcm0gaXMgZWl0aGVyIExpbnV4IG9yIG1hY09TLlxyXG4gICAgICAgIC8vIEFkZCAnc2gnIHN1cHBvcnQuXHJcbiAgICAgICAgc3VwcG9ydGVkX3NoZWxscy5wdXNoKFwic2hcIik7XHJcbiAgICB9XHJcblxyXG4gICAgZm9yIChjb25zdCBzdXBwb3J0ZWRfc2hlbGxfcGF0aCBvZiBzdXBwb3J0ZWRfc2hlbGxzKSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgdGhhdCB0aGUgc2hlbGwgZmlsZSBuYW1lcyBtYXRjaC4gSXQgZG9lc24ndCBtYXR0ZXIgaW4gd2hpY2ggZGlyZWN0b3J5IHRoZSBzaGVsbCBpcyBsb2NhdGVkIGluLlxyXG4gICAgICAgIGlmIChleHRyYWN0RmlsZU5hbWUoc3VwcG9ydGVkX3NoZWxsX3BhdGgpLnRvTG93ZXJDYXNlKCkgPT09IHNoZWxsX2ZpbGVfbmFtZS50b0xvd2VyQ2FzZSgpKSB7XHJcbiAgICAgICAgICAgIC8vIFRoZSBzaGVsbCBjYW4gYmUgY29uc2lkZXJlZCB0byBiZSBzdXBwb3J0ZWQuXHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBmYWxzZTtcclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuLy8gU0VUVElOR1MgQU5EIERFRkFVTFQgVkFMVUVTXHJcbmltcG9ydCB7U2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbn0gZnJvbSBcIi4vU2hlbGxDb21tYW5kQ29uZmlndXJhdGlvblwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi9tYWluXCI7XHJcbmltcG9ydCB7XHJcbiAgICBDdXN0b21WYXJpYWJsZUNvbmZpZ3VyYXRpb24sXHJcbiAgICBQcm9tcHRDb25maWd1cmF0aW9uLFxyXG59IGZyb20gXCIuLi9pbXBvcnRzXCI7XHJcbmltcG9ydCB7T3V0cHV0V3JhcHBlckNvbmZpZ3VyYXRpb259IGZyb20gXCIuLi9tb2RlbHMvb3V0cHV0X3dyYXBwZXIvT3V0cHV0V3JhcHBlclwiO1xyXG5pbXBvcnQge1xyXG4gICAgR2xvYmFsVmFyaWFibGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uLFxyXG59IGZyb20gXCIuLi92YXJpYWJsZXMvVmFyaWFibGVcIjtcclxuXHJcbmV4cG9ydCB0eXBlIFNldHRpbmdzVmVyc2lvblN0cmluZyA9IFwicHJpb3ItdG8tMC43LjBcIiB8IHN0cmluZztcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgU0NfTWFpblNldHRpbmdzIHtcclxuXHJcbiAgICAvLyBDb21tb246XHJcbiAgICBzZXR0aW5nc192ZXJzaW9uOiBTZXR0aW5nc1ZlcnNpb25TdHJpbmc7XHJcblxyXG4gICAgLy8gSGlkZGVuIHNldHRpbmdzIChubyBVSSBjb250cm9scyBpbiB0aGUgc2V0dGluZ3MgcGFuZWwpXHJcbiAgICAvKipcclxuICAgICAqIElmIHRydWUsIGxvZ2dpbmcgc3R1ZmYgdG8gY29uc29sZS5sb2coKSB3aWxsIGJlIGVuYWJsZWQuXHJcbiAgICAgKiBNaWdodCBhbHNvIGVuYWJsZSBzb21lIHRlc3Rpbmcge3t2YXJpYWJsZXN9fSBpbiB0aGUgZnV0dXJlLCBwZXJoYXBzLlxyXG4gICAgICovXHJcbiAgICBkZWJ1ZzogYm9vbGVhbjtcclxuICAgIG9ic2lkaWFuX2NvbW1hbmRfcGFsZXR0ZV9wcmVmaXg6IHN0cmluZztcclxuXHJcbiAgICAvLyBWYXJpYWJsZXM6XHJcbiAgICBwcmV2aWV3X3ZhcmlhYmxlc19pbl9jb21tYW5kX3BhbGV0dGU6IGJvb2xlYW47XHJcbiAgICBzaG93X2F1dG9jb21wbGV0ZV9tZW51OiBib29sZWFuO1xyXG5cclxuICAgIC8vIEVudmlyb25tZW50czpcclxuICAgIHdvcmtpbmdfZGlyZWN0b3J5OiBzdHJpbmc7XHJcbiAgICBkZWZhdWx0X3NoZWxsczogSVBsYXRmb3JtU3BlY2lmaWNTdHJpbmc7XHJcbiAgICBlbnZpcm9ubWVudF92YXJpYWJsZV9wYXRoX2F1Z21lbnRhdGlvbnM6IElQbGF0Zm9ybVNwZWNpZmljU3RyaW5nO1xyXG5cclxuICAgIC8vIE91dHB1dDpcclxuICAgIGVycm9yX21lc3NhZ2VfZHVyYXRpb246IG51bWJlcjtcclxuICAgIG5vdGlmaWNhdGlvbl9tZXNzYWdlX2R1cmF0aW9uOiBudW1iZXI7XHJcbiAgICBleGVjdXRpb25fbm90aWZpY2F0aW9uX21vZGU6IEV4ZWN1dGlvbk5vdGlmaWNhdGlvbk1vZGU7XHJcbiAgICBvdXRwdXRfY2hhbm5lbF9jbGlwYm9hcmRfYWxzb19vdXRwdXRzX3RvX25vdGlmaWNhdGlvbjogYm9vbGVhbjtcclxuXHJcbiAgICAvLyBFdmVudHM6XHJcbiAgICBlbmFibGVfZXZlbnRzOiBib29sZWFuO1xyXG5cclxuICAgIC8vIE1vZGFsczpcclxuICAgIGFwcHJvdmVfbW9kYWxzX2J5X3ByZXNzaW5nX2VudGVyX2tleTogYm9vbGVhbjtcclxuXHJcbiAgICAvLyBTaGVsbCBjb21tYW5kczpcclxuICAgIC8qKiBJZiBpdCdzIGEgbnVtYmVyLCBsaW1pdCB0aGUgbWF4IGhlaWdodCBvZiBhIHRleHRhcmVhLiBJZiBpdCdzIGZhbHNlLCBkb24ndCBsaW1pdCBhdCBhbGwuICovXHJcbiAgICBtYXhfdmlzaWJsZV9saW5lc19pbl9zaGVsbF9jb21tYW5kX2ZpZWxkczogbnVtYmVyIHwgZmFsc2U7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBXYXMgYmVmb3JlIDAuMTUuMDogQW4gb2JqZWN0IHdoZXJlIHRoZSBrZXkgd2FzIGFuIGlkIGFuZCB2YWx1ZSB3YXMgYSBTaGVsbENvbW1hbmRDb25maWd1cmF0aW9uIG9iamVjdC5cclxuICAgICAqIE5vdyBpdCdzIGFuIGFycmF5IG9mIFNoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb24gb2JqZWN0cy5cclxuICAgICAqL1xyXG4gICAgc2hlbGxfY29tbWFuZHM6IFNoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb25bXTtcclxuXHJcbiAgICAvLyBQcm9tcHRzOlxyXG4gICAgcHJvbXB0czogUHJvbXB0Q29uZmlndXJhdGlvbltdO1xyXG5cclxuICAgIC8vIEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmb3IgYnVpbHQtaW4gdmFyaWFibGVzLiAoQ3VycmVudGx5IGp1c3QgZ2xvYmFsIGRlZmF1bHQgdmFsdWVzKS5cclxuICAgIGJ1aWx0aW5fdmFyaWFibGVzOiB7XHJcbiAgICAgICAgW3ZhcmlhYmxlTmFtZTogc3RyaW5nXToge1xyXG4gICAgICAgICAgICBkZWZhdWx0X3ZhbHVlOiBHbG9iYWxWYXJpYWJsZURlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24gfCBudWxsLFxyXG4gICAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgLy8gQ3VzdG9tIHZhcmlhYmxlc1xyXG4gICAgY3VzdG9tX3ZhcmlhYmxlczogQ3VzdG9tVmFyaWFibGVDb25maWd1cmF0aW9uW107XHJcblxyXG4gICAgLy8gT3V0cHV0IHdyYXBwZXJzXHJcbiAgICBvdXRwdXRfd3JhcHBlcnM6IE91dHB1dFdyYXBwZXJDb25maWd1cmF0aW9uW107XHJcblxyXG4gICAgLy8gTGVnYWN5OlxyXG4gICAgLyoqIEBkZXByZWNhdGVkIFVzZSBzaGVsbF9jb21tYW5kcyBvYmplY3QgaW5zdGVhZCBvZiB0aGlzIGFycmF5LiBGcm9tIG5vdyBvbiwgdGhpcyBhcnJheSBjYW4gYmUgdXNlZCBvbmx5IGZvciBtaWdyYXRpbmcgb2xkIGNvbmZpZ3VyYXRpb24gdG8gc2hlbGxfY29tbWFuZHMuKi9cclxuICAgIGNvbW1hbmRzPzogc3RyaW5nW107XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXREZWZhdWx0U2V0dGluZ3MoaXNfbmV3X2luc3RhbGxhdGlvbjogYm9vbGVhbik6IFNDX01haW5TZXR0aW5ncyB7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAgIC8vIENvbW1vbjpcclxuICAgICAgICBzZXR0aW5nc192ZXJzaW9uOiBpc19uZXdfaW5zdGFsbGF0aW9uXHJcbiAgICAgICAgICAgID8gU0NfUGx1Z2luLlNldHRpbmdzVmVyc2lvbiAvLyBGb3IgbmV3IGluc3RhbGxhdGlvbnMsIGEgc3BlY2lmaWMgc2V0dGluZ3MgdmVyc2lvbiBudW1iZXIgY2FuIGJlIHVzZWQsIGFzIG1pZ3JhdGlvbnMgZG8gbm90IG5lZWQgdG8gYmUgdGFrZW4gaW50byBhY2NvdW50LlxyXG4gICAgICAgICAgICA6IFwicHJpb3ItdG8tMC43LjBcIiAgLy8gVGhpcyB3aWxsIGJlIHN1YnN0aXR1dGVkIGJ5IFNoZWxsQ29tbWFuZHNQbHVnaW4uc2F2ZVNldHRpbmdzKCkgd2hlbiB0aGUgc2V0dGluZ3MgYXJlIHNhdmVkLlxyXG4gICAgICAgICxcclxuXHJcbiAgICAgICAgLy8gSGlkZGVuIHNldHRpbmdzIChubyBVSSBjb250cm9scyBpbiB0aGUgc2V0dGluZ3MgcGFuZWwpXHJcbiAgICAgICAgZGVidWc6IGZhbHNlLFxyXG4gICAgICAgIG9ic2lkaWFuX2NvbW1hbmRfcGFsZXR0ZV9wcmVmaXg6IFwiRXhlY3V0ZTogXCIsXHJcblxyXG4gICAgICAgIC8vIFZhcmlhYmxlczpcclxuICAgICAgICBwcmV2aWV3X3ZhcmlhYmxlc19pbl9jb21tYW5kX3BhbGV0dGU6IHRydWUsXHJcbiAgICAgICAgc2hvd19hdXRvY29tcGxldGVfbWVudTogdHJ1ZSxcclxuXHJcbiAgICAgICAgLy8gRW52aXJvbm1lbnRzOlxyXG4gICAgICAgIHdvcmtpbmdfZGlyZWN0b3J5OiBcIlwiLFxyXG4gICAgICAgIGRlZmF1bHRfc2hlbGxzOiB7fSxcclxuICAgICAgICBlbnZpcm9ubWVudF92YXJpYWJsZV9wYXRoX2F1Z21lbnRhdGlvbnM6IHt9LFxyXG5cclxuICAgICAgICAvLyBPdXRwdXQ6XHJcbiAgICAgICAgZXJyb3JfbWVzc2FnZV9kdXJhdGlvbjogMjAsXHJcbiAgICAgICAgbm90aWZpY2F0aW9uX21lc3NhZ2VfZHVyYXRpb246IDEwLFxyXG4gICAgICAgIGV4ZWN1dGlvbl9ub3RpZmljYXRpb25fbW9kZTogXCJkaXNhYmxlZFwiLFxyXG4gICAgICAgIG91dHB1dF9jaGFubmVsX2NsaXBib2FyZF9hbHNvX291dHB1dHNfdG9fbm90aWZpY2F0aW9uOiB0cnVlLFxyXG5cclxuICAgICAgICAvLyBFdmVudHM6XHJcbiAgICAgICAgZW5hYmxlX2V2ZW50czogdHJ1ZSxcclxuXHJcbiAgICAgICAgLy8gTW9kYWxzOlxyXG4gICAgICAgIGFwcHJvdmVfbW9kYWxzX2J5X3ByZXNzaW5nX2VudGVyX2tleTogdHJ1ZSxcclxuXHJcbiAgICAgICAgLy8gU2hlbGwgY29tbWFuZHM6XHJcbiAgICAgICAgbWF4X3Zpc2libGVfbGluZXNfaW5fc2hlbGxfY29tbWFuZF9maWVsZHM6IGZhbHNlLCAvLyBObyBsaW1pdCBieSBkZWZhdWx0LlxyXG4gICAgICAgIHNoZWxsX2NvbW1hbmRzOiBbXSxcclxuXHJcbiAgICAgICAgLy8gUHJvbXB0czpcclxuICAgICAgICBwcm9tcHRzOiBbXSxcclxuXHJcbiAgICAgICAgLy8gQWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZvciBidWlsdC1pbiB2YXJpYWJsZXM6XHJcbiAgICAgICAgYnVpbHRpbl92YXJpYWJsZXM6IHt9LFxyXG5cclxuICAgICAgICAvLyBDdXN0b20gdmFyaWFibGVzXHJcbiAgICAgICAgY3VzdG9tX3ZhcmlhYmxlczogW10sXHJcblxyXG4gICAgICAgIC8vIE91dHB1dCB3cmFwcGVyc1xyXG4gICAgICAgIG91dHB1dF93cmFwcGVyczogW10sXHJcbiAgICB9O1xyXG59XHJcblxyXG4vKipcclxuICogQWxsIE9TZXMgc3VwcG9ydGVkIGJ5IHRoZSBTaGVsbCBjb21tYW5kcyBwbHVnaW4uXHJcbiAqIFZhbHVlcyBhcmUgYm9ycm93ZWQgZnJvbSBOb2RlSlMuUGxhdGZvcm0uXHJcbiAqIFwiZGFyd2luXCIgPSBNYWNpbnRvc2guXHJcbiAqXHJcbiAqIFRoaXMgdHlwZSBtdXN0IGJlIHN5bmNocm9ub3VzIHRvIElPcGVyYXRpbmdTeXN0ZW1TcGVjaWZpY1N0cmluZyBpbnRlcmZhY2UuXHJcbiAqXHJcbiAqIEBzZWUgTm9kZUpTLlBsYXRmb3JtXHJcbiAqL1xyXG5leHBvcnQgdHlwZSBQbGF0Zm9ybUlkID0gXCJkYXJ3aW5cIiB8IFwibGludXhcIiB8IFwid2luMzJcIjtcclxuXHJcbmV4cG9ydCBjb25zdCBQbGF0Zm9ybU5hbWVzOiBJUGxhdGZvcm1TcGVjaWZpY1N0cmluZyA9IHtcclxuICAgIGRhcndpbjogXCJNYWNpbnRvc2hcIixcclxuICAgIGxpbnV4OiBcIkxpbnV4XCIsXHJcbiAgICB3aW4zMjogXCJXaW5kb3dzXCIsXHJcbn07XHJcblxyXG4vKipcclxuICogQWxsIE9TZXMgc3VwcG9ydGVkIGJ5IHRoZSBTaGVsbCBjb21tYW5kcyBwbHVnaW4uXHJcbiAqIFZhbHVlcyBhcmUgYm9ycm93ZWQgZnJvbSBOb2RlSlMuUGxhdGZvcm0uXHJcbiAqXHJcbiAqIFRoaXMgaW50ZXJmYWNlIG11c3QgYmUgc3luY2hyb25vdXMgdG8gT3BlcmF0aW5nU3lzdGVtTmFtZSB0eXBlLlxyXG4gKlxyXG4gKiBAc2VlIE5vZGVKUy5QbGF0Zm9ybVxyXG4gKi9cclxuZXhwb3J0IGludGVyZmFjZSBJUGxhdGZvcm1TcGVjaWZpY1N0cmluZyB7XHJcbiAgICAvKiogVGhpcyBpcyBNYWNpbnRvc2ggKi9cclxuICAgIGRhcndpbj86IHN0cmluZyxcclxuICAgIGxpbnV4Pzogc3RyaW5nLFxyXG4gICAgd2luMzI/OiBzdHJpbmcsXHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgSVBsYXRmb3JtU3BlY2lmaWNTdHJpbmdXaXRoRGVmYXVsdCBleHRlbmRzIElQbGF0Zm9ybVNwZWNpZmljU3RyaW5ne1xyXG4gICAgZGVmYXVsdDogc3RyaW5nLFxyXG59XHJcblxyXG5leHBvcnQgdHlwZSBJQ29tbWFuZFBhbGV0dGVPcHRpb25zID0ge1xyXG4gICAgZW5hYmxlZDogc3RyaW5nO1xyXG4gICAgdW5saXN0ZWQ6IHN0cmluZztcclxuICAgIGRpc2FibGVkOiBzdHJpbmc7XHJcbn1cclxuXHJcbmV4cG9ydCBjb25zdCBDb21tYW5kUGFsZXR0ZU9wdGlvbnM6IElDb21tYW5kUGFsZXR0ZU9wdGlvbnMgPSB7XHJcbiAgICBlbmFibGVkOiBcIkNvbW1hbmQgcGFsZXR0ZSAmIGhvdGtleXNcIixcclxuICAgIHVubGlzdGVkOiBcIkhvdGtleXMgb25seVwiLFxyXG4gICAgZGlzYWJsZWQ6IFwiRXhjbHVkZWRcIixcclxufTtcclxuXHJcbmV4cG9ydCB0eXBlIEV4ZWN1dGlvbk5vdGlmaWNhdGlvbk1vZGUgPSBcImRpc2FibGVkXCIgfCBcInF1aWNrXCIgfCBcInBlcm1hbmVudFwiIHwgXCJpZi1sb25nXCI7IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1xyXG4gICAgQ2hpbGRQcm9jZXNzLFxyXG4gICAgc3Bhd24sXHJcbiAgICBTcGF3bk9wdGlvbnMsXHJcbn0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcclxuaW1wb3J0IHtcclxuICAgIGNsb25lT2JqZWN0LFxyXG4gICAgZ2V0T3BlcmF0aW5nU3lzdGVtLFxyXG4gICAgZ2V0VmF1bHRBYnNvbHV0ZVBhdGgsXHJcbn0gZnJvbSBcIi4vQ29tbW9uXCI7XHJcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcInBhdGhcIjtcclxuaW1wb3J0ICogYXMgZnMgZnJvbSBcImZzXCI7XHJcbmltcG9ydCB7XHJcbiAgICBoYW5kbGVCdWZmZXJlZE91dHB1dCxcclxuICAgIHN0YXJ0UmVhbHRpbWVPdXRwdXRIYW5kbGluZyxcclxufSBmcm9tIFwiLi9vdXRwdXRfY2hhbm5lbHMvT3V0cHV0Q2hhbm5lbEZ1bmN0aW9uc1wiO1xyXG5pbXBvcnQge1NoZWxsQ29tbWFuZFBhcnNpbmdQcm9jZXNzLCBTaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0LCBUU2hlbGxDb21tYW5kfSBmcm9tIFwiLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7aXNTaGVsbFN1cHBvcnRlZH0gZnJvbSBcIi4vU2hlbGxcIjtcclxuaW1wb3J0IHtkZWJ1Z0xvZ30gZnJvbSBcIi4vRGVidWdcIjtcclxuaW1wb3J0IHtTQ19FdmVudH0gZnJvbSBcIi4vZXZlbnRzL1NDX0V2ZW50XCI7XHJcbmltcG9ydCB7XHJcbiAgICBDb25maXJtYXRpb25Nb2RhbCxcclxuICAgIGNvbnZlcnROZXdsaW5lc1RvUEFUSFNlcGFyYXRvcnMsXHJcbiAgICBnZXRQQVRIRW52aXJvbm1lbnRWYXJpYWJsZU5hbWUsXHJcbiAgICBnZXRQQVRIU2VwYXJhdG9yLFxyXG4gICAgUHJlYWN0aW9uLFxyXG59IGZyb20gXCIuL2ltcG9ydHNcIjtcclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi9tYWluXCI7XHJcbmltcG9ydCB7XHJcbiAgICBFeGVjdXRpb25Ob3RpZmljYXRpb25Nb2RlLFxyXG4gICAgUGxhdGZvcm1OYW1lcyxcclxufSBmcm9tIFwiLi9zZXR0aW5ncy9TQ19NYWluU2V0dGluZ3NcIjtcclxuaW1wb3J0IHtcclxuICAgIE91dHB1dENoYW5uZWxDb2RlLFxyXG4gICAgT3V0cHV0Q2hhbm5lbENvZGVzLFxyXG4gICAgT3V0cHV0U3RyZWFtLFxyXG59IGZyb20gXCIuL291dHB1dF9jaGFubmVscy9PdXRwdXRDaGFubmVsQ29kZVwiO1xyXG5pbXBvcnQge1JlYWRhYmxlfSBmcm9tIFwic3RyZWFtXCI7XHJcbmltcG9ydCB7Tm90aWNlfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHtPdXRwdXRDaGFubmVsfSBmcm9tIFwiLi9vdXRwdXRfY2hhbm5lbHMvT3V0cHV0Q2hhbm5lbFwiO1xyXG5pbXBvcnQge1BhcnNpbmdSZXN1bHR9IGZyb20gXCIuL3ZhcmlhYmxlcy9wYXJzZVZhcmlhYmxlc1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNoZWxsQ29tbWFuZEV4ZWN1dG9yIHtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBwcml2YXRlIHBsdWdpbjogU0NfUGx1Z2luLFxyXG4gICAgICAgIHByaXZhdGUgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kLFxyXG5cclxuICAgICAgICAvKiogTmVlZGVkIGZvciBQcmVhY3Rpb25zIHRvIGJlIGFibGUgdG8gYWNjZXNzIGFsbCB2YXJpYWJsZXMsIGluIGNhc2UgYW55IHZhcmlhYmxlcyBhcmUgdXNlZCBieSBhIFByZWFjdGlvbi4gVXNlIG51bGwsIGlmIHRoZSBzaGVsbCBjb21tYW5kIGV4ZWN1dGlvbiBoYXBwZW5zIG91dHNpZGUgb2YgYW55IGV2ZW50IGNvbnRleHQuICovXHJcbiAgICAgICAgcHJpdmF0ZSBzY19ldmVudDogU0NfRXZlbnQgfCBudWxsLFxyXG4gICAgKSB7fVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUGVyZm9ybXMgcHJlYWN0aW9ucywgYW5kIGlmIHRoZXkgYWxsIGdpdmUgcmVzb2x2ZWQgUHJvbWlzZXMsIGV4ZWN1dGVzIHRoZSBzaGVsbCBjb21tYW5kLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgYXN5bmMgZG9QcmVhY3Rpb25zQW5kRXhlY3V0ZVNoZWxsQ29tbWFuZChwYXJzaW5nX3Byb2Nlc3M/OiBTaGVsbENvbW1hbmRQYXJzaW5nUHJvY2Vzcywgb3ZlcnJpZGluZ19vdXRwdXRfY2hhbm5lbD86IE91dHB1dENoYW5uZWxDb2RlKSB7XHJcbiAgICAgICAgY29uc3QgcHJlYWN0aW9ucyA9IHRoaXMudF9zaGVsbF9jb21tYW5kLmdldFByZWFjdGlvbnMoKTtcclxuXHJcbiAgICAgICAgLy8gRG9lcyBhbiBhbHJlYWR5IHN0YXJ0ZWQgUGFyc2luZ1Byb2Nlc3MgZXhpc3Q/XHJcbiAgICAgICAgaWYgKCFwYXJzaW5nX3Byb2Nlc3MpIHtcclxuICAgICAgICAgICAgLy8gTm8gUGFyc2luZ1Byb2Nlc3MgeWV0LlxyXG4gICAgICAgICAgICAvLyBDcmVhdGUgb25lIGFuZCBwYXJzZSBhbGwgdmFyaWFibGVzIHRoYXQgYXJlIHNhZmUgdG8gcGFyc2UgYmVmb3JlIHByZWFjdGlvbnMuXHJcbiAgICAgICAgICAgIGRlYnVnTG9nKFwiR29pbmcgdG8gcHJlcGFyZSBwb3NzaWJsZSBQcmVhY3Rpb25zLCBidXQgd2lsbCBmaXJzdCBzdGFydCBhIHZhcmlhYmxlIHBhcnNpbmcgcHJvY2Vzcy4gRGVwZW5kaW5nIG9uIHBvc3NpYmxlIFByZWFjdGlvbnMsIHRoaXMgbWlnaHQgbm90IHlldCBwYXJzZSBhbGwgdmFyaWFibGVzLlwiKTtcclxuICAgICAgICAgICAgcGFyc2luZ19wcm9jZXNzID0gdGhpcy50X3NoZWxsX2NvbW1hbmQuY3JlYXRlUGFyc2luZ1Byb2Nlc3ModGhpcy5zY19ldmVudCk7XHJcbiAgICAgICAgICAgIC8vIFBhcnNlIHRoZSBmaXJzdCBzZXQgb2YgdmFyaWFibGVzLCBub3QgYWxsIHNldHMuXHJcbiAgICAgICAgICAgIGlmICghYXdhaXQgcGFyc2luZ19wcm9jZXNzLnByb2Nlc3MoKSkge1xyXG4gICAgICAgICAgICAgICAgLy8gU29tZSBlcnJvcnMgaGFwcGVuZWQuXHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIldpbGwgbm90IHByZXBhcmUgcG9zc2libGUgUHJlYWN0aW9ucywgYmVjYXVzZSB0aGUgcGFyc2luZyBwcm9jZXNzIGZhaWxlZC4gV2lsbCBjYW5jZWwgc2hlbGwgY29tbWFuZCBleGVjdXRpb24uXCIpO1xyXG4gICAgICAgICAgICAgICAgcGFyc2luZ19wcm9jZXNzLmRpc3BsYXlFcnJvck1lc3NhZ2VzKCk7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBkZWJ1Z0xvZyhcIkdvaW5nIHRvIHByZXBhcmUgcG9zc2libGUgUHJlYWN0aW9ucyB3aXRoIGFuIGFscmVhZHkgc3RhcnRlZCB2YXJpYWJsZSBwYXJzaW5nIHByb2Nlc3MuXCIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGEgcGlwZWxpbmUgZm9yIHByZWFjdGlvbnMuXHJcbiAgICAgICAgbGV0IHByZWFjdGlvbl9waXBlbGluZSA9IFByb21pc2UucmVzb2x2ZSh0cnVlKTsgLy8gV2lsbCBjb250YWluIGEgc2VyaWVzIG9mIHByZWFjdGlvbiBwZXJmb3Jtcy5cclxuXHJcbiAgICAgICAgLy8gQ29uZmlybSBleGVjdXRpb24gZnJvbSBhIHVzZXIsIGlmIG5lZWRlZC5cclxuICAgICAgICAvLyBJIGhhdmVuJ3QgZGVjaWRlZCB5ZXQgaWYgSSB3YW50IHRvIG1vdmUgdGhpcyB0byBiZSBpdHMgb3duIFByZWFjdGlvbiBzdWJjbGFzcy4gTWlnaHQgbWFrZSBzZW5zZSwgYnV0IHJlcXVpcmVzIGNvbmZpZ3VyYXRpb24gbWlncmF0aW9uLlxyXG4gICAgICAgIGlmICh0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRDb25maWd1cmF0aW9uKCkuY29uZmlybV9leGVjdXRpb24pIHtcclxuICAgICAgICAgICAgcHJlYWN0aW9uX3BpcGVsaW5lID0gcHJlYWN0aW9uX3BpcGVsaW5lLnRoZW4oKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgZGVidWdMb2coXCJBc2tpbmcgYSBjb25maXJtYXRpb24gZnJvbSBhIHVzZXIgdG8gZXhlY3V0ZSBzaGVsbCBjb21tYW5kICNcIiArIHRoaXMudF9zaGVsbF9jb21tYW5kLmdldElkKCkpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBjb25maXJtYXRpb25fbW9kYWwgPSBuZXcgQ29uZmlybWF0aW9uTW9kYWwoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRBbGlhc09yU2hlbGxDb21tYW5kKCksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiRXhlY3V0ZSB0aGlzIHNoZWxsIGNvbW1hbmQ/XCIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiWWVzLCBleGVjdXRlXCIsXHJcbiAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgICAgICBjb25maXJtYXRpb25fbW9kYWwub3BlbigpO1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbmZpcm1hdGlvbl9tb2RhbC5wcm9taXNlLnRoZW4oKGV4ZWN1dGlvbl9jb25maXJtZWQ6IGJvb2xlYW4pID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGV4ZWN1dGlvbl9jb25maXJtZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZSBQcm9tcHRNb2RhbCBoYXMgYmVlbiBjbG9zZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBpZiB1c2VyIHdhbnRlZCB0byBleGVjdXRlIHRoZSBzaGVsbCBjb21tYW5kIG9yIGNhbmNlbC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChleGVjdXRpb25fY29uZmlybWVkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVXNlciB3YW50cyB0byBleGVjdXRlLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiVXNlciBjb25maXJtZWQgdG8gZXhlY3V0ZSBzaGVsbCBjb21tYW5kICNcIiArIHRoaXMudF9zaGVsbF9jb21tYW5kLmdldElkKCkpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUodHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVzZXIgd2FudHMgdG8gY2FuY2VsLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiVXNlciBjYW5jZWxsZWQgZXhlY3V0aW9uIG9mIHNoZWxsIGNvbW1hbmQgI1wiICsgdGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0SWQoKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShmYWxzZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBQZXJmb3JtIHByZWFjdGlvbnNcclxuICAgICAgICBwcmVhY3Rpb25zLmZvckVhY2goKHByZWFjdGlvbjogUHJlYWN0aW9uKSA9PiB7XHJcbiAgICAgICAgICAgIGRlYnVnTG9nKGBBZGRpbmcgUHJlYWN0aW9uIG9mIHR5cGUgJyR7cHJlYWN0aW9uLmNvbmZpZ3VyYXRpb24udHlwZX0nIHRvIHBpcGVsaW5lLmApO1xyXG4gICAgICAgICAgICBwcmVhY3Rpb25fcGlwZWxpbmUgPSBwcmVhY3Rpb25fcGlwZWxpbmUudGhlbigoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhgQ2FsbGluZyBQcmVhY3Rpb24gb2YgdHlwZSAnJHtwcmVhY3Rpb24uY29uZmlndXJhdGlvbi50eXBlfScuYCk7XHJcbiAgICAgICAgICAgICAgICBpZiAoIXBhcnNpbmdfcHJvY2Vzcykge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFNob3VsZCBoYXZlIGEgUGFyc2luZ1Byb2Nlc3MgYXQgdGhpcyBwb2ludC5cclxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyBwYXJzaW5nIHByb2Nlc3MuIENhbm5vdCBkbyBwcmVhY3Rpb24uXCIpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHByZWFjdGlvbi5wZXJmb3JtKHBhcnNpbmdfcHJvY2VzcywgdGhpcy5zY19ldmVudCk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIGlmICgwID09PSBwcmVhY3Rpb25zLmxlbmd0aCkge1xyXG4gICAgICAgICAgICBkZWJ1Z0xvZyhcIk5vIFByZWFjdGlvbnMgdG8gcGVyZm9ybS4gVGhpcyBpcyBvay5cIik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBwcmVhY3Rpb25fcGlwZWxpbmUudGhlbihhc3luYyAoY2FuX2V4ZWN1dGU6IGJvb2xlYW4pID0+IHtcclxuICAgICAgICAgICAgaWYgKGNhbl9leGVjdXRlKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBQYXJzZSBlaXRoZXIgYWxsIHZhcmlhYmxlcywgb3IgaWYgc29tZSB2YXJpYWJsZXMgYXJlIGFscmVhZHkgcGFyc2VkLCB0aGVuIGp1c3QgdGhlIHJlc3QuIE1pZ2h0IGFsc28gYmUgdGhhdFxyXG4gICAgICAgICAgICAgICAgLy8gYWxsIHZhcmlhYmxlcyBhcmUgYWxyZWFkeSBwYXJzZWQuXHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIlBhcnNpbmcgYWxsIHRoZSByZXN0IG9mIHRoZSB2YXJpYWJsZXMgKGlmIHRoZXJlIGFyZSBhbnkgbGVmdCkuXCIpO1xyXG4gICAgICAgICAgICAgICAgaWYgKCFwYXJzaW5nX3Byb2Nlc3MpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBTaG91bGQgaGF2ZSBhIFBhcnNpbmdQcm9jZXNzIGF0IHRoaXMgcG9pbnQuXHJcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gcGFyc2luZyBwcm9jZXNzLiBDYW5ub3QgZXhlY3V0ZSBzaGVsbCBjb21tYW5kLlwiKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGlmIChhd2FpdCBwYXJzaW5nX3Byb2Nlc3MucHJvY2Vzc1Jlc3QoKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFBhcnNpbmcgdGhlIHJlc3Qgb2YgdGhlIHZhcmlhYmxlcyBzdWNjZWVkZWRcclxuICAgICAgICAgICAgICAgICAgICAvLyBFeGVjdXRlIHRoZSBzaGVsbCBjb21tYW5kLlxyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhcnNpbmdfcmVzdWx0cyA9IHBhcnNpbmdfcHJvY2Vzcy5nZXRQYXJzaW5nUmVzdWx0cygpO1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHQ6IFNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQgPSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNoZWxsX2NvbW1hbmQ6IChwYXJzaW5nX3Jlc3VsdHNbXCJzaGVsbF9jb21tYW5kXCJdIGFzIFBhcnNpbmdSZXN1bHQpLnBhcnNlZF9jb250ZW50IGFzIHN0cmluZyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgYWxpYXM6IChwYXJzaW5nX3Jlc3VsdHNbXCJhbGlhc1wiXSBhcyBQYXJzaW5nUmVzdWx0KS5wYXJzZWRfY29udGVudCBhcyBzdHJpbmcsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGVudmlyb25tZW50X3ZhcmlhYmxlX3BhdGhfYXVnbWVudGF0aW9uOiAocGFyc2luZ19yZXN1bHRzLmVudmlyb25tZW50X3ZhcmlhYmxlX3BhdGhfYXVnbWVudGF0aW9uIGFzIFBhcnNpbmdSZXN1bHQpLnBhcnNlZF9jb250ZW50IGFzIHN0cmluZyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgc3RkaW5Db250ZW50OiBwYXJzaW5nX3Jlc3VsdHMuc3RkaW5Db250ZW50Py5wYXJzZWRfY29udGVudCBhcyBzdHJpbmcsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dF93cmFwcGVyX3N0ZG91dDogcGFyc2luZ19yZXN1bHRzLm91dHB1dF93cmFwcGVyX3N0ZG91dD8ucGFyc2VkX2NvbnRlbnQgYXMgc3RyaW5nLCAvLyBPdXRwdXQgd3JhcHBlcnMgYXJlIG5vdCBhbHdheXMgcHJlc2VudC4gSWYgdGhleSBhcmUgYWJzZW50LCB1c2UgdW5kZWZpbmVkLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBvdXRwdXRfd3JhcHBlcl9zdGRlcnI6IHBhcnNpbmdfcmVzdWx0cy5vdXRwdXRfd3JhcHBlcl9zdGRlcnI/LnBhcnNlZF9jb250ZW50IGFzIHN0cmluZyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgc3VjY2VlZGVkOiB0cnVlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvcl9tZXNzYWdlczogW10sXHJcbiAgICAgICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIldpbGwgY2FsbCBTaGVsbENvbW1hbmRFeGVjdXRvci5leGVjdXRlU2hlbGxDb21tYW5kKCkuXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZXhlY3V0ZVNoZWxsQ29tbWFuZChzaGVsbF9jb21tYW5kX3BhcnNpbmdfcmVzdWx0LCBvdmVycmlkaW5nX291dHB1dF9jaGFubmVsKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gUGFyc2luZyBoYXMgZmFpbGVkLlxyXG4gICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiUGFyc2luZyB0aGUgcmVzdCBvZiB0aGUgdmFyaWFibGVzIGZhaWxlZC5cIik7XHJcbiAgICAgICAgICAgICAgICAgICAgcGFyc2luZ19wcm9jZXNzLmRpc3BsYXlFcnJvck1lc3NhZ2VzKCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBDYW5jZWwgZXhlY3V0aW9uXHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIlNoZWxsIGNvbW1hbmQgZXhlY3V0aW9uIGNhbmNlbGxlZC5cIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuXHJcblxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRG9lcyBub3QgYXNrIGZvciBjb25maXJtYXRpb24gYmVmb3JlIGV4ZWN1dGlvbi4gVGhpcyBzaG91bGQgb25seSBiZSBjYWxsZWQgaWY6IGEpIGEgY29uZmlybWF0aW9uIGlzIGFscmVhZHkgYXNrZWQgZnJvbSBhIHVzZXIsIG9yIGIpIHRoaXMgY29tbWFuZCBpcyBkZWZpbmVkIG5vdCB0byBuZWVkIGEgY29uZmlybWF0aW9uLlxyXG4gICAgICogVXNlIGNvbmZpcm1BbmRFeGVjdXRlU2hlbGxDb21tYW5kKCkgaW5zdGVhZCB0byBoYXZlIGEgY29uZmlybWF0aW9uIGFza2VkIGJlZm9yZSB0aGUgZXhlY3V0aW9uLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBzaGVsbF9jb21tYW5kX3BhcnNpbmdfcmVzdWx0IFRoZSBhY3R1YWwgc2hlbGwgY29tbWFuZCB0aGF0IHdpbGwgYmUgZXhlY3V0ZWQgaXMgdGFrZW4gZnJvbSB0aGlzIG9iamVjdCdzICcuc2hlbGxfY29tbWFuZCcgcHJvcGVydHkuXHJcbiAgICAgKiBAcGFyYW0gb3ZlcnJpZGluZ19vdXRwdXRfY2hhbm5lbCBPcHRpb25hbC4gSWYgc3BlY2lmaWVkLCBhbGwgb3V0cHV0IHN0cmVhbXMgd2lsbCBiZSBkaXJlY3RlZCB0byB0aGlzIG91dHB1dCBjaGFubmVsLiBPdGhlcndpc2UsIG91dHB1dCBjaGFubmVscyBhcmUgZGV0ZXJtaW5lZCBmcm9tIHRoaXMudF9zaGVsbF9jb21tYW5kLlxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGV4ZWN1dGVTaGVsbENvbW1hbmQoc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdDogU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdCwgb3ZlcnJpZGluZ19vdXRwdXRfY2hhbm5lbD86IE91dHB1dENoYW5uZWxDb2RlKSB7XHJcbiAgICAgICAgY29uc3Qgd29ya2luZ19kaXJlY3RvcnkgPSB0aGlzLmdldFdvcmtpbmdEaXJlY3RvcnkoKTtcclxuXHJcbiAgICAgICAgLy8gRGVmaW5lIG91dHB1dCBjaGFubmVsc1xyXG4gICAgICAgIGxldCBvdXRwdXRDaGFubmVscyA9IHRoaXMudF9zaGVsbF9jb21tYW5kLmdldE91dHB1dENoYW5uZWxzKCk7XHJcbiAgICAgICAgaWYgKG92ZXJyaWRpbmdfb3V0cHV0X2NoYW5uZWwpIHtcclxuICAgICAgICAgICAgLy8gSWdub3JlIHRoZSBzaGVsbCBjb21tYW5kJ3Mgbm9ybWFsIGNoYW5uZWxzIGFuZCB1c2UgdGVtcG9yYXJpbHkgc29tZXRoaW5nIGVsc2UuXHJcbiAgICAgICAgICAgb3V0cHV0Q2hhbm5lbHMgPSB7XHJcbiAgICAgICAgICAgICAgICdzdGRvdXQnOiBvdmVycmlkaW5nX291dHB1dF9jaGFubmVsLFxyXG4gICAgICAgICAgICAgICAnc3RkZXJyJzogb3ZlcnJpZGluZ19vdXRwdXRfY2hhbm5lbCxcclxuICAgICAgICAgICB9O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgdGhhdCB0aGUgc2hlbGwgY29tbWFuZCBpcyBub3QgZW1wdHlcclxuICAgICAgICBjb25zdCBzaGVsbF9jb21tYW5kID0gc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdC5zaGVsbF9jb21tYW5kLnRyaW0oKTtcclxuICAgICAgICBpZiAoIXNoZWxsX2NvbW1hbmQubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgIC8vIEl0IGlzIGVtcHR5XHJcbiAgICAgICAgICAgIGNvbnN0IGVycm9yX21lc3NhZ2UgPSB0aGlzLmdldEVycm9yTWVzc2FnZUZvckVtcHR5U2hlbGxDb21tYW5kKCk7XHJcbiAgICAgICAgICAgIGRlYnVnTG9nKGVycm9yX21lc3NhZ2UpO1xyXG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5uZXdFcnJvcihlcnJvcl9tZXNzYWdlKTtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgdGhhdCB0aGUgY3VycmVudGx5IGRlZmluZWQgc2hlbGwgaXMgc3VwcG9ydGVkIGJ5IHRoaXMgcGx1Z2luLiBJZiB1c2luZyBzeXN0ZW0gZGVmYXVsdCBzaGVsbCwgaXQncyBwb3NzaWJsZVxyXG4gICAgICAgIC8vIHRoYXQgdGhlIHNoZWxsIGlzIHNvbWV0aGluZyB0aGF0IGlzIG5vdCBzdXBwb3J0ZWQuIEFsc28sIHRoZSBzZXR0aW5ncyBmaWxlIGNhbiBiZSBlZGl0ZWQgbWFudWFsbHksIGFuZCBpbmNvcnJlY3RcclxuICAgICAgICAvLyBzaGVsbCBjYW4gYmUgd3JpdHRlbiB0aGVyZS5cclxuICAgICAgICBjb25zdCBzaGVsbCA9IHRoaXMudF9zaGVsbF9jb21tYW5kLmdldFNoZWxsKCk7XHJcbiAgICAgICAgaWYgKCFpc1NoZWxsU3VwcG9ydGVkKHNoZWxsKSkge1xyXG4gICAgICAgICAgICBkZWJ1Z0xvZyhcIlNoZWxsIGlzIG5vdCBzdXBwb3J0ZWQ6IFwiICsgc2hlbGwpO1xyXG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5uZXdFcnJvcihcIlRoaXMgcGx1Z2luIGRvZXMgbm90IHN1cHBvcnQgdGhlIGZvbGxvd2luZyBzaGVsbDogXCIgKyBzaGVsbCk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIERlZmluZSBhbiBvYmplY3QgZm9yIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICAgICAgICBjb25zdCBlbnZpcm9ubWVudF92YXJpYWJsZXMgPSBjbG9uZU9iamVjdDx0eXBlb2YgcHJvY2Vzcy5lbnY+KHByb2Nlc3MuZW52KTsgLy8gTmVlZCB0byBjbG9uZSBwcm9jZXNzLmVudiwgb3RoZXJ3aXNlIHRoZSBtb2RpZmljYXRpb25zIGJlbG93IHdpbGwgYmUgc3RvcmVkIHBlcm1hbmVudGx5IHVudGlsIE9ic2lkaWFuIGlzIGhhcmQtcmVzdGFydGVkICg9IGNsb3NlZCBhbmQgbGF1bmNoZWQgYWdhaW4pLlxyXG5cclxuICAgICAgICAvLyBBdWdtZW50IHRoZSBQQVRIIGVudmlyb25tZW50IHZhcmlhYmxlIChpZiB3YW50ZWQpXHJcbiAgICAgICAgY29uc3QgYXVnbWVudGVkX3BhdGggPSB0aGlzLmF1Z21lbnRQQVRIRW52aXJvbm1lbnRWYXJpYWJsZShzaGVsbF9jb21tYW5kX3BhcnNpbmdfcmVzdWx0LmVudmlyb25tZW50X3ZhcmlhYmxlX3BhdGhfYXVnbWVudGF0aW9uKTtcclxuICAgICAgICBpZiAoYXVnbWVudGVkX3BhdGgubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICBlbnZpcm9ubWVudF92YXJpYWJsZXNbZ2V0UEFUSEVudmlyb25tZW50VmFyaWFibGVOYW1lKCldID0gYXVnbWVudGVkX3BhdGg7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBDaGVjayB0aGF0IHRoZSB3b3JraW5nIGRpcmVjdG9yeSBleGlzdHMgYW5kIGlzIGEgZm9sZGVyXHJcbiAgICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHdvcmtpbmdfZGlyZWN0b3J5KSkge1xyXG4gICAgICAgICAgICAvLyBXb3JraW5nIGRpcmVjdG9yeSBkb2VzIG5vdCBleGlzdFxyXG4gICAgICAgICAgICAvLyBQcmV2ZW50IGV4ZWN1dGlvblxyXG4gICAgICAgICAgICBkZWJ1Z0xvZyhcIldvcmtpbmcgZGlyZWN0b3J5IGRvZXMgbm90IGV4aXN0OiBcIiArIHdvcmtpbmdfZGlyZWN0b3J5KTtcclxuICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3RXJyb3IoXCJXb3JraW5nIGRpcmVjdG9yeSBkb2VzIG5vdCBleGlzdDogXCIgKyB3b3JraW5nX2RpcmVjdG9yeSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2UgaWYgKCFmcy5sc3RhdFN5bmMod29ya2luZ19kaXJlY3RvcnkpLmlzRGlyZWN0b3J5KCkpIHtcclxuICAgICAgICAgICAgLy8gV29ya2luZyBkaXJlY3RvcnkgaXMgbm90IGEgZGlyZWN0b3J5LlxyXG4gICAgICAgICAgICAvLyBQcmV2ZW50IGV4ZWN1dGlvblxyXG4gICAgICAgICAgICBkZWJ1Z0xvZyhcIldvcmtpbmcgZGlyZWN0b3J5IGV4aXN0cyBidXQgaXMgbm90IGEgZm9sZGVyOiBcIiArIHdvcmtpbmdfZGlyZWN0b3J5KTtcclxuICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3RXJyb3IoXCJXb3JraW5nIGRpcmVjdG9yeSBleGlzdHMgYnV0IGlzIG5vdCBhIGZvbGRlcjogXCIgKyB3b3JraW5nX2RpcmVjdG9yeSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gV29ya2luZyBkaXJlY3RvcnkgaXMgT0tcclxuICAgICAgICAgICAgLy8gUHJlcGFyZSBleGVjdXRpb24gb3B0aW9uc1xyXG4gICAgICAgICAgICBjb25zdCBvcHRpb25zOiBTcGF3bk9wdGlvbnMgPSB7XHJcbiAgICAgICAgICAgICAgICBcImN3ZFwiOiB3b3JraW5nX2RpcmVjdG9yeSxcclxuICAgICAgICAgICAgICAgIFwic2hlbGxcIjogc2hlbGwsXHJcbiAgICAgICAgICAgICAgICBcImVudlwiOiBlbnZpcm9ubWVudF92YXJpYWJsZXMsXHJcbiAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAvLyBFeGVjdXRlIHRoZSBzaGVsbCBjb21tYW5kXHJcbiAgICAgICAgICAgIGRlYnVnTG9nKFwiRXhlY3V0aW5nIGNvbW1hbmQgXCIgKyBzaGVsbF9jb21tYW5kICsgXCIgaW4gXCIgKyB3b3JraW5nX2RpcmVjdG9yeSArIFwiLi4uXCIpO1xyXG4gICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgY2hpbGRfcHJvY2VzcyA9IHNwYXduKHNoZWxsX2NvbW1hbmQsIG9wdGlvbnMpO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIFBhc3Mgc3RkaW4gY29udGVudCAoaWYgZGVmaW5lZClcclxuICAgICAgICAgICAgICAgIGlmICh1bmRlZmluZWQgIT09IHNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHQuc3RkaW5Db250ZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gU3RkaW4gY29udGVudCBpcyBkZWZpbmVkXHJcbiAgICAgICAgICAgICAgICAgICAgZGVidWdMb2coXCJTdGRpbiBjb250ZW50IGlzIHByZXNlbnQgaW4gcGFyc2luZyByZXN1bHQuIFdpbGwgd3JpdGUgaXQgdG8gdGhlIHByb2Nlc3MuXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChudWxsID09PSBjaGlsZF9wcm9jZXNzLnN0ZGluKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5vaW5zcGVjdGlvbiBFeGNlcHRpb25DYXVnaHRMb2NhbGx5SlM6IFRoZSBleGNlcHRpb24gaXMgY2F1Z2h0IGxvY2FsbHkgYmVsb3csIGJ1dCBpdCdzIG9rIGJlY2F1c2UgaXQncyB0aGVuIHJldGhyb3duIGFzIHRoZSBlcnJvciBtZXNzYWdlIGRvZXMgbm90IG1hdGNoICcvc3Bhd25cXHMrRU5BTUVUT09MT05HL2knLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJTaGVsbCBjb21tYW5kIGV4ZWN1dGlvbiBwcm9jZXNzIGRvZXMgbm90IGhhdmUgYSBzdGFuZGFyZCBpbnB1dCBzdHJlYW0gKHN0ZGluKS5cIik7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkX3Byb2Nlc3Muc3RkaW4ud3JpdGUoc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdC5zdGRpbkNvbnRlbnQpO1xyXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkX3Byb2Nlc3Muc3RkaW4uZW5kKCk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiTm8gc3RkaW4gY29udGVudCBpcyBwcmVzZW50IGluIHBhcnNpbmcgcmVzdWx0LlwiKTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAvLyBDb21tb24gZXJyb3IgaGFuZGxpbmcgcmVnYXJkbGVzcyBvZiBvdXRwdXQgaGFuZGxpbmcgbW9kZVxyXG4gICAgICAgICAgICAgICAgY2hpbGRfcHJvY2Vzcy5vbihcImVycm9yXCIsIChlcnJvcjogRXJyb3IpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBQcm9iYWJseSBtb3N0IGVycm9ycyB3aWxsIE5PVCBlbmQgdXAgaGVyZSwgSSBndWVzcyB0aGlzIGV2ZW50IG9jY3VycyBmb3Igc29tZSByYXJlIGVycm9ycy5cclxuICAgICAgICAgICAgICAgICAgICAvL1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIEEgcXVvdGUgZnJvbSBodHRwczovL25vZGVqcy5vcmcvYXBpL2NoaWxkX3Byb2Nlc3MuaHRtbCNldmVudC1lcnJvciAocmVhZCAyMDIyLTEwLTI5KTpcclxuICAgICAgICAgICAgICAgICAgICAvLyA+IFRoZSAnZXJyb3InIGV2ZW50IGlzIGVtaXR0ZWQgd2hlbmV2ZXI6XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gPiAtIFRoZSBwcm9jZXNzIGNvdWxkIG5vdCBiZSBzcGF3bmVkLCBvclxyXG4gICAgICAgICAgICAgICAgICAgIC8vID4gLSBUaGUgcHJvY2VzcyBjb3VsZCBub3QgYmUga2lsbGVkLCBvclxyXG4gICAgICAgICAgICAgICAgICAgIC8vID4gLSBTZW5kaW5nIGEgbWVzc2FnZSB0byB0aGUgY2hpbGQgcHJvY2VzcyBmYWlsZWQuXHJcblxyXG4gICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiU2hlbGwgY29tbWFuZCBmYWlsZWQgdG8gZXhlY3V0ZTogUmVjZWl2ZWQgYSBub24tc3RkZXJyIGVycm9yIG1lc3NhZ2U6IFwiICsgZXJyb3IubWVzc2FnZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3RXJyb3IoXCJTaGVsbCBjb21tYW5kIGZhaWxlZCB0byBleGVjdXRlLiBFcnJvcjogXCIgKyBlcnJvci5tZXNzYWdlKTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIERlZmluZSBvdXRwdXQgZW5jb2RpbmdcclxuICAgICAgICAgICAgICAgIGlmIChudWxsID09PSBjaGlsZF9wcm9jZXNzLnN0ZG91dCB8fCBudWxsID09IGNoaWxkX3Byb2Nlc3Muc3RkZXJyKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGV4Y2VwdGlvbiBpcyBjYXVnaHQgbG9jYWxseSBiZWxvdywgYnV0IGl0J3Mgb2sgYmVjYXVzZSBpdCdzIHRoZW4gcmV0aHJvd24gYXMgdGhlIGVycm9yIG1lc3NhZ2UgZG9lcyBub3QgbWF0Y2ggJy9zcGF3blxccytFTkFNRVRPT0xPTkcvaScuXHJcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2hpbGQgcHJvY2VzcydzIHN0ZG91dCBhbmQvb3Igc3RkZXJyIHN0cmVhbSBpcyBudWxsLlwiKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGNoaWxkX3Byb2Nlc3Muc3Rkb3V0LnNldEVuY29kaW5nKFwidXRmOFwiKTsgLy8gUmVjZWl2ZSBzdGRvdXQgYW5kIC4uLlxyXG4gICAgICAgICAgICAgICAgY2hpbGRfcHJvY2Vzcy5zdGRlcnIuc2V0RW5jb2RpbmcoXCJ1dGY4XCIpOyAvLyAuLi4gc3RkZXJyIGFzIHN0cmluZ3MsIG5vdCBhcyBCdWZmZXIgb2JqZWN0cy5cclxuXHJcbiAgICAgICAgICAgICAgICAvLyBEZWZpbmUgYSB0ZXJtaW5hdG9yXHJcbiAgICAgICAgICAgICAgICBjb25zdCBwcm9jZXNzVGVybWluYXRvciA9ICgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBjaGlsZF9wcm9jZXNzLmtpbGwoXCJTSUdURVJNXCIpO1xyXG4gICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBIb29rIGludG8gY2hpbGRfcHJvY2VzcyBmb3Igb3V0cHV0IGhhbmRsaW5nXHJcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKHRoaXMudF9zaGVsbF9jb21tYW5kLmdldE91dHB1dEhhbmRsaW5nTW9kZSgpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBcImJ1ZmZlcmVkXCI6IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3V0cHV0IHdpbGwgYmUgYnVmZmVyZWQgYW5kIGhhbmRsZWQgYXMgYSBzaW5nbGUgYmF0Y2guXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlQnVmZmVyZWRPdXRwdXQoY2hpbGRfcHJvY2Vzcywgc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdCwgb3V0cHV0Q2hhbm5lbHMpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIGNhc2UgXCJyZWFsdGltZVwiOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE91dHB1dCB3aWxsIGJlIGhhbmRsZWQgb24tdGhlLWdvLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZVJlYWx0aW1lT3V0cHV0KGNoaWxkX3Byb2Nlc3MsIHNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHQsIG91dHB1dENoYW5uZWxzLCBwcm9jZXNzVGVybWluYXRvcik7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIC8vIERpc3BsYXkgYSBub3RpZmljYXRpb24gb2YgdGhlIGV4ZWN1dGlvbiAoaWYgd2FudGVkKS5cclxuICAgICAgICAgICAgICAgIGlmIChcImRpc2FibGVkXCIgIT09IHRoaXMucGx1Z2luLnNldHRpbmdzLmV4ZWN1dGlvbl9ub3RpZmljYXRpb25fbW9kZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2hvd0V4ZWN1dGlvbk5vdGlmaWNhdGlvbihjaGlsZF9wcm9jZXNzLCBzaGVsbF9jb21tYW5kLCB0aGlzLnBsdWdpbi5zZXR0aW5ncy5leGVjdXRpb25fbm90aWZpY2F0aW9uX21vZGUsIHByb2Nlc3NUZXJtaW5hdG9yKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSBjYXRjaCAoZXhjZXB0aW9uKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBBbiBleGNlcHRpb24gaGFzIGhhcHBlbmVkLlxyXG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIHNoZWxsIGNvbW1hbmQgd2FzIHRvbyBsb25nLlxyXG4gICAgICAgICAgICAgICAgaWYgKGV4Y2VwdGlvbi5tZXNzYWdlLm1hdGNoKC9zcGF3blxccytFTkFNRVRPT0xPTkcvaSkpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBJdCB3YXMgdG9vIGxvbmcuIFNob3cgYW4gZXJyb3IgbWVzc2FnZS5cclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5uZXdFcnJvcihcIlNoZWxsIGNvbW1hbmQgZXhlY3V0aW9uIGZhaWxlZCBiZWNhdXNlIGl0J3MgdG9vIGxvbmc6IFwiICsgc2hlbGxfY29tbWFuZC5sZW5ndGggKyBcIiBjaGFyYWN0ZXJzLiAoVW5mb3J0dW5hdGVseSB0aGUgbWF4IGxpbWl0IGlzIHVua25vd24pLlwiKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIHNoZWxsIGNvbW1hbmQgd2FzIG5vdCB0b28gbG9uZywgdGhpcyBleGNlcHRpb24gaXMgYWJvdXQgc29tZXRoaW5nIGVsc2UuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gUmV0aHJvdyB0aGUgZXhjZXB0aW9uLlxyXG4gICAgICAgICAgICAgICAgICAgIHRocm93ICBleGNlcHRpb247XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBoYW5kbGVCdWZmZXJlZE91dHB1dChjaGlsZF9wcm9jZXNzOiBDaGlsZFByb2Nlc3MsIHNoZWxsX2NvbW1hbmRfcGFyc2luZ19yZXN1bHQ6IFNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQsIG91dHB1dENoYW5uZWxzOiBPdXRwdXRDaGFubmVsQ29kZXMpIHtcclxuICAgICAgICBjaGlsZF9wcm9jZXNzLm9uKFwiZXhpdFwiLCAoZXhpdENvZGU6IG51bWJlciB8IG51bGwpID0+IHtcclxuICAgICAgICAgICAgLy8gZXhpdENvZGUgaXMgbnVsbCBpZiB1c2VyIHRlcm1pbmF0ZWQgdGhlIHByb2Nlc3MuIFJlZmVyZW5jZTogaHR0cHM6Ly9ub2RlanMub3JnL2FwaS9jaGlsZF9wcm9jZXNzLmh0bWwjZXZlbnQtZXhpdCAocmVhZCBvbiAyMDIyLTExLTI3KS5cclxuXHJcbiAgICAgICAgICAgIC8vIEdldCBvdXRwdXRzXHJcbiAgICAgICAgICAgIGlmIChudWxsID09PSBjaGlsZF9wcm9jZXNzLnN0ZG91dCB8fCBudWxsID09IGNoaWxkX3Byb2Nlc3Muc3RkZXJyKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGUgZXhjZXB0aW9uIGlzIGNhdWdodCBsb2NhbGx5IGJlbG93LCBidXQgaXQncyBvayBiZWNhdXNlIGl0J3MgdGhlbiByZXRocm93biBhcyB0aGUgZXJyb3IgbWVzc2FnZSBkb2VzIG5vdCBtYXRjaCAnL3NwYXduXFxzK0VOQU1FVE9PTE9ORy9pJy5cclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNoaWxkIHByb2Nlc3MncyBzdGRvdXQgYW5kL29yIHN0ZGVyciBzdHJlYW0gaXMgbnVsbC5cIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgY29uc3Qgc3Rkb3V0OiBzdHJpbmcgPSBjaGlsZF9wcm9jZXNzLnN0ZG91dC5yZWFkKCkgPz8gXCJcIjtcclxuICAgICAgICAgICAgbGV0IHN0ZGVycjogc3RyaW5nID0gY2hpbGRfcHJvY2Vzcy5zdGRlcnIucmVhZCgpID8/IFwiXCI7IC8vIGxldCBpbnN0ZWFkIG9mIGNvbnN0OiBzdGRlcnIgY2FuIGJlIGVtcHRpZWQgbGF0ZXIgZHVlIHRvIGlnbm9yaW5nLlxyXG5cclxuICAgICAgICAgICAgLy8gRGlkIHRoZSBzaGVsbCBjb21tYW5kIGV4ZWN1dGUgc3VjY2Vzc2Z1bGx5P1xyXG4gICAgICAgICAgICBpZiAoZXhpdENvZGUgPT09IG51bGwgfHwgZXhpdENvZGUgPiAwKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBTb21lIGVycm9yIG9jY3VycmVkXHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkNvbW1hbmQgZXhlY3V0ZWQgYW5kIGZhaWxlZC4gRXJyb3IgbnVtYmVyOiBcIiArIGV4aXRDb2RlICsgXCIuIFN0ZGVycjogXCIgKyBzdGRlcnIpO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoaXMgZXJyb3Igc2hvdWxkIGJlIGRpc3BsYXllZCB0byB0aGUgdXNlciBvciBub3RcclxuICAgICAgICAgICAgICAgIGlmIChudWxsICE9PSBleGl0Q29kZSAmJiB0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRJZ25vcmVFcnJvckNvZGVzKCkuY29udGFpbnMoZXhpdENvZGUpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIHVzZXIgaGFzIGlnbm9yZWQgdGhpcyBlcnJvci5cclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIlVzZXIgaGFzIGlnbm9yZWQgdGhpcyBlcnJvciwgc28gd29uJ3QgZGlzcGxheSBpdC5cIik7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vIEhhbmRsZSBvbmx5IHN0ZG91dCBvdXRwdXQgc3RyZWFtXHJcbiAgICAgICAgICAgICAgICAgICAgc3RkZXJyID0gXCJcIjtcclxuICAgICAgICAgICAgICAgICAgICBleGl0Q29kZSA9IG51bGw7IC8vIFRPRE86IGNvbnNpZGVyIGlmIGV4aXRDb2RlIHNob3VsZCBqdXN0IGJlIGxlZnQgdW50b3VjaGVkLiBJdCBjb3VsZCBiZSBpbmZvcm1hdGl2ZSB0byAnQXNrIGFmdGVyIGV4ZWN1dGlvbicgb3V0cHV0IGNoYW5uZWwgdGhhdCBzaG93cyBleGl0IGNvZGUgdG8gdXNlci5cclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGVycm9yIGNhbiBiZSBzaG93bi5cclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIldpbGwgZGlzcGxheSB0aGUgZXJyb3IgdG8gdXNlci5cIik7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gSGFuZGxlIGF0IGxlYXN0IHN0ZG91dCAoYW5kIG1heWJlIHN0ZGVycikgb3V0cHV0IHN0cmVhbVxyXG4gICAgICAgICAgICAgICAgaGFuZGxlQnVmZmVyZWRPdXRwdXQodGhpcy5wbHVnaW4sIHRoaXMudF9zaGVsbF9jb21tYW5kLCBzaGVsbF9jb21tYW5kX3BhcnNpbmdfcmVzdWx0LCBzdGRvdXQsIHN0ZGVyciwgZXhpdENvZGUsIG91dHB1dENoYW5uZWxzKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIFByb2JhYmx5IG5vIGVycm9ycywgYnV0IGRvIG9uZSBtb3JlIGNoZWNrLlxyXG5cclxuICAgICAgICAgICAgICAgIC8vIEV2ZW4gd2hlbiAnZXJyb3InIGlzIG51bGwgYW5kIGV2ZXJ5dGhpbmcgc2hvdWxkIGJlIG9rLCB0aGVyZSBtYXkgc3RpbGwgYmUgZXJyb3IgbWVzc2FnZXMgb3V0cHV0dGVkIGluIHN0ZGVyci5cclxuICAgICAgICAgICAgICAgIGlmIChzdGRlcnIubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIENoZWNrIGEgc3BlY2lhbCBjYXNlOiBzaG91bGQgZXJyb3IgY29kZSAwIGJlIGlnbm9yZWQ/XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMudF9zaGVsbF9jb21tYW5kLmdldElnbm9yZUVycm9yQ29kZXMoKS5jb250YWlucygwKSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBFeGl0IGNvZGUgMCBpcyBvbiB0aGUgaWdub3JlIGxpc3QsIHNvIHN1cHByZXNzIHN0ZGVyciBvdXRwdXQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0ZGVyciA9IFwiXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiU2hlbGwgY29tbWFuZCBleGVjdXRlZDogRW5jb3VudGVyZWQgZXJyb3IgY29kZSAwLCBidXQgc3RkZXJyIGlzIGlnbm9yZWQuXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiU2hlbGwgY29tbWFuZCBleGVjdXRlZDogRW5jb3VudGVyZWQgZXJyb3IgY29kZSAwLCBhbmQgc3RkZXJyIHdpbGwgYmUgcmVsYXllZCB0byBhbiBvdXRwdXQgaGFuZGxlci5cIik7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIlNoZWxsIGNvbW1hbmQgZXhlY3V0ZWQ6IE5vIGVycm9ycy5cIik7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gSGFuZGxlIG91dHB1dFxyXG4gICAgICAgICAgICAgICAgaGFuZGxlQnVmZmVyZWRPdXRwdXQodGhpcy5wbHVnaW4sIHRoaXMudF9zaGVsbF9jb21tYW5kLCBzaGVsbF9jb21tYW5kX3BhcnNpbmdfcmVzdWx0LCBzdGRvdXQsIHN0ZGVyciwgMCwgb3V0cHV0Q2hhbm5lbHMpOyAvLyBVc2UgemVybyBhcyBhbiBlcnJvciBjb2RlIGluc3RlYWQgb2YgbnVsbCAoMCBtZWFucyBubyBlcnJvcikuIElmIHN0ZGVyciBoYXBwZW5zIHRvIGNvbnRhaW4gc29tZXRoaW5nLCBleGl0IGNvZGUgMCBnZXRzIGRpc3BsYXllZCBpbiBhbiBlcnJvciBiYWxsb29uIChpZiB0aGF0IGlzIHNlbGVjdGVkIGFzIGEgY2hhbm5lbCBmb3Igc3RkZXJyKS5cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgaGFuZGxlUmVhbHRpbWVPdXRwdXQoXHJcbiAgICAgICAgICAgIGNoaWxkUHJvY2VzczogQ2hpbGRQcm9jZXNzLFxyXG4gICAgICAgICAgICBzaGVsbF9jb21tYW5kX3BhcnNpbmdfcmVzdWx0OiBTaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0LFxyXG4gICAgICAgICAgICBvdXRwdXRDaGFubmVsQ29kZXM6IE91dHB1dENoYW5uZWxDb2RlcyxcclxuICAgICAgICAgICAgcHJvY2Vzc1Rlcm1pbmF0b3I6ICgoKSA9PiB2b2lkKSB8IG51bGwsXHJcbiAgICAgICAgKSB7XHJcblxyXG4gICAgICAgIC8vIFByZXBhcmUgb3V0cHV0IGNoYW5uZWxzXHJcbiAgICAgICAgY29uc3Qgb3V0cHV0Q2hhbm5lbHMgPSBzdGFydFJlYWx0aW1lT3V0cHV0SGFuZGxpbmcoXHJcbiAgICAgICAgICAgIHRoaXMucGx1Z2luLFxyXG4gICAgICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZCxcclxuICAgICAgICAgICAgc2hlbGxfY29tbWFuZF9wYXJzaW5nX3Jlc3VsdCxcclxuICAgICAgICAgICAgb3V0cHV0Q2hhbm5lbENvZGVzLFxyXG4gICAgICAgICAgICBwcm9jZXNzVGVybWluYXRvcixcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBEZWZpbmUgYW4gb3V0cHV0IGhhbmRsZXJcclxuICAgICAgICBjb25zdCBoYW5kbGVOZXdPdXRwdXRDb250ZW50ID0gYXN5bmMgKG91dHB1dFN0cmVhbU5hbWU6IE91dHB1dFN0cmVhbSwgcmVhZGFibGVTdHJlYW06IFJlYWRhYmxlKSA9PiB7XHJcbiAgICAgICAgICAgIGlmIChudWxsID09PSBjaGlsZFByb2Nlc3Muc3Rkb3V0IHx8IG51bGwgPT0gY2hpbGRQcm9jZXNzLnN0ZGVycikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2hpbGQgcHJvY2VzcydzIHN0ZG91dCBhbmQvb3Igc3RkZXJyIHN0cmVhbSBpcyBudWxsLlwiKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gRG9uJ3QgZW1pdCBuZXcgZXZlbnRzIHdoaWxlIHRoZSBjdXJyZW50IGhhbmRsaW5nIGlzIGluIHByb2dyZXNzLiAoSSB0aGluaykgaXQgbWlnaHQgY2F1c2UgYSByYWNlIGNvbmRpdGlvbiB3aGVyZSBhIHNpbXVsdGFuZW91cyBoYW5kbGluZyBjb3VsZCBvdmVyd3JpdGUgYW5vdGhlciBoYW5kbGluZydzIGRhdGEuIFBhdXNlIGJvdGggc3RyZWFtcywgbm90IGp1c3QgdGhlIGN1cnJlbnQgb25lLCB0byBtYWludGFpbiBjb3JyZWN0IGhhbmRsaW5nIG9yZGVyIGFsc28gYmV0d2VlbiB0aGUgdHdvIHN0cmVhbXMuXHJcbiAgICAgICAgICAgIGNoaWxkUHJvY2Vzcy5zdGRvdXQucGF1c2UoKTtcclxuICAgICAgICAgICAgY2hpbGRQcm9jZXNzLnN0ZGVyci5wYXVzZSgpO1xyXG5cclxuICAgICAgICAgICAgY29uc3Qgb3V0cHV0Q29udGVudCA9IHJlYWRhYmxlU3RyZWFtLnJlYWQoKSA/PyBcIlwiO1xyXG4gICAgICAgICAgICBjb25zdCBvdXRwdXRDaGFubmVsOiBPdXRwdXRDaGFubmVsIHwgdW5kZWZpbmVkID0gb3V0cHV0Q2hhbm5lbHNbb3V0cHV0U3RyZWFtTmFtZV07XHJcbiAgICAgICAgICAgIGlmICh1bmRlZmluZWQgPT09IG91dHB1dENoYW5uZWwpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk91dHB1dCBjaGFubmVsIGlzIHVuZGVmaW5lZC5cIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgYXdhaXQgb3V0cHV0Q2hhbm5lbC5oYW5kbGVSZWFsdGltZShvdXRwdXRTdHJlYW1OYW1lLCBvdXRwdXRDb250ZW50KTtcclxuXHJcbiAgICAgICAgICAgIC8vIENhbiBlbWl0IG5ldyBldmVudHMgYWdhaW4uXHJcbiAgICAgICAgICAgIGNoaWxkUHJvY2Vzcy5zdGRvdXQucmVzdW1lKCk7XHJcbiAgICAgICAgICAgIGNoaWxkUHJvY2Vzcy5zdGRlcnIucmVzdW1lKCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgLy8gSG9vayBpbnRvIG91dHB1dCBzdHJlYW1zJyAoc3VjaCBhcyBzdGRvdXQgYW5kIHN0ZGVycikgb3V0cHV0IHJldHJpZXZpbmcgZXZlbnRzLlxyXG4gICAgICAgIC8vIE5vdGUgdGhhdCB0aGVyZSBtaWdodCBiZSBqdXN0IG9uZSBzdHJlYW0sIGUuZy4gb25seSBzdGRlcnIsIGlmIHN0ZG91dCBpcyBpZ25vcmVkLiBJbiB0aGUgZnV0dXJlLCB0aGVyZSBtaWdodCBhbHNvIGJlIG1vcmUgdGhhbiB0d28gc3RyZWFtcywgd2hlbiBjdXN0b20gc3RyZWFtcyBhcmUgaW1wbGVtZW50ZWQuXHJcbiAgICAgICAgZm9yIChjb25zdCBvdXRwdXRTdHJlYW1OYW1lIG9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKG91dHB1dENoYW5uZWxzKSBhcyBPdXRwdXRTdHJlYW1bXSkge1xyXG4gICAgICAgICAgICBjb25zdCByZWFkYWJsZVN0cmVhbTogUmVhZGFibGUgfCBudWxsID0gY2hpbGRQcm9jZXNzW291dHB1dFN0cmVhbU5hbWVdO1xyXG4gICAgICAgICAgICBpZiAobnVsbCA9PT0gcmVhZGFibGVTdHJlYW0pIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNoaWxkIHByb2Nlc3MncyByZWFkYWJsZSBzdHJlYW0gJ1wiK291dHB1dFN0cmVhbU5hbWUrXCInIGlzIG51bGwuXCIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHJlYWRhYmxlU3RyZWFtLm9uKFxyXG4gICAgICAgICAgICAgICAgXCJyZWFkYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgKCkgPT4gaGFuZGxlTmV3T3V0cHV0Q29udGVudChvdXRwdXRTdHJlYW1OYW1lLCByZWFkYWJsZVN0cmVhbSksXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBIb29rIGludG8gZXhpdCBldmVudHNcclxuICAgICAgICBjaGlsZFByb2Nlc3Mub24oXCJleGl0XCIsIChleGl0Q29kZTogbnVtYmVyLCBzaWduYWw6IHN0cmluZyAvKiBUT0RPOiBQYXNzIHNpZ25hbCB0byBjaGFubmVscyBzbyBpdCBjYW4gYmUgc2hvd24gdG8gdXNlcnMgaW4gdGhlIGZ1dHVyZSAqLykgPT4ge1xyXG4gICAgICAgICAgICAvLyBDYWxsIGFsbCBPdXRwdXRDaGFubmVscycgZW5kUmVhbHRpbWUoKS5cclxuICAgICAgICAgICAgY29uc3QgYWxyZWFkeUNhbGxlZENoYW5uZWxDb2RlczogT3V0cHV0Q2hhbm5lbENvZGVbXSA9IFtdO1xyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IG91dHB1dFN0cmVhbU5hbWUgb2YgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMob3V0cHV0Q2hhbm5lbHMpIGFzIE91dHB1dFN0cmVhbVtdKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBvdXRwdXRDaGFubmVsOiBPdXRwdXRDaGFubmVsIHwgdW5kZWZpbmVkID0gb3V0cHV0Q2hhbm5lbHNbb3V0cHV0U3RyZWFtTmFtZV07XHJcbiAgICAgICAgICAgICAgICBpZiAodW5kZWZpbmVkID09PSBvdXRwdXRDaGFubmVsKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiT3V0cHV0IGNoYW5uZWwgaXMgdW5kZWZpbmVkLlwiKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGNvbnN0IG91dHB1dENoYW5uZWxDb2RlOiBPdXRwdXRDaGFubmVsQ29kZSA9IG91dHB1dENoYW5uZWxDb2Rlc1tvdXRwdXRTdHJlYW1OYW1lXTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBFbnN1cmUgdGhpcyBPdXRwdXRDaGFubmVsIGhhcyBub3QgeWV0IGJlZW4gY2FsbGVkLlxyXG4gICAgICAgICAgICAgICAgaWYgKCFhbHJlYWR5Q2FsbGVkQ2hhbm5lbENvZGVzLmluY2x1ZGVzKG91dHB1dENoYW5uZWxDb2RlKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIE5vdCB5ZXQgY2FsbGVkLCBzbyBkbyB0aGUgY2FsbC5cclxuICAgICAgICAgICAgICAgICAgICBvdXRwdXRDaGFubmVsLmVuZFJlYWx0aW1lKGV4aXRDb2RlKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gTWFyayB0aGF0IHRoaXMgY2hhbm5lbCdzIGVuZFJlYWx0aW1lKCkgaGFzIGFscmVhZHkgYmVlbiBjYWxsZWQuIFNvbHZlcyBhIHNpdHVhdGlvbiB3aGVyZSBzdGRlcnIgYW5kIHN0ZG91dCB1c2VzIHRoZSBzYW1lIGNoYW5uZWwsIGluIHdoaWNoIGNhc2UgZW5kUmVhbHRpbWUoKSBzaG91bGQgbm90IGJlIGFjY2lkZW50YWxseSBjYWxsZWQgdHdpY2UuXHJcbiAgICAgICAgICAgICAgICAgICAgYWxyZWFkeUNhbGxlZENoYW5uZWxDb2Rlcy5wdXNoKG91dHB1dENoYW5uZWxDb2RlKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgZ2V0V29ya2luZ0RpcmVjdG9yeSgpIHtcclxuICAgICAgICAvLyBSZXR1cm5zIGVpdGhlciBhIHVzZXIgZGVmaW5lZCB3b3JraW5nIGRpcmVjdG9yeSwgb3IgYW4gYXV0b21hdGljYWxseSBkZXRlY3RlZCBvbmUuXHJcbiAgICAgICAgY29uc3Qgd29ya2luZ19kaXJlY3RvcnkgPSB0aGlzLnBsdWdpbi5zZXR0aW5ncy53b3JraW5nX2RpcmVjdG9yeTtcclxuICAgICAgICBpZiAod29ya2luZ19kaXJlY3RvcnkubGVuZ3RoID09IDApIHtcclxuICAgICAgICAgICAgLy8gTm8gd29ya2luZyBkaXJlY3Rvcnkgc3BlY2lmaWVkLCBzbyB1c2UgdGhlIHZhdWx0IGRpcmVjdG9yeS5cclxuICAgICAgICAgICAgcmV0dXJuIGdldFZhdWx0QWJzb2x1dGVQYXRoKHRoaXMucGx1Z2luLmFwcCk7XHJcbiAgICAgICAgfSBlbHNlIGlmICghcGF0aC5pc0Fic29sdXRlKHdvcmtpbmdfZGlyZWN0b3J5KSkge1xyXG4gICAgICAgICAgICAvLyBUaGUgd29ya2luZyBkaXJlY3RvcnkgaXMgcmVsYXRpdmUuXHJcbiAgICAgICAgICAgIC8vIEhlbHAgdG8gbWFrZSBpdCByZWZlciB0byB0aGUgdmF1bHQncyBkaXJlY3RvcnkuIFdpdGhvdXQgdGhpcywgdGhlIHJlbGF0aXZlIHBhdGggd291bGQgcmVmZXIgdG8gT2JzaWRpYW4ncyBpbnN0YWxsYXRpb24gZGlyZWN0b3J5IChhdCBsZWFzdCBvbiBXaW5kb3dzKS5cclxuICAgICAgICAgICAgcmV0dXJuIHBhdGguam9pbihnZXRWYXVsdEFic29sdXRlUGF0aCh0aGlzLnBsdWdpbi5hcHApLCB3b3JraW5nX2RpcmVjdG9yeSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB3b3JraW5nX2RpcmVjdG9yeTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGF1Z21lbnRQQVRIRW52aXJvbm1lbnRWYXJpYWJsZShwYXRoX2F1Z21lbnRhdGlvbjogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgICAgICBwYXRoX2F1Z21lbnRhdGlvbiA9IGNvbnZlcnROZXdsaW5lc1RvUEFUSFNlcGFyYXRvcnMocGF0aF9hdWdtZW50YXRpb24sIGdldE9wZXJhdGluZ1N5c3RlbSgpKTtcclxuICAgICAgICAvLyBDaGVjayBpZiB0aGVyZSdzIGFueXRoaW5nIHRvIGF1Z21lbnQuXHJcbiAgICAgICAgaWYgKHBhdGhfYXVnbWVudGF0aW9uLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgLy8gQXVnbWVudC5cclxuICAgICAgICAgICAgY29uc3Qgb3JpZ2luYWxfcGF0aDogc3RyaW5nIHwgdW5kZWZpbmVkID0gcHJvY2Vzcy5lbnZbZ2V0UEFUSEVudmlyb25tZW50VmFyaWFibGVOYW1lKCldO1xyXG4gICAgICAgICAgICBpZiAodW5kZWZpbmVkID09PSBvcmlnaW5hbF9wYXRoKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJwcm9jZXNzLmVudiBkb2VzIG5vdCBjb250YWluICdcIiArIGdldFBBVEhFbnZpcm9ubWVudFZhcmlhYmxlTmFtZSgpICsgXCInLlwiKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBsZXQgYXVnbWVudGVkX3BhdGg6IHN0cmluZztcclxuICAgICAgICAgICAgaWYgKHBhdGhfYXVnbWVudGF0aW9uLmNvbnRhaW5zKG9yaWdpbmFsX3BhdGgpKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGUgYXVnbWVudGF0aW9uIGNvbnRhaW5zIHRoZSBvcmlnaW5hbCBQQVRILlxyXG4gICAgICAgICAgICAgICAgLy8gU2ltcGx5IHJlcGxhY2UgdGhlIHdob2xlIG9yaWdpbmFsIFBBVEggd2l0aCB0aGUgYXVnbWVudGVkIG9uZSwgYXMgdGhlcmUncyBubyBuZWVkIHRvIGNhcmUgYWJvdXQgaW5jbHVkaW5nXHJcbiAgICAgICAgICAgICAgICAvLyB0aGUgb3JpZ2luYWwgY29udGVudC5cclxuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiQXVnbWVudGluZyBlbnZpcm9ubWVudCB2YXJpYWJsZSBQQVRIIHNvIGl0IHdpbGwgYmVjb21lIFwiICsgcGF0aF9hdWdtZW50YXRpb24pO1xyXG4gICAgICAgICAgICAgICAgYXVnbWVudGVkX3BhdGggPSBwYXRoX2F1Z21lbnRhdGlvbjtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIFRoZSBhdWdtZW50YXRpb24gZG9lcyBub3QgY29udGFpbiB0aGUgb3JpZ2luYWwgUEFUSC5cclxuICAgICAgICAgICAgICAgIC8vIEluc3RlYWQgb2Ygc2ltcGx5IHJlcGxhY2luZyB0aGUgb3JpZ2luYWwgUEFUSCwgYXBwZW5kIHRoZSBhdWdtZW50YXRpb24gYWZ0ZXIgaXQuXHJcbiAgICAgICAgICAgICAgICBjb25zdCBzZXBhcmF0b3IgPSBnZXRQQVRIU2VwYXJhdG9yKGdldE9wZXJhdGluZ1N5c3RlbSgpKTtcclxuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiQXVnbWVudGluZyBlbnZpcm9ubWVudCB2YXJpYWJsZSBQQVRIIGJ5IGFkZGluZyBcIiArIHNlcGFyYXRvciArIHBhdGhfYXVnbWVudGF0aW9uICsgXCIgYWZ0ZXIgaXQuXCIpO1xyXG4gICAgICAgICAgICAgICAgYXVnbWVudGVkX3BhdGggPSBvcmlnaW5hbF9wYXRoICsgc2VwYXJhdG9yICsgcGF0aF9hdWdtZW50YXRpb247XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgZGVidWdMb2coXCJQQVRIIGF1Z21lbnRhdGlvbiByZXN1bHQ6IFwiICsgYXVnbWVudGVkX3BhdGgpO1xyXG4gICAgICAgICAgICByZXR1cm4gYXVnbWVudGVkX3BhdGg7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gTm8gYXVnbWVudGluZyBpcyBuZWVkZWQuXHJcbiAgICAgICAgICAgIGRlYnVnTG9nKFwiTm8gYXVnbWVudGF0aW9uIGlzIGRlZmluZWQgZm9yIGVudmlyb25tZW50IHZhcmlhYmxlIFBBVEguIFRoaXMgaXMgY29tcGxldGVseSBvay5cIik7XHJcbiAgICAgICAgICAgIHJldHVybiBcIlwiO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoaXMgbWV0aG9kIHNob3VsZCBvbmx5IGJlIGNhbGxlZCBpZiBpdCdzIGZpcnN0IGNoZWNrZWQgdGhhdCBuZWl0aGVyIHNoZWxsIGNvbW1hbmQgdmVyc2lvbiBmb3IgdGhlIGN1cnJlbnQgcGxhdGZvcm0gbm9yIGEgJ2RlZmF1bHQnIHZlcnNpb24gZXhpc3RzLlxyXG4gICAgICpcclxuICAgICAqIEBwcml2YXRlXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgZ2V0RXJyb3JNZXNzYWdlRm9yRW1wdHlTaGVsbENvbW1hbmQoKTogc3RyaW5nIHtcclxuICAgICAgICBpZiAodGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0Tm9uRW1wdHlQbGF0Zm9ybUlkcygpLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgLy8gVGhlIHNoZWxsIGNvbW1hbmQgY29udGFpbnMgdmVyc2lvbnMgZm9yIG90aGVyIHBsYXRmb3JtcywgYnV0IG5vdCBmb3IgdGhlIGN1cnJlbnQgb25lLlxyXG4gICAgICAgICAgICBjb25zdCBjdXJyZW50X3BsYXRmb3JtX25hbWUgPSBQbGF0Zm9ybU5hbWVzW2dldE9wZXJhdGluZ1N5c3RlbSgpXTtcclxuICAgICAgICAgICAgY29uc3QgdmVyc2lvbl93b3JkID0gdGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0Tm9uRW1wdHlQbGF0Zm9ybUlkcygpLmxlbmd0aCA+IDEgPyBcInZlcnNpb25zXCIgOiBcImEgdmVyc2lvblwiO1xyXG4gICAgICAgICAgICBjb25zdCBvdGhlcl9wbGF0Zm9ybV9uYW1lcyA9IHRoaXMudF9zaGVsbF9jb21tYW5kLmdldE5vbkVtcHR5UGxhdGZvcm1JZHMoKS5tYXAocGxhdGZvcm1faWQgPT4gUGxhdGZvcm1OYW1lc1twbGF0Zm9ybV9pZF0pLmpvaW4oXCIgYW5kIFwiKTtcclxuICAgICAgICAgICAgcmV0dXJuIGBUaGUgc2hlbGwgY29tbWFuZCBkb2VzIG5vdCBoYXZlIGEgdmVyc2lvbiBmb3IgJHtjdXJyZW50X3BsYXRmb3JtX25hbWV9LCBpdCBvbmx5IGhhcyAke3ZlcnNpb25fd29yZH0gZm9yICR7b3RoZXJfcGxhdGZvcm1fbmFtZXN9LmA7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gVGhlIHNoZWxsIGNvbW1hbmQgZG9lc24ndCBjb250YWluIGEgdmVyc2lvbiBmb3IgYW55IHBsYXRmb3JtcywgaXQncyBjb21wbGV0ZWx5IGVtcHR5LlxyXG4gICAgICAgICAgICByZXR1cm4gXCJUaGUgc2hlbGwgY29tbWFuZCBpcyBlbXB0eS4gOihcIjtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEaXNwbGF5cyBhIG5vdGlmaWNhdGlvbiBiYWxsb29uIGluZGljYXRpbmcgYSB1c2VyIHRoYXQgYSBzaGVsbCBjb21tYW5kIGlzIGJlaW5nIGV4ZWN1dGVkLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBjaGlsZF9wcm9jZXNzXHJcbiAgICAgKiBAcGFyYW0gc2hlbGxfY29tbWFuZFxyXG4gICAgICogQHBhcmFtIGV4ZWN1dGlvbl9ub3RpZmljYXRpb25fbW9kZVxyXG4gICAgICogQHBhcmFtIHByb2Nlc3NUZXJtaW5hdG9yIFdpbGwgYmUgY2FsbGVkIGlmIHVzZXIgY2xpY2tzICdSZXF1ZXN0IHRvIHRlcm1pbmF0ZSB0aGUgcHJvY2VzcycgaWNvbi5cclxuICAgICAqIEBwcml2YXRlXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgc2hvd0V4ZWN1dGlvbk5vdGlmaWNhdGlvbihcclxuICAgICAgICBjaGlsZF9wcm9jZXNzOiBDaGlsZFByb2Nlc3MsXHJcbiAgICAgICAgc2hlbGxfY29tbWFuZDogc3RyaW5nLFxyXG4gICAgICAgIGV4ZWN1dGlvbl9ub3RpZmljYXRpb25fbW9kZTogRXhlY3V0aW9uTm90aWZpY2F0aW9uTW9kZSxcclxuICAgICAgICBwcm9jZXNzVGVybWluYXRvcjogKCkgPT4gdm9pZCxcclxuICAgICkge1xyXG4gICAgICAgIGNvbnN0IGNyZWF0ZVJlcXVlc3RUZXJtaW5hdGluZ0J1dHRvbiA9IChub3RpY2U6IE5vdGljZSkgPT4ge1xyXG4gICAgICAgICAgICAvLyBAdHMtaWdub3JlIE5vdGljZS5ub3RpY2VFbCBiZWxvbmdzIHRvIE9ic2lkaWFuJ3MgUFJJVkFURSBBUEksIGFuZCBpdCBtYXkgY2hhbmdlIHdpdGhvdXQgYSBwcmlvciBub3RpY2UuIE9ubHlcclxuICAgICAgICAgICAgLy8gY3JlYXRlIHRoZSBidXR0b24gaWYgbm90aWNlRWwgZXhpc3RzIGFuZCBpcyBhbiBIVE1MRWxlbWVudC5cclxuICAgICAgICAgICAgY29uc3Qgbm90aWNlRWwgPSBub3RpY2Uubm90aWNlRWw7XHJcbiAgICAgICAgICAgIGlmICh1bmRlZmluZWQgIT09IG5vdGljZUVsICYmIG5vdGljZUVsIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLmNyZWF0ZVJlcXVlc3RUZXJtaW5hdGluZ0J1dHRvbihub3RpY2VFbCwgcHJvY2Vzc1Rlcm1pbmF0b3IpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgY29uc3QgZXhlY3V0aW9uX25vdGlmaWNhdGlvbl9tZXNzYWdlID0gXCJFeGVjdXRpbmc6IFwiICsgKHRoaXMudF9zaGVsbF9jb21tYW5kLmdldEFsaWFzKCkgfHwgc2hlbGxfY29tbWFuZCk7XHJcbiAgICAgICAgc3dpdGNoIChleGVjdXRpb25fbm90aWZpY2F0aW9uX21vZGUpIHtcclxuICAgICAgICAgICAgY2FzZSBcInF1aWNrXCI6IHtcclxuICAgICAgICAgICAgICAgIC8vIFJldHJpZXZlIHRoZSB0aW1lb3V0IGZyb20gc2V0dGluZ3MgZGVmaW5lZCBieSBhIHVzZXIuXHJcbiAgICAgICAgICAgICAgICBjb25zdCBwcm9jZXNzTm90aWZpY2F0aW9uID0gdGhpcy5wbHVnaW4ubmV3Tm90aWZpY2F0aW9uKGV4ZWN1dGlvbl9ub3RpZmljYXRpb25fbWVzc2FnZSwgdW5kZWZpbmVkKTtcclxuICAgICAgICAgICAgICAgIGNyZWF0ZVJlcXVlc3RUZXJtaW5hdGluZ0J1dHRvbihwcm9jZXNzTm90aWZpY2F0aW9uKTtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGNhc2UgXCJwZXJtYW5lbnRcIjoge1xyXG4gICAgICAgICAgICAgICAgLy8gU2hvdyB0aGUgbm90aWZpY2F0aW9uIHVudGlsIHRoZSBwcm9jZXNzIGVuZHMuXHJcbiAgICAgICAgICAgICAgICBjb25zdCBwcm9jZXNzTm90aWZpY2F0aW9uID0gdGhpcy5wbHVnaW4ubmV3Tm90aWZpY2F0aW9uKGV4ZWN1dGlvbl9ub3RpZmljYXRpb25fbWVzc2FnZSwgMCk7XHJcbiAgICAgICAgICAgICAgICBjcmVhdGVSZXF1ZXN0VGVybWluYXRpbmdCdXR0b24ocHJvY2Vzc05vdGlmaWNhdGlvbik7XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gSGlkZSB0aGUgbm90aWZpY2F0aW9uIHdoZW4gdGhlIHByb2Nlc3MgZmluaXNoZXMuXHJcbiAgICAgICAgICAgICAgICBjaGlsZF9wcm9jZXNzLm9uKFwiZXhpdFwiLCAoKSA9PiBwcm9jZXNzTm90aWZpY2F0aW9uLmhpZGUoKSk7XHJcbiAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBjYXNlIFwiaWYtbG9uZ1wiOiB7XHJcbiAgICAgICAgICAgICAgICAvLyBPbmx5IHNob3cgdGhlIG5vdGlmaWNhdGlvbiBpZiB0aGUgcHJvY2VzcyBydW5zIGZvciBhbiBleHRlbmRlZCBwZXJpb2Qgb2YgdGltZSAoZGVmaW5lZCBiZWxvdykuXHJcbiAgICAgICAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIHByb2Nlc3MgaXMgc3RpbGwgcnVubmluZy5cclxuICAgICAgICAgICAgICAgICAgICBpZiAobnVsbCA9PT0gY2hpbGRfcHJvY2Vzcy5leGl0Q29kZSAmJiAhY2hpbGRfcHJvY2Vzcy5raWxsZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhlIHByb2Nlc3MgaXMgc3RpbGwgcnVubmluZy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGlzcGxheSBub3RpZmljYXRpb24uXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHByb2Nlc3NOb3RpZmljYXRpb24gPSB0aGlzLnBsdWdpbi5uZXdOb3RpZmljYXRpb24oZXhlY3V0aW9uX25vdGlmaWNhdGlvbl9tZXNzYWdlLCAwKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlUmVxdWVzdFRlcm1pbmF0aW5nQnV0dG9uKHByb2Nlc3NOb3RpZmljYXRpb24pO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSGlkZSB0aGUgbm90aWZpY2F0aW9uIHdoZW4gdGhlIHByb2Nlc3MgZmluaXNoZXMuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNoaWxkX3Byb2Nlc3Mub24oXCJleGl0XCIsICgpID0+IHByb2Nlc3NOb3RpZmljYXRpb24uaGlkZSgpKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9LCAyMDAwKTsgLy8gSWYgeW91IGNoYW5nZSB0aGUgdGltZW91dCwgY2hhbmdlIGRvY3VtZW50YXRpb24sIHRvbyFcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge2RlYnVnTG9nfSBmcm9tIFwiLi4vRGVidWdcIjtcclxuaW1wb3J0IHtcclxuICAgIE1vZGVsXHJcbn0gZnJvbSBcIi4uL2ltcG9ydHNcIjtcclxuXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBJbnN0YW5jZSB7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDb25maWd1cmF0aW9uIG9mIHRoZSBwYXJlbnQgaW5zdGFuY2UuIEUuZy4gaWYgdGhlIGN1cnJlbnQgaW5zdGFuY2UgaXMgYSBQcm9tcHRGaWVsZCwgdGhlbiBwYXJlbnRfY29uZmlndXJhdGlvbnMgaXMgYSBQcm9tcHQncyBjb25maWd1cmF0aW9uLlxyXG4gICAgICogQ2FuIGJlIHRydXN0ZWQgdG8gYWx3YXlzIGV4aXN0LCB1bmxpa2UgcGFyZW50X2luc3RhbmNlLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgcGFyZW50X2NvbmZpZ3VyYXRpb246IEluc3RhbmNlQ29uZmlndXJhdGlvbjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEUuZy4gaWYgdGhlIGN1cnJlbnQgaW5zdGFuY2UgaXMgYSBQcm9tcHRGaWVsZCwgdGhlbiBwYXJlbnRfaW5zdGFuY2UgaXMgYSBQcm9tcHQuXHJcbiAgICAgKiBPbmx5IHByZXNlbnQgZm9yIGluc3RhbmNlcyB3aG9zZSBwYXJlbnQgaXMgc29tZXRoaW5nIGVsc2UgdGhhbiB0aGUgcm9vdCBzZXR0aW5ncyBvYmplY3QuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBwYXJlbnRfaW5zdGFuY2U6IEluc3RhbmNlIHwgbnVsbDtcclxuXHJcbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcHVibGljIHJlYWRvbmx5IG1vZGVsOiBNb2RlbCxcclxuICAgICAgICBwdWJsaWMgcmVhZG9ubHkgY29uZmlndXJhdGlvbjogSW5zdGFuY2VDb25maWd1cmF0aW9uLFxyXG4gICAgICAgIHBhcmVudF9pbnN0YW5jZV9vcl9jb25maWd1cmF0aW9uOiBJbnN0YW5jZSB8IEluc3RhbmNlQ29uZmlndXJhdGlvbixcclxuICAgICkge1xyXG4gICAgICAgIGRlYnVnTG9nKHRoaXMuY29uc3RydWN0b3IubmFtZSArIFwiOiBDcmVhdGluZyBhIG5ldyBpbnN0YW5jZS5cIik7XHJcblxyXG4gICAgICAgIC8vIERldGVybWluZSBwYXJlbnQgdHlwZVxyXG4gICAgICAgIGlmIChwYXJlbnRfaW5zdGFuY2Vfb3JfY29uZmlndXJhdGlvbiBpbnN0YW5jZW9mIEluc3RhbmNlKSB7XHJcbiAgICAgICAgICAgIC8vIEl0J3MgYW4gaW5zdGFuY2Ugb2JqZWN0XHJcbiAgICAgICAgICAgIHRoaXMucGFyZW50X2luc3RhbmNlID0gcGFyZW50X2luc3RhbmNlX29yX2NvbmZpZ3VyYXRpb247XHJcbiAgICAgICAgICAgIHRoaXMucGFyZW50X2NvbmZpZ3VyYXRpb24gPSB0aGlzLnBhcmVudF9pbnN0YW5jZS5jb25maWd1cmF0aW9uO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIEl0J3MgYSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICAgICAgICAgICAgLy8gTm8gcGFyZW50IGluc3RhbmNlIGlzIGF2YWlsYWJsZSwgc28gcHJvYmFibHkgdGhpcyBpcyBhYm91dCBTQ19NYWluU2V0dGluZ3Mgb2JqZWN0LCBhcyBpdCBkb2VzIG5vdCBoYXZlIE1vZGVsL0luc3RhbmNlIGNsYXNzZXMgKGF0IGxlYXN0IHlldCkuXHJcbiAgICAgICAgICAgIHRoaXMucGFyZW50X2luc3RhbmNlID0gbnVsbDsgLy8gSXQncyBudWxsIGFscmVhZHksIGJ1dCBkbyB0aGlzIGp1c3QgdG8gbWFrZSBhIHN0YXRlbWVudC5cclxuICAgICAgICAgICAgdGhpcy5wYXJlbnRfY29uZmlndXJhdGlvbiA9IHBhcmVudF9pbnN0YW5jZV9vcl9jb25maWd1cmF0aW9uO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgYWJzdHJhY3QgZ2V0VGl0bGUoKTogc3RyaW5nO1xyXG5cclxuICAgIHB1YmxpYyBzZXRJZlZhbGlkKGZpZWxkOiBzdHJpbmcsIHZhbHVlOiB1bmtub3duKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMubW9kZWwudmFsaWRhdGVWYWx1ZSh0aGlzLCBmaWVsZCwgdmFsdWUpLnRoZW4oKCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb25bZmllbGRdID0gdmFsdWU7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIEluc3RhbmNlQ29uZmlndXJhdGlvbiB7XHJcbiAgICBba2V5OiBzdHJpbmddOiBhbnk7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uL21haW5cIjtcclxuaW1wb3J0IHtTZXR0aW5nfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHtkZWJ1Z0xvZ30gZnJvbSBcIi4uL0RlYnVnXCI7XHJcbmltcG9ydCB7XHJcbiAgICBDb25maXJtYXRpb25Nb2RhbCxcclxuICAgIEluc3RhbmNlLFxyXG4gICAgSW5zdGFuY2VDb25maWd1cmF0aW9uLFxyXG59IGZyb20gXCIuLi9pbXBvcnRzXCI7XHJcblxyXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgTW9kZWwge1xyXG5cclxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihcclxuICAgICAgICBwdWJsaWMgcmVhZG9ubHkgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICApIHt9XHJcblxyXG4gICAgcHVibGljIGFic3RyYWN0IGdldFNpbmd1bGFyTmFtZSgpOiBzdHJpbmc7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKlRPRE86IENoYW5nZSB0aGlzIHRvIHB1YmxpYyBhbmQgY2FsbCBpdCBmcm9tIEluc3RhbmNlLmNvbnN0cnVjdG9yKCkgYW5kIHN0b3JlIHRoZSByZXN1bHQgaW4gYSBuZXcgcHJvcGVydHkgSW5zdGFuY2UucGFyZW50X3JlbGF0aW9uLiBNYWtlIG90aGVyIGNhbGxlcnMgdXNlIHRoZSBuZXcgcHJvcGVydHkgaW5zdGVhZCBvZiBjYWxsaW5nIHRoaXMgbWV0aG9kLlxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3QgZGVmaW5lUGFyZW50Q29uZmlndXJhdGlvblJlbGF0aW9uKGluc3RhbmNlOiBJbnN0YW5jZSk6IFBhcmVudE1vZGVsT25lVG9PbmVSZWxhdGlvbiB8IFBhcmVudE1vZGVsT25lVG9NYW55SW5kZXhSZWxhdGlvbiB8IFBhcmVudE1vZGVsT25lVG9NYW55SWRSZWxhdGlvbjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIENyZWF0ZXMgaW5zdGFuY2Ugb2JqZWN0cyBmcm9tIGFscmVhZHkgZXhpc3RpbmcgY29uZmlndXJhdGlvbi4gSS5lLiBkb2VzIG5vdCBjcmVhdGUgTkVXIGluc3RhbmNlcyBvciBuZXcgY29uZmlndXJhdGlvbnMuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBhYnN0cmFjdCBsb2FkSW5zdGFuY2VzKHBhcmVudF9pbnN0YW5jZV9vcl9jb25maWd1cmF0aW9uOiBJbnN0YW5jZSB8IEluc3RhbmNlQ29uZmlndXJhdGlvbik6IFNldDxJbnN0YW5jZT4gfCBNYXA8c3RyaW5nLCBJbnN0YW5jZT47XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDcmVhdGVzIGEgbmV3IGluc3RhbmNlIGFuZCBhZGRzIGl0cyBjb25maWd1cmF0aW9uIHRvIHRoZSBwYXJlbnQgY29uZmlndXJhdGlvbi5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGFic3RyYWN0IG5ld0luc3RhbmNlKHBhcmVudF9pbnN0YW5jZV9vcl9jb25maWd1cmF0aW9uOiBJbnN0YW5jZSB8IEluc3RhbmNlQ29uZmlndXJhdGlvbik6IEluc3RhbmNlO1xyXG5cclxuICAgIHB1YmxpYyBhYnN0cmFjdCBnZXREZWZhdWx0Q29uZmlndXJhdGlvbigpOiBJbnN0YW5jZUNvbmZpZ3VyYXRpb247XHJcblxyXG4gICAgcHVibGljIGNyZWF0ZVNldHRpbmdGaWVsZHMoaW5zdGFuY2U6IEluc3RhbmNlLCBwYXJlbnRfZWxlbWVudDogSFRNTEVsZW1lbnQsIHdpdGhfZGVsZXRpb24gPSB0cnVlKSB7XHJcbiAgICAgICAgZGVidWdMb2codGhpcy5jb25zdHJ1Y3Rvci5uYW1lICsgXCI6IENyZWF0aW5nIHNldHRpbmcgZmllbGRzLlwiKTtcclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGEgY29udGFpbmVyXHJcbiAgICAgICAgY29uc3Qgc2V0dGluZ19maWVsZHNfY29udGFpbmVyID0gcGFyZW50X2VsZW1lbnQuY3JlYXRlRGl2KCk7IC8vIENyZWF0ZSBhIG5lc3RlZCBjb250YWluZXIgdGhhdCBjYW4gYmUgZWFzaWx5IGRlbGV0ZWQgaWYgdGhlIGluc3RhbmNlIGlzIGRlbGV0ZWQuXHJcblxyXG4gICAgICAgIGNvbnN0IG1haW5fc2V0dGluZ19maWVsZCA9IHRoaXMuX2NyZWF0ZVNldHRpbmdGaWVsZHMoaW5zdGFuY2UsIHNldHRpbmdfZmllbGRzX2NvbnRhaW5lcik7XHJcbiAgICAgICAgaWYgKHdpdGhfZGVsZXRpb24pIHtcclxuICAgICAgICAgICAgbWFpbl9zZXR0aW5nX2ZpZWxkLmFkZEV4dHJhQnV0dG9uKGJ1dHRvbiA9PiBidXR0b25cclxuICAgICAgICAgICAgICAgIC5zZXRJY29uKFwidHJhc2hcIilcclxuICAgICAgICAgICAgICAgIC5zZXRUb29sdGlwKFwiRGVsZXRlIHRoaXMgXCIgKyB0aGlzLmdldFNpbmd1bGFyTmFtZSgpLnRvTG9jYWxlTG93ZXJDYXNlKCkpXHJcbiAgICAgICAgICAgICAgICAub25DbGljaygoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIHRyYXNoIGljb24gaGFzIGJlZW4gY2xpY2tlZFxyXG4gICAgICAgICAgICAgICAgICAgIC8vIE9wZW4gdXAgYSBtb2RhbCBhc2tpbmcgZm9yIGNvbmZpcm1hdGlvbiBpZiB0aGUgaW5zdGFuY2UgY2FuIGJlIGRlbGV0ZWQgZnJvbSB0aGlzLnBhcmVudF9jb25maWd1cmF0aW9uLlxyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNvbmZpcm1hdGlvbl9tb2RhbCA9IG5ldyBDb25maXJtYXRpb25Nb2RhbChcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiRGVsZXRlIFwiICsgdGhpcy5nZXRTaW5ndWxhck5hbWUoKS50b0xvY2FsZUxvd2VyQ2FzZSgpICsgXCI6IFwiICsgaW5zdGFuY2UuZ2V0VGl0bGUoKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgXCJBcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gZGVsZXRlIHRoaXMgXCIgKyB0aGlzLmdldFNpbmd1bGFyTmFtZSgpLnRvTG9jYWxlTG93ZXJDYXNlKCkgKyBcIj9cIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgXCJZZXMsIGRlbGV0ZVwiLFxyXG4gICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uZmlybWF0aW9uX21vZGFsLm9wZW4oKTtcclxuICAgICAgICAgICAgICAgICAgICBjb25maXJtYXRpb25fbW9kYWwucHJvbWlzZS50aGVuKGFzeW5jIChkZWxldGlvbl9jb25maXJtZWQ6IGJvb2xlYW4pID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGRlbGV0aW9uX2NvbmZpcm1lZCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVXNlciBoYXMgY29uZmlybWVkIHRoZSBkZWxldGlvbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERlbGV0ZSB0aGUgY29uZmlndXJhdGlvbiBhbmQgcmVtb3ZlIHRoZSBpbnN0YW5jZSBmcm9tIGN1c3RvbSBjb2xsZWN0aW9ucy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGVsZXRlSW5zdGFuY2UoaW5zdGFuY2UpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERlbGV0ZSBzZXR0aW5nIGZpZWxkcy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldHRpbmdfZmllbGRzX2NvbnRhaW5lci5yZW1vdmUoKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTYXZlIHNldHRpbmdzXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBtYWluX3NldHRpbmdfZmllbGQ7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDcmVhdGVzIHNldHRpbmcgZmllbGRzIGludG8gdGhlIGdpdmVuIGNvbnRhaW5lcl9lbGVtZW50LCBhbmQgdGhlbiByZXR1cm5zIHRoZSBtYWluIFNldHRpbmcgdGhhdFxyXG4gICAgICogY2FuIGJlIHVzZWQgZm9yIGluamVjdGluZyBhIGRlbGV0aW5nIGJ1dHRvbiBpbnRvLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBpbnN0YW5jZVxyXG4gICAgICogQHBhcmFtIGNvbnRhaW5lcl9lbGVtZW50XHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCBfY3JlYXRlU2V0dGluZ0ZpZWxkcyhpbnN0YW5jZTogSW5zdGFuY2UsIGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCk6IFNldHRpbmc7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEZWxldGVzIHRoZSBpbnN0YW5jZSBmcm9tIGNvbmZpZ3VyYXRpb24sIGFuZCBjYWxscyBfZGVsZXRlQ2hpbGQoKSB3aGljaCB3aWxsIGRlbGV0ZSB0aGUgaW5zdGFuY2UgZnJvbSBjdXN0b20gY29sbGVjdGlvbnMuXHJcbiAgICAgKlxyXG4gICAgICogQ2FuIGJlIG1hZGUgcHVibGljIGlmIG5lZWRlZC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGRlbGV0ZUluc3RhbmNlKGluc3RhbmNlOiBJbnN0YW5jZSkge1xyXG4gICAgICAgIGRlYnVnTG9nKHRoaXMuY29uc3RydWN0b3IubmFtZSArIFwiOiBEZWxldGluZyBhbiBpbnN0YW5jZS5cIik7XHJcbiAgICAgICAgdGhpcy5fZGVsZXRlSW5zdGFuY2UoaW5zdGFuY2UpO1xyXG4gICAgICAgIGNvbnN0IHJlbGF0aW9uID0gdGhpcy5kZWZpbmVQYXJlbnRDb25maWd1cmF0aW9uUmVsYXRpb24oaW5zdGFuY2UpO1xyXG4gICAgICAgIHN3aXRjaCAocmVsYXRpb24udHlwZSkge1xyXG4gICAgICAgICAgICAvLyBjYXNlIFwib25lLXRvLW9uZVwiOiAvLyBUT0RPOiBVbmNvbW1lbnQgd2hlbiBmaXJzdCBtb2RlbCB0aGF0IG5lZWRzIHRoaXMgaXMgaW1wbGVtZW50ZWQuXHJcbiAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIGEgcmVsYXRpb24gd2hlcmUgJ2tleScgcG9pbnRzIGRpcmVjdGx5IHRvIHRoZSBpbnN0YW5jZSdzIGNvbmZpZ3VyYXRpb24uXHJcbiAgICAgICAgICAgICAgICAvLyBkZWxldGUgdGhpcy5wYXJlbnRfY29uZmlndXJhdGlvblt0aGlzLnJlbGF0aW9uLmtleV07XHJcbiAgICAgICAgICAgICAgICAvLyBicmVhaztcclxuICAgICAgICAgICAgY2FzZSBcIm9uZS10by1tYW55LWluZGV4XCI6IHtcclxuICAgICAgICAgICAgICAgIC8vIFRoaXMgaXMgYSByZWxhdGlvbiB3aGVyZSAna2V5JyBwb2ludHMgdG8gYW4gaW5kZXhlZCBhcnJheSBvZiBpbnN0YW5jZSBjb25maWd1cmF0aW9ucy4gVXNlICdpbmRleCcgdG8gcGljayB0aGUgY29ycmVjdCBpbnN0YW5jZSBjb25maWd1cmF0aW9uLlxyXG4gICAgICAgICAgICAgICAgaW5zdGFuY2UucGFyZW50X2NvbmZpZ3VyYXRpb25bcmVsYXRpb24ua2V5XS5zcGxpY2UocmVsYXRpb24uaW5kZXgsIDEpOyAvLyBEbyBub3QgdXNlIGRlbGV0ZSwgYXMgaXQgd291bGQgcGxhY2UgbnVsbCBpbiB0aGUgbGlzdC5cclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICB9IGNhc2UgXCJvbmUtdG8tbWFueS1pZFwiOiB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIGEgcmVsYXRpb24gd2hlcmUgJ2tleScgcG9pbnRzIHRvIGFuIGluZGV4ZWQgYXJyYXkgb2YgaW5zdGFuY2UgY29uZmlndXJhdGlvbnMuIFVzZSAnaWQnIHRvIGRldGVybWluZSB0aGUgY29ycmVjdCBpbmRleC5cclxuICAgICAgICAgICAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5pZFRvSW5kZXgoaW5zdGFuY2UucGFyZW50X2NvbmZpZ3VyYXRpb25bcmVsYXRpb24ua2V5XSwgcmVsYXRpb24uaWQpO1xyXG4gICAgICAgICAgICAgICAgaWYgKG51bGwgPT09IGluZGV4KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gU29tZXRoaW5nIHdlbnQgd3JvbmdcclxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7dGhpcy5jb25zdHJ1Y3Rvci5uYW1lfS5kZWxldGVJbnN0YW5jZSgpOiBDb3VsZCBub3QgZmluZCBhbiBpbmRleCBmb3IgaWQgJHtyZWxhdGlvbi5pZH0uYCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBpbnN0YW5jZS5wYXJlbnRfY29uZmlndXJhdGlvbltyZWxhdGlvbi5rZXldLnNwbGljZShpbmRleCwgMSk7IC8vIERvIG5vdCB1c2UgZGVsZXRlLCBhcyBpdCB3b3VsZCBwbGFjZSBudWxsIGluIHRoZSBsaXN0LlxyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcblx0XHRcdH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBpZFRvSW5kZXgoY29uZmlndXJhdGlvbnM6IEluc3RhbmNlQ29uZmlndXJhdGlvbltdLCBpZDogc3RyaW5nKTogbnVtYmVyIHwgbnVsbCB7XHJcbiAgICAgICAgbGV0IHJlc3VsdF9pbmRleCA9IG51bGw7XHJcbiAgICAgICAgY29uZmlndXJhdGlvbnMuZm9yRWFjaCgoaW5zdGFuY2VfY29uZmlndXJhdGlvbjogSW5zdGFuY2VDb25maWd1cmF0aW9uLCBpbmRleCkgPT4ge1xyXG4gICAgICAgICAgICBpZiAoaW5zdGFuY2VfY29uZmlndXJhdGlvbi5pZCA9PT0gaWQpIHtcclxuICAgICAgICAgICAgICAgIC8vIFRoaXMgaXMgdGhlIGNvcnJlY3QgY29uZmlndXJhdGlvbi5cclxuICAgICAgICAgICAgICAgIHJlc3VsdF9pbmRleCA9IGluZGV4O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgcmV0dXJuIHJlc3VsdF9pbmRleDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFRoaXMgc2hvdWxkIGRlbGV0ZSB0aGUgaW5zdGFuY2UgZnJvbSBjdXN0b20gY29sbGVjdGlvbnMuIEl0IHNob3VsZCBiZSBvdmVycmlkZGVuIGJ5IGFsbCBJbnN0YW5jZSBjbGFzc2VzIHRoYXQgaGF2ZSBkZWxldGFibGUgY2hpbGRyZW4uXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBfZGVsZXRlSW5zdGFuY2UoaW5zdGFuY2U6IEluc3RhbmNlKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMuY29uc3RydWN0b3IubmFtZSArIFwiLmRlbGV0ZUluc3RhbmNlKCk6IFRoaXMgY2xhc3MgZG9lcyBub3Qgb3ZlcnJpZGUgX2RlbGV0ZUluc3RhbmNlKCkgbWV0aG9kLiBNYXliZSB0aGUgY2xhc3MgaXMgbm90IHN1cHBvc2VkIHRvIGhhdmUgY2hpbGRyZW4/XCIpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBhYnN0cmFjdCB2YWxpZGF0ZVZhbHVlKGluc3RhbmNlOiBJbnN0YW5jZSwgZmllbGQ6IHN0cmluZywgdmFsdWU6IHVua25vd24pOiBQcm9taXNlPHZvaWQ+O1xyXG5cclxufVxyXG5cclxuLyoqXHJcbiAqIEBhYnN0cmFjdCBUaGlzIGludGVyZmFjZSBzaG91bGQgbm90IGJlIHVzZWQgZGlyZWN0bHkuIFVzZSBvbmUgb2YgdGhlIGNoaWxkIGludGVyZmFjZXMgaW5zdGVhZC5cclxuICovXHJcbmludGVyZmFjZSBQYXJlbnRNb2RlbFJlbGF0aW9uIHtcclxuICAgIHR5cGU6IFwib25lLXRvLW9uZVwiIHwgXCJvbmUtdG8tbWFueS1pbmRleFwiIHwgXCJvbmUtdG8tbWFueS1pZFwiO1xyXG4gICAga2V5OiBzdHJpbmc7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgUGFyZW50TW9kZWxPbmVUb09uZVJlbGF0aW9uIGV4dGVuZHMgUGFyZW50TW9kZWxSZWxhdGlvbiB7XHJcbiAgICB0eXBlOiBcIm9uZS10by1vbmVcIjtcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBQYXJlbnRNb2RlbE9uZVRvTWFueUluZGV4UmVsYXRpb24gZXh0ZW5kcyBQYXJlbnRNb2RlbFJlbGF0aW9uIHtcclxuICAgIHR5cGU6IFwib25lLXRvLW1hbnktaW5kZXhcIjtcclxuICAgIGluZGV4OiBudW1iZXI7IC8vIFRPRE86IEZpbmQgYSB3YXkgdG8gdXNlIHNvbWV0aGluZyBsaWtlOiBrZXlvZiBJbnN0YW5jZUNvbmZpZ3VyYXRpb25bdGhpc1tcImtleVwiXV0gLiAna2V5b2YnIG5lZWRzIHRvIGJlIHJlcGxhY2VkIHdpdGggc29tZXRoaW5nIHN1aXRhYmxlIGZvciBhIG51bWVyaWMgaW5kZXggb2YgYW4gYXJyYXkuICdrZXlvZicgaXMgb25seSBhcHBsaWNhYmxlIGZvciBvYmplY3RzLlxyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFBhcmVudE1vZGVsT25lVG9NYW55SWRSZWxhdGlvbiBleHRlbmRzIFBhcmVudE1vZGVsUmVsYXRpb24ge1xyXG4gICAgdHlwZTogXCJvbmUtdG8tbWFueS1pZFwiO1xyXG4gICAgaWQ6IHN0cmluZztcclxufVxyXG5cclxuXHJcbi8vIE1vZGVsIGNsYXNzIGNvbGxlY3Rpb25cclxuXHJcbmNvbnN0IG1vZGVsX2NsYXNzZXM6IE1hcDxzdHJpbmcsIE1vZGVsPiA9IG5ldyBNYXAoKTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBpbnRyb2R1Y2VNb2RlbENsYXNzKG1vZGVsX2NsYXNzOiBNb2RlbCkge1xyXG4gICAgbW9kZWxfY2xhc3Nlcy5zZXQobW9kZWxfY2xhc3MuY29uc3RydWN0b3IubmFtZSwgbW9kZWxfY2xhc3MpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZ2V0TW9kZWw8TW9kZWxDbGFzcz4obW9kZWxfY2xhc3NfbmFtZTogc3RyaW5nKTogTW9kZWxDbGFzcyAge1xyXG4gICAgcmV0dXJuIG1vZGVsX2NsYXNzZXMuZ2V0KG1vZGVsX2NsYXNzX25hbWUpIGFzIHVua25vd24gYXMgTW9kZWxDbGFzcztcclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtJbnN0YW5jZX0gZnJvbSBcIi4uL0luc3RhbmNlXCI7XHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uLy4uL21haW5cIjtcclxuaW1wb3J0IHtTQ19NYWluU2V0dGluZ3N9IGZyb20gXCIuLi8uLi9zZXR0aW5ncy9TQ19NYWluU2V0dGluZ3NcIjtcclxuaW1wb3J0IHtnZXRJREdlbmVyYXRvcn0gZnJvbSBcIi4uLy4uL0lER2VuZXJhdG9yXCI7XHJcbmltcG9ydCB7T3V0cHV0V3JhcHBlck1vZGVsfSBmcm9tIFwiLi9PdXRwdXRXcmFwcGVyTW9kZWxcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBPdXRwdXRXcmFwcGVyIGV4dGVuZHMgSW5zdGFuY2Uge1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIHB1YmxpYyBtb2RlbDogT3V0cHV0V3JhcHBlck1vZGVsLFxyXG4gICAgICAgIHByb3RlY3RlZCBwbHVnaW46IFNDX1BsdWdpbixcclxuICAgICAgICBwdWJsaWMgY29uZmlndXJhdGlvbjogT3V0cHV0V3JhcHBlckNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgcHVibGljIHBhcmVudF9jb25maWd1cmF0aW9uOiBTQ19NYWluU2V0dGluZ3MsXHJcbiAgICApIHtcclxuICAgICAgICBzdXBlcihtb2RlbCwgY29uZmlndXJhdGlvbiwgcGFyZW50X2NvbmZpZ3VyYXRpb24pO1xyXG5cclxuICAgICAgICAvLyBJbnRyb2R1Y2UgdGhlIElEIHRvIGFuIElEIGdlbmVyYXRvciBzbyB0aGF0IGl0IHdvbid0IGFjY2lkZW50YWxseSBnZW5lcmF0ZSB0aGUgc2FtZSBJRCBhZ2FpbiB3aGVuIGNyZWF0aW5nIG5ldyBPdXRwdXRXcmFwcGVycy5cclxuICAgICAgICBnZXRJREdlbmVyYXRvcigpLmFkZFJlc2VydmVkSUQoY29uZmlndXJhdGlvbi5pZCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldElEKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24uaWQ7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldFRpdGxlKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24udGl0bGU7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldENvbnRlbnQoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbi5jb250ZW50O1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRDb25maWd1cmF0aW9uKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb247XHJcbiAgICB9XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgT3V0cHV0V3JhcHBlckNvbmZpZ3VyYXRpb24ge1xyXG4gICAgaWQ6IHN0cmluZztcclxuICAgIHRpdGxlOiBzdHJpbmc7XHJcbiAgICBjb250ZW50OiBzdHJpbmc7XHJcbn0iLCIoZnVuY3Rpb24gKGdsb2JhbCwgZmFjdG9yeSkge1xuICB0eXBlb2YgZXhwb3J0cyA9PT0gJ29iamVjdCcgJiYgdHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcgPyBtb2R1bGUuZXhwb3J0cyA9IGZhY3RvcnkoKSA6XG4gIHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCA/IGRlZmluZShmYWN0b3J5KSA6XG4gIChnbG9iYWwgPSB0eXBlb2YgZ2xvYmFsVGhpcyAhPT0gJ3VuZGVmaW5lZCcgPyBnbG9iYWxUaGlzIDogZ2xvYmFsIHx8IHNlbGYsIGdsb2JhbC5hdXRvY29tcGxldGUgPSBmYWN0b3J5KCkpO1xufSh0aGlzLCAoZnVuY3Rpb24gKCkgeyAndXNlIHN0cmljdCc7XG5cbiAgLypcclxuICAgKiBodHRwczovL2dpdGh1Yi5jb20va3JhYWRlbi9hdXRvY29tcGxldGVcclxuICAgKiBDb3B5cmlnaHQgKGMpIDIwMTYgRGVueXMgS3Jhc25vc2hjaG9rXHJcbiAgICogTUlUIExpY2Vuc2VcclxuICAgKi9cclxuICBmdW5jdGlvbiBhdXRvY29tcGxldGUoc2V0dGluZ3MpIHtcclxuICAgICAgLy8ganVzdCBhbiBhbGlhcyB0byBtaW5pbWl6ZSBKUyBmaWxlIHNpemVcclxuICAgICAgdmFyIGRvYyA9IGRvY3VtZW50O1xyXG4gICAgICB2YXIgY29udGFpbmVyID0gc2V0dGluZ3MuY29udGFpbmVyIHx8IGRvYy5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xyXG4gICAgICB2YXIgY29udGFpbmVyU3R5bGUgPSBjb250YWluZXIuc3R5bGU7XHJcbiAgICAgIHZhciB1c2VyQWdlbnQgPSBuYXZpZ2F0b3IudXNlckFnZW50O1xyXG4gICAgICB2YXIgbW9iaWxlRmlyZWZveCA9IH51c2VyQWdlbnQuaW5kZXhPZihcIkZpcmVmb3hcIikgJiYgfnVzZXJBZ2VudC5pbmRleE9mKFwiTW9iaWxlXCIpO1xyXG4gICAgICB2YXIgZGVib3VuY2VXYWl0TXMgPSBzZXR0aW5ncy5kZWJvdW5jZVdhaXRNcyB8fCAwO1xyXG4gICAgICB2YXIgcHJldmVudFN1Ym1pdCA9IHNldHRpbmdzLnByZXZlbnRTdWJtaXQgfHwgZmFsc2U7XHJcbiAgICAgIHZhciBkaXNhYmxlQXV0b1NlbGVjdCA9IHNldHRpbmdzLmRpc2FibGVBdXRvU2VsZWN0IHx8IGZhbHNlO1xyXG4gICAgICAvLyAna2V5dXAnIGV2ZW50IHdpbGwgbm90IGJlIGZpcmVkIG9uIE1vYmlsZSBGaXJlZm94LCBzbyB3ZSBoYXZlIHRvIHVzZSAnaW5wdXQnIGV2ZW50IGluc3RlYWRcclxuICAgICAgdmFyIGtleVVwRXZlbnROYW1lID0gbW9iaWxlRmlyZWZveCA/IFwiaW5wdXRcIiA6IFwia2V5dXBcIjtcclxuICAgICAgdmFyIGl0ZW1zID0gW107XHJcbiAgICAgIHZhciBpbnB1dFZhbHVlID0gXCJcIjtcclxuICAgICAgdmFyIG1pbkxlbiA9IDI7XHJcbiAgICAgIHZhciBzaG93T25Gb2N1cyA9IHNldHRpbmdzLnNob3dPbkZvY3VzO1xyXG4gICAgICB2YXIgc2VsZWN0ZWQ7XHJcbiAgICAgIHZhciBrZXlwcmVzc0NvdW50ZXIgPSAwO1xyXG4gICAgICB2YXIgZGVib3VuY2VUaW1lcjtcclxuICAgICAgaWYgKHNldHRpbmdzLm1pbkxlbmd0aCAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICBtaW5MZW4gPSBzZXR0aW5ncy5taW5MZW5ndGg7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKCFzZXR0aW5ncy5pbnB1dCkge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiaW5wdXQgdW5kZWZpbmVkXCIpO1xyXG4gICAgICB9XHJcbiAgICAgIHZhciBpbnB1dCA9IHNldHRpbmdzLmlucHV0O1xyXG4gICAgICBjb250YWluZXIuY2xhc3NOYW1lID0gXCJhdXRvY29tcGxldGUgXCIgKyAoc2V0dGluZ3MuY2xhc3NOYW1lIHx8IFwiXCIpO1xyXG4gICAgICAvLyBJT1MgaW1wbGVtZW50YXRpb24gZm9yIGZpeGVkIHBvc2l0aW9uaW5nIGhhcyBtYW55IGJ1Z3MsIHNvIHdlIHdpbGwgdXNlIGFic29sdXRlIHBvc2l0aW9uaW5nXHJcbiAgICAgIGNvbnRhaW5lclN0eWxlLnBvc2l0aW9uID0gXCJhYnNvbHV0ZVwiO1xyXG4gICAgICAvKipcclxuICAgICAgICogRGV0YWNoIHRoZSBjb250YWluZXIgZnJvbSBET01cclxuICAgICAgICovXHJcbiAgICAgIGZ1bmN0aW9uIGRldGFjaCgpIHtcclxuICAgICAgICAgIHZhciBwYXJlbnQgPSBjb250YWluZXIucGFyZW50Tm9kZTtcclxuICAgICAgICAgIGlmIChwYXJlbnQpIHtcclxuICAgICAgICAgICAgICBwYXJlbnQucmVtb3ZlQ2hpbGQoY29udGFpbmVyKTtcclxuICAgICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICAvKipcclxuICAgICAgICogQ2xlYXIgZGVib3VuY2luZyB0aW1lciBpZiBhc3NpZ25lZFxyXG4gICAgICAgKi9cclxuICAgICAgZnVuY3Rpb24gY2xlYXJEZWJvdW5jZVRpbWVyKCkge1xyXG4gICAgICAgICAgaWYgKGRlYm91bmNlVGltZXIpIHtcclxuICAgICAgICAgICAgICB3aW5kb3cuY2xlYXJUaW1lb3V0KGRlYm91bmNlVGltZXIpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIC8qKlxyXG4gICAgICAgKiBBdHRhY2ggdGhlIGNvbnRhaW5lciB0byBET01cclxuICAgICAgICovXHJcbiAgICAgIGZ1bmN0aW9uIGF0dGFjaCgpIHtcclxuICAgICAgICAgIGlmICghY29udGFpbmVyLnBhcmVudE5vZGUpIHtcclxuICAgICAgICAgICAgICBkb2MuYm9keS5hcHBlbmRDaGlsZChjb250YWluZXIpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIC8qKlxyXG4gICAgICAgKiBDaGVjayBpZiBjb250YWluZXIgZm9yIGF1dG9jb21wbGV0ZSBpcyBkaXNwbGF5ZWRcclxuICAgICAgICovXHJcbiAgICAgIGZ1bmN0aW9uIGNvbnRhaW5lckRpc3BsYXllZCgpIHtcclxuICAgICAgICAgIHJldHVybiAhIWNvbnRhaW5lci5wYXJlbnROb2RlO1xyXG4gICAgICB9XHJcbiAgICAgIC8qKlxyXG4gICAgICAgKiBDbGVhciBhdXRvY29tcGxldGUgc3RhdGUgYW5kIGhpZGUgY29udGFpbmVyXHJcbiAgICAgICAqL1xyXG4gICAgICBmdW5jdGlvbiBjbGVhcigpIHtcclxuICAgICAgICAgIC8vIHByZXZlbnQgdGhlIHVwZGF0ZSBjYWxsIGlmIHRoZXJlIGFyZSBwZW5kaW5nIEFKQVggcmVxdWVzdHNcclxuICAgICAgICAgIGtleXByZXNzQ291bnRlcisrO1xyXG4gICAgICAgICAgaXRlbXMgPSBbXTtcclxuICAgICAgICAgIGlucHV0VmFsdWUgPSBcIlwiO1xyXG4gICAgICAgICAgc2VsZWN0ZWQgPSB1bmRlZmluZWQ7XHJcbiAgICAgICAgICBkZXRhY2goKTtcclxuICAgICAgfVxyXG4gICAgICAvKipcclxuICAgICAgICogVXBkYXRlIGF1dG9jb21wbGV0ZSBwb3NpdGlvblxyXG4gICAgICAgKi9cclxuICAgICAgZnVuY3Rpb24gdXBkYXRlUG9zaXRpb24oKSB7XHJcbiAgICAgICAgICBpZiAoIWNvbnRhaW5lckRpc3BsYXllZCgpKSB7XHJcbiAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgY29udGFpbmVyU3R5bGUuaGVpZ2h0ID0gXCJhdXRvXCI7XHJcbiAgICAgICAgICBjb250YWluZXJTdHlsZS53aWR0aCA9IGlucHV0Lm9mZnNldFdpZHRoICsgXCJweFwiO1xyXG4gICAgICAgICAgdmFyIG1heEhlaWdodCA9IDA7XHJcbiAgICAgICAgICB2YXIgaW5wdXRSZWN0O1xyXG4gICAgICAgICAgZnVuY3Rpb24gY2FsYygpIHtcclxuICAgICAgICAgICAgICB2YXIgZG9jRWwgPSBkb2MuZG9jdW1lbnRFbGVtZW50O1xyXG4gICAgICAgICAgICAgIHZhciBjbGllbnRUb3AgPSBkb2NFbC5jbGllbnRUb3AgfHwgZG9jLmJvZHkuY2xpZW50VG9wIHx8IDA7XHJcbiAgICAgICAgICAgICAgdmFyIGNsaWVudExlZnQgPSBkb2NFbC5jbGllbnRMZWZ0IHx8IGRvYy5ib2R5LmNsaWVudExlZnQgfHwgMDtcclxuICAgICAgICAgICAgICB2YXIgc2Nyb2xsVG9wID0gd2luZG93LnBhZ2VZT2Zmc2V0IHx8IGRvY0VsLnNjcm9sbFRvcDtcclxuICAgICAgICAgICAgICB2YXIgc2Nyb2xsTGVmdCA9IHdpbmRvdy5wYWdlWE9mZnNldCB8fCBkb2NFbC5zY3JvbGxMZWZ0O1xyXG4gICAgICAgICAgICAgIGlucHV0UmVjdCA9IGlucHV0LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgICAgICAgICAgIHZhciB0b3AgPSBpbnB1dFJlY3QudG9wICsgaW5wdXQub2Zmc2V0SGVpZ2h0ICsgc2Nyb2xsVG9wIC0gY2xpZW50VG9wO1xyXG4gICAgICAgICAgICAgIHZhciBsZWZ0ID0gaW5wdXRSZWN0LmxlZnQgKyBzY3JvbGxMZWZ0IC0gY2xpZW50TGVmdDtcclxuICAgICAgICAgICAgICBjb250YWluZXJTdHlsZS50b3AgPSB0b3AgKyBcInB4XCI7XHJcbiAgICAgICAgICAgICAgY29udGFpbmVyU3R5bGUubGVmdCA9IGxlZnQgKyBcInB4XCI7XHJcbiAgICAgICAgICAgICAgbWF4SGVpZ2h0ID0gd2luZG93LmlubmVySGVpZ2h0IC0gKGlucHV0UmVjdC50b3AgKyBpbnB1dC5vZmZzZXRIZWlnaHQpO1xyXG4gICAgICAgICAgICAgIGlmIChtYXhIZWlnaHQgPCAwKSB7XHJcbiAgICAgICAgICAgICAgICAgIG1heEhlaWdodCA9IDA7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGNvbnRhaW5lclN0eWxlLnRvcCA9IHRvcCArIFwicHhcIjtcclxuICAgICAgICAgICAgICBjb250YWluZXJTdHlsZS5ib3R0b20gPSBcIlwiO1xyXG4gICAgICAgICAgICAgIGNvbnRhaW5lclN0eWxlLmxlZnQgPSBsZWZ0ICsgXCJweFwiO1xyXG4gICAgICAgICAgICAgIGNvbnRhaW5lclN0eWxlLm1heEhlaWdodCA9IG1heEhlaWdodCArIFwicHhcIjtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIC8vIHRoZSBjYWxjIG1ldGhvZCBtdXN0IGJlIGNhbGxlZCB0d2ljZSwgb3RoZXJ3aXNlIHRoZSBjYWxjdWxhdGlvbiBtYXkgYmUgd3Jvbmcgb24gcmVzaXplIGV2ZW50IChjaHJvbWUgYnJvd3NlcilcclxuICAgICAgICAgIGNhbGMoKTtcclxuICAgICAgICAgIGNhbGMoKTtcclxuICAgICAgICAgIGlmIChzZXR0aW5ncy5jdXN0b21pemUgJiYgaW5wdXRSZWN0KSB7XHJcbiAgICAgICAgICAgICAgc2V0dGluZ3MuY3VzdG9taXplKGlucHV0LCBpbnB1dFJlY3QsIGNvbnRhaW5lciwgbWF4SGVpZ2h0KTtcclxuICAgICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICAvKipcclxuICAgICAgICogUmVkcmF3IHRoZSBhdXRvY29tcGxldGUgZGl2IGVsZW1lbnQgd2l0aCBzdWdnZXN0aW9uc1xyXG4gICAgICAgKi9cclxuICAgICAgZnVuY3Rpb24gdXBkYXRlKCkge1xyXG4gICAgICAgICAgLy8gZGVsZXRlIGFsbCBjaGlsZHJlbiBmcm9tIGF1dG9jb21wbGV0ZSBET00gY29udGFpbmVyXHJcbiAgICAgICAgICB3aGlsZSAoY29udGFpbmVyLmZpcnN0Q2hpbGQpIHtcclxuICAgICAgICAgICAgICBjb250YWluZXIucmVtb3ZlQ2hpbGQoY29udGFpbmVyLmZpcnN0Q2hpbGQpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgLy8gZnVuY3Rpb24gZm9yIHJlbmRlcmluZyBhdXRvY29tcGxldGUgc3VnZ2VzdGlvbnNcclxuICAgICAgICAgIHZhciByZW5kZXIgPSBmdW5jdGlvbiAoaXRlbSwgY3VycmVudFZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgdmFyIGl0ZW1FbGVtZW50ID0gZG9jLmNyZWF0ZUVsZW1lbnQoXCJkaXZcIik7XHJcbiAgICAgICAgICAgICAgaXRlbUVsZW1lbnQudGV4dENvbnRlbnQgPSBpdGVtLmxhYmVsIHx8IFwiXCI7XHJcbiAgICAgICAgICAgICAgcmV0dXJuIGl0ZW1FbGVtZW50O1xyXG4gICAgICAgICAgfTtcclxuICAgICAgICAgIGlmIChzZXR0aW5ncy5yZW5kZXIpIHtcclxuICAgICAgICAgICAgICByZW5kZXIgPSBzZXR0aW5ncy5yZW5kZXI7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICAvLyBmdW5jdGlvbiB0byByZW5kZXIgYXV0b2NvbXBsZXRlIGdyb3Vwc1xyXG4gICAgICAgICAgdmFyIHJlbmRlckdyb3VwID0gZnVuY3Rpb24gKGdyb3VwTmFtZSwgY3VycmVudFZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgdmFyIGdyb3VwRGl2ID0gZG9jLmNyZWF0ZUVsZW1lbnQoXCJkaXZcIik7XHJcbiAgICAgICAgICAgICAgZ3JvdXBEaXYudGV4dENvbnRlbnQgPSBncm91cE5hbWU7XHJcbiAgICAgICAgICAgICAgcmV0dXJuIGdyb3VwRGl2O1xyXG4gICAgICAgICAgfTtcclxuICAgICAgICAgIGlmIChzZXR0aW5ncy5yZW5kZXJHcm91cCkge1xyXG4gICAgICAgICAgICAgIHJlbmRlckdyb3VwID0gc2V0dGluZ3MucmVuZGVyR3JvdXA7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICB2YXIgZnJhZ21lbnQgPSBkb2MuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpO1xyXG4gICAgICAgICAgdmFyIHByZXZHcm91cCA9IFwiIzk/JFwiO1xyXG4gICAgICAgICAgaXRlbXMuZm9yRWFjaChmdW5jdGlvbiAoaXRlbSkge1xyXG4gICAgICAgICAgICAgIGlmIChpdGVtLmdyb3VwICYmIGl0ZW0uZ3JvdXAgIT09IHByZXZHcm91cCkge1xyXG4gICAgICAgICAgICAgICAgICBwcmV2R3JvdXAgPSBpdGVtLmdyb3VwO1xyXG4gICAgICAgICAgICAgICAgICB2YXIgZ3JvdXBEaXYgPSByZW5kZXJHcm91cChpdGVtLmdyb3VwLCBpbnB1dFZhbHVlKTtcclxuICAgICAgICAgICAgICAgICAgaWYgKGdyb3VwRGl2KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICBncm91cERpdi5jbGFzc05hbWUgKz0gXCIgZ3JvdXBcIjtcclxuICAgICAgICAgICAgICAgICAgICAgIGZyYWdtZW50LmFwcGVuZENoaWxkKGdyb3VwRGl2KTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB2YXIgZGl2ID0gcmVuZGVyKGl0ZW0sIGlucHV0VmFsdWUpO1xyXG4gICAgICAgICAgICAgIGlmIChkaXYpIHtcclxuICAgICAgICAgICAgICAgICAgZGl2LmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCBmdW5jdGlvbiAoZXYpIHtcclxuICAgICAgICAgICAgICAgICAgICAgIHNldHRpbmdzLm9uU2VsZWN0KGl0ZW0sIGlucHV0KTtcclxuICAgICAgICAgICAgICAgICAgICAgIGNsZWFyKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgZXYuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICBpZiAoaXRlbSA9PT0gc2VsZWN0ZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgIGRpdi5jbGFzc05hbWUgKz0gXCIgc2VsZWN0ZWRcIjtcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICBmcmFnbWVudC5hcHBlbmRDaGlsZChkaXYpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgY29udGFpbmVyLmFwcGVuZENoaWxkKGZyYWdtZW50KTtcclxuICAgICAgICAgIGlmIChpdGVtcy5sZW5ndGggPCAxKSB7XHJcbiAgICAgICAgICAgICAgaWYgKHNldHRpbmdzLmVtcHR5TXNnKSB7XHJcbiAgICAgICAgICAgICAgICAgIHZhciBlbXB0eSA9IGRvYy5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xyXG4gICAgICAgICAgICAgICAgICBlbXB0eS5jbGFzc05hbWUgPSBcImVtcHR5XCI7XHJcbiAgICAgICAgICAgICAgICAgIGVtcHR5LnRleHRDb250ZW50ID0gc2V0dGluZ3MuZW1wdHlNc2c7XHJcbiAgICAgICAgICAgICAgICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZChlbXB0eSk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICBjbGVhcigpO1xyXG4gICAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgYXR0YWNoKCk7XHJcbiAgICAgICAgICB1cGRhdGVQb3NpdGlvbigpO1xyXG4gICAgICAgICAgdXBkYXRlU2Nyb2xsKCk7XHJcbiAgICAgIH1cclxuICAgICAgZnVuY3Rpb24gdXBkYXRlSWZEaXNwbGF5ZWQoKSB7XHJcbiAgICAgICAgICBpZiAoY29udGFpbmVyRGlzcGxheWVkKCkpIHtcclxuICAgICAgICAgICAgICB1cGRhdGUoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBmdW5jdGlvbiByZXNpemVFdmVudEhhbmRsZXIoKSB7XHJcbiAgICAgICAgICB1cGRhdGVJZkRpc3BsYXllZCgpO1xyXG4gICAgICB9XHJcbiAgICAgIGZ1bmN0aW9uIHNjcm9sbEV2ZW50SGFuZGxlcihlKSB7XHJcbiAgICAgICAgICBpZiAoZS50YXJnZXQgIT09IGNvbnRhaW5lcikge1xyXG4gICAgICAgICAgICAgIHVwZGF0ZUlmRGlzcGxheWVkKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgZnVuY3Rpb24ga2V5dXBFdmVudEhhbmRsZXIoZXYpIHtcclxuICAgICAgICAgIHZhciBrZXlDb2RlID0gZXYud2hpY2ggfHwgZXYua2V5Q29kZSB8fCAwO1xyXG4gICAgICAgICAgdmFyIGlnbm9yZSA9IHNldHRpbmdzLmtleXNUb0lnbm9yZSB8fCBbMzggLyogVXAgKi8sIDEzIC8qIEVudGVyICovLCAyNyAvKiBFc2MgKi8sIDM5IC8qIFJpZ2h0ICovLCAzNyAvKiBMZWZ0ICovLCAxNiAvKiBTaGlmdCAqLywgMTcgLyogQ3RybCAqLywgMTggLyogQWx0ICovLCAyMCAvKiBDYXBzTG9jayAqLywgOTEgLyogV2luZG93c0tleSAqLywgOSAvKiBUYWIgKi9dO1xyXG4gICAgICAgICAgZm9yICh2YXIgX2kgPSAwLCBpZ25vcmVfMSA9IGlnbm9yZTsgX2kgPCBpZ25vcmVfMS5sZW5ndGg7IF9pKyspIHtcclxuICAgICAgICAgICAgICB2YXIga2V5ID0gaWdub3JlXzFbX2ldO1xyXG4gICAgICAgICAgICAgIGlmIChrZXlDb2RlID09PSBrZXkpIHtcclxuICAgICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGlmIChrZXlDb2RlID49IDExMiAvKiBGMSAqLyAmJiBrZXlDb2RlIDw9IDEyMyAvKiBGMTIgKi8gJiYgIXNldHRpbmdzLmtleXNUb0lnbm9yZSkge1xyXG4gICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIC8vIHRoZSBkb3duIGtleSBpcyB1c2VkIHRvIG9wZW4gYXV0b2NvbXBsZXRlXHJcbiAgICAgICAgICBpZiAoa2V5Q29kZSA9PT0gNDAgLyogRG93biAqLyAmJiBjb250YWluZXJEaXNwbGF5ZWQoKSkge1xyXG4gICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHN0YXJ0RmV0Y2goMCAvKiBLZXlib2FyZCAqLyk7XHJcbiAgICAgIH1cclxuICAgICAgLyoqXHJcbiAgICAgICAqIEF1dG9tYXRpY2FsbHkgbW92ZSBzY3JvbGwgYmFyIGlmIHNlbGVjdGVkIGl0ZW0gaXMgbm90IHZpc2libGVcclxuICAgICAgICovXHJcbiAgICAgIGZ1bmN0aW9uIHVwZGF0ZVNjcm9sbCgpIHtcclxuICAgICAgICAgIHZhciBlbGVtZW50cyA9IGNvbnRhaW5lci5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKFwic2VsZWN0ZWRcIik7XHJcbiAgICAgICAgICBpZiAoZWxlbWVudHMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICAgIHZhciBlbGVtZW50ID0gZWxlbWVudHNbMF07XHJcbiAgICAgICAgICAgICAgLy8gbWFrZSBncm91cCB2aXNpYmxlXHJcbiAgICAgICAgICAgICAgdmFyIHByZXZpb3VzID0gZWxlbWVudC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nO1xyXG4gICAgICAgICAgICAgIGlmIChwcmV2aW91cyAmJiBwcmV2aW91cy5jbGFzc05hbWUuaW5kZXhPZihcImdyb3VwXCIpICE9PSAtMSAmJiAhcHJldmlvdXMucHJldmlvdXNFbGVtZW50U2libGluZykge1xyXG4gICAgICAgICAgICAgICAgICBlbGVtZW50ID0gcHJldmlvdXM7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGlmIChlbGVtZW50Lm9mZnNldFRvcCA8IGNvbnRhaW5lci5zY3JvbGxUb3ApIHtcclxuICAgICAgICAgICAgICAgICAgY29udGFpbmVyLnNjcm9sbFRvcCA9IGVsZW1lbnQub2Zmc2V0VG9wO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgdmFyIHNlbGVjdEJvdHRvbSA9IGVsZW1lbnQub2Zmc2V0VG9wICsgZWxlbWVudC5vZmZzZXRIZWlnaHQ7XHJcbiAgICAgICAgICAgICAgICAgIHZhciBjb250YWluZXJCb3R0b20gPSBjb250YWluZXIuc2Nyb2xsVG9wICsgY29udGFpbmVyLm9mZnNldEhlaWdodDtcclxuICAgICAgICAgICAgICAgICAgaWYgKHNlbGVjdEJvdHRvbSA+IGNvbnRhaW5lckJvdHRvbSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgY29udGFpbmVyLnNjcm9sbFRvcCArPSBzZWxlY3RCb3R0b20gLSBjb250YWluZXJCb3R0b207XHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgLyoqXHJcbiAgICAgICAqIFNlbGVjdCB0aGUgcHJldmlvdXMgaXRlbSBpbiBzdWdnZXN0aW9uc1xyXG4gICAgICAgKi9cclxuICAgICAgZnVuY3Rpb24gc2VsZWN0UHJldigpIHtcclxuICAgICAgICAgIGlmIChpdGVtcy5sZW5ndGggPCAxKSB7XHJcbiAgICAgICAgICAgICAgc2VsZWN0ZWQgPSB1bmRlZmluZWQ7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICBpZiAoc2VsZWN0ZWQgPT09IGl0ZW1zWzBdKSB7XHJcbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkID0gaXRlbXNbaXRlbXMubGVuZ3RoIC0gMV07XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gaXRlbXMubGVuZ3RoIC0gMTsgaSA+IDA7IGktLSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgaWYgKHNlbGVjdGVkID09PSBpdGVtc1tpXSB8fCBpID09PSAxKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWQgPSBpdGVtc1tpIC0gMV07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgLyoqXHJcbiAgICAgICAqIFNlbGVjdCB0aGUgbmV4dCBpdGVtIGluIHN1Z2dlc3Rpb25zXHJcbiAgICAgICAqL1xyXG4gICAgICBmdW5jdGlvbiBzZWxlY3ROZXh0KCkge1xyXG4gICAgICAgICAgaWYgKGl0ZW1zLmxlbmd0aCA8IDEpIHtcclxuICAgICAgICAgICAgICBzZWxlY3RlZCA9IHVuZGVmaW5lZDtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGlmICghc2VsZWN0ZWQgfHwgc2VsZWN0ZWQgPT09IGl0ZW1zW2l0ZW1zLmxlbmd0aCAtIDFdKSB7XHJcbiAgICAgICAgICAgICAgc2VsZWN0ZWQgPSBpdGVtc1swXTtcclxuICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IChpdGVtcy5sZW5ndGggLSAxKTsgaSsrKSB7XHJcbiAgICAgICAgICAgICAgaWYgKHNlbGVjdGVkID09PSBpdGVtc1tpXSkge1xyXG4gICAgICAgICAgICAgICAgICBzZWxlY3RlZCA9IGl0ZW1zW2kgKyAxXTtcclxuICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGZ1bmN0aW9uIGtleWRvd25FdmVudEhhbmRsZXIoZXYpIHtcclxuICAgICAgICAgIHZhciBrZXlDb2RlID0gZXYud2hpY2ggfHwgZXYua2V5Q29kZSB8fCAwO1xyXG4gICAgICAgICAgaWYgKGtleUNvZGUgPT09IDM4IC8qIFVwICovIHx8IGtleUNvZGUgPT09IDQwIC8qIERvd24gKi8gfHwga2V5Q29kZSA9PT0gMjcgLyogRXNjICovKSB7XHJcbiAgICAgICAgICAgICAgdmFyIGNvbnRhaW5lcklzRGlzcGxheWVkID0gY29udGFpbmVyRGlzcGxheWVkKCk7XHJcbiAgICAgICAgICAgICAgaWYgKGtleUNvZGUgPT09IDI3IC8qIEVzYyAqLykge1xyXG4gICAgICAgICAgICAgICAgICBjbGVhcigpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgaWYgKCFjb250YWluZXJJc0Rpc3BsYXllZCB8fCBpdGVtcy5sZW5ndGggPCAxKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAga2V5Q29kZSA9PT0gMzggLyogVXAgKi9cclxuICAgICAgICAgICAgICAgICAgICAgID8gc2VsZWN0UHJldigpXHJcbiAgICAgICAgICAgICAgICAgICAgICA6IHNlbGVjdE5leHQoKTtcclxuICAgICAgICAgICAgICAgICAgdXBkYXRlKCk7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgICAgaWYgKGNvbnRhaW5lcklzRGlzcGxheWVkKSB7XHJcbiAgICAgICAgICAgICAgICAgIGV2LnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICBpZiAoa2V5Q29kZSA9PT0gMTMgLyogRW50ZXIgKi8pIHtcclxuICAgICAgICAgICAgICBpZiAoc2VsZWN0ZWQpIHtcclxuICAgICAgICAgICAgICAgICAgaWYgKHByZXZlbnRTdWJtaXQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgc2V0dGluZ3Mub25TZWxlY3Qoc2VsZWN0ZWQsIGlucHV0KTtcclxuICAgICAgICAgICAgICAgICAgY2xlYXIoKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgZnVuY3Rpb24gZm9jdXNFdmVudEhhbmRsZXIoKSB7XHJcbiAgICAgICAgICBpZiAoc2hvd09uRm9jdXMpIHtcclxuICAgICAgICAgICAgICBzdGFydEZldGNoKDEgLyogRm9jdXMgKi8pO1xyXG4gICAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGZ1bmN0aW9uIHN0YXJ0RmV0Y2godHJpZ2dlcikge1xyXG4gICAgICAgICAgLy8gSWYgbXVsdGlwbGUga2V5cyB3ZXJlIHByZXNzZWQsIGJlZm9yZSB3ZSBnZXQgYW4gdXBkYXRlIGZyb20gc2VydmVyLFxyXG4gICAgICAgICAgLy8gdGhpcyBtYXkgY2F1c2UgcmVkcmF3aW5nIGF1dG9jb21wbGV0ZSBtdWx0aXBsZSB0aW1lcyBhZnRlciB0aGUgbGFzdCBrZXkgd2FzIHByZXNzZWQuXHJcbiAgICAgICAgICAvLyBUbyBhdm9pZCB0aGlzLCB0aGUgbnVtYmVyIG9mIHRpbWVzIGtleWJvYXJkIHdhcyBwcmVzc2VkIHdpbGwgYmUgc2F2ZWQgYW5kIGNoZWNrZWQgYmVmb3JlIHJlZHJhdy5cclxuICAgICAgICAgIHZhciBzYXZlZEtleXByZXNzQ291bnRlciA9ICsra2V5cHJlc3NDb3VudGVyO1xyXG4gICAgICAgICAgdmFyIGlucHV0VGV4dCA9IGlucHV0LnZhbHVlO1xyXG4gICAgICAgICAgdmFyIGN1cnNvclBvcyA9IGlucHV0LnNlbGVjdGlvblN0YXJ0IHx8IDA7XHJcbiAgICAgICAgICBpZiAoaW5wdXRUZXh0Lmxlbmd0aCA+PSBtaW5MZW4gfHwgdHJpZ2dlciA9PT0gMSAvKiBGb2N1cyAqLykge1xyXG4gICAgICAgICAgICAgIGNsZWFyRGVib3VuY2VUaW1lcigpO1xyXG4gICAgICAgICAgICAgIGRlYm91bmNlVGltZXIgPSB3aW5kb3cuc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICAgIHNldHRpbmdzLmZldGNoKGlucHV0VGV4dCwgZnVuY3Rpb24gKGVsZW1lbnRzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICBpZiAoa2V5cHJlc3NDb3VudGVyID09PSBzYXZlZEtleXByZXNzQ291bnRlciAmJiBlbGVtZW50cykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW1zID0gZWxlbWVudHM7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgaW5wdXRWYWx1ZSA9IGlucHV0VGV4dDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZCA9IChpdGVtcy5sZW5ndGggPCAxIHx8IGRpc2FibGVBdXRvU2VsZWN0KSA/IHVuZGVmaW5lZCA6IGl0ZW1zWzBdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICB9LCB0cmlnZ2VyLCBjdXJzb3JQb3MpO1xyXG4gICAgICAgICAgICAgIH0sIHRyaWdnZXIgPT09IDAgLyogS2V5Ym9hcmQgKi8gPyBkZWJvdW5jZVdhaXRNcyA6IDApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgY2xlYXIoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBmdW5jdGlvbiBibHVyRXZlbnRIYW5kbGVyKCkge1xyXG4gICAgICAgICAgLy8gd2UgbmVlZCB0byBkZWxheSBjbGVhciwgYmVjYXVzZSB3aGVuIHdlIGNsaWNrIG9uIGFuIGl0ZW0sIGJsdXIgd2lsbCBiZSBjYWxsZWQgYmVmb3JlIGNsaWNrIGFuZCByZW1vdmUgaXRlbXMgZnJvbSBET01cclxuICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgIGlmIChkb2MuYWN0aXZlRWxlbWVudCAhPT0gaW5wdXQpIHtcclxuICAgICAgICAgICAgICAgICAgY2xlYXIoKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LCAyMDApO1xyXG4gICAgICB9XHJcbiAgICAgIC8qKlxyXG4gICAgICAgKiBGaXhlcyAjMjY6IG9uIGxvbmcgY2xpY2tzIGZvY3VzIHdpbGwgYmUgbG9zdCBhbmQgb25TZWxlY3QgbWV0aG9kIHdpbGwgbm90IGJlIGNhbGxlZFxyXG4gICAgICAgKi9cclxuICAgICAgY29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoXCJtb3VzZWRvd25cIiwgZnVuY3Rpb24gKGV2dCkge1xyXG4gICAgICAgICAgZXZ0LnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgZXZ0LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgIH0pO1xyXG4gICAgICAvKipcclxuICAgICAgICogRml4ZXMgIzMwOiBhdXRvY29tcGxldGUgY2xvc2VzIHdoZW4gc2Nyb2xsYmFyIGlzIGNsaWNrZWQgaW4gSUVcclxuICAgICAgICogU2VlOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvOTIxMDI2Ny8xMzE3MjM0OVxyXG4gICAgICAgKi9cclxuICAgICAgY29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoXCJmb2N1c1wiLCBmdW5jdGlvbiAoKSB7IHJldHVybiBpbnB1dC5mb2N1cygpOyB9KTtcclxuICAgICAgLyoqXHJcbiAgICAgICAqIFRoaXMgZnVuY3Rpb24gd2lsbCByZW1vdmUgRE9NIGVsZW1lbnRzIGFuZCBjbGVhciBldmVudCBoYW5kbGVyc1xyXG4gICAgICAgKi9cclxuICAgICAgZnVuY3Rpb24gZGVzdHJveSgpIHtcclxuICAgICAgICAgIGlucHV0LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJmb2N1c1wiLCBmb2N1c0V2ZW50SGFuZGxlcik7XHJcbiAgICAgICAgICBpbnB1dC5yZW1vdmVFdmVudExpc3RlbmVyKFwia2V5ZG93blwiLCBrZXlkb3duRXZlbnRIYW5kbGVyKTtcclxuICAgICAgICAgIGlucHV0LnJlbW92ZUV2ZW50TGlzdGVuZXIoa2V5VXBFdmVudE5hbWUsIGtleXVwRXZlbnRIYW5kbGVyKTtcclxuICAgICAgICAgIGlucHV0LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJibHVyXCIsIGJsdXJFdmVudEhhbmRsZXIpO1xyXG4gICAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJyZXNpemVcIiwgcmVzaXplRXZlbnRIYW5kbGVyKTtcclxuICAgICAgICAgIGRvYy5yZW1vdmVFdmVudExpc3RlbmVyKFwic2Nyb2xsXCIsIHNjcm9sbEV2ZW50SGFuZGxlciwgdHJ1ZSk7XHJcbiAgICAgICAgICBjbGVhckRlYm91bmNlVGltZXIoKTtcclxuICAgICAgICAgIGNsZWFyKCk7XHJcbiAgICAgIH1cclxuICAgICAgLy8gc2V0dXAgZXZlbnQgaGFuZGxlcnNcclxuICAgICAgaW5wdXQuYWRkRXZlbnRMaXN0ZW5lcihcImtleWRvd25cIiwga2V5ZG93bkV2ZW50SGFuZGxlcik7XHJcbiAgICAgIGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoa2V5VXBFdmVudE5hbWUsIGtleXVwRXZlbnRIYW5kbGVyKTtcclxuICAgICAgaW5wdXQuYWRkRXZlbnRMaXN0ZW5lcihcImJsdXJcIiwgYmx1ckV2ZW50SGFuZGxlcik7XHJcbiAgICAgIGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoXCJmb2N1c1wiLCBmb2N1c0V2ZW50SGFuZGxlcik7XHJcbiAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwicmVzaXplXCIsIHJlc2l6ZUV2ZW50SGFuZGxlcik7XHJcbiAgICAgIGRvYy5hZGRFdmVudExpc3RlbmVyKFwic2Nyb2xsXCIsIHNjcm9sbEV2ZW50SGFuZGxlciwgdHJ1ZSk7XHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICBkZXN0cm95OiBkZXN0cm95XHJcbiAgICAgIH07XHJcbiAgfVxuXG4gIHJldHVybiBhdXRvY29tcGxldGU7XG5cbn0pKSk7XG4vLyMgc291cmNlTWFwcGluZ1VSTD1hdXRvY29tcGxldGUuanMubWFwXG4iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7SUF1dG9jb21wbGV0ZUl0ZW19IGZyb20gXCIuLi9zZXR0aW5ncy9zZXR0aW5nX2VsZW1lbnRzL0F1dG9jb21wbGV0ZVwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi9tYWluXCI7XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZ2V0VmFyaWFibGVBdXRvY29tcGxldGVJdGVtcyhwbHVnaW46IFNDX1BsdWdpbikge1xyXG4gICAgaWYgKDAgPT09IGF1dG9jb21wbGV0ZV9pdGVtcy5sZW5ndGgpIHtcclxuICAgICAgICBwbHVnaW4uZ2V0VmFyaWFibGVzKCkuZm9yRWFjaCgodmFyaWFibGUpID0+IHtcclxuICAgICAgICAgICAgYXV0b2NvbXBsZXRlX2l0ZW1zLnB1c2goLi4udmFyaWFibGUuZ2V0QXV0b2NvbXBsZXRlSXRlbXMoKSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gYXV0b2NvbXBsZXRlX2l0ZW1zO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRWYXJpYWJsZUF1dG9jb21wbGV0ZUl0ZW1zKCkge1xyXG4gICAgd2hpbGUgKGF1dG9jb21wbGV0ZV9pdGVtcy5sZW5ndGgpIHtcclxuICAgICAgICBhdXRvY29tcGxldGVfaXRlbXMucG9wKCk7XHJcbiAgICB9XHJcbn1cclxuXHJcbmNvbnN0IGF1dG9jb21wbGV0ZV9pdGVtczogSUF1dG9jb21wbGV0ZUl0ZW1bXSA9IFtdOyIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IGF1dG9jb21wbGV0ZSBmcm9tIFwiYXV0b2NvbXBsZXRlclwiO1xyXG5pbXBvcnQge1xyXG4gICAgcGFyc2VZYW1sLFxyXG4gICAgc2V0SWNvbixcclxufSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi4vLi4vbWFpblwiO1xyXG5pbXBvcnQge0F1dG9jb21wbGV0ZVJlc3VsdH0gZnJvbSBcImF1dG9jb21wbGV0ZXIvYXV0b2NvbXBsZXRlXCI7XHJcbmltcG9ydCB7Z2V0VmFyaWFibGVBdXRvY29tcGxldGVJdGVtc30gZnJvbSBcIi4uLy4uL3ZhcmlhYmxlcy9nZXRWYXJpYWJsZUF1dG9jb21wbGV0ZUl0ZW1zXCI7XHJcbmltcG9ydCB7Z290b1VSTH0gZnJvbSBcIi4uLy4uL0NvbW1vblwiO1xyXG5cclxuLyoqXHJcbiAqXHJcbiAqIEBwYXJhbSBwbHVnaW4gVXNlZCBmb3IgZ2V0dGluZyBhIGxpc3Qgb2YgVmFyaWFibGUgYXV0b2NvbXBsZXRlIGl0ZW1zLlxyXG4gKiBAcGFyYW0gaW5wdXRfZWxlbWVudFxyXG4gKiBAcGFyYW0gY2FsbF9vbl9jb21wbGV0aW9uIEEgZnVuY3Rpb24gdGhhdCB3aWxsIGJlIGNhbGxlZCB3aGVuIGEgdXNlciBoYXMgc2VsZWN0ZWQgYSBzdWdnZXN0aW9uIGFuZCBwZXJmb3JtZWQgdGhlIGF1dG9jb21wbGV0ZSBhY3Rpb24uIG9uQ2hhbmdlIGV2ZW50IHdpbGwgbm90IGJlIGNhbGxlZCwgYmVjYXVzZSBpdCB3b3VsZCB0cmlnZ2VyIG9wZW5pbmcgdGhlIGF1dG9jb21wbGV0ZSBtZW51IGFnYWluLCBzbyB0aGF0J3Mgd2h5IGEgc2VwYXJhdGUgY2FsbGJhY2sgaXMgdXNlZC5cclxuICogQHBhcmFtIGV4dHJhX2F1dG9jb21wbGV0ZV9pdGVtc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUF1dG9jb21wbGV0ZShwbHVnaW46IFNDX1BsdWdpbiwgaW5wdXRfZWxlbWVudDogSFRNTElucHV0RWxlbWVudCB8IEhUTUxUZXh0QXJlYUVsZW1lbnQsIGNhbGxfb25fY29tcGxldGlvbjogKGZpZWxkX3ZhbHVlOiBzdHJpbmcpID0+IHZvaWQsIGV4dHJhX2F1dG9jb21wbGV0ZV9pdGVtczogSUF1dG9jb21wbGV0ZUl0ZW1bXSA9IFtdKSB7XHJcblxyXG4gICAgY29uc3QgYXV0b2NvbXBsZXRlTWVudTogQXV0b2NvbXBsZXRlUmVzdWx0ID0gIGF1dG9jb21wbGV0ZTxJQXV0b2NvbXBsZXRlSXRlbT4oe1xyXG4gICAgICAgIGlucHV0OiBpbnB1dF9lbGVtZW50LFxyXG4gICAgICAgIGZldGNoOiAoaW5wdXRfdmFsdWVfYnV0X25vdF91c2VkOiBzdHJpbmcsIHVwZGF0ZTogKGl0ZW1zOiBJQXV0b2NvbXBsZXRlSXRlbVtdKSA9PiB2b2lkKSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IGF1dG9jb21wbGV0ZV9pdGVtcyA9IG1lcmdlX2FuZF9zb3J0X2F1dG9jb21wbGV0ZV9pdGVtcyhnZXRWYXJpYWJsZUF1dG9jb21wbGV0ZUl0ZW1zKHBsdWdpbiksIEN1c3RvbUF1dG9jb21wbGV0ZUl0ZW1zLCBleHRyYV9hdXRvY29tcGxldGVfaXRlbXMpO1xyXG4gICAgICAgICAgICBjb25zdCBtYXhfc3VnZ2VzdGlvbnMgPSAzMDtcclxuXHJcbiAgICAgICAgICAgIC8vIEdldCB0aGUgc28gZmFyIHR5cGVkIHRleHQgLSBleGNsdWRlIGV2ZXJ5dGhpbmcgdGhhdCBpcyBvbiB0aGUgcmlnaHQgc2lkZSBvZiB0aGUgY2FyZXQuXHJcbiAgICAgICAgICAgIGNvbnN0IGNhcmV0X3Bvc2l0aW9uOiBudW1iZXIgfCBudWxsID0gaW5wdXRfZWxlbWVudC5zZWxlY3Rpb25TdGFydDtcclxuICAgICAgICAgICAgaWYgKG51bGwgPT09IGNhcmV0X3Bvc2l0aW9uKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjcmVhdGVBdXRvY29tcGxldGUoKTogZmV0Y2goKTogY2FyZXRfcG9zaXRpb24gaXMgbnVsbC5cIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgY29uc3QgdHlwZWRfdGV4dDogc3RyaW5nID0gaW5wdXRfZWxlbWVudC52YWx1ZS5zbGljZSgwLCBjYXJldF9wb3NpdGlvbik7XHJcbiAgICAgICAgICAgIGNvbnN0IHNlYXJjaF9xdWVyeSA9IGdldF9zZWFyY2hfcXVlcnkodHlwZWRfdGV4dCk7XHJcblxyXG4gICAgICAgICAgICBpZiAoXCJcIiA9PT0gc2VhcmNoX3F1ZXJ5LnNlYXJjaF90ZXh0KSB7XHJcbiAgICAgICAgICAgICAgICAvLyBObyBzdWdnZXN0aW9ucyBmb3IgZW1wdHkgd29yZC5cclxuICAgICAgICAgICAgICAgIHVwZGF0ZShbXSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGUgd29yZCBpcyBub3QgZW1wdHksIHNvIGNhbiBzdWdnZXN0IHNvbWV0aGluZy5cclxuICAgICAgICAgICAgICAgIGxldCBtYXRjaGVkX2l0ZW1zID0gYXV0b2NvbXBsZXRlX2l0ZW1zLmZpbHRlcihpdGVtID0+IGl0ZW1fbWF0Y2goaXRlbSwgc2VhcmNoX3F1ZXJ5KSk7XHJcbiAgICAgICAgICAgICAgICBzb3J0X2F1dG9jb21wbGV0ZV9pdGVtcyhtYXRjaGVkX2l0ZW1zLCBzZWFyY2hfcXVlcnkpO1xyXG4gICAgICAgICAgICAgICAgbWF0Y2hlZF9pdGVtcyA9IG1hdGNoZWRfaXRlbXMuc2xpY2UoMCwgbWF4X3N1Z2dlc3Rpb25zKTsgLy8gTGltaXQgdG8gYSByZWFzb25hYmxlIGFtb3VudCBvZiBzdWdnZXN0aW9ucy5cclxuICAgICAgICAgICAgICAgIHVwZGF0ZShtYXRjaGVkX2l0ZW1zKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgb25TZWxlY3Q6IChpdGVtKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIEEgdXNlciBoYXMgc2VsZWN0ZWQgYW4gaXRlbSB0byBiZSBhdXRvY29tcGxldGVkXHJcblxyXG4gICAgICAgICAgICAvLyBHZXQgdGhlIGl0ZW0gdGV4dCBhbmQgYWxyZWFkeSB0eXBlZCB0ZXh0XHJcbiAgICAgICAgICAgIGxldCBzdXBwbGVtZW50ID0gaXRlbS52YWx1ZTtcclxuICAgICAgICAgICAgbGV0IGNhcmV0X3Bvc2l0aW9uOiBudW1iZXIgfCBudWxsID0gaW5wdXRfZWxlbWVudC5zZWxlY3Rpb25TdGFydDtcclxuICAgICAgICAgICAgaWYgKG51bGwgPT09IGNhcmV0X3Bvc2l0aW9uKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjcmVhdGVBdXRvY29tcGxldGUoKTogZmV0Y2goKTogY2FyZXRfcG9zaXRpb24gaXMgbnVsbC5cIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgY29uc3QgdHlwZWRfdGV4dCA9IGlucHV0X2VsZW1lbnQudmFsdWUuc2xpY2UoMCwgY2FyZXRfcG9zaXRpb24pO1xyXG4gICAgICAgICAgICBjb25zdCBzZWFyY2hfcXVlcnkgPSBnZXRfc2VhcmNoX3F1ZXJ5KHR5cGVkX3RleHQpO1xyXG4gICAgICAgICAgICBjb25zdCBzZWFyY2hfdGV4dCA9IHNlYXJjaF9xdWVyeS5zZWFyY2hfdGV4dDtcclxuXHJcbiAgICAgICAgICAgIC8vIFNwZWNpYWwgY2FzZTogQ2hlY2sgaWYgfX0gaGFwcGVucyB0byBhcHBlYXIgYWZ0ZXIgdGhlIGNhcmV0XHJcbiAgICAgICAgICAgIGNvbnN0IGFmdGVyX2NhcmV0ID0gaW5wdXRfZWxlbWVudC52YWx1ZS5zbGljZShjYXJldF9wb3NpdGlvbiwgY2FyZXRfcG9zaXRpb24gKyAyKTtcclxuICAgICAgICAgICAgaWYgKFwifX1cIiA9PT0gYWZ0ZXJfY2FyZXQpIHtcclxuICAgICAgICAgICAgICAgIC8vIFRoZSByZXBsYWNpbmcgd2lsbCBoYXBwZW4gaW4gYSB7e3ZhcmlhYmxlfX0uXHJcbiAgICAgICAgICAgICAgICAvLyBEbyBub3QgYWNjaWRlbnRhbGx5IGluc2VydCBhbm90aGVyIH19IHBhaXIuXHJcbiAgICAgICAgICAgICAgICBzdXBwbGVtZW50ID0gc3VwcGxlbWVudC5yZXBsYWNlKC9cXH1cXH0kL3UsIFwiXCIpOyAvLyBPbmx5IHJlbW92ZXMgYSB0cmFpbGluZyB9fSBpZiB0aGVyZSBpcyBvbmUuXHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIFRyeSB0byBzYXZlIHBhcnQgb2YgdGhlIGJlZ2lubmluZywgaW4gY2FzZSBpdCBzZWVtcyBsaWtlIG5vdCBiZWluZyBwYXJ0IG9mIHRoZSBzZWFyY2ggcXVlcnkuXHJcbiAgICAgICAgICAgIGxldCByZXBsYWNlX3N0YXJ0ID0gZmluZF9zdGFydGluZ19wb3NpdGlvbihzZWFyY2hfdGV4dCwgc3VwcGxlbWVudCk7IC8vIFRoZSBsZW5ndGggZGlmZmVyZW5jZSBvZiB0eXBlZF90ZXh0IGFuZCBzZWFyY2hfdGV4dCB3aWxsIGJlIGFkZGVkIGhlcmUgYmVsb3cuXHJcbiAgICAgICAgICAgIGlmIChmYWxzZSA9PT0gcmVwbGFjZV9zdGFydCkge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhpcyBzaG91bGQgbmV2ZXIgaGFwcGVuLCBidXQgaWYgaXQgZG9lcywgZG8gbm90IHJlcGxhY2UgYW55dGhpbmcsIGp1c3QgaW5zZXJ0LlxyXG4gICAgICAgICAgICAgICAgcmVwbGFjZV9zdGFydCA9IGNhcmV0X3Bvc2l0aW9uO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgLy8gQWRqdXN0IHRoZSBwb3NpdGlvblxyXG4gICAgICAgICAgICAgICAgcmVwbGFjZV9zdGFydCArPSB0eXBlZF90ZXh0Lmxlbmd0aCAtIHNlYXJjaF90ZXh0Lmxlbmd0aDtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ2hvb3NlIGEgbWV0aG9kIGZvciBkb2luZyB0aGUgaW5zZXJ0aW5nXHJcbiAgICAgICAgICAgIGlmICh1bmRlZmluZWQgIT09IGRvY3VtZW50LmV4ZWNDb21tYW5kKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBleGVjQ29tbWFuZCgpIGlzIGRlcHJlY2F0ZWQsIGJ1dCBhdmFpbGFibGUuXHJcbiAgICAgICAgICAgICAgICAvLyBVc2UgaXQgdG8gZG8gdGhlIGluc2VydGlvbiwgYmVjYXVzZSB0aGlzIHdheSBhbiB1bmRvIGhpc3RvcnkgY2FuIGJlIHByZXNlcnZlZC5cclxuICAgICAgICAgICAgICAgIGlucHV0X2VsZW1lbnQuc2V0U2VsZWN0aW9uUmFuZ2UocmVwbGFjZV9zdGFydCwgY2FyZXRfcG9zaXRpb24pOyAvLyBGaXJzdCBzZWxlY3QgdGhlIHBhcnQgdGhhdCB3aWxsIGJlIHJlcGxhY2VkLCBiZWNhdXNlIGV4ZWNDb21tYW5kKCkgZG9lcyBub3Qgc3VwcG9ydCBkZWZpbmluZyBwb3NpdGlvbnMuIFRoaXMgYWRkcyBhIGN1bWJlcnNvbWUgc2VsZWN0aW9uIHN0ZXAgdG8gdGhlIHVuZG8gaGlzdG9yeSwgYnV0IGF0IGxlYXN0IHVuZG9pbmcgd29ya3MuXHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5leGVjQ29tbWFuZChcImluc2VydFRleHRcIiwgZmFsc2UsIHN1cHBsZW1lbnQpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgLy8gZXhlY0NvbW1hbmQoKSBpcyBub3QgYXZhaWxhYmxlIGFueW1vcmUuXHJcbiAgICAgICAgICAgICAgICAvLyBVc2Ugc2V0UmFuZ2VUZXh0KCkgdG8gZG8gdGhlIGluc2VydGlvbi4gSXQgd2lsbCBjbGVhciB1bmRvIGhpc3RvcnksIGJ1dCBhdCBsZWFzdCB0aGUgaW5zZXJ0aW9uIHdvcmtzLlxyXG4gICAgICAgICAgICAgICAgaW5wdXRfZWxlbWVudC5zZXRSYW5nZVRleHQoc3VwcGxlbWVudCwgcmVwbGFjZV9zdGFydCwgY2FyZXRfcG9zaXRpb24pO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBNb3ZlIHRoZSBjYXJldCB0byBhIGxvZ2ljYWwgY29udGludWF0aW9uIHBvaW50XHJcbiAgICAgICAgICAgIGNhcmV0X3Bvc2l0aW9uID0gcmVwbGFjZV9zdGFydCArIHN1cHBsZW1lbnQubGVuZ3RoO1xyXG4gICAgICAgICAgICBpZiAoc3VwcGxlbWVudC5tYXRjaCgvOlxcfVxcfSQvdSkpIHtcclxuICAgICAgICAgICAgICAgIC8vIFBsYWNlIHRoZSBjYXJldCBhZnRlciB0aGUgY29sb24sIGluc3RlYWQgb2YgYWZ0ZXIgfX0uXHJcbiAgICAgICAgICAgICAgICBjYXJldF9wb3NpdGlvbiAtPSAyO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGlucHV0X2VsZW1lbnQuc2V0U2VsZWN0aW9uUmFuZ2UoY2FyZXRfcG9zaXRpb24sIGNhcmV0X3Bvc2l0aW9uKTtcclxuXHJcbiAgICAgICAgICAgIC8vIENhbGwgYSBob29rXHJcbiAgICAgICAgICAgIGNhbGxfb25fY29tcGxldGlvbihpbnB1dF9lbGVtZW50LnZhbHVlKTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIHJlbmRlcjogKGl0ZW0pID0+IHtcclxuICAgICAgICAgICAgY29uc3QgZGl2X2VsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xyXG4gICAgICAgICAgICBkaXZfZWxlbWVudC5jcmVhdGVTcGFuKHt0ZXh0OiBpdGVtLnZhbHVlLCBhdHRyOiB7Y2xhc3M6IFwiU0MtYXV0b2NvbXBsZXRlLXZhbHVlXCJ9fSk7XHJcbiAgICAgICAgICAgIGlmIChpdGVtLmhlbHBfdGV4dCkge1xyXG4gICAgICAgICAgICAgICAgZGl2X2VsZW1lbnQuY3JlYXRlU3Bhbih7dGV4dDogXCI6IFwiLCBhdHRyOiB7Y2xhc3M6IFwiU0MtYXV0b2NvbXBsZXRlLXNlcGFyYXRvclwifX0pO1xyXG4gICAgICAgICAgICAgICAgZGl2X2VsZW1lbnQuY3JlYXRlU3Bhbih7YXR0cjoge2NsYXNzOiBcIlNDLWF1dG9jb21wbGV0ZS1oZWxwLXRleHRcIn19KS5pbnNlcnRBZGphY2VudEhUTUwoXCJiZWZvcmVlbmRcIiwgaXRlbS5oZWxwX3RleHQpO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBEb2N1bWVudGF0aW9uIGxpbmtcclxuICAgICAgICAgICAgY29uc3QgZG9jdW1lbnRhdGlvbkxpbms6IHN0cmluZyB8IHVuZGVmaW5lZCA9IGl0ZW0uZG9jdW1lbnRhdGlvbkxpbms7XHJcbiAgICAgICAgICAgIGlmICh1bmRlZmluZWQgIT09IGRvY3VtZW50YXRpb25MaW5rKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBkb2N1bWVudGF0aW9uTGlua0VsZW1lbnQgPSBkaXZfZWxlbWVudC5jcmVhdGVFbChcImFcIiwge2F0dHI6IHtcInRpdGxlXCI6IFwiRG9jdW1lbnRhdGlvbjogXCIgKyBpdGVtLnZhbHVlfX0pOyAvLyBVc2UgXCJ0aXRsZVwiIGluc3RlYWQgb2YgXCJhcmlhLWxhYmVsXCIsIGJlY2F1c2UgSSBkb24ndCBrbm93IGhvdyB0byBtYWtlIFwiYXJpYS1sYWJlbFwiIHNob3cgYSB0b29sdGlwIGJveCBvbiBhIGN1c3RvbSBlbGVtZW50LlxyXG4gICAgICAgICAgICAgICAgc2V0SWNvbihkb2N1bWVudGF0aW9uTGlua0VsZW1lbnQsIFwiaGVscFwiKTtcclxuICAgICAgICAgICAgICAgIGRvY3VtZW50YXRpb25MaW5rRWxlbWVudC5hZGRDbGFzcyhcIlNDLWF1dG9jb21wbGV0ZS1saW5rLWljb25cIik7XHJcbiAgICAgICAgICAgICAgICBkb2N1bWVudGF0aW9uTGlua0VsZW1lbnQub25DbGlja0V2ZW50KChldmVudCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIGdvdG9VUkwoZG9jdW1lbnRhdGlvbkxpbmspO1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IE5vdCBuZWVkZWQsIEkgZ3Vlc3MuXHJcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7IC8vIERvIG5vdCBjbG9zZSB0aGUgYXV0b2NvbXBsZXRlIG1lbnUuXHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgcmV0dXJuIGRpdl9lbGVtZW50O1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgbWluTGVuZ3RoOiAyLCAvLyBNaW5pbXVtIGxlbmd0aCB3aGVuIGF1dG9jb21wbGV0ZSBtZW51IHNob3VsZCBwb3AgdXAuXHJcbiAgICAgICAgY2xhc3NOYW1lOiBcIlNDLWF1dG9jb21wbGV0ZVwiLCAvLyBUaGUgY29tcG9uZW50IGFsd2F5cyBoYXMgYSBjbGFzcyAnYXV0b2NvbXBsZXRlJywgYnV0IGFkZCAnU0MtYXV0b2NvbXBsZXRlJyBzbyB0aGF0IFNDJ3MgQ1NTIGNhbiB0YXJnZXQgJ1NDLWF1dG9jb21wbGV0ZScsIHNvIGl0IHdpbGwgbm90IG1lc3MgdXAgc3R1ZmYgaWYgT2JzaWRpYW4gaGFwcGVucyB0byBoYXZlIGFuIGVsZW1lbnQgd2l0aCBjbGFzcyAnYXV0b2NvbXBsZXRlJy5cclxuICAgICAgICBrZXlzVG9JZ25vcmU6IFsgMzggLyogVXAgKi8sIDEzIC8qIEVudGVyICovLCAyNyAvKiBFc2MgKi8sIDE2IC8qIFNoaWZ0ICovLCAxNyAvKiBDdHJsICovLCAxOCAvKiBBbHQgKi8sIDIwIC8qIENhcHNMb2NrICovLCA5MSAvKiBXaW5kb3dzS2V5ICovLCA5IC8qIFRhYiAqLyBdLCAvLyBEZWZpbmVkIGp1c3QgdG8gcHJldmVudCBpZ25vcmluZyBsZWZ0IGFuZCByaWdodCBrZXlzLlxyXG4gICAgICAgIHByZXZlbnRTdWJtaXQ6IHRydWUsIC8vIFByZXZlbnRzIGNyZWF0aW5nIG5ld2xpbmVzIGluIHRleHRhcmVhcyB3aGVuIGVudGVyIGlzIHByZXNzZWQgaW4gdGhlIGF1dG9jb21wbGV0ZSBtZW51LlxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gTWFrZSB0aGUgcGx1Z2luIGFibGUgdG8gY2xvc2UgdGhlIG1lbnUgaWYgdGhlIHBsdWdpbiBpcyBkaXNhYmxlZCAob3IgcmVzdGFydGVkKS5cclxuICAgIHBsdWdpbi5yZWdpc3RlckF1dG9jb21wbGV0ZU1lbnUoYXV0b2NvbXBsZXRlTWVudSk7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgSUF1dG9jb21wbGV0ZUl0ZW0ge1xyXG4gICAgaGVscF90ZXh0OiBzdHJpbmc7XHJcbiAgICB2YWx1ZTogc3RyaW5nO1xyXG4gICAgZ3JvdXA6IHN0cmluZztcclxuICAgIHR5cGU6IEF1dG9jb21wbGV0ZVNlYXJjaFF1ZXJ5VHlwZTtcclxuICAgIGRvY3VtZW50YXRpb25MaW5rPzogc3RyaW5nO1xyXG59XHJcblxyXG5mdW5jdGlvbiBpdGVtX21hdGNoKGl0ZW06IElBdXRvY29tcGxldGVJdGVtLCBzZWFyY2hfcXVlcnk6IElBdXRvY29tcGxldGVTZWFyY2hRdWVyeSk6IGJvb2xlYW4ge1xyXG4gICAgY29uc3QgaXRlbV92YWx1ZSA9IGl0ZW0udmFsdWUudG9Mb2NhbGVMb3dlckNhc2UoKTtcclxuICAgIGNvbnN0IHNlYXJjaF90ZXh0ID0gc2VhcmNoX3F1ZXJ5LnNlYXJjaF90ZXh0LnRvTG9jYWxlTG93ZXJDYXNlKCk7XHJcblxyXG4gICAgLy8gTWF0Y2ggcXVlcnkgdHlwZVxyXG4gICAgaWYgKGl0ZW0udHlwZSAhPT0gc2VhcmNoX3F1ZXJ5LnNlYXJjaF90eXBlKSB7XHJcbiAgICAgICAgLy8gSWYgdGhlIHF1ZXJ5IHR5cGUgaXMgZGlmZmVyZW50LCBkbyBub3QgaW5jbHVkZSB0aGlzIGl0ZW0uXHJcbiAgICAgICAgLy8gVGhpcyBjYW4gaGFwcGVuIGUuZy4gaWYge3sgaXMgdHlwZWQsIGFuZCB0aGUgaXRlbSBpcyBub3QgYSB2YXJpYWJsZSwgb3Ige3shIGlzIHR5cGVkLCBhbmQgdGhlIGl0ZW0gaXMgbm90IGFuIHVuZXNjYXBlZCB2YXJpYWJsZS5cclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTWF0Y2ggdGV4dFxyXG4gICAgbGV0IHNlYXJjaF9jaGFyYWN0ZXI6IHN0cmluZztcclxuICAgIGxldCBzZWFyY2hfcG9zaXRpb24gPSAwO1xyXG4gICAgZm9yIChsZXQgc2VhcmNoX2NoYXJhY3Rlcl9pbmRleCA9IDA7IHNlYXJjaF9jaGFyYWN0ZXJfaW5kZXggPCBzZWFyY2hfdGV4dC5sZW5ndGg7IHNlYXJjaF9jaGFyYWN0ZXJfaW5kZXgrKykge1xyXG4gICAgICAgIHNlYXJjaF9jaGFyYWN0ZXIgPSBzZWFyY2hfdGV4dFtzZWFyY2hfY2hhcmFjdGVyX2luZGV4XTtcclxuICAgICAgICBpZiAoaXRlbV92YWx1ZS5pbmNsdWRlcyhzZWFyY2hfY2hhcmFjdGVyLCBzZWFyY2hfcG9zaXRpb24pKSB7XHJcbiAgICAgICAgICAgIC8vIFRoaXMgY2hhcmFjdGVyIHdhcyBmb3VuZCBpbiBpdGVtX3ZhbHVlLlxyXG4gICAgICAgICAgICBzZWFyY2hfcG9zaXRpb24gPSBpdGVtX3ZhbHVlLmluZGV4T2Yoc2VhcmNoX2NoYXJhY3Rlciwgc2VhcmNoX3Bvc2l0aW9uKSArIDE7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gVGhpcyBjaGFyYWN0ZXIgd2FzIG5vdCBmb3VuZC5cclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiB0cnVlO1xyXG59XHJcblxyXG5mdW5jdGlvbiBmaW5kX3N0YXJ0aW5nX3Bvc2l0aW9uKHR5cGVkX3RleHQ6IHN0cmluZywgc3VwcGxlbWVudDogc3RyaW5nKSB7XHJcbiAgICB0eXBlZF90ZXh0ID0gdHlwZWRfdGV4dC50b0xvY2FsZUxvd2VyQ2FzZSgpO1xyXG4gICAgc3VwcGxlbWVudCA9IHN1cHBsZW1lbnQudG9Mb2NhbGVMb3dlckNhc2UoKTtcclxuICAgIGZvciAobGV0IHN1cHBsZW1lbnRfaW5kZXggPSBzdXBwbGVtZW50Lmxlbmd0aDsgc3VwcGxlbWVudF9pbmRleCA+PSAwOyBzdXBwbGVtZW50X2luZGV4LS0pIHtcclxuICAgICAgICBjb25zdCBwYXJ0aWFsX3N1cHBsZW1lbnQgPSBzdXBwbGVtZW50LnNsaWNlKDAsIHN1cHBsZW1lbnRfaW5kZXgpO1xyXG4gICAgICAgIGlmICh0eXBlZF90ZXh0LmNvbnRhaW5zKHBhcnRpYWxfc3VwcGxlbWVudCkpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHR5cGVkX3RleHQuaW5kZXhPZihwYXJ0aWFsX3N1cHBsZW1lbnQpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBmYWxzZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNvcnRzIGluIHBsYWNlLCBkb2VzIG5vdCBtYWtlIGEgY29weS5cclxuICogQHBhcmFtIGF1dG9jb21wbGV0ZV9pdGVtc1xyXG4gKiBAcGFyYW0gc2VhcmNoX3F1ZXJ5XHJcbiAqL1xyXG5mdW5jdGlvbiBzb3J0X2F1dG9jb21wbGV0ZV9pdGVtcyhhdXRvY29tcGxldGVfaXRlbXM6IElBdXRvY29tcGxldGVJdGVtW10sIHNlYXJjaF9xdWVyeTogSUF1dG9jb21wbGV0ZVNlYXJjaFF1ZXJ5KTogdm9pZCB7XHJcblxyXG4gICAgY29uc3Qgc2VhcmNoX3RleHRfZXhjbHVkaW5nX2N1cmx5X2JyYWNrZXRzID0gc2VhcmNoX3F1ZXJ5LnNlYXJjaF90ZXh0LnJlcGxhY2UoL157eyE/LywgXCJcIik7XHJcblxyXG4gICAgZnVuY3Rpb24gZ2V0X2NvbW1vbl9iZWdpbm5pbmdfbGVuZ3RoKGF1dG9jb21wbGV0ZV9pdGVtOiBJQXV0b2NvbXBsZXRlSXRlbSwgc2VhcmNoX3F1ZXJ5OiBJQXV0b2NvbXBsZXRlU2VhcmNoUXVlcnkpIHtcclxuICAgICAgICBjb25zdCBzZWFyY2hfdGV4dCA9IHNlYXJjaF9xdWVyeS5zZWFyY2hfdGV4dC50b0xvY2FsZUxvd2VyQ2FzZSgpO1xyXG4gICAgICAgIGNvbnN0IGl0ZW1fdmFsdWUgPSBhdXRvY29tcGxldGVfaXRlbS52YWx1ZS50b0xvY2FsZUxvd2VyQ2FzZSgpO1xyXG4gICAgICAgIGNvbnN0IHNob3J0ZXN0X2xlbmd0aCA9IE1hdGgubWluKHNlYXJjaF90ZXh0Lmxlbmd0aCwgaXRlbV92YWx1ZS5sZW5ndGgpO1xyXG4gICAgICAgIGZvciAobGV0IGNoYXJhY3Rlcl9pbmRleCA9IDA7IGNoYXJhY3Rlcl9pbmRleCA8IHNob3J0ZXN0X2xlbmd0aDsgY2hhcmFjdGVyX2luZGV4KyspIHtcclxuICAgICAgICAgICAgY29uc3Qgc2VhcmNoX2NoYXJhY3RlciA9IHNlYXJjaF90ZXh0W2NoYXJhY3Rlcl9pbmRleF07XHJcbiAgICAgICAgICAgIGNvbnN0IGl0ZW1fY2hhcmFjdGVyID0gaXRlbV92YWx1ZVtjaGFyYWN0ZXJfaW5kZXhdO1xyXG4gICAgICAgICAgICBpZiAoc2VhcmNoX2NoYXJhY3RlciAhPT0gaXRlbV9jaGFyYWN0ZXIpIHtcclxuICAgICAgICAgICAgICAgIC8vIFRoZSBjb21tb24gYmVnaW5uaW5nIGhhcyBlbmRlZC5cclxuICAgICAgICAgICAgICAgIHJldHVybiBjaGFyYWN0ZXJfaW5kZXg7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHNob3J0ZXN0X2xlbmd0aDtcclxuICAgIH1cclxuXHJcbiAgICBhdXRvY29tcGxldGVfaXRlbXMuc29ydCgoYTogSUF1dG9jb21wbGV0ZUl0ZW0sIGI6IElBdXRvY29tcGxldGVJdGVtKSA9PiB7XHJcbiAgICAgICAgY29uc3QgYm9vc3RfYSA9IE1hdGgubWF4KGdldF9jb21tb25fYmVnaW5uaW5nX2xlbmd0aChhLCBzZWFyY2hfcXVlcnkpLCAxKTsgLy8gQm9vc3RzIGFyZSB1c2VkIGFzIG11bHRpcGxpZXJzLFxyXG4gICAgICAgIGNvbnN0IGJvb3N0X2IgPSBNYXRoLm1heChnZXRfY29tbW9uX2JlZ2lubmluZ19sZW5ndGgoYiwgc2VhcmNoX3F1ZXJ5KSwgMSk7IC8vIHNvIHRoZXkgY2Fubm90IGJlIHplcm8uXHJcbiAgICAgICAgY29uc3QgYV9sZW5ndGggPSBhLnZhbHVlLmxlbmd0aCAqIGJvb3N0X2I7IC8vIGJvb3N0X2Igd29yc2VucyBBICg9IG1ha2VzIGl0IGFydGlmaWNpYWxseSBcImxvbmdlclwiKVxyXG4gICAgICAgIGNvbnN0IGJfbGVuZ3RoID0gYi52YWx1ZS5sZW5ndGggKiBib29zdF9hOyAvLyBib29zdF9hIHdvcnNlbnMgQlxyXG4gICAgICAgIC8vIERldGVybWluZSBzb3J0aW5nIG1ldGhvZC4gSWYgdGhlIHNlYXJjaCBxdWVyeSBpcyBqdXN0IGEgY291cGxlIG9mIGNoYXJhY3RlcnMsIHRoZSBtYXRjaGVzIHdvdWxkIGJlIHF1aXRlIHZhZ3VlLCBzb3J0aW5nIGJ5IHRoZSBtYXRjaGVkIGl0ZW1zJyBsZW5ndGggd291bGQgbm90IHRlbGwgbXVjaCwgYW5kIHRoZSBsaXN0IHdvdWxkIGp1c3QgbG9vayBzdHJhbmdlbHkgb3JkZXJlZC5cclxuICAgICAgICBpZiAoc2VhcmNoX3RleHRfZXhjbHVkaW5nX2N1cmx5X2JyYWNrZXRzLmxlbmd0aCA8IDIgfHwgYV9sZW5ndGggPT09IGJfbGVuZ3RoKSB7XHJcbiAgICAgICAgICAgIC8vIFNvcnQgYWxwaGFiZXRpY2FsbHkuXHJcbiAgICAgICAgICAgIHJldHVybiBhLnZhbHVlID4gYi52YWx1ZSA/IDEgOiAtMTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBTb3J0IGJ5IGxlbmd0aHMuIFRoZSBzaG9ydGVzdCBpdGVtIGlzIHByZWZlcnJlZC4gSWYgYW4gaXRlbSBoYXMgYSBsb25nIGNvbW1vbiBiZWdpbm5pbmcgd2l0aCB0aGUgc2VhcmNoIHF1ZXJ5LCBib29zdCB0aGUgaXRlbSB1cC5cclxuICAgICAgICAgICAgcmV0dXJuIGFfbGVuZ3RoIC0gYl9sZW5ndGg7XHJcbiAgICAgICAgfVxyXG4gICAgfSk7XHJcbn1cclxuXHJcblxyXG5jb25zdCBDdXN0b21BdXRvY29tcGxldGVJdGVtczogSUF1dG9jb21wbGV0ZUl0ZW1bXSA9IFtdO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGFkZEN1c3RvbUF1dG9jb21wbGV0ZUl0ZW1zKGN1c3RvbV9hdXRvY29tcGxldGVfeWFtbDogc3RyaW5nKSB7XHJcblxyXG4gICAgLy8gRW5zdXJlIHRoZSBjb250ZW50IGlzIG5vdCBlbXB0eVxyXG4gICAgaWYgKDAgPT09IGN1c3RvbV9hdXRvY29tcGxldGVfeWFtbC50cmltKCkubGVuZ3RoKSB7XHJcbiAgICAgICAgcmV0dXJuIFwiVGhlIGNvbnRlbnQgaXMgZW1wdHkuXCI7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVHJ5IHRvIHBhcnNlIFlBTUwgc3ludGF4XHJcblx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnlcclxuICAgIGxldCB5YW1sOiBhbnk7IC8vICdhbnknIGlzIGRlZmluZWQgaW4gb2JzaWRpYW4uZC50cyBmb3IgdGhlIHJldHVybiB0eXBlIG9mIHBhcnNlWWFtbCgpLCBzbyBJIG1hZGUgRVNMaW50IGlnbm9yZSBpdC5cclxuICAgIHRyeSB7XHJcbiAgICAgICAgeWFtbCA9IHBhcnNlWWFtbChjdXN0b21fYXV0b2NvbXBsZXRlX3lhbWwpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAvLyBBIHN5bnRheCBlcnJvciBoYXMgYXBwZWFyZWQuXHJcbiAgICAgICAgcmV0dXJuIGVycm9yLm1lc3NhZ2U7XHJcbiAgICB9XHJcbiAgICBpZiAobnVsbCA9PT0geWFtbCB8fCB0eXBlb2YgeWFtbCAhPT0gXCJvYmplY3RcIikge1xyXG4gICAgICAgIHJldHVybiBcIlVuYWJsZSB0byBwYXJzZSB0aGUgY29udGVudCBkdWUgdG8gdW5rbm93biByZWFzb24uXCI7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSXRlcmF0ZSBhdXRvY29tcGxldGUgaXRlbSBncm91cHNcclxuICAgIGNvbnN0IGdyb3VwX25hbWVzID0gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoeWFtbCk7XHJcbiAgICBjb25zdCBlcnJvcl9tZXNzYWdlczogc3RyaW5nW10gPSBbXTtcclxuICAgIGdyb3VwX25hbWVzLmZvckVhY2goKGdyb3VwX25hbWU6IHN0cmluZykgPT4ge1xyXG4gICAgICAgIGNvbnN0IGdyb3VwX2l0ZW1zID0geWFtbFtncm91cF9uYW1lXTtcclxuICAgICAgICBjb25zdCBncm91cF9pdGVtX3ZhbHVlcyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGdyb3VwX2l0ZW1zKTtcclxuXHJcbiAgICAgICAgLy8gSXRlcmF0ZSBhbGwgYXV0b2NvbXBsZXRlIGl0ZW1zIGluIHRoZSBncm91cFxyXG4gICAgICAgIGdyb3VwX2l0ZW1fdmFsdWVzLmZvckVhY2goKGF1dG9jb21wbGV0ZV9pdGVtX3ZhbHVlOiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgY29uc3QgYXV0b2NvbXBsZXRlX2l0ZW1fbGFiZWwgPSBncm91cF9pdGVtc1thdXRvY29tcGxldGVfaXRlbV92YWx1ZV07XHJcbiAgICAgICAgICAgIGlmICh0eXBlb2YgYXV0b2NvbXBsZXRlX2l0ZW1fbGFiZWwgIT09IFwic3RyaW5nXCIpIHtcclxuICAgICAgICAgICAgICAgIGVycm9yX21lc3NhZ2VzLnB1c2goXCJBdXRvY29tcGxldGUgaXRlbSAnXCIgKyBhdXRvY29tcGxldGVfaXRlbV92YWx1ZSArIFwiJyBoYXMgYW4gaW5jb3JyZWN0IGhlbHAgdGV4dCB0eXBlOiBcIiArIGF1dG9jb21wbGV0ZV9pdGVtX2xhYmVsICsgXCIgaXMgYSBcIiArIHR5cGVvZiBhdXRvY29tcGxldGVfaXRlbV9sYWJlbCArIFwiLCBidXQgaXQgc2hvdWxkIGJlIGEgc3RyaW5nLlwiKTtcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIGEgY29ycmVjdCB0eXBlIGZvciB0aGUgaXRlbVxyXG4gICAgICAgICAgICBsZXQgdHlwZTogQXV0b2NvbXBsZXRlU2VhcmNoUXVlcnlUeXBlID0gXCJvdGhlclwiO1xyXG4gICAgICAgICAgICBpZiAoYXV0b2NvbXBsZXRlX2l0ZW1fdmFsdWUuc3RhcnRzV2l0aChcInt7XCIpKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIGEgdmFyaWFibGVcclxuICAgICAgICAgICAgICAgIHR5cGUgPSBcIm5vcm1hbC12YXJpYWJsZVwiO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBUaGUgaXRlbSBpcyBvaywgYWRkIGl0IHRvIHRoZSBsaXN0XHJcbiAgICAgICAgICAgIEN1c3RvbUF1dG9jb21wbGV0ZUl0ZW1zLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IGF1dG9jb21wbGV0ZV9pdGVtX3ZhbHVlLFxyXG4gICAgICAgICAgICAgICAgaGVscF90ZXh0OiBhdXRvY29tcGxldGVfaXRlbV9sYWJlbCxcclxuICAgICAgICAgICAgICAgIGdyb3VwOiBncm91cF9uYW1lLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogdHlwZSxcclxuICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICBpZiAodHlwZSA9PT0gXCJub3JtYWwtdmFyaWFibGVcIikge1xyXG4gICAgICAgICAgICAgICAgLy8gQWRkIGFuIHVuZXNjYXBlZCB2ZXJzaW9uIG9mIHRoZSB2YXJpYWJsZSwgdG9vXHJcbiAgICAgICAgICAgICAgICBDdXN0b21BdXRvY29tcGxldGVJdGVtcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogYXV0b2NvbXBsZXRlX2l0ZW1fdmFsdWUucmVwbGFjZSgvXlxce1xcey91LCBcInt7IVwiKSwgLy8gQWRkIGFuIGV4Y2xhbWF0aW9uIG1hcmsgdG8gdGhlIHZhcmlhYmxlIG5hbWUuXHJcbiAgICAgICAgICAgICAgICAgICAgaGVscF90ZXh0OiBhdXRvY29tcGxldGVfaXRlbV9sYWJlbCxcclxuICAgICAgICAgICAgICAgICAgICBncm91cDogZ3JvdXBfbmFtZSxcclxuICAgICAgICAgICAgICAgICAgICB0eXBlOiBcInVuZXNjYXBlZC12YXJpYWJsZVwiLFxyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgIH0pO1xyXG4gICAgaWYgKGVycm9yX21lc3NhZ2VzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAvLyBTb21ldGhpbmcgZmFpbGVkXHJcbiAgICAgICAgcmV0dXJuIGVycm9yX21lc3NhZ2VzLmpvaW4oXCI7IFwiKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBbGwgb2tcclxuICAgIHJldHVybiB0cnVlO1xyXG59XHJcblxyXG4vKipcclxuICogVE9ETzogQ2FuIHRoZSBzb3J0aW5nIGJlIHJlbW92ZWQgZnJvbSBoZXJlPyBOb3cgYXV0b2NvbXBsZXRlIGl0ZW1zIGFyZSBzb3J0ZWQgYWdhaW4gZXZlcnkgdGltZSB3aGVuIGZpbHRlcmluZywgYmFzZWQgb24gdGhlIGtleXdvcmQgKGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL29ic2lkaWFuLXNoZWxsY29tbWFuZHMvaXNzdWVzLzI0OSkuXHJcbiAqIEBwYXJhbSBhdXRvY29tcGxldGVfaXRlbV9zZXRzXHJcbiAqL1xyXG5mdW5jdGlvbiBtZXJnZV9hbmRfc29ydF9hdXRvY29tcGxldGVfaXRlbXMoLi4uYXV0b2NvbXBsZXRlX2l0ZW1fc2V0czogSUF1dG9jb21wbGV0ZUl0ZW1bXVtdKSB7XHJcbiAgICBjb25zdCBtZXJnZWRfYXV0b2NvbXBsZXRlX2l0ZW1zOiBJQXV0b2NvbXBsZXRlSXRlbVtdID0gKG5ldyBBcnJheTxJQXV0b2NvbXBsZXRlSXRlbT4oKSkuY29uY2F0KC4uLmF1dG9jb21wbGV0ZV9pdGVtX3NldHMpO1xyXG4gICAgcmV0dXJuIG1lcmdlZF9hdXRvY29tcGxldGVfaXRlbXMuc29ydCgoYSwgYikgPT4ge1xyXG4gICAgICAgIC8vIEZpcnN0IGNvbXBhcmUgZ3JvdXBzXHJcbiAgICAgICAgaWYgKGEuZ3JvdXAgPCBiLmdyb3VwKSB7XHJcbiAgICAgICAgICAgIC8vIGEncyBncm91cCBzaG91bGQgY29tZSBiZWZvcmUgYidzIGdyb3VwLlxyXG4gICAgICAgICAgICByZXR1cm4gLTE7XHJcbiAgICAgICAgfSBlbHNlIGlmIChhLmdyb3VwID4gYi5ncm91cCkge1xyXG4gICAgICAgICAgICAvLyBhJ3MgZ3JvdXAgc2hvdWxkIGNvbWUgYWZ0ZXIgYidzIGdyb3VwLlxyXG4gICAgICAgICAgICByZXR1cm4gMTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBUaGUgZ3JvdXBzIGFyZSB0aGUgc2FtZS5cclxuICAgICAgICAgICAgLy8gQ29tcGFyZSB2YWx1ZXMuXHJcbiAgICAgICAgICAgIGlmIChhLnZhbHVlIDwgYi52YWx1ZSkge1xyXG4gICAgICAgICAgICAgICAgLy8gYSBzaG91bGQgY29tZSBiZWZvcmUgYi5cclxuICAgICAgICAgICAgICAgIHJldHVybiAtMTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhLnZhbHVlID4gYi52YWx1ZSkge1xyXG4gICAgICAgICAgICAgICAgLy8gYSBzaG91bGQgY29tZSBhZnRlciBiLlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIDE7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGUgdmFsdWVzIGFyZSB0aGUgc2FtZS5cclxuICAgICAgICAgICAgICAgIC8vIFRoZSBvcmRlciBkb2VzIG5vdCBtYXR0ZXIuXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gMDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH0pO1xyXG59XHJcblxyXG50eXBlIEF1dG9jb21wbGV0ZVNlYXJjaFF1ZXJ5VHlwZSA9IFwib3RoZXJcIiB8IFwibm9ybWFsLXZhcmlhYmxlXCIgfCBcInVuZXNjYXBlZC12YXJpYWJsZVwiO1xyXG5pbnRlcmZhY2UgSUF1dG9jb21wbGV0ZVNlYXJjaFF1ZXJ5IHtcclxuICAgIHNlYXJjaF90ZXh0OiBzdHJpbmc7XHJcbiAgICBzZWFyY2hfdHlwZTogQXV0b2NvbXBsZXRlU2VhcmNoUXVlcnlUeXBlO1xyXG59XHJcblxyXG4vKipcclxuICogUmVkdWNlcyBhbiBpbnB1dCBzdHJpbmcgdG8gdGhlIG5lYXJlc3QgbG9naWNhbCB3b3JkLlxyXG4gKiBAcGFyYW0gdHlwZWRfdGV4dFxyXG4gKi9cclxuZnVuY3Rpb24gZ2V0X3NlYXJjaF9xdWVyeSh0eXBlZF90ZXh0OiBzdHJpbmcpOiBJQXV0b2NvbXBsZXRlU2VhcmNoUXVlcnkge1xyXG4gICAgY29uc3Qgc2VhcmNoVGV4dE1hdGNoQXJyYXk6IFJlZ0V4cE1hdGNoQXJyYXkgfCBudWxsID0gdHlwZWRfdGV4dC5tYXRjaCgvXFxTKj8kL3UpOyAvLyBBbiBhcnJheSwgYnV0IG9ubHkgb25lIG1hdGNoIGlzIGV4cGVjdGVkLlxyXG4gICAgaWYgKG51bGwgPT09IHNlYXJjaFRleHRNYXRjaEFycmF5KSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiZ2V0X3NlYXJjaF9xdWVyeSgpOiBSZWdleCBtYXRjaCBmYWlsZWQuXCIpO1xyXG4gICAgfVxyXG4gICAgbGV0IHNlYXJjaF90ZXh0ID0gc2VhcmNoVGV4dE1hdGNoQXJyYXlbMF07IC8vIFJlZHVjZSB0aGUgdGV4dCAtIGxpbWl0IHRvIGEgc2luZ2xlIHdvcmQgKD0gZXhjbHVkZSBzcGFjZXMgYW5kIGV2ZXJ5dGhpbmcgYmVmb3JlIHRoZW0pLlxyXG4gICAgbGV0IHNlYXJjaF90eXBlOiBBdXRvY29tcGxldGVTZWFyY2hRdWVyeVR5cGUgPSBcIm90aGVyXCI7IC8vIE1heSBiZSBvdmVyd3JpdHRlbi5cclxuXHJcbiAgICBpZiAoc2VhcmNoX3RleHQuY29udGFpbnMoXCJ9fVwiKSkge1xyXG4gICAgICAgIC8vIFRoZSBxdWVyeSBoYXBwZW5zIHJpZ2h0IGFmdGVyIGEge3t2YXJpYWJsZX19LlxyXG4gICAgICAgIC8vIE1ha2UgdGhlIHF1ZXJ5IHN0cmluZyB0byBzdGFydCBhZnRlciB0aGUgfX0gcGFpciwgaS5lLiByZW1vdmUgfX0gYW5kIGV2ZXJ5dGhpbmcgYmVmb3JlIGl0LiBUaGlzIGltcHJvdmVzIHRoZSBzZWFyY2guXHJcbiAgICAgICAgc2VhcmNoX3RleHQgPSBzZWFyY2hfdGV4dC5yZXBsYWNlKC8uK1xcfVxcfS91LCBcIlwiKTtcclxuICAgIH1cclxuICAgIGlmIChzZWFyY2hfdGV4dC5jb250YWlucyhcInt7XCIpKSB7XHJcbiAgICAgICAgLy8gQSB7e3ZhcmlhYmxlfX0gaXMgYmVpbmcgcXVlcmllZC5cclxuICAgICAgICAvLyBNYWtlIHRoZSBxdWVyeSBzdHJpbmcgdG8gc3RhcnQgZnJvbSB0aGUge3sgcGFpciwgaS5lLiByZW1vdmUgZXZlcnl0aGluZyBiZWZvcmUge3sgLiBUaGlzIGltcHJvdmVzIHRoZSBzZWFyY2guXHJcbiAgICAgICAgc2VhcmNoX3RleHQgPSBzZWFyY2hfdGV4dC5yZXBsYWNlKC8uK1xce1xcey91LCBcInt7XCIpO1xyXG4gICAgICAgIGlmIChzZWFyY2hfdGV4dC5jb250YWlucyhcInt7IVwiKSkge1xyXG4gICAgICAgICAgICAvLyBBbiBfdW5lc2NhcGVkXyB2YXJpYWJsZSBpcyBzZWFyY2hlZCBmb3IuXHJcbiAgICAgICAgICAgIHNlYXJjaF90eXBlID0gXCJ1bmVzY2FwZWQtdmFyaWFibGVcIjtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBBIG5vcm1hbCB2YXJpYWJsZSBpcyBzZWFyY2hlZCBmb3IuXHJcbiAgICAgICAgICAgIHNlYXJjaF90eXBlID0gXCJub3JtYWwtdmFyaWFibGVcIjtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAgIHNlYXJjaF90ZXh0OiBzZWFyY2hfdGV4dCxcclxuICAgICAgICBzZWFyY2hfdHlwZTogc2VhcmNoX3R5cGUsXHJcbiAgICB9O1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX01vZGFsfSBmcm9tIFwiLi4vLi4vU0NfTW9kYWxcIjtcclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi4vLi4vbWFpblwiO1xyXG5pbXBvcnQge1xyXG4gICAgU2V0dGluZyxcclxufSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHtPdXRwdXRXcmFwcGVyfSBmcm9tIFwiLi9PdXRwdXRXcmFwcGVyXCI7XHJcbmltcG9ydCB7Y3JlYXRlQXV0b2NvbXBsZXRlfSBmcm9tIFwiLi4vLi4vc2V0dGluZ3Mvc2V0dGluZ19lbGVtZW50cy9BdXRvY29tcGxldGVcIjtcclxuaW1wb3J0IHtWYXJpYWJsZV9PdXRwdXR9IGZyb20gXCIuLi8uLi92YXJpYWJsZXMvVmFyaWFibGVfT3V0cHV0XCI7XHJcblxyXG5leHBvcnQgY2xhc3MgT3V0cHV0V3JhcHBlclNldHRpbmdzTW9kYWwgZXh0ZW5kcyBTQ19Nb2RhbCB7XHJcblxyXG4gICAgcHJpdmF0ZSBhcHByb3ZlZCA9IGZhbHNlO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIHBsdWdpbjogU0NfUGx1Z2luLFxyXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgb3V0cHV0X3dyYXBwZXI6IE91dHB1dFdyYXBwZXIsXHJcblxyXG4gICAgICAgIC8qKiBDYW4gYmUgdW5kZWZpbmVkIGlmIHRoZSBvdXRwdXQgd3JhcHBlciBpcyBjcmVhdGVkIGZyb20gYSBwbGFjZSB3aGVyZSB0aGVyZSBpcyBubyBuYW1lIGVsZW1lbnQuICovXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBvdXRwdXRfd3JhcHBlcl9uYW1lX3NldHRpbmc/OiBTZXR0aW5nLFxyXG5cclxuICAgICAgICAvKiogSWYgZGVmaW5lZCwgYSBidXR0b24gd2lsbCBiZSBhZGRlZCBhbmQgb25fYWZ0ZXJfYXBwcm92YWwoKSAvIG9uX2FmdGVyX2NhbmNlbGxpbmcoKSB3aWxsIGJlIGNhbGxlZCBkZXBlbmRpbmcgb24gd2hldGhlciB0aGUgYnV0dG9uIHdhcyBjbGlja2VkIG9yIG5vdC4gKi9cclxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IG9rX2J1dHRvbl90ZXh0Pzogc3RyaW5nLFxyXG5cclxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IG9uX2FmdGVyX2FwcHJvdmFsPzogKCkgPT4gdm9pZCxcclxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IG9uX2FmdGVyX2NhbmNlbGxpbmc/OiAoKSA9PiB2b2lkLFxyXG4gICAgKSB7XHJcbiAgICAgICAgc3VwZXIocGx1Z2luKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgb25PcGVuKCk6IHZvaWQge1xyXG4gICAgICAgIHN1cGVyLm9uT3BlbigpO1xyXG4gICAgICAgIGNvbnN0IGNvbnRhaW5lcl9lbGVtZW50ID0gdGhpcy5tb2RhbEVsLmNyZWF0ZURpdigpO1xyXG4gICAgICAgIGNvbnRhaW5lcl9lbGVtZW50LmFkZENsYXNzKFwiU0Mtc2V0dGluZy1ncm91cFwiKTsgLy8gTWFrZSBzZXR0aW5nIGZpZWxkcyB3aWRlciBpbiB0aGlzIGNvbnRhaW5lci5cclxuXHJcbiAgICAgICAgLy8gVGl0bGVcclxuICAgICAgICBjb25zdCB0aXRsZV9zZXR0aW5nID0gbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKFwiT3V0cHV0IHdyYXBwZXIgdGl0bGVcIilcclxuICAgICAgICAgICAgLnNldERlc2MoXCJPbmx5IHVzZWQgaW4gc2V0dGluZ3MsIHdpbGwgbm90IGFwcGVhciBpbiBvdXRwdXQuXCIpXHJcbiAgICAgICAgICAgIC5hZGRUZXh0KHRleHQgPT4gdGV4dFxyXG4gICAgICAgICAgICAgICAgLnNldFZhbHVlKHRoaXMub3V0cHV0X3dyYXBwZXIuZ2V0VGl0bGUoKSlcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAobmV3X3RpdGxlOiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLm91dHB1dF93cmFwcGVyLmdldENvbmZpZ3VyYXRpb24oKS50aXRsZSA9IG5ld190aXRsZTtcclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVXBkYXRlIHRoZSB0aXRsZSBpbiBhIG5hbWUgc2V0dGluZy4gKE9ubHkgaWYgdGhlIG1vZGFsIHdhcyBjcmVhdGVkIGZyb20gYSBwbGFjZSB3aGVyZSBhbiBPdXRwdXRXcmFwcGVyIG5hbWUgZWxlbWVudCBleGlzdHMpLlxyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMub3V0cHV0X3dyYXBwZXJfbmFtZV9zZXR0aW5nPy5zZXROYW1lKG5ld190aXRsZSk7XHJcbiAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG4gICAgICAgIGNvbnN0IHRpdGxlX2lucHV0X2VsZW1lbnQ6IEhUTUxJbnB1dEVsZW1lbnQgPSB0aXRsZV9zZXR0aW5nLmNvbnRyb2xFbC5maW5kKFwiaW5wdXRcIikgYXMgSFRNTElucHV0RWxlbWVudDtcclxuXHJcbiAgICAgICAgLy8gQ29udGVudFxyXG4gICAgICAgIGNvbnN0IG91dHB1dF92YXJpYWJsZSA9IG5ldyBWYXJpYWJsZV9PdXRwdXQodGhpcy5wbHVnaW4sIFwiXCIpOyAvLyBGb3IgZ2V0dGluZyBhbiBhdXRvY29tcGxldGUgaXRlbS5cclxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJDb250ZW50XCIpXHJcbiAgICAgICAgICAgIC5zZXREZXNjKFwiVXNlIHt7b3V0cHV0fX0gYXMgYSBwbGFjZWhvbGRlciBmb3IgdGV4dCB0aGF0IHdpbGwgYmUgcmVjZWl2ZWQgZnJvbSBhIHNoZWxsIGNvbW1hbmQuIE90aGVyIHZhcmlhYmxlcyBhcmUgYXZhaWxhYmxlLCB0b28uXCIpXHJcbiAgICAgICAgICAgIC5hZGRUZXh0QXJlYSh0ZXh0YXJlYV9jb21wb25lbnQgPT4gdGV4dGFyZWFfY29tcG9uZW50XHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUodGhpcy5vdXRwdXRfd3JhcHBlci5jb25maWd1cmF0aW9uLmNvbnRlbnQpXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKG5ld19jb250ZW50OiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLm91dHB1dF93cmFwcGVyLmNvbmZpZ3VyYXRpb24uY29udGVudCA9IG5ld19jb250ZW50O1xyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgIC50aGVuKCh0ZXh0YXJlYV9jb21wb25lbnQpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBBdXRvY29tcGxldGUgZm9yIENvbnRlbnQuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMucGx1Z2luLnNldHRpbmdzLnNob3dfYXV0b2NvbXBsZXRlX21lbnUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlQXV0b2NvbXBsZXRlKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0YXJlYV9jb21wb25lbnQuaW5wdXRFbCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICgpID0+IHRleHRhcmVhX2NvbXBvbmVudC5vbkNoYW5nZWQoKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dF92YXJpYWJsZS5nZXRBdXRvY29tcGxldGVJdGVtcygpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG5cclxuICAgICAgICAvLyBGb2N1cyBvbiB0aGUgdGl0bGUgZmllbGQuXHJcbiAgICAgICAgdGl0bGVfaW5wdXRfZWxlbWVudC5mb2N1cygpO1xyXG5cclxuICAgICAgICAvLyBPayBidXR0b25cclxuICAgICAgICBjb25zdCBva0J1dHRvblRleHQ6IHN0cmluZyB8IHVuZGVmaW5lZCA9IHRoaXMub2tfYnV0dG9uX3RleHQ7XHJcbiAgICAgICAgaWYgKG9rQnV0dG9uVGV4dCkge1xyXG4gICAgICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgICAgIC5hZGRCdXR0b24oYnV0dG9uID0+IGJ1dHRvblxyXG4gICAgICAgICAgICAgICAgICAgIC5zZXRCdXR0b25UZXh0KG9rQnV0dG9uVGV4dClcclxuICAgICAgICAgICAgICAgICAgICAub25DbGljaygoKSA9PiB0aGlzLmFwcHJvdmUoKSksXHJcbiAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgIDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGFwcHJvdmUoKTogdm9pZCB7XHJcbiAgICAgICAgaWYgKHRoaXMub25fYWZ0ZXJfYXBwcm92YWwpIHtcclxuICAgICAgICAgICAgdGhpcy5hcHByb3ZlZCA9IHRydWU7XHJcbiAgICAgICAgICAgIHRoaXMub25fYWZ0ZXJfYXBwcm92YWwoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5jbG9zZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbkNsb3NlKCk6IHZvaWQge1xyXG4gICAgICAgIHN1cGVyLm9uQ2xvc2UoKTtcclxuXHJcbiAgICAgICAgLy8gQ2FsbCBhIGNhbmNlbGxpbmcgaG9vayBpZiBvbmUgaXMgZGVmaW5lZCAoYW5kIGlmIHRoZSBjbG9zaW5nIGhhcHBlbnMgZHVlIHRvIGNhbmNlbGxpbmcsIGkuZS4gdGhlIG9rIGJ1dHRvbiBpcyBOT1QgY2xpY2tlZCkuXHJcbiAgICAgICAgaWYgKCF0aGlzLmFwcHJvdmVkICYmIHRoaXMub25fYWZ0ZXJfY2FuY2VsbGluZykge1xyXG4gICAgICAgICAgICB0aGlzLm9uX2FmdGVyX2NhbmNlbGxpbmcoKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7XHJcbiAgICBNb2RlbCxcclxuICAgIFBhcmVudE1vZGVsT25lVG9NYW55SWRSZWxhdGlvbixcclxufSBmcm9tIFwiLi4vTW9kZWxcIjtcclxuaW1wb3J0IHtTZXR0aW5nfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHtcclxuICAgIE91dHB1dFdyYXBwZXIsXHJcbiAgICBPdXRwdXRXcmFwcGVyQ29uZmlndXJhdGlvbixcclxufSBmcm9tIFwiLi9PdXRwdXRXcmFwcGVyXCI7XHJcbmltcG9ydCB7ZGVidWdMb2d9IGZyb20gXCIuLi8uLi9EZWJ1Z1wiO1xyXG5pbXBvcnQge2dldElER2VuZXJhdG9yfSBmcm9tIFwiLi4vLi4vSURHZW5lcmF0b3JcIjtcclxuaW1wb3J0IHtPdXRwdXRTdHJlYW19IGZyb20gXCIuLi8uLi9vdXRwdXRfY2hhbm5lbHMvT3V0cHV0Q2hhbm5lbENvZGVcIjtcclxuaW1wb3J0IHtPdXRwdXRXcmFwcGVyU2V0dGluZ3NNb2RhbH0gZnJvbSBcIi4vT3V0cHV0V3JhcHBlclNldHRpbmdzTW9kYWxcIjtcclxuaW1wb3J0IHtTQ19NYWluU2V0dGluZ3N9IGZyb20gXCIuLi8uLi9zZXR0aW5ncy9TQ19NYWluU2V0dGluZ3NcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBPdXRwdXRXcmFwcGVyTW9kZWwgZXh0ZW5kcyBNb2RlbCB7XHJcblxyXG4gICAgcHJpdmF0ZSBvdXRwdXRfd3JhcHBlcnMgPSBuZXcgT3V0cHV0V3JhcHBlck1hcCgpO1xyXG5cclxuICAgIHByb3RlY3RlZCBfY3JlYXRlU2V0dGluZ0ZpZWxkcyhvdXRwdXRfd3JhcHBlcjogT3V0cHV0V3JhcHBlciwgY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KTogU2V0dGluZyB7XHJcbiAgICAgICAgZGVidWdMb2coXCJDcmVhdGluZyBzZXR0aW5nIGZpZWxkcyBmb3IgYW4gT3V0cHV0V3JhcHBlciBpbnN0YW5jZS5cIik7XHJcbiAgICAgICAgY29uc3Qgb3V0cHV0X3dyYXBwZXJfbmFtZV9zZXR0aW5nID0gbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC8vIENvbmZpZ3VyYXRpb24gYnV0dG9uXHJcbiAgICAgICAgICAgIC5zZXROYW1lKG91dHB1dF93cmFwcGVyLmdldFRpdGxlKCkpXHJcbiAgICAgICAgICAgIC5hZGRFeHRyYUJ1dHRvbihidXR0b24gPT4gYnV0dG9uXHJcbiAgICAgICAgICAgICAgICAuc2V0VG9vbHRpcChcIkRlZmluZSBvdXRwdXQgd3JhcHBlciBjb250ZW50XCIpXHJcbiAgICAgICAgICAgICAgICAuc2V0SWNvbihcImdlYXJcIilcclxuICAgICAgICAgICAgICAgIC5vbkNsaWNrKCgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLm9wZW5TZXR0aW5nc01vZGFsKG91dHB1dF93cmFwcGVyLCBvdXRwdXRfd3JhcHBlcl9uYW1lX3NldHRpbmcpO1xyXG4gICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcbiAgICAgICAgcmV0dXJuIG91dHB1dF93cmFwcGVyX25hbWVfc2V0dGluZztcclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgZGVmaW5lUGFyZW50Q29uZmlndXJhdGlvblJlbGF0aW9uKG91dHB1dF93cmFwcGVyOiBPdXRwdXRXcmFwcGVyKTogUGFyZW50TW9kZWxPbmVUb01hbnlJZFJlbGF0aW9uIHtcclxuICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICB0eXBlOiBcIm9uZS10by1tYW55LWlkXCIsXHJcbiAgICAgICAgICAgIGtleTogXCJvdXRwdXRfd3JhcHBlcnNcIixcclxuICAgICAgICAgICAgaWQ6IG91dHB1dF93cmFwcGVyLmdldElEKCksXHJcbiAgICAgICAgfTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0U2luZ3VsYXJOYW1lKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIFwiT3V0cHV0IHdyYXBwZXJcIjtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgbG9hZEluc3RhbmNlcyhwYXJlbnRfY29uZmlndXJhdGlvbjogU0NfTWFpblNldHRpbmdzKTogT3V0cHV0V3JhcHBlck1hcCB7XHJcbiAgICAgICAgZGVidWdMb2coXCJMb2FkaW5nIE91dHB1dFdyYXBwZXIgaW5zdGFuY2VzLlwiKTtcclxuICAgICAgICB0aGlzLm91dHB1dF93cmFwcGVycyA9IG5ldyBPdXRwdXRXcmFwcGVyTWFwKCk7XHJcbiAgICAgICAgcGFyZW50X2NvbmZpZ3VyYXRpb24ub3V0cHV0X3dyYXBwZXJzLmZvckVhY2goKG91dHB1dF93cmFwcGVyX2NvbmZpZ3VyYXRpb246IE91dHB1dFdyYXBwZXJDb25maWd1cmF0aW9uKSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IG91dHB1dF93cmFwcGVyID0gbmV3IE91dHB1dFdyYXBwZXIodGhpcywgdGhpcy5wbHVnaW4sIG91dHB1dF93cmFwcGVyX2NvbmZpZ3VyYXRpb24sIHBhcmVudF9jb25maWd1cmF0aW9uKTtcclxuICAgICAgICAgICAgdGhpcy5vdXRwdXRfd3JhcHBlcnMuc2V0KG91dHB1dF93cmFwcGVyX2NvbmZpZ3VyYXRpb24uaWQsIG91dHB1dF93cmFwcGVyKTtcclxuICAgICAgICB9KTtcclxuICAgICAgICByZXR1cm4gdGhpcy5vdXRwdXRfd3JhcHBlcnM7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIG5ld0luc3RhbmNlKHBhcmVudF9jb25maWd1cmF0aW9uOiBTQ19NYWluU2V0dGluZ3MpOiBPdXRwdXRXcmFwcGVyIHtcclxuICAgICAgICBkZWJ1Z0xvZyhcIkNyZWF0aW5nIGEgbmV3IE91dHB1dFdyYXBwZXIgaW5zdGFuY2UuXCIpO1xyXG4gICAgICAgIC8vIFRPRE86IE1vdmUgdGhpcyBsb2dpYyB0byB0aGUgYmFzZSBNb2RlbCBjbGFzcy5cclxuXHJcbiAgICAgICAgLy8gU2V0dXAgYSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gYW5kIGdlbmVyYXRlIGFuIElEXHJcbiAgICAgICAgY29uc3Qgb3V0cHV0X3dyYXBwZXJfY29uZmlndXJhdGlvbiA9IHRoaXMuZ2V0RGVmYXVsdENvbmZpZ3VyYXRpb24oKTtcclxuXHJcbiAgICAgICAgLy8gSW5zdGFudGlhdGUgYW4gT3V0cHV0V3JhcHBlclxyXG4gICAgICAgIGNvbnN0IG91dHB1dF93cmFwcGVyID0gbmV3IE91dHB1dFdyYXBwZXIodGhpcywgdGhpcy5wbHVnaW4sIG91dHB1dF93cmFwcGVyX2NvbmZpZ3VyYXRpb24sIHRoaXMucGx1Z2luLnNldHRpbmdzKTtcclxuICAgICAgICB0aGlzLm91dHB1dF93cmFwcGVycy5zZXQob3V0cHV0X3dyYXBwZXIuZ2V0SUQoKSwgb3V0cHV0X3dyYXBwZXIpO1xyXG5cclxuICAgICAgICAvLyBTdG9yZSB0aGUgY29uZmlndXJhdGlvbiBpbnRvIHBsdWdpbidzIHNldHRpbmdzXHJcbiAgICAgICAgcGFyZW50X2NvbmZpZ3VyYXRpb24ub3V0cHV0X3dyYXBwZXJzLnB1c2gob3V0cHV0X3dyYXBwZXJfY29uZmlndXJhdGlvbik7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiB0aGUgT3V0cHV0V3JhcHBlclxyXG4gICAgICAgIHJldHVybiBvdXRwdXRfd3JhcHBlcjtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgdmFsaWRhdGVWYWx1ZShvdXRwdXRfd3JhcHBlcjogT3V0cHV0V3JhcHBlciwgZmllbGQ6IHN0cmluZywgdmFsdWU6IHVua25vd24pOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICAvLyBObyB2YWxpZGF0aW9uIGlzIG5lZWRlZCwgSSBndWVzcy4gJ1RpdGxlJyBhbmQgJ2NvbnRlbnQnIGNhbiBib3RoIGJlIGVtcHR5LCBhbHRob3VnaCBhbiBlbXB0eSB0aXRsZSBkb2VzIG5vdCBtYWtlIHNlbnNlLlxyXG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUodW5kZWZpbmVkKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgb3BlblNldHRpbmdzTW9kYWwob3V0cHV0X3dyYXBwZXI6IE91dHB1dFdyYXBwZXIsIG91dHB1dF93cmFwcGVyX25hbWVfc2V0dGluZzogU2V0dGluZykge1xyXG4gICAgICAgIGRlYnVnTG9nKFwiT3BlbmluZyBzZXR0aW5ncyBtb2RhbCBmb3IgYW4gT3V0cHV0V3JhcHBlciBpbnN0YW5jZS5cIik7XHJcbiAgICAgICAgY29uc3QgbW9kYWwgPSBuZXcgT3V0cHV0V3JhcHBlclNldHRpbmdzTW9kYWwodGhpcy5wbHVnaW4sIG91dHB1dF93cmFwcGVyLCBvdXRwdXRfd3JhcHBlcl9uYW1lX3NldHRpbmcpO1xyXG4gICAgICAgIG1vZGFsLm9wZW4oKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0RGVmYXVsdENvbmZpZ3VyYXRpb24oKTogT3V0cHV0V3JhcHBlckNvbmZpZ3VyYXRpb24ge1xyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGlkOiBnZXRJREdlbmVyYXRvcigpLmdlbmVyYXRlSUQoKSxcclxuICAgICAgICAgICAgdGl0bGU6IFwiXCIsXHJcbiAgICAgICAgICAgIGNvbnRlbnQ6IFwiXCIsXHJcbiAgICAgICAgfTtcclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgX2RlbGV0ZUluc3RhbmNlKGRlbGV0YWJsZV9vdXRwdXRfd3JhcHBlcjogT3V0cHV0V3JhcHBlcik6IHZvaWQge1xyXG4gICAgICAgIGRlYnVnTG9nKFwiRGVsZXRpbmcgYW4gT3V0cHV0V3JhcHBlciBpbnN0YW5jZS5cIik7XHJcblxyXG4gICAgICAgIC8vIFJlbW92ZSB0aGUgT3V0cHV0V3JhcHBlciBmcm9tIGFsbCBUU2hlbGxDb21tYW5kcyB0aGF0IHVzZSBpdC5cclxuICAgICAgICBjb25zdCBzaGVsbF9jb21tYW5kcyA9IHRoaXMucGx1Z2luLmdldFRTaGVsbENvbW1hbmRzKCk7XHJcbiAgICAgICAgZm9yIChjb25zdCBzaGVsbF9jb21tYW5kX2lkIGluIHNoZWxsX2NvbW1hbmRzKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHRfc2hlbGxfY29tbWFuZCA9IHNoZWxsX2NvbW1hbmRzW3NoZWxsX2NvbW1hbmRfaWRdO1xyXG4gICAgICAgICAgICBjb25zdCBvdXRwdXRfd3JhcHBlcnMgPSB0X3NoZWxsX2NvbW1hbmQuZ2V0Q29uZmlndXJhdGlvbigpLm91dHB1dF93cmFwcGVycztcclxuICAgICAgICAgICAgT2JqZWN0LmVhY2gob3V0cHV0X3dyYXBwZXJzLCAob3V0cHV0X3dyYXBwZXJfaWQ6IHN0cmluZywgb3V0cHV0X3N0cmVhbTogT3V0cHV0U3RyZWFtKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBpZiAob3V0cHV0X3dyYXBwZXJfaWQgPT09IGRlbGV0YWJsZV9vdXRwdXRfd3JhcHBlci5nZXRJRCgpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gQSBzaGVsbCBjb21tYW5kIHVzZXMgdGhlIG91dHB1dCB3cmFwcGVyIHRoYXQgaXMgYWJvdXQgdG8gYmUgZGVsZXRlZC5cclxuICAgICAgICAgICAgICAgICAgICAvLyBDb25maWd1cmUgdGhlIHNoZWxsIGNvbW1hbmQgbm90IHRvIHVzZSBhbnkgb3V0cHV0IHdyYXBwZXIuXHJcbiAgICAgICAgICAgICAgICAgICAgb3V0cHV0X3dyYXBwZXJzW291dHB1dF9zdHJlYW1dID0gbnVsbDtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBSZW1vdmUgdGhlIE91dHB1dFdyYXBwZXIgZnJvbSB0aGlzIGNsYXNzJ3MgaW50ZXJuYWwgbGlzdC5cclxuICAgICAgICB0aGlzLm91dHB1dF93cmFwcGVycy5kZWxldGUoZGVsZXRhYmxlX291dHB1dF93cmFwcGVyLmdldElEKCkpO1xyXG4gICAgfVxyXG5cclxufVxyXG5cclxuZXhwb3J0IGNsYXNzIE91dHB1dFdyYXBwZXJNYXAgZXh0ZW5kcyBNYXA8c3RyaW5nLCBPdXRwdXRXcmFwcGVyPiB7fSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi4vbWFpblwiO1xyXG5pbXBvcnQge2RlYnVnTG9nfSBmcm9tIFwiLi4vRGVidWdcIjtcclxuaW1wb3J0IHtcclxuICAgIEN1c3RvbVZhcmlhYmxlTW9kZWwsXHJcbiAgICBpbnRyb2R1Y2VNb2RlbENsYXNzLFxyXG4gICAgUHJvbXB0RmllbGRNb2RlbCxcclxuICAgIFByb21wdE1vZGVsLFxyXG59IGZyb20gXCIuLi9pbXBvcnRzXCI7XHJcbmltcG9ydCB7T3V0cHV0V3JhcHBlck1vZGVsfSBmcm9tIFwiLi9vdXRwdXRfd3JhcHBlci9PdXRwdXRXcmFwcGVyTW9kZWxcIjtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBpbnRyb2R1Y2VNb2RlbHMocGx1Z2luOiBTQ19QbHVnaW4pIHtcclxuICAgIGRlYnVnTG9nKFwiSW50cm9kdWNpbmcgbW9kZWxzLlwiKTtcclxuXHJcbiAgICAvLyBLZWVwIGluIGFscGhhYmV0aWNhbCBvcmRlciwgaWYgcG9zc2libGUuXHJcbiAgICBpbnRyb2R1Y2VNb2RlbENsYXNzKG5ldyBDdXN0b21WYXJpYWJsZU1vZGVsKHBsdWdpbikpO1xyXG4gICAgaW50cm9kdWNlTW9kZWxDbGFzcyhuZXcgUHJvbXB0RmllbGRNb2RlbChwbHVnaW4pKTtcclxuICAgIGludHJvZHVjZU1vZGVsQ2xhc3MobmV3IFByb21wdE1vZGVsKHBsdWdpbikpO1xyXG4gICAgaW50cm9kdWNlTW9kZWxDbGFzcyhuZXcgT3V0cHV0V3JhcHBlck1vZGVsKHBsdWdpbikpO1xyXG59XHJcbiIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtcclxuICAgIEdsb2JhbFZhcmlhYmxlRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbixcclxuICAgIFZhcmlhYmxlLFxyXG59IGZyb20gXCIuL1ZhcmlhYmxlXCI7XHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uL21haW5cIjtcclxuaW1wb3J0IHtDdXN0b21WYXJpYWJsZUluc3RhbmNlfSBmcm9tIFwiLi4vbW9kZWxzL2N1c3RvbV92YXJpYWJsZS9DdXN0b21WYXJpYWJsZUluc3RhbmNlXCI7XHJcbmltcG9ydCB7cmVzZXRWYXJpYWJsZUF1dG9jb21wbGV0ZUl0ZW1zfSBmcm9tIFwiLi9nZXRWYXJpYWJsZUF1dG9jb21wbGV0ZUl0ZW1zXCI7XHJcbmltcG9ydCB7ZGVidWdMb2d9IGZyb20gXCIuLi9EZWJ1Z1wiO1xyXG5cclxuLyoqXHJcbiAqIFRoaXMgY2xhc3Mgc2VydmVzIGFzIHRoZSBhY3R1YWwgb3BlcmF0aW9uYWwgdmFyaWFibGUgY2xhc3MgZm9yIGN1c3RvbSB2YXJpYWJsZXMuIEl0J3MgcGFpcmVkIHdpdGggdGhlIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UgY2xhc3MsIHdoaWNoIGFjdHNcclxuICogYXMgYSBjb25maWd1cmF0aW9uIGNsYXNzIHRvIGhhbmRsZSBzZXR0aW5ncyB0b2dldGhlciB3aXRoIEN1c3RvbVZhcmlhYmxlTW9kZWwgY2xhc3MuXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgQ3VzdG9tVmFyaWFibGUgZXh0ZW5kcyBWYXJpYWJsZSB7XHJcblxyXG4gICAgcHJpdmF0ZSB2YWx1ZTogc3RyaW5nIHwgbnVsbCA9IG51bGw7IC8vIFRPRE86IFdoZW4gaW1wbGVtZW50aW5nIHZhcmlhYmxlIHR5cGVzLCBtYWtlIHRoaXMgY2xhc3MgYWJzdHJhY3QgYW5kIGxldCBzdWJjbGFzc2VzIGRlZmluZSB0aGUgdHlwZSBvZiB0aGlzIHByb3BlcnR5LlxyXG5cclxuICAgIHByb3RlY3RlZCBhbHdheXNfYXZhaWxhYmxlID0gZmFsc2U7XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgcHJpdmF0ZSBjdXN0b21fdmFyaWFibGVfaW5zdGFuY2U6IEN1c3RvbVZhcmlhYmxlSW5zdGFuY2VcclxuICAgICkge1xyXG4gICAgICAgIHN1cGVyKHBsdWdpbik7XHJcbiAgICAgICAgdGhpcy51cGRhdGVQcm9wZXJ0aWVzKCk7XHJcbiAgICAgICAgZGVidWdMb2coYExvYWRlZCBDdXN0b21WYXJpYWJsZSAke3RoaXMudmFyaWFibGVfbmFtZX0uYCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGFzeW5jIGdlbmVyYXRlVmFsdWUoKTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgICAgICBpZiAobnVsbCA9PT0gdGhpcy52YWx1ZSkge1xyXG4gICAgICAgICAgICBkZWJ1Z0xvZyhgQ3VzdG9tIHZhcmlhYmxlICR7dGhpcy52YXJpYWJsZV9uYW1lfSBkb2VzIG5vdCBoYXZlIGEgdmFsdWUgeWV0LCBhbmQgbm8gZGVmYXVsdCB2YWx1ZSBpcyBkZWZpbmVkLmApO1xyXG4gICAgICAgICAgICB0aGlzLnRocm93KFwiVGhpcyBjdXN0b20gdmFyaWFibGUgZG9lcyBub3QgaGF2ZSBhIHZhbHVlIHlldCwgYW5kIG5vIGRlZmF1bHQgdmFsdWUgaXMgZGVmaW5lZC5cIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVE9ETzogTWFrZSBpdCBwb3NzaWJsZSB0byBwcmV2ZW50IGNhbGxpbmcgb25DaGFuZ2UgY2FsbGJhY2tzOlxyXG4gICAgICogIC0gTWFrZSBpdCBwb3NzaWJsZSB0byBjYWxsIHRoZSBjYWxsYmFja3MgbGF0ZXIgb3V0c2lkZSB0aGlzIGNsYXNzLlxyXG4gICAgICogIC0gVGhpcyBtYWtlcyBpdCBwb3NzaWJsZSB0byBwcmV2ZW50IHVubmVjZXNzYXJ5IEN1c3RvbVZhcmlhYmxlVmlldyB1cGRhdGVzIHdoZW4gbXVsdGlwbGUgQ3VzdG9tVmFyaWFibGVzIGFyZSBhc3NpZ25lZCB2YWx1ZXMgaW4gb25lIGdvICh2aWEgU2hlbGwgY29tbWFuZCBVUkkpLlxyXG4gICAgICogIC0gU3RvcmUgdGhlIG9sZCB2YWx1ZSBpbnRvIHNvbWUga2luZCBvZiBoaXN0b3J5IGxpc3QuXHJcbiAgICAgKiAgLSBXaGVuIGNhbGxpbmcgdGhlIGNhbGxiYWNrcywgdGhlIGN1cnJlbnQgQ3VzdG9tVmFyaWFibGUgc2hvdWxkIGJlIHBhc3NlZCBhcyBhIHBhcmFtZXRlciBpbnN0ZWFkIG9mIHRoZSAndmFsdWUnIGFuZCAnb2xkX3ZhbHVlJyBwYXJhbWV0ZXJzICh3aGljaCBjYW4gYmUgYWNjZXNzZWQgdmlhIHRoZSBDdXN0b21WYXJpYWJsZSBvYmplY3QpLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB2YWx1ZVxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgYXN5bmMgc2V0VmFsdWUodmFsdWU6IHN0cmluZykge1xyXG4gICAgICAgIGNvbnN0IG9sZF92YWx1ZSA9IHRoaXMudmFsdWU7XHJcbiAgICAgICAgZGVidWdMb2coYEN1c3RvbVZhcmlhYmxlICR7dGhpcy52YXJpYWJsZV9uYW1lfTogU2V0dGluZyB2YWx1ZSB0bzogJHt2YWx1ZX0gKG9sZCB3YXM6ICR7b2xkX3ZhbHVlfSkuYCk7XHJcbiAgICAgICAgdGhpcy52YWx1ZSA9IHZhbHVlO1xyXG5cclxuICAgICAgICAvLyBDYWxsIHRoZSBvbkNoYW5nZSBob29rLlxyXG4gICAgICAgIGF3YWl0IHRoaXMuY2FsbE9uQ2hhbmdlQ2FsbGJhY2tzKHZhbHVlLCBvbGRfdmFsdWUgPz8gXCJcIik7IC8vIFVzZSBcIlwiIGlmIG9sZF92YWx1ZSBpcyBudWxsLlxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmV0cmlldmVzIHZhcmlhYmxlX25hbWUgYW5kIGhlbHBfdGV4dCBwcm9wZXJ0aWVzIGZyb20gdGhlIGFzc29jaWF0ZWQgQ3VzdG9tVmFyaWFibGVJbnN0YW5jZS5cclxuICAgICAqIENhbGxlZCB3aGVuIGxvYWRpbmcgdGhlIEN1c3RvbVZhcmlhYmxlIGFuZCB3aGVuIHRoZSBhc3NvY2lhdGVkIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UncyBzZXR0aW5ncyBhcmUgY2hhbmdlZC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIHVwZGF0ZVByb3BlcnRpZXMoKSB7XHJcbiAgICAgICAgZGVidWdMb2coYEN1c3RvbVZhcmlhYmxlICR7dGhpcy52YXJpYWJsZV9uYW1lfTogVXBkYXRpbmcgdmFyaWFibGUgbmFtZSBhbmQgaGVscCB0ZXh0LmApO1xyXG4gICAgICAgIHRoaXMudmFyaWFibGVfbmFtZSA9IHRoaXMuY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlLmdldFByZWZpeGVkTmFtZSgpO1xyXG4gICAgICAgIHRoaXMuaGVscF90ZXh0ID0gdGhpcy5jdXN0b21fdmFyaWFibGVfaW5zdGFuY2UuY29uZmlndXJhdGlvbi5kZXNjcmlwdGlvbjtcclxuICAgICAgICByZXNldFZhcmlhYmxlQXV0b2NvbXBsZXRlSXRlbXMoKTsgLy8gTWFrZSBhdXRvY29tcGxldGUgbGlzdHMgcmVsb2FkIHRoZWlyIGNvbnRlbnQgaW4gb3JkZXIgdG8gZ2V0IHRoZSBuZXcgdmFyaWFibGUgbmFtZS9oZWxwIHRleHQuXHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldElkZW50aWZpZXIoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlLmdldElEKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBBZGRzIHRoZSBnaXZlbiBjYWxsYmFjayBmdW5jdGlvbiB0byBhIHN0YWNrIG9mIGZ1bmN0aW9ucyB0aGF0IHdpbGwgYmUgY2FsbGVkIHdoZW5ldmVyIHRoaXMgQ3VzdG9tVmFyaWFibGUncyB2YWx1ZSBjaGFuZ2VzLlxyXG4gICAgICogQHBhcmFtIG9uX2NoYW5nZV9jYWxsYmFja1xyXG4gICAgICovXHJcbiAgICBwdWJsaWMgb25DaGFuZ2Uob25fY2hhbmdlX2NhbGxiYWNrOiBUQ3VzdG9tVmFyaWFibGVPbkNoYW5nZUNhbGxiYWNrKSB7XHJcbiAgICAgICAgdGhpcy5vbl9jaGFuZ2VfY2FsbGJhY2tzLmFkZChvbl9jaGFuZ2VfY2FsbGJhY2spO1xyXG4gICAgfVxyXG4gICAgcHJpdmF0ZSBvbl9jaGFuZ2VfY2FsbGJhY2tzID0gbmV3IFNldDxUQ3VzdG9tVmFyaWFibGVPbkNoYW5nZUNhbGxiYWNrPigpO1xyXG5cclxuICAgIHByaXZhdGUgYXN5bmMgY2FsbE9uQ2hhbmdlQ2FsbGJhY2tzKG5ld192YWx1ZTogc3RyaW5nLCBvbGRfdmFsdWU6IHN0cmluZykge1xyXG4gICAgICAgIGRlYnVnTG9nKGBDdXN0b21WYXJpYWJsZSAke3RoaXMudmFyaWFibGVfbmFtZX06IENhbGxpbmcgb25DaGFuZ2UgY2FsbGJhY2tzLmApO1xyXG4gICAgICAgIGZvciAoY29uc3Qgb25fY2hhbmdlX2NhbGxiYWNrIG9mIHRoaXMub25fY2hhbmdlX2NhbGxiYWNrcykge1xyXG4gICAgICAgICAgICBhd2FpdCBvbl9jaGFuZ2VfY2FsbGJhY2sodGhpcywgbmV3X3ZhbHVlLCBvbGRfdmFsdWUpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0Q29uZmlndXJhdGlvbigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jdXN0b21fdmFyaWFibGVfaW5zdGFuY2UuY29uZmlndXJhdGlvbjtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0R2xvYmFsRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbigpOiBHbG9iYWxWYXJpYWJsZURlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24gfCBudWxsIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jdXN0b21fdmFyaWFibGVfaW5zdGFuY2UuY29uZmlndXJhdGlvbi5kZWZhdWx0X3ZhbHVlO1xyXG4gICAgfVxyXG59XHJcblxyXG50eXBlIFRDdXN0b21WYXJpYWJsZU9uQ2hhbmdlQ2FsbGJhY2sgPSAodmFyaWFibGU6IEN1c3RvbVZhcmlhYmxlLCBuZXdfdmFsdWU6IHN0cmluZywgb2xkX3ZhbHVlOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD47IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX01haW5TZXR0aW5nc30gZnJvbSBcIi4uLy4uL3NldHRpbmdzL1NDX01haW5TZXR0aW5nc1wiO1xyXG5pbXBvcnQge1xyXG4gICAgQ3VzdG9tVmFyaWFibGUsXHJcbiAgICBDdXN0b21WYXJpYWJsZUNvbmZpZ3VyYXRpb24sXHJcbiAgICBDdXN0b21WYXJpYWJsZU1vZGVsLFxyXG4gICAgZ2V0SURHZW5lcmF0b3IsXHJcbiAgICBJbnN0YW5jZSxcclxufSBmcm9tIFwiLi4vLi4vaW1wb3J0c1wiO1xyXG5pbXBvcnQge2RlYnVnTG9nfSBmcm9tIFwiLi4vLi4vRGVidWdcIjtcclxuXHJcbi8qKlxyXG4gKiBUaGlzIGNsYXNzIHNlcnZlcyBhcyBhbiBhY2Nlc3NvciB0byBDdXN0b21WYXJpYWJsZSBjb25maWd1cmF0aW9ucy4gSXQncyBwYWlyZWQgd2l0aCB0aGUgQ3VzdG9tVmFyaWFibGUgY2xhc3MsIHdoaWNoIGFjdHNcclxuICogYXMgYW4gb3BlcmF0aW9uYWwgY2xhc3MgdG8gaW1wbGVtZW50IHRoZSB2YXJpYWJsZSBmdW5jdGlvbmFsaXR5LlxyXG4gKlxyXG4gKiBUT0RPOiBEZWNpZGUgYSBiZXR0ZXIgbmFtZSBmb3IgdGhpcyBjbGFzcy4gSXQncyB0b28gZWFzeSB0byBjb25mdXNlIHdpdGggdGhlIEN1c3RvbVZhcmlhYmxlIGNsYXNzIG5hbWUuXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSBleHRlbmRzIEluc3RhbmNlIHtcclxuICAgIHB1YmxpYyByZWFkb25seSBwYXJlbnRfY29uZmlndXJhdGlvbjogU0NfTWFpblNldHRpbmdzO1xyXG4gICAgcHVibGljIGNvbmZpZ3VyYXRpb246IEN1c3RvbVZhcmlhYmxlQ29uZmlndXJhdGlvbjtcclxuICAgIHByaXZhdGUgY3VzdG9tX3ZhcmlhYmxlOiBDdXN0b21WYXJpYWJsZSB8IG51bGwgPSBudWxsO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIHB1YmxpYyByZWFkb25seSBtb2RlbDogQ3VzdG9tVmFyaWFibGVNb2RlbCxcclxuICAgICAgICBjb25maWd1cmF0aW9uOiBDdXN0b21WYXJpYWJsZUNvbmZpZ3VyYXRpb24sXHJcbiAgICAgICAgcGFyZW50X2NvbmZpZ3VyYXRpb246IFNDX01haW5TZXR0aW5ncyxcclxuICAgICkge1xyXG4gICAgICAgIHN1cGVyKG1vZGVsLCBjb25maWd1cmF0aW9uLCBwYXJlbnRfY29uZmlndXJhdGlvbik7XHJcblxyXG4gICAgICAgIC8vIEludHJvZHVjZSB0aGUgSUQgdG8gYW4gSUQgZ2VuZXJhdG9yIHNvIHRoYXQgaXQgd29uJ3QgYWNjaWRlbnRhbGx5IGdlbmVyYXRlIHRoZSBzYW1lIElEIGFnYWluIHdoZW4gY3JlYXRpbmcgbmV3IEN1c3RvbVZhcmlhYmxlSW5zdGFuY2VzLlxyXG4gICAgICAgIGdldElER2VuZXJhdG9yKCkuYWRkUmVzZXJ2ZWRJRChjb25maWd1cmF0aW9uLmlkKTtcclxuXHJcbiAgICAgICAgZGVidWdMb2coYExvYWRlZCBDdXN0b21WYXJpYWJsZUluc3RhbmNlICR7dGhpcy5nZXRJRCgpfS5gKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0SUQoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbi5pZDtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0RnVsbE5hbWUoKSB7XHJcbiAgICAgICAgcmV0dXJuIGB7eyR7dGhpcy5nZXRQcmVmaXhlZE5hbWUoKX19fWA7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBBZGRzIGFuIHVuZGVyc2NvcmUgaW4gZnJvbnQgb2YgdGhlIG5hbWUuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXRQcmVmaXhlZE5hbWUoKSB7XHJcbiAgICAgICAgcmV0dXJuIFwiX1wiICsgdGhpcy5jb25maWd1cmF0aW9uLm5hbWU7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldFRpdGxlKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0RnVsbE5hbWUoKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0Q3VzdG9tVmFyaWFibGUoKTogQ3VzdG9tVmFyaWFibGUge1xyXG4gICAgICAgIGlmICghdGhpcy5jdXN0b21fdmFyaWFibGUpIHtcclxuICAgICAgICAgICAgZGVidWdMb2coYEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UgJHt0aGlzLmdldElEKCl9OiBDYW5ub3QgZmluZCBhIEN1c3RvbVZhcmlhYmxlLiBNYXliZSBpdCdzIG5vdCBsb2FkZWQ/YCk7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzLmNvbnN0cnVjdG9yLm5hbWUgKyBcIi5nZXRWYXJpYWJsZSgpOiBDYW5ub3QgZmluZCBhIEN1c3RvbVZhcmlhYmxlLiBNYXliZSBpdCdzIG5vdCBsb2FkZWQ/XCIpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdGhpcy5jdXN0b21fdmFyaWFibGU7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGNyZWF0ZUN1c3RvbVZhcmlhYmxlKCk6IEN1c3RvbVZhcmlhYmxlIHtcclxuICAgICAgICBkZWJ1Z0xvZyhgQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSAke3RoaXMuZ2V0SUQoKX06IENyZWF0aW5nIGFuIG9wZXJhdGlvbmFsIEN1c3RvbVZhcmlhYmxlLmApO1xyXG4gICAgICAgIHRoaXMuY3VzdG9tX3ZhcmlhYmxlID0gbmV3IEN1c3RvbVZhcmlhYmxlKHRoaXMubW9kZWwucGx1Z2luLCB0aGlzKTtcclxuICAgICAgICB0aGlzLmN1c3RvbV92YXJpYWJsZS5vbkNoYW5nZShhc3luYyAoKSA9PiBhd2FpdCB0aGlzLm1vZGVsLnBsdWdpbi51cGRhdGVDdXN0b21WYXJpYWJsZVZpZXdzKCkpO1xyXG4gICAgICAgIHJldHVybiB0aGlzLmN1c3RvbV92YXJpYWJsZTtcclxuICAgIH1cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtTQ19FdmVudH0gZnJvbSBcIi4vU0NfRXZlbnRcIjtcclxuaW1wb3J0IHtUU2hlbGxDb21tYW5kfSBmcm9tIFwiLi4vVFNoZWxsQ29tbWFuZFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNDX0V2ZW50X29uTGF5b3V0UmVhZHkgZXh0ZW5kcyBTQ19FdmVudCB7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X2NvZGUgPSBcIm9uLWxheW91dC1yZWFkeVwiO1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF90aXRsZSA9IFwiT2JzaWRpYW4gc3RhcnRzXCI7XHJcbiAgICBwcm90ZWN0ZWQgcmVnaXN0ZXJfYWZ0ZXJfY2hhbmdpbmdfc2V0dGluZ3MgPSBmYWxzZTtcclxuXHJcbiAgICBwcm90ZWN0ZWQgX3JlZ2lzdGVyKHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCkge1xyXG4gICAgICAgIHRoaXMuYXBwLndvcmtzcGFjZS5vbkxheW91dFJlYWR5KGFzeW5jICgpID0+IGF3YWl0IHRoaXMudHJpZ2dlcih0X3NoZWxsX2NvbW1hbmQpKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7IC8vIFRoZSBiYXNlIGNsYXNzIGRvZXMgbm90IG5lZWQgdG8gcmVnaXN0ZXIgYW55dGhpbmcuXHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIF91bnJlZ2lzdGVyKHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCk6IHZvaWQge1xyXG4gICAgICAgIC8vIE5vIG5lZWQgdG8gdW5yZWdpc3RlciwgYmVjYXVzZSB0aGlzIGV2ZW50IGhhcHBlbnMgb25seSBvbmNlIHdoZW4gT2JzaWRpYW4gc3RhcnRzLiBJZiB0aGUgZXZlbnQgaXMgbm90IGVuYWJsZWQgZm9yIGEgc2hlbGwgY29tbWFuZCwgbmV4dCB0aW1lIE9ic2lkaWFuIHN0YXJ0cywgdGhpcyBldmVudCB3b24ndCBnZXQgcmVnaXN0ZXJlZC5cclxuICAgIH1cclxuXHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U0NfV29ya3NwYWNlRXZlbnR9IGZyb20gXCIuL1NDX1dvcmtzcGFjZUV2ZW50XCI7XHJcblxyXG5leHBvcnQgY2xhc3MgU0NfRXZlbnRfb25RdWl0IGV4dGVuZHMgU0NfV29ya3NwYWNlRXZlbnQge1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF9jb2RlID0gXCJvbi1xdWl0XCI7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X3RpdGxlID0gXCJPYnNpZGlhbiBxdWl0c1wiO1xyXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHdvcmtzcGFjZV9ldmVudCA9IFwicXVpdFwiO1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX1dvcmtzcGFjZUV2ZW50fSBmcm9tIFwiLi9TQ19Xb3Jrc3BhY2VFdmVudFwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFNDX0V2ZW50X29uQWN0aXZlTGVhZkNoYW5nZWQgZXh0ZW5kcyBTQ19Xb3Jrc3BhY2VFdmVudCB7XHJcbiAgICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IGV2ZW50X2NvZGUgPSBcIm9uLWFjdGl2ZS1sZWFmLWNoYW5nZWRcIjtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgZXZlbnRfdGl0bGUgPSBcIlN3aXRjaGluZyB0aGUgYWN0aXZlIHBhbmVcIjtcclxuICAgIHByb3RlY3RlZCByZWFkb25seSB3b3Jrc3BhY2VfZXZlbnQgPSBcImFjdGl2ZS1sZWFmLWNoYW5nZVwiO1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX0V2ZW50fSBmcm9tIFwiLi9TQ19FdmVudFwiO1xyXG5pbXBvcnQge1RTaGVsbENvbW1hbmR9IGZyb20gXCIuLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRDb25maWd1cmF0aW9ufSBmcm9tIFwiLi9TQ19FdmVudENvbmZpZ3VyYXRpb25cIjtcclxuaW1wb3J0IHtOb3RpY2UsIFNldHRpbmd9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5cclxuXHJcbmV4cG9ydCBjbGFzcyBTQ19FdmVudF9FdmVyeU5TZWNvbmRzIGV4dGVuZHMgU0NfRXZlbnQge1xyXG4gICAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBldmVudF9jb2RlID0gXCJldmVyeS1uLXNlY29uZHNcIjtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgZXZlbnRfdGl0bGUgPSBcIkV2ZXJ5IG4gc2Vjb25kc1wiO1xyXG4gICAgcHJvdGVjdGVkIGRlZmF1bHRfY29uZmlndXJhdGlvbjogQ29uZmlndXJhdGlvbiA9IHtcclxuICAgICAgICBlbmFibGVkOiBmYWxzZSxcclxuICAgICAgICBzZWNvbmRzOiA2MCxcclxuICAgIH07XHJcbiAgICBwcml2YXRlIGludGVydmFsc19pZHM6IHtcclxuICAgICAgICBba2V5OiBzdHJpbmddOiBudW1iZXI7IC8vIGtleTogVFNoZWxsQ29tbWFuZCBpZCwgdmFsdWU6IHNldEludGVydmFsKCkgaWQuXHJcbiAgICB9ID0ge307XHJcblxyXG4gICAgcHJvdGVjdGVkIF9yZWdpc3Rlcih0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQpIHtcclxuICAgICAgICBjb25zdCBtaWxsaXNlY29uZHM6IG51bWJlciA9IHRoaXMuZ2V0Q29uZmlndXJhdGlvbih0X3NoZWxsX2NvbW1hbmQpLnNlY29uZHMgKiAxMDAwO1xyXG4gICAgICAgIGNvbnN0IGludGVydmFsX2lkOiBudW1iZXIgPSB3aW5kb3cuc2V0SW50ZXJ2YWwoXHJcbiAgICAgICAgICAgIGFzeW5jICgpID0+IGF3YWl0IHRoaXMudHJpZ2dlcih0X3NoZWxsX2NvbW1hbmQpLFxyXG4gICAgICAgICAgICBtaWxsaXNlY29uZHMsXHJcbiAgICAgICAgKTtcclxuICAgICAgICB0aGlzLnBsdWdpbi5yZWdpc3RlckludGVydmFsKGludGVydmFsX2lkKTtcclxuICAgICAgICB0aGlzLmludGVydmFsc19pZHNbdF9zaGVsbF9jb21tYW5kLmdldElkKCldID0gaW50ZXJ2YWxfaWQ7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlOyAvLyBUaGUgYmFzZSBjbGFzcyBkb2VzIG5vdCBuZWVkIHRvIHJlZ2lzdGVyIGFueXRoaW5nLlxyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBfdW5yZWdpc3Rlcih0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQpOiB2b2lkIHtcclxuICAgICAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbCh0aGlzLmludGVydmFsc19pZHNbdF9zaGVsbF9jb21tYW5kLmdldElkKCldKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIE92ZXJyaWRkZW4gb25seSB0byBjaGFuZ2UgdGhlIHJldHVybiB0eXBlLlxyXG4gICAgICogQHBhcmFtIHRfc2hlbGxfY29tbWFuZFxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgZ2V0Q29uZmlndXJhdGlvbih0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQpOiBDb25maWd1cmF0aW9uIHtcclxuICAgICAgICByZXR1cm4gc3VwZXIuZ2V0Q29uZmlndXJhdGlvbih0X3NoZWxsX2NvbW1hbmQpIGFzIENvbmZpZ3VyYXRpb247XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGNyZWF0ZUV4dHJhU2V0dGluZ3NGaWVsZHMoZXh0cmFfc2V0dGluZ3NfY29udGFpbmVyOiBIVE1MRGl2RWxlbWVudCwgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKTogdm9pZCB7XHJcbiAgICAgICAgY29uc3QgY29uZmlndXJhdGlvbjogQ29uZmlndXJhdGlvbiA9IHRoaXMuZ2V0Q29uZmlndXJhdGlvbih0X3NoZWxsX2NvbW1hbmQpO1xyXG4gICAgICAgIGxldCBhcHBseV9zZWNvbmRzOiBudW1iZXI7XHJcbiAgICAgICAgbmV3IFNldHRpbmcoZXh0cmFfc2V0dGluZ3NfY29udGFpbmVyKVxyXG4gICAgICAgICAgICAuc2V0TmFtZShcIlNlY29uZHNcIilcclxuICAgICAgICAgICAgLnNldERlc2MoXCJOZWVkcyB0byBiZSBhdCBsZWFzdCAxLiBDdXJyZW50bHkgc3VwcG9ydHMgb25seSBpbnRlZ2Vycy5cIilcclxuICAgICAgICAgICAgLmFkZFRleHQodGV4dCA9PiB0ZXh0XHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUoY29uZmlndXJhdGlvbi5zZWNvbmRzLnRvU3RyaW5nKCkpXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoKHJhd192YWx1ZTogc3RyaW5nKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgYXBwbHlfc2Vjb25kcyA9IHBhcnNlSW50KHJhd192YWx1ZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gRG9uJ3Qgc2F2ZSBoZXJlLCBiZWNhdXNlIHRoZSB1c2VyIG1pZ2h0IHN0aWxsIGJlIGVkaXRpbmcgdGhlIG51bWJlci5cclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgICAgIC5hZGRCdXR0b24oYnV0dG9uID0+IGJ1dHRvblxyXG4gICAgICAgICAgICAgICAgLnNldEJ1dHRvblRleHQoXCJBcHBseVwiKVxyXG4gICAgICAgICAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICh1bmRlZmluZWQgPT0gYXBwbHlfc2Vjb25kcyB8fCBhcHBseV9zZWNvbmRzID09PSB0aGlzLmdldENvbmZpZ3VyYXRpb24odF9zaGVsbF9jb21tYW5kKS5zZWNvbmRzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBOb3RpY2UoXCJZb3UgZGlkbid0IGNoYW5nZSB0aGUgc2Vjb25kcyFcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChpc05hTihhcHBseV9zZWNvbmRzKSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBuZXcgTm90aWNlKFwiVGhlIHNlY29uZHMgbmVlZCB0byBiZSBhbiBpbnRlZ2VyIVwiKTtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGFwcGx5X3NlY29uZHMgPD0gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBuZXcgTm90aWNlKFwiVGhlIHNlY29uZHMgbmVlZCB0byBiZSBhdCBsZWFzdCAxIVwiKTtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBBbGwgb2ssIHNhdmUuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZ2V0Q29uZmlndXJhdGlvbih0X3NoZWxsX2NvbW1hbmQpLnNlY29uZHMgPSBhcHBseV9zZWNvbmRzO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlLXJlZ2lzdGVyIHRvIGFwcGx5IHRoZSBjaGFuZ2VcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy51bnJlZ2lzdGVyKHRfc2hlbGxfY29tbWFuZCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVnaXN0ZXIodF9zaGVsbF9jb21tYW5kKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIERvbmVcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5ub3RpY2VBYm91dEVuYWJsaW5nKHRfc2hlbGxfY29tbWFuZCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbkFmdGVyRW5hYmxpbmcodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5ub3RpY2VBYm91dEVuYWJsaW5nKHRfc2hlbGxfY29tbWFuZCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBub3RpY2VBYm91dEVuYWJsaW5nKHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCkge1xyXG4gICAgICAgIG5ldyBOb3RpY2UoXCJUaGUgc2hlbGwgY29tbWFuZCB3aWxsIHJ1biBldmVyeSBcIiArIHRoaXMuZ2V0Q29uZmlndXJhdGlvbih0X3NoZWxsX2NvbW1hbmQpLnNlY29uZHMgKyBcIiBzZWNvbmRzXCIpO1xyXG4gICAgfVxyXG59XHJcblxyXG5pbnRlcmZhY2UgQ29uZmlndXJhdGlvbiBleHRlbmRzIFNDX0V2ZW50Q29uZmlndXJhdGlvbiB7XHJcbiAgICBzZWNvbmRzOiBudW1iZXIsXHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7VFNoZWxsQ29tbWFuZH0gZnJvbSBcIi4uL1RTaGVsbENvbW1hbmRcIjtcclxuaW1wb3J0IHtFZGl0b3IsIE1hcmtkb3duVmlldywgTWVudX0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7U0NfTWVudUV2ZW50fSBmcm9tIFwiLi9TQ19NZW51RXZlbnRcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBTQ19FdmVudF9FZGl0b3JNZW51IGV4dGVuZHMgU0NfTWVudUV2ZW50IHtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgZXZlbnRfY29kZSA9IFwiZWRpdG9yLW1lbnVcIjtcclxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgZXZlbnRfdGl0bGUgPSBcIkVkaXRvciBtZW51XCI7XHJcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgd29ya3NwYWNlX2V2ZW50ID0gXCJlZGl0b3ItbWVudVwiO1xyXG5cclxuICAgIHByb3RlY3RlZCBnZXRUcmlnZ2VyKHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCkge1xyXG4gICAgICAgIHJldHVybiBhc3luYyAobWVudTogTWVudSwgZWRpdG9yOiBFZGl0b3IsIHZpZXc6IE1hcmtkb3duVmlldykgPT4ge1xyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLmFkZFRTaGVsbENvbW1hbmRUb01lbnUodF9zaGVsbF9jb21tYW5kLCBtZW51KTtcclxuICAgICAgICB9O1xyXG4gICAgfVxyXG5cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi4vbWFpblwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X29uTGF5b3V0UmVhZHl9IGZyb20gXCIuL1NDX0V2ZW50X29uTGF5b3V0UmVhZHlcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9vblF1aXR9IGZyb20gXCIuL1NDX0V2ZW50X29uUXVpdFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X29uQWN0aXZlTGVhZkNoYW5nZWR9IGZyb20gXCIuL1NDX0V2ZW50X29uQWN0aXZlTGVhZkNoYW5nZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9FdmVyeU5TZWNvbmRzfSBmcm9tIFwiLi9TQ19FdmVudF9FdmVyeU5TZWNvbmRzXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZU1lbnV9IGZyb20gXCIuL1NDX0V2ZW50X0ZpbGVNZW51XCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRm9sZGVyTWVudX0gZnJvbSBcIi4vU0NfRXZlbnRfRm9sZGVyTWVudVwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0VkaXRvck1lbnV9IGZyb20gXCIuL1NDX0V2ZW50X0VkaXRvck1lbnVcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlQ3JlYXRlZH0gZnJvbSBcIi4vU0NfRXZlbnRfRmlsZUNyZWF0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlRGVsZXRlZH0gZnJvbSBcIi4vU0NfRXZlbnRfRmlsZURlbGV0ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkfSBmcm9tIFwiLi9TQ19FdmVudF9GaWxlQ29udGVudE1vZGlmaWVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRmlsZU1vdmVkfSBmcm9tIFwiLi9TQ19FdmVudF9GaWxlTW92ZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9GaWxlUmVuYW1lZH0gZnJvbSBcIi4vU0NfRXZlbnRfRmlsZVJlbmFtZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudF9Gb2xkZXJDcmVhdGVkfSBmcm9tIFwiLi9TQ19FdmVudF9Gb2xkZXJDcmVhdGVkXCI7XHJcbmltcG9ydCB7U0NfRXZlbnRfRm9sZGVyRGVsZXRlZH0gZnJvbSBcIi4vU0NfRXZlbnRfRm9sZGVyRGVsZXRlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZvbGRlck1vdmVkfSBmcm9tIFwiLi9TQ19FdmVudF9Gb2xkZXJNb3ZlZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50X0ZvbGRlclJlbmFtZWR9IGZyb20gXCIuL1NDX0V2ZW50X0ZvbGRlclJlbmFtZWRcIjtcclxuaW1wb3J0IHtTQ19FdmVudH0gZnJvbSBcIi4vU0NfRXZlbnRcIjtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRTQ19FdmVudHMocGx1Z2luOiBTQ19QbHVnaW4pIHtcclxuICAgIGlmIChldmVudExpc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgLy8gQ2FjaGUgdGhlIGxpc3Qgb2YgU0NfRXZlbnQgb2JqZWN0c1xyXG4gICAgICAgIGV2ZW50TGlzdC5wdXNoKFxyXG4gICAgICAgICAgICBuZXcgU0NfRXZlbnRfb25MYXlvdXRSZWFkeShwbHVnaW4pLFxyXG4gICAgICAgICAgICBuZXcgU0NfRXZlbnRfb25RdWl0KHBsdWdpbiksXHJcbiAgICAgICAgICAgIG5ldyBTQ19FdmVudF9vbkFjdGl2ZUxlYWZDaGFuZ2VkKHBsdWdpbiksXHJcbiAgICAgICAgICAgIG5ldyBTQ19FdmVudF9FdmVyeU5TZWNvbmRzKHBsdWdpbiksXHJcbiAgICAgICAgICAgIG5ldyBTQ19FdmVudF9GaWxlTWVudShwbHVnaW4pLFxyXG4gICAgICAgICAgICBuZXcgU0NfRXZlbnRfRm9sZGVyTWVudShwbHVnaW4pLFxyXG4gICAgICAgICAgICBuZXcgU0NfRXZlbnRfRWRpdG9yTWVudShwbHVnaW4pLFxyXG4gICAgICAgICAgICBuZXcgU0NfRXZlbnRfRmlsZUNvbnRlbnRNb2RpZmllZChwbHVnaW4pLFxyXG4gICAgICAgICAgICBuZXcgU0NfRXZlbnRfRmlsZUNyZWF0ZWQocGx1Z2luKSxcclxuICAgICAgICAgICAgbmV3IFNDX0V2ZW50X0ZpbGVEZWxldGVkKHBsdWdpbiksXHJcbiAgICAgICAgICAgIG5ldyBTQ19FdmVudF9GaWxlTW92ZWQocGx1Z2luKSxcclxuICAgICAgICAgICAgbmV3IFNDX0V2ZW50X0ZpbGVSZW5hbWVkKHBsdWdpbiksXHJcbiAgICAgICAgICAgIG5ldyBTQ19FdmVudF9Gb2xkZXJDcmVhdGVkKHBsdWdpbiksXHJcbiAgICAgICAgICAgIG5ldyBTQ19FdmVudF9Gb2xkZXJEZWxldGVkKHBsdWdpbiksXHJcbiAgICAgICAgICAgIG5ldyBTQ19FdmVudF9Gb2xkZXJNb3ZlZChwbHVnaW4pLFxyXG4gICAgICAgICAgICBuZXcgU0NfRXZlbnRfRm9sZGVyUmVuYW1lZChwbHVnaW4pLFxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZXZlbnRMaXN0O1xyXG59XHJcbmNvbnN0IGV2ZW50TGlzdDogU0NfRXZlbnRbXSA9IFtdO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFNDX0V2ZW50KHBsdWdpbjogU0NfUGx1Z2luLCBzY19ldmVudF9jbGFzczogdHlwZW9mIFNDX0V2ZW50KTogU0NfRXZlbnQgfCB1bmRlZmluZWQge1xyXG4gICAgbGV0IGZvdW5kX3NjX2V2ZW50OiBTQ19FdmVudCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcclxuICAgIGdldFNDX0V2ZW50cyhwbHVnaW4pLmZvckVhY2goKHNjX2V2ZW50OiBTQ19FdmVudCkgPT4ge1xyXG4gICAgICAgIGlmIChzY19ldmVudCBpbnN0YW5jZW9mIHNjX2V2ZW50X2NsYXNzKSB7XHJcbiAgICAgICAgICAgIGZvdW5kX3NjX2V2ZW50ID0gc2NfZXZlbnQ7XHJcbiAgICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICByZXR1cm4gZm91bmRfc2NfZXZlbnQ7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7c2V0SWNvbn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7dW5pcXVlQXJyYXl9IGZyb20gXCIuL0NvbW1vblwiO1xyXG5cclxuLyoqXHJcbiAqIEEgd3JhcHBlciBmb3IgT2JzaWRpYW4ncyBzZXRJY29uKCksIGJ1dCB3aXRoIHRoZSBkaWZmZXJlbmNlIHRoYXQgdGhpcyBvbmUgZG9lcyBub3QgbmVlZCBhIGNvbnRhaW5lciBhcyBhIHBhcmFtZXRlci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRJY29uSFRNTChpY29uX2lkOiBzdHJpbmcpIHtcclxuICAgIGlmICghaWNvbl9pZCkge1xyXG4gICAgICAgIHJldHVybiBcIlwiO1xyXG4gICAgfVxyXG4gICAgY29uc3QgaWNvbl9jb250YWluZXIgPSBkb2N1bWVudC5ib2R5LmNyZWF0ZUVsKFwiZGl2XCIpOyAvLyBBIHRlbXBvcmFyeSBlbGVtZW50LCB3aWxsIGJlIGRlbGV0ZWQgc29vbi4gTm90IG5pY2UgdG8gY3JlYXRlIGEgdGVtcG9yYXJ5IGVsZW1lbnQgaW4gdGhlIGJvZHksIGJ1dCBJIGRvbid0IGtub3cgYW55IGJldHRlciB3YXkuXHJcbiAgICBzZXRJY29uKGljb25fY29udGFpbmVyLCBpY29uX2lkKTtcclxuICAgIGNvbnN0IGljb25faHRtbCA9IGljb25fY29udGFpbmVyLmlubmVySFRNTDtcclxuICAgIGljb25fY29udGFpbmVyLnJlbW92ZSgpO1xyXG4gICAgcmV0dXJuIGljb25faHRtbDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEBhdXRob3IgVGhlIGxpc3QgaXMgcHJvdmlkZWQgYnkgcGhpYnIwLlxyXG4gKiBAbGluayBodHRwczovL2Rpc2NvcmQuY29tL2NoYW5uZWxzLzY4NjA1MzcwODI2MTIyODU3Ny84NDAyODYyNjQ5NjQwMjIzMDIvOTY4MjQ4NTg4NjQxNjY1MDc1XHJcbiAqIEBkZXNjcmlwdGlvbiBwaGlicjA6IFwiVXBkYXRlZCBJY29uIExpc3QgZm9yIE9ic2lkaWFuIHYwLjE0LjcrIChsdWNpZGUgaWNvbnMgdjAuMzAuMCArIG9ic2lkaWFucyBvd24pXCJcclxuICogQGNvcHlyaWdodCBUaGUgY29weXJpZ2h0IHN0YXRlbWVudCBhdCB0aGUgdG9wIG9mIHRoaXMgZmlsZSBkb2VzIG5vdCBhZmZlY3QgdGhpcyBsaXN0IG9mIGljb25zLlxyXG4gKiBUT0RPOiBUaGUgbGlzdCBzZWVtcyB0byBtaXNzIHNvbWUgaWNvbnMsIGF0IGxlYXN0ICdnZWFyJy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBJQ09OX0xJU1QgPSBbXCJhY3Rpdml0eVwiLFwiYWlycGxheVwiLFwiYWxhcm0tY2hlY2tcIixcImFsYXJtLWNsb2NrLW9mZlwiLFwiYWxhcm0tY2xvY2tcIixcImFsYXJtLW1pbnVzXCIsXCJhbGFybS1wbHVzXCIsXCJhbGJ1bVwiLFwiYWxlcnQtY2lyY2xlXCIsXCJhbGVydC1vY3RhZ29uXCIsXCJhbGVydC10cmlhbmdsZVwiLFwiYWxpZ24tY2VudGVyLWhvcml6b250YWxcIixcImFsaWduLWNlbnRlci12ZXJ0aWNhbFwiLFwiYWxpZ24tY2VudGVyXCIsXCJhbGlnbi1lbmQtaG9yaXpvbnRhbFwiLFwiYWxpZ24tZW5kLXZlcnRpY2FsXCIsXCJhbGlnbi1ob3Jpem9udGFsLWRpc3RyaWJ1dGUtY2VudGVyXCIsXCJhbGlnbi1ob3Jpem9udGFsLWRpc3RyaWJ1dGUtZW5kXCIsXCJhbGlnbi1ob3Jpem9udGFsLWRpc3RyaWJ1dGUtc3RhcnRcIixcImFsaWduLWhvcml6b250YWwtanVzdGlmeS1jZW50ZXJcIixcImFsaWduLWhvcml6b250YWwtanVzdGlmeS1lbmRcIixcImFsaWduLWhvcml6b250YWwtanVzdGlmeS1zdGFydFwiLFwiYWxpZ24taG9yaXpvbnRhbC1zcGFjZS1hcm91bmRcIixcImFsaWduLWhvcml6b250YWwtc3BhY2UtYmV0d2VlblwiLFwiYWxpZ24tanVzdGlmeVwiLFwiYWxpZ24tbGVmdFwiLFwiYWxpZ24tcmlnaHRcIixcImFsaWduLXN0YXJ0LWhvcml6b250YWxcIixcImFsaWduLXN0YXJ0LXZlcnRpY2FsXCIsXCJhbGlnbi12ZXJ0aWNhbC1kaXN0cmlidXRlLWNlbnRlclwiLFwiYWxpZ24tdmVydGljYWwtZGlzdHJpYnV0ZS1lbmRcIixcImFsaWduLXZlcnRpY2FsLWRpc3RyaWJ1dGUtc3RhcnRcIixcImFsaWduLXZlcnRpY2FsLWp1c3RpZnktY2VudGVyXCIsXCJhbGlnbi12ZXJ0aWNhbC1qdXN0aWZ5LWVuZFwiLFwiYWxpZ24tdmVydGljYWwtanVzdGlmeS1zdGFydFwiLFwiYWxpZ24tdmVydGljYWwtc3BhY2UtYXJvdW5kXCIsXCJhbGlnbi12ZXJ0aWNhbC1zcGFjZS1iZXR3ZWVuXCIsXCJhbmNob3JcIixcImFwZXJ0dXJlXCIsXCJhcmNoaXZlXCIsXCJhcnJvdy1iaWctZG93blwiLFwiYXJyb3ctYmlnLWxlZnRcIixcImFycm93LWJpZy1yaWdodFwiLFwiYXJyb3ctYmlnLXVwXCIsXCJhcnJvdy1kb3duLWNpcmNsZVwiLFwiYXJyb3ctZG93bi1sZWZ0XCIsXCJhcnJvdy1kb3duLXJpZ2h0XCIsXCJhcnJvdy1kb3duXCIsXCJhcnJvdy1sZWZ0LWNpcmNsZVwiLFwiYXJyb3ctbGVmdC1yaWdodFwiLFwiYXJyb3ctbGVmdFwiLFwiYXJyb3ctcmlnaHQtY2lyY2xlXCIsXCJhcnJvdy1yaWdodFwiLFwiYXJyb3ctdXAtY2lyY2xlXCIsXCJhcnJvdy11cC1sZWZ0XCIsXCJhcnJvdy11cC1yaWdodFwiLFwiYXJyb3ctdXBcIixcImFzdGVyaXNrXCIsXCJhdC1zaWduXCIsXCJhd2FyZFwiLFwiYXhlXCIsXCJiYW5rbm90ZVwiLFwiYmFyLWNoYXJ0LTJcIixcImJhci1jaGFydFwiLFwiYmFzZWxpbmVcIixcImJhdHRlcnktY2hhcmdpbmdcIixcImJhdHRlcnktZnVsbFwiLFwiYmF0dGVyeS1sb3dcIixcImJhdHRlcnktbWVkaXVtXCIsXCJiYXR0ZXJ5XCIsXCJiZWFrZXJcIixcImJlbGwtbWludXNcIixcImJlbGwtb2ZmXCIsXCJiZWxsLXBsdXNcIixcImJlbGwtcmluZ1wiLFwiYmVsbFwiLFwiYmlrZVwiLFwiYmluYXJ5XCIsXCJiaXRjb2luXCIsXCJibHVldG9vdGgtY29ubmVjdGVkXCIsXCJibHVldG9vdGgtb2ZmXCIsXCJibHVldG9vdGgtc2VhcmNoaW5nXCIsXCJibHVldG9vdGhcIixcImJvbGRcIixcImJvb2stb3BlblwiLFwiYm9va1wiLFwiYm9va21hcmstbWludXNcIixcImJvb2ttYXJrLXBsdXNcIixcImJvb2ttYXJrXCIsXCJib3RcIixcImJveC1zZWxlY3RcIixcImJveFwiLFwiYnJpZWZjYXNlXCIsXCJicnVzaFwiLFwiYnVnXCIsXCJidWlsZGluZy0yXCIsXCJidWlsZGluZ1wiLFwiYnVzXCIsXCJjYWxjdWxhdG9yXCIsXCJjYWxlbmRhclwiLFwiY2FtZXJhLW9mZlwiLFwiY2FtZXJhXCIsXCJjYXJcIixcImNhcnJvdFwiLFwiY2FzdFwiLFwiY2hlY2stY2lyY2xlLTJcIixcImNoZWNrLWNpcmNsZVwiLFwiY2hlY2stc3F1YXJlXCIsXCJjaGVja1wiLFwiY2hldnJvbi1kb3duXCIsXCJjaGV2cm9uLWZpcnN0XCIsXCJjaGV2cm9uLWxhc3RcIixcImNoZXZyb24tbGVmdFwiLFwiY2hldnJvbi1yaWdodFwiLFwiY2hldnJvbi11cFwiLFwiY2hldnJvbnMtZG93bi11cFwiLFwiY2hldnJvbnMtZG93blwiLFwiY2hldnJvbnMtbGVmdFwiLFwiY2hldnJvbnMtcmlnaHRcIixcImNoZXZyb25zLXVwLWRvd25cIixcImNoZXZyb25zLXVwXCIsXCJjaHJvbWVcIixcImNpcmNsZS1zbGFzaGVkXCIsXCJjaXJjbGVcIixcImNsaXBib2FyZC1jaGVja1wiLFwiY2xpcGJvYXJkLWNvcHlcIixcImNsaXBib2FyZC1saXN0XCIsXCJjbGlwYm9hcmQteFwiLFwiY2xpcGJvYXJkXCIsXCJjbG9jay0xXCIsXCJjbG9jay0xMFwiLFwiY2xvY2stMTFcIixcImNsb2NrLTEyXCIsXCJjbG9jay0yXCIsXCJjbG9jay0zXCIsXCJjbG9jay00XCIsXCJjbG9jay01XCIsXCJjbG9jay02XCIsXCJjbG9jay03XCIsXCJjbG9jay04XCIsXCJjbG9jay05XCIsXCJjbG9ja1wiLFwiY2xvdWQtZHJpenpsZVwiLFwiY2xvdWQtZm9nXCIsXCJjbG91ZC1oYWlsXCIsXCJjbG91ZC1saWdodG5pbmdcIixcImNsb3VkLW1vb25cIixcImNsb3VkLW9mZlwiLFwiY2xvdWQtcmFpbi13aW5kXCIsXCJjbG91ZC1yYWluXCIsXCJjbG91ZC1zbm93XCIsXCJjbG91ZC1zdW5cIixcImNsb3VkXCIsXCJjbG91ZHlcIixcImNsb3ZlclwiLFwiY29kZS0yXCIsXCJjb2RlXCIsXCJjb2RlcGVuXCIsXCJjb2Rlc2FuZGJveFwiLFwiY29mZmVlXCIsXCJjb2luc1wiLFwiY29sdW1uc1wiLFwiY29tbWFuZFwiLFwiY29tcGFzc1wiLFwiY29udGFjdFwiLFwiY29udHJhc3RcIixcImNvb2tpZVwiLFwiY29weVwiLFwiY29weWxlZnRcIixcImNvcHlyaWdodFwiLFwiY29ybmVyLWRvd24tbGVmdFwiLFwiY29ybmVyLWRvd24tcmlnaHRcIixcImNvcm5lci1sZWZ0LWRvd25cIixcImNvcm5lci1sZWZ0LXVwXCIsXCJjb3JuZXItcmlnaHQtZG93blwiLFwiY29ybmVyLXJpZ2h0LXVwXCIsXCJjb3JuZXItdXAtbGVmdFwiLFwiY29ybmVyLXVwLXJpZ2h0XCIsXCJjcHVcIixcImNyZWRpdC1jYXJkXCIsXCJjcm9wXCIsXCJjcm9zc1wiLFwiY3Jvc3NoYWlyXCIsXCJjcm93blwiLFwiY3VycmVuY3lcIixcImRhdGFiYXNlXCIsXCJkZWxldGVcIixcImRpY2UtMVwiLFwiZGljZS0yXCIsXCJkaWNlLTNcIixcImRpY2UtNFwiLFwiZGljZS01XCIsXCJkaWNlLTZcIixcImRpc2NcIixcImRpdmlkZS1jaXJjbGVcIixcImRpdmlkZS1zcXVhcmVcIixcImRpdmlkZVwiLFwiZG9sbGFyLXNpZ25cIixcImRvd25sb2FkLWNsb3VkXCIsXCJkb3dubG9hZFwiLFwiZHJpYmJibGVcIixcImRyb3BsZXRcIixcImRyb3BsZXRzXCIsXCJkcnVtc3RpY2tcIixcImVkaXQtMlwiLFwiZWRpdC0zXCIsXCJlZGl0XCIsXCJlZ2dcIixcImVxdWFsLW5vdFwiLFwiZXF1YWxcIixcImVyYXNlclwiLFwiZXVyb1wiLFwiZXhwYW5kXCIsXCJleHRlcm5hbC1saW5rXCIsXCJleWUtb2ZmXCIsXCJleWVcIixcImZhY2Vib29rXCIsXCJmYXN0LWZvcndhcmRcIixcImZlYXRoZXJcIixcImZpZ21hXCIsXCJmaWxlLWNoZWNrLTJcIixcImZpbGUtY2hlY2tcIixcImZpbGUtY29kZVwiLFwiZmlsZS1kaWdpdFwiLFwiZmlsZS1pbnB1dFwiLFwiZmlsZS1taW51cy0yXCIsXCJmaWxlLW1pbnVzXCIsXCJmaWxlLW91dHB1dFwiLFwiZmlsZS1wbHVzLTJcIixcImZpbGUtcGx1c1wiLFwiZmlsZS1zZWFyY2hcIixcImZpbGUtdGV4dFwiLFwiZmlsZS14LTJcIixcImZpbGUteFwiLFwiZmlsZVwiLFwiZmlsZXNcIixcImZpbG1cIixcImZpbHRlclwiLFwiZmxhZy1vZmZcIixcImZsYWctdHJpYW5nbGUtbGVmdFwiLFwiZmxhZy10cmlhbmdsZS1yaWdodFwiLFwiZmxhZ1wiLFwiZmxhbWVcIixcImZsYXNobGlnaHQtb2ZmXCIsXCJmbGFzaGxpZ2h0XCIsXCJmbGFzay1jb25pY2FsXCIsXCJmbGFzay1yb3VuZFwiLFwiZm9sZGVyLW1pbnVzXCIsXCJmb2xkZXItb3BlblwiLFwiZm9sZGVyLXBsdXNcIixcImZvbGRlclwiLFwiZm9ybS1pbnB1dFwiLFwiZm9yd2FyZFwiLFwiZnJhbWVcIixcImZyYW1lclwiLFwiZnJvd25cIixcImZ1bmN0aW9uLXNxdWFyZVwiLFwiZ2FtZXBhZC0yXCIsXCJnYW1lcGFkXCIsXCJnYXVnZVwiLFwiZ2F2ZWxcIixcImdlbVwiLFwiZ2hvc3RcIixcImdpZnRcIixcImdpdC1icmFuY2gtcGx1c1wiLFwiZ2l0LWJyYW5jaFwiLFwiZ2l0LWNvbW1pdFwiLFwiZ2l0LWZvcmtcIixcImdpdC1tZXJnZVwiLFwiZ2l0LXB1bGwtcmVxdWVzdFwiLFwiZ2l0aHViXCIsXCJnaXRsYWJcIixcImdsYXNzZXNcIixcImdsb2JlLTJcIixcImdsb2JlXCIsXCJncmFiXCIsXCJncmFkdWF0aW9uLWNhcFwiLFwiZ3JpZFwiLFwiZ3JpcC1ob3Jpem9udGFsXCIsXCJncmlwLXZlcnRpY2FsXCIsXCJoYW1tZXJcIixcImhhbmQtbWV0YWxcIixcImhhbmRcIixcImhhcmQtZHJpdmVcIixcImhhcmQtaGF0XCIsXCJoYXNoXCIsXCJoYXplXCIsXCJoZWFkcGhvbmVzXCIsXCJoZWFydFwiLFwiaGVscC1jaXJjbGVcIixcImhleGFnb25cIixcImhpZ2hsaWdodGVyXCIsXCJoaXN0b3J5XCIsXCJob21lXCIsXCJpbWFnZS1taW51c1wiLFwiaW1hZ2Utb2ZmXCIsXCJpbWFnZS1wbHVzXCIsXCJpbWFnZVwiLFwiaW1wb3J0XCIsXCJpbmJveFwiLFwiaW5kZW50XCIsXCJpbmRpYW4tcnVwZWVcIixcImluZmluaXR5XCIsXCJpbmZvXCIsXCJpbnNwZWN0XCIsXCJpbnN0YWdyYW1cIixcIml0YWxpY1wiLFwiamFwYW5lc2UteWVuXCIsXCJrZXlcIixcImtleWJvYXJkXCIsXCJsYW5kbWFya1wiLFwibGFuZ3VhZ2VzXCIsXCJsYXB0b3AtMlwiLFwibGFwdG9wXCIsXCJsYXNzby1zZWxlY3RcIixcImxhc3NvXCIsXCJsYXllcnNcIixcImxheW91dC1kYXNoYm9hcmRcIixcImxheW91dC1ncmlkXCIsXCJsYXlvdXQtbGlzdFwiLFwibGF5b3V0LXRlbXBsYXRlXCIsXCJsYXlvdXRcIixcImxpYnJhcnlcIixcImxpZmUtYnVveVwiLFwibGlnaHRidWxiLW9mZlwiLFwibGlnaHRidWxiXCIsXCJsaW5rLTItb2ZmXCIsXCJsaW5rLTJcIixcImxpbmtcIixcImxpbmtlZGluXCIsXCJsaXN0LWNoZWNrc1wiLFwibGlzdC1taW51c1wiLFwibGlzdC1vcmRlcmVkXCIsXCJsaXN0LXBsdXNcIixcImxpc3QteFwiLFwibGlzdFwiLFwibG9hZGVyLTJcIixcImxvYWRlclwiLFwibG9jYXRlLWZpeGVkXCIsXCJsb2NhdGUtb2ZmXCIsXCJsb2NhdGVcIixcImxvY2tcIixcImxvZy1pblwiLFwibG9nLW91dFwiLFwibWFpbFwiLFwibWFwLXBpblwiLFwibWFwXCIsXCJtYXhpbWl6ZS0yXCIsXCJtYXhpbWl6ZVwiLFwibWVnYXBob25lXCIsXCJtZWhcIixcIm1lbnVcIixcIm1lc3NhZ2UtY2lyY2xlXCIsXCJtZXNzYWdlLXNxdWFyZVwiLFwibWljLW9mZlwiLFwibWljXCIsXCJtaW5pbWl6ZS0yXCIsXCJtaW5pbWl6ZVwiLFwibWludXMtY2lyY2xlXCIsXCJtaW51cy1zcXVhcmVcIixcIm1pbnVzXCIsXCJtb25pdG9yLW9mZlwiLFwibW9uaXRvci1zcGVha2VyXCIsXCJtb25pdG9yXCIsXCJtb29uXCIsXCJtb3JlLWhvcml6b250YWxcIixcIm1vcmUtdmVydGljYWxcIixcIm1vdW50YWluLXNub3dcIixcIm1vdW50YWluXCIsXCJtb3VzZS1wb2ludGVyLTJcIixcIm1vdXNlLXBvaW50ZXItY2xpY2tcIixcIm1vdXNlLXBvaW50ZXJcIixcIm1vdXNlXCIsXCJtb3ZlLWRpYWdvbmFsLTJcIixcIm1vdmUtZGlhZ29uYWxcIixcIm1vdmUtaG9yaXpvbnRhbFwiLFwibW92ZS12ZXJ0aWNhbFwiLFwibW92ZVwiLFwibXVzaWNcIixcIm5hdmlnYXRpb24tMlwiLFwibmF2aWdhdGlvblwiLFwibmV0d29ya1wiLFwib2N0YWdvblwiLFwib3B0aW9uXCIsXCJvdXRkZW50XCIsXCJwYWNrYWdlLWNoZWNrXCIsXCJwYWNrYWdlLW1pbnVzXCIsXCJwYWNrYWdlLXBsdXNcIixcInBhY2thZ2Utc2VhcmNoXCIsXCJwYWNrYWdlLXhcIixcInBhY2thZ2VcIixcInBhbGV0dGVcIixcInBhbG10cmVlXCIsXCJwYXBlcmNsaXBcIixcInBhdXNlLWNpcmNsZVwiLFwicGF1c2Utb2N0YWdvblwiLFwicGF1c2VcIixcInBlbi10b29sXCIsXCJwZW5jaWxcIixcInBlcmNlbnRcIixcInBlcnNvbi1zdGFuZGluZ1wiLFwicGhvbmUtY2FsbFwiLFwicGhvbmUtZm9yd2FyZGVkXCIsXCJwaG9uZS1pbmNvbWluZ1wiLFwicGhvbmUtbWlzc2VkXCIsXCJwaG9uZS1vZmZcIixcInBob25lLW91dGdvaW5nXCIsXCJwaG9uZVwiLFwicGllLWNoYXJ0XCIsXCJwaWdneS1iYW5rXCIsXCJwaW5cIixcInBpcGV0dGVcIixcInBsYW5lXCIsXCJwbGF5LWNpcmNsZVwiLFwicGxheVwiLFwicGx1Zy16YXBcIixcInBsdXMtY2lyY2xlXCIsXCJwbHVzLXNxdWFyZVwiLFwicGx1c1wiLFwicG9ja2V0XCIsXCJwb2RjYXN0XCIsXCJwb2ludGVyXCIsXCJwb3VuZC1zdGVybGluZ1wiLFwicG93ZXItb2ZmXCIsXCJwb3dlclwiLFwicHJpbnRlclwiLFwicXItY29kZVwiLFwicXVvdGVcIixcInJhZGlvLXJlY2VpdmVyXCIsXCJyYWRpb1wiLFwicmVkb1wiLFwicmVmcmVzaC1jY3dcIixcInJlZnJlc2gtY3dcIixcInJlZ2V4XCIsXCJyZXBlYXQtMVwiLFwicmVwZWF0XCIsXCJyZXBseS1hbGxcIixcInJlcGx5XCIsXCJyZXdpbmRcIixcInJvY2tldFwiLFwicm9ja2luZy1jaGFpclwiLFwicm90YXRlLWNjd1wiLFwicm90YXRlLWN3XCIsXCJyc3NcIixcInJ1bGVyXCIsXCJydXNzaWFuLXJ1YmxlXCIsXCJzYXZlXCIsXCJzY2FsZVwiLFwic2Nhbi1saW5lXCIsXCJzY2FuXCIsXCJzY2lzc29yc1wiLFwic2NyZWVuLXNoYXJlLW9mZlwiLFwic2NyZWVuLXNoYXJlXCIsXCJzZWFyY2hcIixcInNlbmRcIixcInNlcGFyYXRvci1ob3Jpem9udGFsXCIsXCJzZXBhcmF0b3ItdmVydGljYWxcIixcInNlcnZlci1jcmFzaFwiLFwic2VydmVyLW9mZlwiLFwic2VydmVyXCIsXCJzZXR0aW5ncy0yXCIsXCJzZXR0aW5nc1wiLFwic2hhcmUtMlwiLFwic2hhcmVcIixcInNoZWV0XCIsXCJzaGllbGQtYWxlcnRcIixcInNoaWVsZC1jaGVja1wiLFwic2hpZWxkLWNsb3NlXCIsXCJzaGllbGQtb2ZmXCIsXCJzaGllbGRcIixcInNoaXJ0XCIsXCJzaG9wcGluZy1iYWdcIixcInNob3BwaW5nLWNhcnRcIixcInNob3ZlbFwiLFwic2hyaW5rXCIsXCJzaHVmZmxlXCIsXCJzaWRlYmFyLWNsb3NlXCIsXCJzaWRlYmFyLW9wZW5cIixcInNpZGViYXJcIixcInNpZ21hXCIsXCJzaWduYWwtaGlnaFwiLFwic2lnbmFsLWxvd1wiLFwic2lnbmFsLW1lZGl1bVwiLFwic2lnbmFsLXplcm9cIixcInNpZ25hbFwiLFwic2tpcC1iYWNrXCIsXCJza2lwLWZvcndhcmRcIixcInNrdWxsXCIsXCJzbGFja1wiLFwic2xhc2hcIixcInNsaWRlcnNcIixcInNtYXJ0cGhvbmUtY2hhcmdpbmdcIixcInNtYXJ0cGhvbmVcIixcInNtaWxlXCIsXCJzbm93Zmxha2VcIixcInNvcnQtYXNjXCIsXCJzb3J0LWRlc2NcIixcInNwZWFrZXJcIixcInNwcm91dFwiLFwic3F1YXJlXCIsXCJzdGFyLWhhbGZcIixcInN0YXJcIixcInN0b3AtY2lyY2xlXCIsXCJzdHJldGNoLWhvcml6b250YWxcIixcInN0cmV0Y2gtdmVydGljYWxcIixcInN0cmlrZXRocm91Z2hcIixcInN1YnNjcmlwdFwiLFwic3VuXCIsXCJzdW5yaXNlXCIsXCJzdW5zZXRcIixcInN1cGVyc2NyaXB0XCIsXCJzd2lzcy1mcmFuY1wiLFwic3dpdGNoLWNhbWVyYVwiLFwidGFibGVcIixcInRhYmxldFwiLFwidGFnXCIsXCJ0YXJnZXRcIixcInRlbnRcIixcInRlcm1pbmFsLXNxdWFyZVwiLFwidGVybWluYWxcIixcInRleHQtY3Vyc29yLWlucHV0XCIsXCJ0ZXh0LWN1cnNvclwiLFwidGhlcm1vbWV0ZXItc25vd2ZsYWtlXCIsXCJ0aGVybW9tZXRlci1zdW5cIixcInRoZXJtb21ldGVyXCIsXCJ0aHVtYnMtZG93blwiLFwidGh1bWJzLXVwXCIsXCJ0aWNrZXRcIixcInRpbWVyLW9mZlwiLFwidGltZXItcmVzZXRcIixcInRpbWVyXCIsXCJ0b2dnbGUtbGVmdFwiLFwidG9nZ2xlLXJpZ2h0XCIsXCJ0b3JuYWRvXCIsXCJ0cmFzaC0yXCIsXCJ0cmFzaFwiLFwidHJlbGxvXCIsXCJ0cmVuZGluZy1kb3duXCIsXCJ0cmVuZGluZy11cFwiLFwidHJpYW5nbGVcIixcInRydWNrXCIsXCJ0di0yXCIsXCJ0dlwiLFwidHdpdGNoXCIsXCJ0d2l0dGVyXCIsXCJ0eXBlXCIsXCJ1bWJyZWxsYVwiLFwidW5kZXJsaW5lXCIsXCJ1bmRvXCIsXCJ1bmxpbmstMlwiLFwidW5saW5rXCIsXCJ1bmxvY2tcIixcInVwbG9hZC1jbG91ZFwiLFwidXBsb2FkXCIsXCJ1c2VyLWNoZWNrXCIsXCJ1c2VyLW1pbnVzXCIsXCJ1c2VyLXBsdXNcIixcInVzZXIteFwiLFwidXNlclwiLFwidXNlcnNcIixcInZlcmlmaWVkXCIsXCJ2aWJyYXRlXCIsXCJ2aWRlby1vZmZcIixcInZpZGVvXCIsXCJ2aWV3XCIsXCJ2b2ljZW1haWxcIixcInZvbHVtZS0xXCIsXCJ2b2x1bWUtMlwiLFwidm9sdW1lLXhcIixcInZvbHVtZVwiLFwid2FsbGV0XCIsXCJ3YW5kXCIsXCJ3YXRjaFwiLFwid2F2ZXNcIixcIndlYmNhbVwiLFwid2lmaS1vZmZcIixcIndpZmlcIixcIndpbmRcIixcIndyYXAtdGV4dFwiLFwid3JlbmNoXCIsXCJ4LWNpcmNsZVwiLFwieC1vY3RhZ29uXCIsXCJ4LXNxdWFyZVwiLFwieFwiLFwieW91dHViZVwiLFwiemFwLW9mZlwiLFwiemFwXCIsXCJ6b29tLWluXCIsXCJ6b29tLW91dFwiLFwic2VhcmNoLWxhcmdlXCIsXCJzZWFyY2hcIixcImFjdGl2aXR5XCIsXCJhaXJwbGF5XCIsXCJhbGFybS1jaGVja1wiLFwiYWxhcm0tY2xvY2stb2ZmXCIsXCJhbGFybS1jbG9ja1wiLFwiYWxhcm0tbWludXNcIixcImFsYXJtLXBsdXNcIixcImFsYnVtXCIsXCJhbGVydC1jaXJjbGVcIixcImFsZXJ0LW9jdGFnb25cIixcImFsZXJ0LXRyaWFuZ2xlXCIsXCJhbGlnbi1jZW50ZXItaG9yaXpvbnRhbFwiLFwiYWxpZ24tY2VudGVyLXZlcnRpY2FsXCIsXCJhbGlnbi1jZW50ZXJcIixcImFsaWduLWVuZC1ob3Jpem9udGFsXCIsXCJhbGlnbi1lbmQtdmVydGljYWxcIixcImFsaWduLWhvcml6b250YWwtZGlzdHJpYnV0ZS1jZW50ZXJcIixcImFsaWduLWhvcml6b250YWwtZGlzdHJpYnV0ZS1lbmRcIixcImFsaWduLWhvcml6b250YWwtZGlzdHJpYnV0ZS1zdGFydFwiLFwiYWxpZ24taG9yaXpvbnRhbC1qdXN0aWZ5LWNlbnRlclwiLFwiYWxpZ24taG9yaXpvbnRhbC1qdXN0aWZ5LWVuZFwiLFwiYWxpZ24taG9yaXpvbnRhbC1qdXN0aWZ5LXN0YXJ0XCIsXCJhbGlnbi1ob3Jpem9udGFsLXNwYWNlLWFyb3VuZFwiLFwiYWxpZ24taG9yaXpvbnRhbC1zcGFjZS1iZXR3ZWVuXCIsXCJhbGlnbi1qdXN0aWZ5XCIsXCJhbGlnbi1sZWZ0XCIsXCJhbGlnbi1yaWdodFwiLFwiYWxpZ24tc3RhcnQtaG9yaXpvbnRhbFwiLFwiYWxpZ24tc3RhcnQtdmVydGljYWxcIixcImFsaWduLXZlcnRpY2FsLWRpc3RyaWJ1dGUtY2VudGVyXCIsXCJhbGlnbi12ZXJ0aWNhbC1kaXN0cmlidXRlLWVuZFwiLFwiYWxpZ24tdmVydGljYWwtZGlzdHJpYnV0ZS1zdGFydFwiLFwiYWxpZ24tdmVydGljYWwtanVzdGlmeS1jZW50ZXJcIixcImFsaWduLXZlcnRpY2FsLWp1c3RpZnktZW5kXCIsXCJhbGlnbi12ZXJ0aWNhbC1qdXN0aWZ5LXN0YXJ0XCIsXCJhbGlnbi12ZXJ0aWNhbC1zcGFjZS1hcm91bmRcIixcImFsaWduLXZlcnRpY2FsLXNwYWNlLWJldHdlZW5cIixcImFuY2hvclwiLFwiYXBlcnR1cmVcIixcImFyY2hpdmVcIixcImFycm93LWJpZy1kb3duXCIsXCJhcnJvdy1iaWctbGVmdFwiLFwiYXJyb3ctYmlnLXJpZ2h0XCIsXCJhcnJvdy1iaWctdXBcIixcImFycm93LWRvd24tY2lyY2xlXCIsXCJhcnJvdy1kb3duLWxlZnRcIixcImFycm93LWRvd24tcmlnaHRcIixcImFycm93LWRvd25cIixcImFycm93LWxlZnQtY2lyY2xlXCIsXCJhcnJvdy1sZWZ0LXJpZ2h0XCIsXCJhcnJvdy1sZWZ0XCIsXCJhcnJvdy1yaWdodC1jaXJjbGVcIixcImFycm93LXJpZ2h0XCIsXCJhcnJvdy11cC1jaXJjbGVcIixcImFycm93LXVwLWxlZnRcIixcImFycm93LXVwLXJpZ2h0XCIsXCJhcnJvdy11cFwiLFwiYXN0ZXJpc2tcIixcImF0LXNpZ25cIixcImF3YXJkXCIsXCJheGVcIixcImJhbmtub3RlXCIsXCJiYXItY2hhcnQtMlwiLFwiYmFyLWNoYXJ0XCIsXCJiYXNlbGluZVwiLFwiYmF0dGVyeS1jaGFyZ2luZ1wiLFwiYmF0dGVyeS1mdWxsXCIsXCJiYXR0ZXJ5LWxvd1wiLFwiYmF0dGVyeS1tZWRpdW1cIixcImJhdHRlcnlcIixcImJlYWtlclwiLFwiYmVsbC1taW51c1wiLFwiYmVsbC1vZmZcIixcImJlbGwtcGx1c1wiLFwiYmVsbC1yaW5nXCIsXCJiZWxsXCIsXCJiaWtlXCIsXCJiaW5hcnlcIixcImJpdGNvaW5cIixcImJsdWV0b290aC1jb25uZWN0ZWRcIixcImJsdWV0b290aC1vZmZcIixcImJsdWV0b290aC1zZWFyY2hpbmdcIixcImJsdWV0b290aFwiLFwiYm9sZFwiLFwiYm9vay1vcGVuXCIsXCJib29rXCIsXCJib29rbWFyay1taW51c1wiLFwiYm9va21hcmstcGx1c1wiLFwiYm9va21hcmtcIixcImJvdFwiLFwiYm94LXNlbGVjdFwiLFwiYm94XCIsXCJicmllZmNhc2VcIixcImJydXNoXCIsXCJidWdcIixcImJ1aWxkaW5nLTJcIixcImJ1aWxkaW5nXCIsXCJidXNcIixcImNhbGN1bGF0b3JcIixcImNhbGVuZGFyXCIsXCJjYW1lcmEtb2ZmXCIsXCJjYW1lcmFcIixcImNhclwiLFwiY2Fycm90XCIsXCJjYXN0XCIsXCJjaGVjay1jaXJjbGUtMlwiLFwiY2hlY2stY2lyY2xlXCIsXCJjaGVjay1zcXVhcmVcIixcImNoZWNrXCIsXCJjaGV2cm9uLWRvd25cIixcImNoZXZyb24tZmlyc3RcIixcImNoZXZyb24tbGFzdFwiLFwiY2hldnJvbi1sZWZ0XCIsXCJjaGV2cm9uLXJpZ2h0XCIsXCJjaGV2cm9uLXVwXCIsXCJjaGV2cm9ucy1kb3duLXVwXCIsXCJjaGV2cm9ucy1kb3duXCIsXCJjaGV2cm9ucy1sZWZ0XCIsXCJjaGV2cm9ucy1yaWdodFwiLFwiY2hldnJvbnMtdXAtZG93blwiLFwiY2hldnJvbnMtdXBcIixcImNocm9tZVwiLFwiY2lyY2xlLXNsYXNoZWRcIixcImNpcmNsZVwiLFwiY2xpcGJvYXJkLWNoZWNrXCIsXCJjbGlwYm9hcmQtY29weVwiLFwiY2xpcGJvYXJkLWxpc3RcIixcImNsaXBib2FyZC14XCIsXCJjbGlwYm9hcmRcIixcImNsb2NrLTFcIixcImNsb2NrLTEwXCIsXCJjbG9jay0xMVwiLFwiY2xvY2stMTJcIixcImNsb2NrLTJcIixcImNsb2NrLTNcIixcImNsb2NrLTRcIixcImNsb2NrLTVcIixcImNsb2NrLTZcIixcImNsb2NrLTdcIixcImNsb2NrLThcIixcImNsb2NrLTlcIixcImx1Y2lkZS1jbG9ja1wiLFwiY2xvdWQtZHJpenpsZVwiLFwiY2xvdWQtZm9nXCIsXCJjbG91ZC1oYWlsXCIsXCJjbG91ZC1saWdodG5pbmdcIixcImNsb3VkLW1vb25cIixcImNsb3VkLW9mZlwiLFwiY2xvdWQtcmFpbi13aW5kXCIsXCJjbG91ZC1yYWluXCIsXCJjbG91ZC1zbm93XCIsXCJjbG91ZC1zdW5cIixcImx1Y2lkZS1jbG91ZFwiLFwiY2xvdWR5XCIsXCJjbG92ZXJcIixcImNvZGUtMlwiLFwiY29kZVwiLFwiY29kZXBlblwiLFwiY29kZXNhbmRib3hcIixcImNvZmZlZVwiLFwiY29pbnNcIixcImNvbHVtbnNcIixcImNvbW1hbmRcIixcImNvbXBhc3NcIixcImNvbnRhY3RcIixcImNvbnRyYXN0XCIsXCJjb29raWVcIixcImNvcHlcIixcImNvcHlsZWZ0XCIsXCJjb3B5cmlnaHRcIixcImNvcm5lci1kb3duLWxlZnRcIixcImNvcm5lci1kb3duLXJpZ2h0XCIsXCJjb3JuZXItbGVmdC1kb3duXCIsXCJjb3JuZXItbGVmdC11cFwiLFwiY29ybmVyLXJpZ2h0LWRvd25cIixcImNvcm5lci1yaWdodC11cFwiLFwiY29ybmVyLXVwLWxlZnRcIixcImNvcm5lci11cC1yaWdodFwiLFwiY3B1XCIsXCJjcmVkaXQtY2FyZFwiLFwiY3JvcFwiLFwibHVjaWRlLWNyb3NzXCIsXCJjcm9zc2hhaXJcIixcImNyb3duXCIsXCJjdXJyZW5jeVwiLFwiZGF0YWJhc2VcIixcImRlbGV0ZVwiLFwiZGljZS0xXCIsXCJkaWNlLTJcIixcImRpY2UtM1wiLFwiZGljZS00XCIsXCJkaWNlLTVcIixcImRpY2UtNlwiLFwiZGlzY1wiLFwiZGl2aWRlLWNpcmNsZVwiLFwiZGl2aWRlLXNxdWFyZVwiLFwiZGl2aWRlXCIsXCJkb2xsYXItc2lnblwiLFwiZG93bmxvYWQtY2xvdWRcIixcImRvd25sb2FkXCIsXCJkcmliYmJsZVwiLFwiZHJvcGxldFwiLFwiZHJvcGxldHNcIixcImRydW1zdGlja1wiLFwiZWRpdC0yXCIsXCJlZGl0LTNcIixcImVkaXRcIixcImVnZ1wiLFwiZXF1YWwtbm90XCIsXCJlcXVhbFwiLFwiZXJhc2VyXCIsXCJldXJvXCIsXCJleHBhbmRcIixcImV4dGVybmFsLWxpbmtcIixcImV5ZS1vZmZcIixcImV5ZVwiLFwiZmFjZWJvb2tcIixcImZhc3QtZm9yd2FyZFwiLFwiZmVhdGhlclwiLFwiZmlnbWFcIixcImZpbGUtY2hlY2stMlwiLFwiZmlsZS1jaGVja1wiLFwiZmlsZS1jb2RlXCIsXCJmaWxlLWRpZ2l0XCIsXCJmaWxlLWlucHV0XCIsXCJmaWxlLW1pbnVzLTJcIixcImZpbGUtbWludXNcIixcImZpbGUtb3V0cHV0XCIsXCJmaWxlLXBsdXMtMlwiLFwiZmlsZS1wbHVzXCIsXCJmaWxlLXNlYXJjaFwiLFwiZmlsZS10ZXh0XCIsXCJmaWxlLXgtMlwiLFwiZmlsZS14XCIsXCJmaWxlXCIsXCJmaWxlc1wiLFwiZmlsbVwiLFwiZmlsdGVyXCIsXCJmbGFnLW9mZlwiLFwiZmxhZy10cmlhbmdsZS1sZWZ0XCIsXCJmbGFnLXRyaWFuZ2xlLXJpZ2h0XCIsXCJmbGFnXCIsXCJmbGFtZVwiLFwiZmxhc2hsaWdodC1vZmZcIixcImZsYXNobGlnaHRcIixcImZsYXNrLWNvbmljYWxcIixcImZsYXNrLXJvdW5kXCIsXCJmb2xkZXItbWludXNcIixcImZvbGRlci1vcGVuXCIsXCJmb2xkZXItcGx1c1wiLFwibHVjaWRlLWZvbGRlclwiLFwiZm9ybS1pbnB1dFwiLFwiZm9yd2FyZFwiLFwiZnJhbWVcIixcImZyYW1lclwiLFwiZnJvd25cIixcImZ1bmN0aW9uLXNxdWFyZVwiLFwiZ2FtZXBhZC0yXCIsXCJnYW1lcGFkXCIsXCJnYXVnZVwiLFwiZ2F2ZWxcIixcImdlbVwiLFwiZ2hvc3RcIixcImdpZnRcIixcImdpdC1icmFuY2gtcGx1c1wiLFwiZ2l0LWJyYW5jaFwiLFwiZ2l0LWNvbW1pdFwiLFwiZ2l0LWZvcmtcIixcImdpdC1tZXJnZVwiLFwiZ2l0LXB1bGwtcmVxdWVzdFwiLFwiZ2l0aHViXCIsXCJnaXRsYWJcIixcImdsYXNzZXNcIixcImdsb2JlLTJcIixcImdsb2JlXCIsXCJncmFiXCIsXCJncmFkdWF0aW9uLWNhcFwiLFwiZ3JpZFwiLFwiZ3JpcC1ob3Jpem9udGFsXCIsXCJncmlwLXZlcnRpY2FsXCIsXCJoYW1tZXJcIixcImhhbmQtbWV0YWxcIixcImhhbmRcIixcImhhcmQtZHJpdmVcIixcImhhcmQtaGF0XCIsXCJoYXNoXCIsXCJoYXplXCIsXCJoZWFkcGhvbmVzXCIsXCJoZWFydFwiLFwiaGVscC1jaXJjbGVcIixcImhleGFnb25cIixcImhpZ2hsaWdodGVyXCIsXCJoaXN0b3J5XCIsXCJob21lXCIsXCJpbWFnZS1taW51c1wiLFwiaW1hZ2Utb2ZmXCIsXCJpbWFnZS1wbHVzXCIsXCJpbWFnZVwiLFwiaW1wb3J0XCIsXCJpbmJveFwiLFwiaW5kZW50XCIsXCJpbmRpYW4tcnVwZWVcIixcImluZmluaXR5XCIsXCJsdWNpZGUtaW5mb1wiLFwiaW5zcGVjdFwiLFwiaW5zdGFncmFtXCIsXCJpdGFsaWNcIixcImphcGFuZXNlLXllblwiLFwia2V5XCIsXCJrZXlib2FyZFwiLFwibGFuZG1hcmtcIixcImx1Y2lkZS1sYW5ndWFnZXNcIixcImxhcHRvcC0yXCIsXCJsYXB0b3BcIixcImxhc3NvLXNlbGVjdFwiLFwibGFzc29cIixcImxheWVyc1wiLFwibGF5b3V0LWRhc2hib2FyZFwiLFwibGF5b3V0LWdyaWRcIixcImxheW91dC1saXN0XCIsXCJsYXlvdXQtdGVtcGxhdGVcIixcImxheW91dFwiLFwibGlicmFyeVwiLFwibGlmZS1idW95XCIsXCJsaWdodGJ1bGItb2ZmXCIsXCJsaWdodGJ1bGJcIixcImxpbmstMi1vZmZcIixcImxpbmstMlwiLFwibHVjaWRlLWxpbmtcIixcImxpbmtlZGluXCIsXCJsaXN0LWNoZWNrc1wiLFwibGlzdC1taW51c1wiLFwibGlzdC1vcmRlcmVkXCIsXCJsaXN0LXBsdXNcIixcImxpc3QteFwiLFwibGlzdFwiLFwibG9hZGVyLTJcIixcImxvYWRlclwiLFwibG9jYXRlLWZpeGVkXCIsXCJsb2NhdGUtb2ZmXCIsXCJsb2NhdGVcIixcImxvY2tcIixcImxvZy1pblwiLFwibG9nLW91dFwiLFwibWFpbFwiLFwibWFwLXBpblwiLFwibWFwXCIsXCJtYXhpbWl6ZS0yXCIsXCJtYXhpbWl6ZVwiLFwibWVnYXBob25lXCIsXCJtZWhcIixcIm1lbnVcIixcIm1lc3NhZ2UtY2lyY2xlXCIsXCJtZXNzYWdlLXNxdWFyZVwiLFwibWljLW9mZlwiLFwibWljXCIsXCJtaW5pbWl6ZS0yXCIsXCJtaW5pbWl6ZVwiLFwibWludXMtY2lyY2xlXCIsXCJtaW51cy1zcXVhcmVcIixcIm1pbnVzXCIsXCJtb25pdG9yLW9mZlwiLFwibW9uaXRvci1zcGVha2VyXCIsXCJtb25pdG9yXCIsXCJtb29uXCIsXCJtb3JlLWhvcml6b250YWxcIixcIm1vcmUtdmVydGljYWxcIixcIm1vdW50YWluLXNub3dcIixcIm1vdW50YWluXCIsXCJtb3VzZS1wb2ludGVyLTJcIixcIm1vdXNlLXBvaW50ZXItY2xpY2tcIixcIm1vdXNlLXBvaW50ZXJcIixcIm1vdXNlXCIsXCJtb3ZlLWRpYWdvbmFsLTJcIixcIm1vdmUtZGlhZ29uYWxcIixcIm1vdmUtaG9yaXpvbnRhbFwiLFwibW92ZS12ZXJ0aWNhbFwiLFwibW92ZVwiLFwibXVzaWNcIixcIm5hdmlnYXRpb24tMlwiLFwibmF2aWdhdGlvblwiLFwibmV0d29ya1wiLFwib2N0YWdvblwiLFwib3B0aW9uXCIsXCJvdXRkZW50XCIsXCJwYWNrYWdlLWNoZWNrXCIsXCJwYWNrYWdlLW1pbnVzXCIsXCJwYWNrYWdlLXBsdXNcIixcInBhY2thZ2Utc2VhcmNoXCIsXCJwYWNrYWdlLXhcIixcInBhY2thZ2VcIixcInBhbGV0dGVcIixcInBhbG10cmVlXCIsXCJwYXBlcmNsaXBcIixcInBhdXNlLWNpcmNsZVwiLFwicGF1c2Utb2N0YWdvblwiLFwicGF1c2VcIixcInBlbi10b29sXCIsXCJsdWNpZGUtcGVuY2lsXCIsXCJwZXJjZW50XCIsXCJwZXJzb24tc3RhbmRpbmdcIixcInBob25lLWNhbGxcIixcInBob25lLWZvcndhcmRlZFwiLFwicGhvbmUtaW5jb21pbmdcIixcInBob25lLW1pc3NlZFwiLFwicGhvbmUtb2ZmXCIsXCJwaG9uZS1vdXRnb2luZ1wiLFwicGhvbmVcIixcInBpZS1jaGFydFwiLFwicGlnZ3ktYmFua1wiLFwibHVjaWRlLXBpblwiLFwicGlwZXR0ZVwiLFwicGxhbmVcIixcInBsYXktY2lyY2xlXCIsXCJwbGF5XCIsXCJwbHVnLXphcFwiLFwicGx1cy1jaXJjbGVcIixcInBsdXMtc3F1YXJlXCIsXCJwbHVzXCIsXCJwb2NrZXRcIixcInBvZGNhc3RcIixcInBvaW50ZXJcIixcInBvdW5kLXN0ZXJsaW5nXCIsXCJwb3dlci1vZmZcIixcInBvd2VyXCIsXCJwcmludGVyXCIsXCJxci1jb2RlXCIsXCJxdW90ZVwiLFwicmFkaW8tcmVjZWl2ZXJcIixcInJhZGlvXCIsXCJyZWRvXCIsXCJyZWZyZXNoLWNjd1wiLFwicmVmcmVzaC1jd1wiLFwicmVnZXhcIixcInJlcGVhdC0xXCIsXCJyZXBlYXRcIixcInJlcGx5LWFsbFwiLFwicmVwbHlcIixcInJld2luZFwiLFwicm9ja2V0XCIsXCJyb2NraW5nLWNoYWlyXCIsXCJyb3RhdGUtY2N3XCIsXCJyb3RhdGUtY3dcIixcInJzc1wiLFwicnVsZXJcIixcInJ1c3NpYW4tcnVibGVcIixcInNhdmVcIixcInNjYWxlXCIsXCJzY2FuLWxpbmVcIixcInNjYW5cIixcInNjaXNzb3JzXCIsXCJzY3JlZW4tc2hhcmUtb2ZmXCIsXCJzY3JlZW4tc2hhcmVcIixcImx1Y2lkZS1zZWFyY2hcIixcInNlbmRcIixcInNlcGFyYXRvci1ob3Jpem9udGFsXCIsXCJzZXBhcmF0b3ItdmVydGljYWxcIixcInNlcnZlci1jcmFzaFwiLFwic2VydmVyLW9mZlwiLFwic2VydmVyXCIsXCJzZXR0aW5ncy0yXCIsXCJzZXR0aW5nc1wiLFwic2hhcmUtMlwiLFwic2hhcmVcIixcInNoZWV0XCIsXCJzaGllbGQtYWxlcnRcIixcInNoaWVsZC1jaGVja1wiLFwic2hpZWxkLWNsb3NlXCIsXCJzaGllbGQtb2ZmXCIsXCJzaGllbGRcIixcInNoaXJ0XCIsXCJzaG9wcGluZy1iYWdcIixcInNob3BwaW5nLWNhcnRcIixcInNob3ZlbFwiLFwic2hyaW5rXCIsXCJzaHVmZmxlXCIsXCJzaWRlYmFyLWNsb3NlXCIsXCJzaWRlYmFyLW9wZW5cIixcInNpZGViYXJcIixcInNpZ21hXCIsXCJzaWduYWwtaGlnaFwiLFwic2lnbmFsLWxvd1wiLFwic2lnbmFsLW1lZGl1bVwiLFwic2lnbmFsLXplcm9cIixcInNpZ25hbFwiLFwic2tpcC1iYWNrXCIsXCJza2lwLWZvcndhcmRcIixcInNrdWxsXCIsXCJzbGFja1wiLFwic2xhc2hcIixcInNsaWRlcnNcIixcInNtYXJ0cGhvbmUtY2hhcmdpbmdcIixcInNtYXJ0cGhvbmVcIixcInNtaWxlXCIsXCJzbm93Zmxha2VcIixcInNvcnQtYXNjXCIsXCJzb3J0LWRlc2NcIixcInNwZWFrZXJcIixcInNwcm91dFwiLFwic3F1YXJlXCIsXCJzdGFyLWhhbGZcIixcImx1Y2lkZS1zdGFyXCIsXCJzdG9wLWNpcmNsZVwiLFwic3RyZXRjaC1ob3Jpem9udGFsXCIsXCJzdHJldGNoLXZlcnRpY2FsXCIsXCJzdHJpa2V0aHJvdWdoXCIsXCJzdWJzY3JpcHRcIixcInN1blwiLFwic3VucmlzZVwiLFwic3Vuc2V0XCIsXCJzdXBlcnNjcmlwdFwiLFwic3dpc3MtZnJhbmNcIixcInN3aXRjaC1jYW1lcmFcIixcInRhYmxlXCIsXCJ0YWJsZXRcIixcInRhZ1wiLFwidGFyZ2V0XCIsXCJ0ZW50XCIsXCJ0ZXJtaW5hbC1zcXVhcmVcIixcInRlcm1pbmFsXCIsXCJ0ZXh0LWN1cnNvci1pbnB1dFwiLFwidGV4dC1jdXJzb3JcIixcInRoZXJtb21ldGVyLXNub3dmbGFrZVwiLFwidGhlcm1vbWV0ZXItc3VuXCIsXCJ0aGVybW9tZXRlclwiLFwidGh1bWJzLWRvd25cIixcInRodW1icy11cFwiLFwidGlja2V0XCIsXCJ0aW1lci1vZmZcIixcInRpbWVyLXJlc2V0XCIsXCJ0aW1lclwiLFwidG9nZ2xlLWxlZnRcIixcInRvZ2dsZS1yaWdodFwiLFwidG9ybmFkb1wiLFwidHJhc2gtMlwiLFwibHVjaWRlLXRyYXNoXCIsXCJ0cmVsbG9cIixcInRyZW5kaW5nLWRvd25cIixcInRyZW5kaW5nLXVwXCIsXCJ0cmlhbmdsZVwiLFwidHJ1Y2tcIixcInR2LTJcIixcInR2XCIsXCJ0d2l0Y2hcIixcInR3aXR0ZXJcIixcInR5cGVcIixcInVtYnJlbGxhXCIsXCJ1bmRlcmxpbmVcIixcInVuZG9cIixcInVubGluay0yXCIsXCJ1bmxpbmtcIixcInVubG9ja1wiLFwidXBsb2FkLWNsb3VkXCIsXCJ1cGxvYWRcIixcInVzZXItY2hlY2tcIixcInVzZXItbWludXNcIixcInVzZXItcGx1c1wiLFwidXNlci14XCIsXCJ1c2VyXCIsXCJ1c2Vyc1wiLFwidmVyaWZpZWRcIixcInZpYnJhdGVcIixcInZpZGVvLW9mZlwiLFwidmlkZW9cIixcInZpZXdcIixcInZvaWNlbWFpbFwiLFwidm9sdW1lLTFcIixcInZvbHVtZS0yXCIsXCJ2b2x1bWUteFwiLFwidm9sdW1lXCIsXCJ3YWxsZXRcIixcIndhbmRcIixcIndhdGNoXCIsXCJ3YXZlc1wiLFwid2ViY2FtXCIsXCJ3aWZpLW9mZlwiLFwid2lmaVwiLFwid2luZFwiLFwid3JhcC10ZXh0XCIsXCJ3cmVuY2hcIixcIngtY2lyY2xlXCIsXCJ4LW9jdGFnb25cIixcIngtc3F1YXJlXCIsXCJ4XCIsXCJ5b3V0dWJlXCIsXCJ6YXAtb2ZmXCIsXCJ6YXBcIixcInpvb20taW5cIixcInpvb20tb3V0XCIsXCJzZWFyY2gtbGFyZ2VcIixcImx1Y2lkZS1zZWFyY2hcIl07XHJcblxyXG4vKipcclxuICogVGhlIG9yaWdpbmFsIElDT05fTElTVCBjb250YWlucyBkdXBsaWNhdGUgZW50cmllcyAoZS5nLiB0d28gXCJhY3Rpdml0eVwiIGl0ZW1zKSBhbmQgaXMgbm90IGluIGFscGhhYmV0aWNhbCBvcmRlci4gVGhpcyBsaXN0IGltcHJvdmVzIGl0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IElDT05fTElTVF9TT1JURURfVU5JUVVFID0gdW5pcXVlQXJyYXkoSUNPTl9MSVNUKS5zb3J0KCk7IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb259IGZyb20gXCIuL3NldHRpbmdzL1NoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb25cIjtcclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi9tYWluXCI7XHJcbmltcG9ydCB7XHJcbiAgICBnZW5lcmF0ZU9ic2lkaWFuQ29tbWFuZE5hbWUsXHJcbiAgICBnZXRPcGVyYXRpbmdTeXN0ZW0sXHJcbiAgICBtZXJnZVNldHMsXHJcbiAgICByZW1vdmVGcm9tU2V0LFxyXG59IGZyb20gXCIuL0NvbW1vblwiO1xyXG5pbXBvcnQge1NDX0V2ZW50fSBmcm9tIFwiLi9ldmVudHMvU0NfRXZlbnRcIjtcclxuaW1wb3J0IHtnZXRTQ19FdmVudHN9IGZyb20gXCIuL2V2ZW50cy9TQ19FdmVudExpc3RcIjtcclxuaW1wb3J0IHtkZWJ1Z0xvZ30gZnJvbSBcIi4vRGVidWdcIjtcclxuaW1wb3J0IHtDb21tYW5kfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHtWYXJpYWJsZVNldH0gZnJvbSBcIi4vdmFyaWFibGVzL2xvYWRWYXJpYWJsZXNcIjtcclxuaW1wb3J0IHtnZXRVc2VkVmFyaWFibGVzfSBmcm9tIFwiLi92YXJpYWJsZXMvcGFyc2VWYXJpYWJsZXNcIjtcclxuaW1wb3J0IHtcclxuICAgIGNyZWF0ZVByZWFjdGlvbixcclxuICAgIEN1c3RvbVZhcmlhYmxlLFxyXG4gICAgZ2V0SURHZW5lcmF0b3IsXHJcbiAgICBnZXRQQVRIQXVnbWVudGF0aW9uLFxyXG4gICAgUGFyc2luZ1Byb2Nlc3MsXHJcbiAgICBQcmVhY3Rpb24sXHJcbiAgICBQcmVhY3Rpb25Db25maWd1cmF0aW9uXHJcbn0gZnJvbSBcIi4vaW1wb3J0c1wiO1xyXG5pbXBvcnQge1xyXG4gICAgVmFyaWFibGUsXHJcbiAgICBJbmhlcml0YWJsZVZhcmlhYmxlRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbixcclxufSBmcm9tIFwiLi92YXJpYWJsZXMvVmFyaWFibGVcIjtcclxuaW1wb3J0IHtcclxuICAgIFBsYXRmb3JtSWQsXHJcbiAgICBQbGF0Zm9ybU5hbWVzLFxyXG59IGZyb20gXCIuL3NldHRpbmdzL1NDX01haW5TZXR0aW5nc1wiO1xyXG5pbXBvcnQge2dldEljb25IVE1MfSBmcm9tIFwiLi9JY29uc1wiO1xyXG5pbXBvcnQge091dHB1dFN0cmVhbX0gZnJvbSBcIi4vb3V0cHV0X2NoYW5uZWxzL091dHB1dENoYW5uZWxDb2RlXCI7XHJcbmltcG9ydCB7T3V0cHV0V3JhcHBlcn0gZnJvbSBcIi4vbW9kZWxzL291dHB1dF93cmFwcGVyL091dHB1dFdyYXBwZXJcIjtcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgVFNoZWxsQ29tbWFuZENvbnRhaW5lciB7XHJcbiAgICBba2V5OiBzdHJpbmddOiBUU2hlbGxDb21tYW5kLFxyXG59XHJcblxyXG4vKipcclxuICogVE9ETzogUmVuYW1lIHRoaXMgY2xhc3MuIFJlcGxhY2UgdGhlIFQgcHJlZml4IHdpdGggc29tZXRoaW5nIGVsc2UuIFRoZSBUIHN0YW5kcyBmb3IgVHlwZSAoa2luZCBvZiBsaWtlIFRGaWxlIGZyb20gT2JzaWRpYW4pLCBidXQgdGhpcyBpcyBub3QgYSB0eXBlLCB0aGlzIGlzIGEgY2xhc3MuIE1heWJlIFNoZWxsQ29tbWFuZEluc3RhbmNlPyBJdCdzIG5vdCB0aGUgYmVzdCBuYW1lLCBidXQgSSBjYW4ndCBjb21lIHVwIHdpdGggYSBiZXR0ZXIgb25lIG5vdy5cclxuICovXHJcbmV4cG9ydCBjbGFzcyBUU2hlbGxDb21tYW5kIHtcclxuXHJcbiAgICBwcml2YXRlIHBsdWdpbjogU0NfUGx1Z2luO1xyXG4gICAgcHJpdmF0ZSBjb25maWd1cmF0aW9uOiBTaGVsbENvbW1hbmRDb25maWd1cmF0aW9uO1xyXG4gICAgcHJpdmF0ZSBvYnNpZGlhbl9jb21tYW5kOiBDb21tYW5kO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yIChwbHVnaW46IFNDX1BsdWdpbiwgY29uZmlndXJhdGlvbjogU2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbikge1xyXG4gICAgICAgIHRoaXMucGx1Z2luID0gcGx1Z2luO1xyXG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbiA9IGNvbmZpZ3VyYXRpb247XHJcblxyXG4gICAgICAgIC8vIEludHJvZHVjZSB0aGUgSUQgdG8gYW4gSUQgZ2VuZXJhdG9yIHNvIHRoYXQgaXQgd29uJ3QgYWNjaWRlbnRhbGx5IGdlbmVyYXRlIHRoZSBzYW1lIElEIGFnYWluIHdoZW4gY3JlYXRpbmcgbmV3IHNoZWxsIGNvbW1hbmRzLlxyXG4gICAgICAgIGdldElER2VuZXJhdG9yKCkuYWRkUmVzZXJ2ZWRJRChjb25maWd1cmF0aW9uLmlkKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0UGx1Z2luKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnBsdWdpbjtcclxuICAgIH1cclxuICAgIC8qKlxyXG4gICAgICogVXNlIHRoaXMgd2hlbiB5b3UgbmVlZCB0byBhbHRlciB0aGUgY29uZmlndXJhdGlvbiB2YWx1ZXMuIGlmIHlvdSBvbmx5IG5lZWQgdG8gcmVhZCBjb25maWd1cmF0aW9uIHZhbHVlcywgdXNlIGdldCooKVxyXG4gICAgICogbWV0aG9kcyBpbnN0ZWFkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZ2V0Q29uZmlndXJhdGlvbigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmF0aW9uO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRJZCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmF0aW9uLmlkO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRTaGVsbCgpOiBzdHJpbmcge1xyXG4gICAgICAgIC8vIENoZWNrIGlmIHRoZSBzaGVsbCBjb21tYW5kIGhhcyBkZWZpbmVkIGEgc3BlY2lmaWMgc2hlbGwuXHJcbiAgICAgICAgY29uc3Qgc2hlbGw6IHN0cmluZyB8IHVuZGVmaW5lZCA9IHRoaXMuY29uZmlndXJhdGlvbi5zaGVsbHNbZ2V0T3BlcmF0aW5nU3lzdGVtKCldO1xyXG4gICAgICAgIGlmICh1bmRlZmluZWQgPT09IHNoZWxsKSB7XHJcbiAgICAgICAgICAgIC8vIFRoZSBzaGVsbCBjb21tYW5kIGRvZXMgbm90IGRlZmluZSBhbiBleHBsaWNpdCBzaGVsbC5cclxuICAgICAgICAgICAgLy8gVXNlIGEgZGVmYXVsdCBzaGVsbCBmcm9tIHRoZSBwbHVnaW4ncyBzZXR0aW5ncy5cclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucGx1Z2luLmdldERlZmF1bHRTaGVsbCgpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIFRoZSBzaGVsbCBjb21tYW5kIGhhcyBhbiBleHBsaWNpdCBzaGVsbCBkZWZpbmVkLlxyXG4gICAgICAgICAgICByZXR1cm4gc2hlbGw7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRTaGVsbHMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbi5zaGVsbHM7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIGEgc2hlbGwgY29tbWFuZCBzdHJpbmcgc3BlY2lmaWMgZm9yIHRoZSBjdXJyZW50IG9wZXJhdGluZyBzeXN0ZW0sIG9yIGEgZ2VuZXJpYyBzaGVsbCBjb21tYW5kIGlmIHRoaXMgc2hlbGxcclxuICAgICAqIGNvbW1hbmQgZG9lcyBub3QgaGF2ZSBhbiBleHBsaWNpdCB2ZXJzaW9uIGZvciB0aGUgY3VycmVudCBPUy5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldFNoZWxsQ29tbWFuZCgpOiBzdHJpbmcge1xyXG4gICAgICAgIC8vIENoZWNrIGlmIHRoZSBzaGVsbCBjb21tYW5kIGhhcyBkZWZpbmVkIGEgc3BlY2lmaWMgY29tbWFuZCBmb3IgdGhpcyBvcGVyYXRpbmcgc3lzdGVtLlxyXG4gICAgICAgIGNvbnN0IHBsYXRmb3JtU3BlY2lmaWNTaGVsbENvbW1hbmQ6IHN0cmluZyB8IHVuZGVmaW5lZCA9IHRoaXMuY29uZmlndXJhdGlvbi5wbGF0Zm9ybV9zcGVjaWZpY19jb21tYW5kc1tnZXRPcGVyYXRpbmdTeXN0ZW0oKV07XHJcbiAgICAgICAgaWYgKHVuZGVmaW5lZCA9PT0gcGxhdGZvcm1TcGVjaWZpY1NoZWxsQ29tbWFuZCkge1xyXG4gICAgICAgICAgICAvLyBObyBjb21tYW5kIGlzIGRlZmluZWQgc3BlY2lmaWNhbGx5IGZvciB0aGlzIG9wZXJhdGluZyBzeXN0ZW0uXHJcbiAgICAgICAgICAgIC8vIFJldHVybiBhbiBcIk9TIGFnbm9zdGljXCIgY29tbWFuZC5cclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbi5wbGF0Zm9ybV9zcGVjaWZpY19jb21tYW5kcy5kZWZhdWx0O1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIFRoZSBzaGVsbCBjb21tYW5kIGhhcyBkZWZpbmVkIGEgc3BlY2lmaWMgY29tbWFuZCBmb3IgdGhpcyBvcGVyYXRpbmcgc3lzdGVtLlxyXG4gICAgICAgICAgICByZXR1cm4gcGxhdGZvcm1TcGVjaWZpY1NoZWxsQ29tbWFuZDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIGEgdmVyc2lvbiBvZiB0aGUgc2hlbGwgY29tbWFuZCB0aGF0IHNob3VsZCBiZSB1c2VkIGlmIG5vIHBsYXRmb3JtIHNwZWNpZmljIGNvbW1hbmQgaXMgZGVmaW5lZCBmb3IgdGhlXHJcbiAgICAgKiBjdXJyZW50IHBsYXRmb3JtLiBJZiB5b3UgcGxhbiB0byB1c2UgdGhpcyBmb3IgZXhlY3V0aW9uLCBjb25zaWRlciB1c2luZyBnZXRTaGVsbENvbW1hbmQoKSBpbnN0ZWFkLCBhcyBpdCB0YWtlcyB0aGVcclxuICAgICAqIGN1cnJlbnQgcGxhdGZvcm0gaW50byBhY2NvdW50LlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZ2V0RGVmYXVsdFNoZWxsQ29tbWFuZCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmF0aW9uLnBsYXRmb3JtX3NwZWNpZmljX2NvbW1hbmRzLmRlZmF1bHQ7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldFBsYXRmb3JtU3BlY2lmaWNTaGVsbENvbW1hbmRzKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24ucGxhdGZvcm1fc3BlY2lmaWNfY29tbWFuZHM7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIGEgbGlzdCBvZiBQbGF0Zm9ybUlkcyB0aGF0IGhhdmUgYSBzaGVsbCBjb21tYW5kIHZlcnNpb24gZGVmaW5lZC4gJ2RlZmF1bHQnIGlzIG5ldmVyIGluY2x1ZGVkIGluIHRoZSBsaXN0LlxyXG4gICAgICpcclxuICAgICAqIFRPRE86IEludmVudCBhIGJldHRlciBuYW1lIGZvciB0aGlzIG1ldGhvZC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldE5vbkVtcHR5UGxhdGZvcm1JZHMoKSB7XHJcbiAgICAgICAgY29uc3QgcGxhdGZvcm1fc3BlY2lmaWNfc2hlbGxfY29tbWFuZHMgPSB0aGlzLmdldFBsYXRmb3JtU3BlY2lmaWNTaGVsbENvbW1hbmRzKCk7XHJcbiAgICAgICAgY29uc3QgcGxhdGZvcm1faWRzX3dpdGhfbm9uX2VtcHR5X3NoZWxsX2NvbW1hbmRzOiBQbGF0Zm9ybUlkW10gPSBbXTtcclxuICAgICAgICBsZXQgcGxhdGZvcm1faWQ6IFBsYXRmb3JtSWQ7XHJcbiAgICAgICAgZm9yIChwbGF0Zm9ybV9pZCBpbiBQbGF0Zm9ybU5hbWVzKSB7IC8vIE5vdGUgdGhhdCB0aGlzIGxvb3AgZG9lcyBub3QgaXRlcmF0ZSAnZGVmYXVsdCcgcGxhdGZvcm0gaWQgKD0gdGhlIGZhbGxiYWNrIHBsYXRmb3JtIGlkIHRoYXQgaXMgdXNlZCB3aGVuIGEgc2hlbGwgY29tbWFuZCBkb2VzIG5vdCBoYXZlIGEgdmVyc2lvbiBmb3IgdGhlIGN1cnJlbnQgcGxhdGZvcm0pLlxyXG4gICAgICAgICAgICBjb25zdCBwbGF0Zm9ybV9zcGVjaWZpY19zaGVsbF9jb21tYW5kID0gcGxhdGZvcm1fc3BlY2lmaWNfc2hlbGxfY29tbWFuZHNbcGxhdGZvcm1faWQgYXMgUGxhdGZvcm1JZF07XHJcbiAgICAgICAgICAgIGlmIChwbGF0Zm9ybV9zcGVjaWZpY19zaGVsbF9jb21tYW5kICYmIFwiXCIgIT09IHBsYXRmb3JtX3NwZWNpZmljX3NoZWxsX2NvbW1hbmQudHJpbSgpKSB7XHJcbiAgICAgICAgICAgICAgICBwbGF0Zm9ybV9pZHNfd2l0aF9ub25fZW1wdHlfc2hlbGxfY29tbWFuZHMucHVzaChwbGF0Zm9ybV9pZCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHBsYXRmb3JtX2lkc193aXRoX25vbl9lbXB0eV9zaGVsbF9jb21tYW5kcztcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0SWNvbklkKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24uaWNvbjtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0SWNvbkhUTUwoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuY29uZmlndXJhdGlvbi5pY29uKSB7XHJcbiAgICAgICAgICAgIC8vIEFuIGljb24gaXMgZGVmaW5lZC5cclxuICAgICAgICAgICAgcmV0dXJuIGdldEljb25IVE1MKHRoaXMuY29uZmlndXJhdGlvbi5pY29uKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBObyBpY29uIGlzIGRlZmluZWQuXHJcbiAgICAgICAgICAgIHJldHVybiBcIlwiO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0QWxpYXMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbi5hbGlhcztcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFRPRE86IFVzZSB0aGlzIG1ldGhvZCBpbiBhbGwgcGxhY2VzIHdoZXJlIHNpbWlsYXIgbG9naWMgaXMgbmVlZGVkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZ2V0QWxpYXNPclNoZWxsQ29tbWFuZCgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24uYWxpYXMgfHwgdGhpcy5nZXRTaGVsbENvbW1hbmQoKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0Q29uZmlybUV4ZWN1dGlvbigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmF0aW9uLmNvbmZpcm1fZXhlY3V0aW9uO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRJZ25vcmVFcnJvckNvZGVzKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24uaWdub3JlX2Vycm9yX2NvZGVzO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRJbnB1dENoYW5uZWxzKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24uaW5wdXRfY29udGVudHM7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldE91dHB1dENoYW5uZWxPcmRlcigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmF0aW9uLm91dHB1dF9jaGFubmVsX29yZGVyO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRPdXRwdXRDaGFubmVscygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmF0aW9uLm91dHB1dF9jaGFubmVscztcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0T3V0cHV0SGFuZGxpbmdNb2RlKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24ub3V0cHV0X2hhbmRsaW5nX21vZGU7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBGaW5kcyBhbiBvdXRwdXQgd3JhcHBlciB0aGF0IHNob3VsZCBiZSB1c2VkIGZvciB0aGUgZ2l2ZW4gT3V0cHV0U3RyZWFtLiBSZXR1cm5zIG51bGwsIGlmIG5vIE91dHB1dFdyYXBwZXIgc2hvdWxkXHJcbiAgICAgKiBiZSB1c2VkLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBvdXRwdXRfc3RyZWFtXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXRPdXRwdXRXcmFwcGVyKG91dHB1dF9zdHJlYW06IE91dHB1dFN0cmVhbSk6IE91dHB1dFdyYXBwZXIgfCBudWxsIHtcclxuICAgICAgICBjb25zdCBvdXRwdXRfd3JhcHBlcl9pZCA9IHRoaXMuY29uZmlndXJhdGlvbi5vdXRwdXRfd3JhcHBlcnNbb3V0cHV0X3N0cmVhbV07XHJcbiAgICAgICAgaWYgKCFvdXRwdXRfd3JhcHBlcl9pZCkge1xyXG4gICAgICAgICAgICAvLyBObyBvdXRwdXQgd3JhcHBlciBpcyBkZWZpbmVkIGZvciB0aGlzIG91dHB1dCBzdHJlYW0gaW4gdGhpcyBzaGVsbCBjb21tYW5kLlxyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZm9yIChjb25zdCBvdXRwdXRfd3JhcHBlciBvZiB0aGlzLnBsdWdpbi5nZXRPdXRwdXRXcmFwcGVycygpLnZhbHVlcygpKSB7XHJcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoaXMgaXMgdGhlIG91dHB1dCB3cmFwcGVyIGRlZmluZWQgZm9yIHRoaXMgc2hlbGwgY29tbWFuZC5cclxuICAgICAgICAgICAgaWYgKG91dHB1dF93cmFwcGVyLmdldElEKCkgPT09IG91dHB1dF93cmFwcGVyX2lkKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGUgY29ycmVjdCBvdXRwdXQgd3JhcHBlciB3YXMgZm91bmQuXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gb3V0cHV0X3dyYXBwZXI7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiT3V0cHV0V3JhcHBlciB3aXRoIElEIFwiICsgb3V0cHV0X3dyYXBwZXJfaWQgKyBcIiB3YXMgbm90IGZvdW5kLlwiKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENoZWNrcyBpZiBkaWZmZXJlbnQgb3V0cHV0IHN0cmVhbXMgY2FuIGJlIHdyYXBwZWQgdG9nZXRoZXIuIEluIGFkZGl0aW9uIHRvIHRoaXMsIGNvbWJpbmluZyBvdXRwdXQgc3RyZWFtcyBhbHNvXHJcbiAgICAgKiByZXF1aXJlcyB0aGUgT3V0cHV0Q2hhbm5lbHMgdG8gYmUgdGhlIHNhbWUsIGJ1dCB0aGF0J3Mgbm90IGNoZWNrZWQgaW4gdGhpcyBtZXRob2QuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBpc091dHB1dFdyYXBwZXJTdGRvdXRTYW1lQXNTdGRlcnIoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbi5vdXRwdXRfd3JhcHBlcnNbXCJzdGRvdXRcIl0gPT09IHRoaXMuY29uZmlndXJhdGlvbi5vdXRwdXRfd3JhcHBlcnNbXCJzdGRlcnJcIl07XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEV2ZW50c0NvbmZpZ3VyYXRpb24oKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbi5ldmVudHM7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEV2ZW50Q29uZmlndXJhdGlvbihzY19ldmVudDogU0NfRXZlbnQpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5nZXRFdmVudHNDb25maWd1cmF0aW9uKClbc2NfZXZlbnQuc3RhdGljKCkuZ2V0Q29kZSgpXSB8fCBzY19ldmVudC5nZXREZWZhdWx0Q29uZmlndXJhdGlvbihmYWxzZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGlzU0NfRXZlbnRFbmFibGVkKGV2ZW50X2NvZGU6IHN0cmluZykge1xyXG4gICAgICAgIGNvbnN0IGV2ZW50c19jb25maWd1cmF0aW9uID0gIHRoaXMuZ2V0RXZlbnRzQ29uZmlndXJhdGlvbigpO1xyXG4gICAgICAgIGlmICh1bmRlZmluZWQgPT09IGV2ZW50c19jb25maWd1cmF0aW9uW2V2ZW50X2NvZGVdKSB7XHJcbiAgICAgICAgICAgIC8vIE5vdCBlbmFibGVkXHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBNYXliZSBlbmFibGVkXHJcbiAgICAgICAgICAgIHJldHVybiBldmVudHNfY29uZmlndXJhdGlvbltldmVudF9jb2RlXS5lbmFibGVkO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENhbGxlZCB3aGVuIGNoYW5naW5nIGV2ZW50IHNldHRpbmdzIGluIFNoZWxsQ29tbWFuZEV4dHJhT3B0aW9uc01vZGFsLlxyXG4gICAgICogcGx1Z2luLnNhdmVTZXR0aW5ncygpIG5lZWRzIHRvIGJlIGNhbGxlZCBhZnRlciB0aGlzIVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBzY19ldmVudFxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZW5hYmxlU0NfRXZlbnQoc2NfZXZlbnQ6IFNDX0V2ZW50KSB7XHJcbiAgICAgICAgY29uc3QgZXZlbnRfY29kZSA9IHNjX2V2ZW50LnN0YXRpYygpLmdldENvZGUoKTtcclxuICAgICAgICBjb25zdCBldmVudHNfY29uZmlndXJhdGlvbiA9ICB0aGlzLmdldEV2ZW50c0NvbmZpZ3VyYXRpb24oKTtcclxuICAgICAgICBpZiAodW5kZWZpbmVkID09PSBldmVudHNfY29uZmlndXJhdGlvbltldmVudF9jb2RlXSkge1xyXG4gICAgICAgICAgICAvLyBOb3QgZW5hYmxlZFxyXG4gICAgICAgICAgICAvLyBFbmFibGVcclxuICAgICAgICAgICAgZXZlbnRzX2NvbmZpZ3VyYXRpb25bZXZlbnRfY29kZV0gPSBzY19ldmVudC5nZXREZWZhdWx0Q29uZmlndXJhdGlvbih0cnVlKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBNYXliZSBlbmFibGVkXHJcbiAgICAgICAgICAgIGlmICghZXZlbnRzX2NvbmZpZ3VyYXRpb25bZXZlbnRfY29kZV0uZW5hYmxlZCkge1xyXG4gICAgICAgICAgICAgICAgZXZlbnRzX2NvbmZpZ3VyYXRpb25bZXZlbnRfY29kZV0uZW5hYmxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKHNjX2V2ZW50LmNhblJlZ2lzdGVyQWZ0ZXJDaGFuZ2luZ1NldHRpbmdzKCkpIHtcclxuICAgICAgICAgICAgdGhpcy5yZWdpc3RlclNDX0V2ZW50KHNjX2V2ZW50KTtcclxuICAgICAgICB9XHJcbiAgICAgICAgc2NfZXZlbnQub25BZnRlckVuYWJsaW5nKHRoaXMpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ2FsbGVkIHdoZW4gY2hhbmdpbmcgZXZlbnQgc2V0dGluZ3MgaW4gU2hlbGxDb21tYW5kRXh0cmFPcHRpb25zTW9kYWwuXHJcbiAgICAgKiBwbHVnaW4uc2F2ZVNldHRpbmdzKCkgbmVlZHMgdG8gYmUgY2FsbGVkIGFmdGVyIHRoaXMhXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHNjX2V2ZW50XHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBkaXNhYmxlU0NfRXZlbnQoc2NfZXZlbnQ6IFNDX0V2ZW50KSB7XHJcbiAgICAgICAgY29uc3QgZXZlbnRfY29kZSA9IHNjX2V2ZW50LnN0YXRpYygpLmdldENvZGUoKTtcclxuICAgICAgICBjb25zdCBldmVudHNfY29uZmlndXJhdGlvbiA9ICB0aGlzLmdldEV2ZW50c0NvbmZpZ3VyYXRpb24oKTtcclxuICAgICAgICBpZiAodW5kZWZpbmVkICE9PSBldmVudHNfY29uZmlndXJhdGlvbltldmVudF9jb2RlXSkge1xyXG4gICAgICAgICAgICAvLyBNYXliZSBlbmFibGVkXHJcbiAgICAgICAgICAgIGlmIChldmVudHNfY29uZmlndXJhdGlvbltldmVudF9jb2RlXS5lbmFibGVkKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBJcyBlbmFibGVkLlxyXG4gICAgICAgICAgICAgICAgLy8gRGlzYWJsZS5cclxuICAgICAgICAgICAgICAgIGNvbnN0IGNvbmZpZ3VyYXRpb25fcHJvcGVydHlfbmFtZXMgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhldmVudHNfY29uZmlndXJhdGlvbltldmVudF9jb2RlXSk7XHJcbiAgICAgICAgICAgICAgICBpZiAoY29uZmlndXJhdGlvbl9wcm9wZXJ0eV9uYW1lcy5sZW5ndGggPiAxKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlcmUncyBtb3JlIHNldHRpbmdzIHRoYW4ganVzdCAnZW5hYmxlJy5cclxuICAgICAgICAgICAgICAgICAgICAvLyBEaXNhYmxlIGJ5IHNldHRpbmcgJ2VuYWJsZScgdG8gZmFsc2UsIGRvbid0IGZsdXNoIHRoZSBzZXR0aW5ncywgdGhleSBjYW4gYmUgdXNlZnVsIGlmIHRoZSBldmVudCBnZXRzIHJlLWVuYWJsZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRzX2NvbmZpZ3VyYXRpb25bZXZlbnRfY29kZV0uZW5hYmxlZCA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyAnZW5hYmxlZCcgaXMgdGhlIG9ubHkgc2V0dGluZy5cclxuICAgICAgICAgICAgICAgICAgICAvLyBEaXNhYmxlIGJ5IHJlbW92aW5nIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb21wbGV0ZWx5IHRvIG1ha2UgdGhlIHNldHRpbmdzIGZpbGUgY2xlYW5lci5cclxuICAgICAgICAgICAgICAgICAgICBkZWxldGUgZXZlbnRzX2NvbmZpZ3VyYXRpb25bZXZlbnRfY29kZV07XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKHNjX2V2ZW50LmNhblJlZ2lzdGVyQWZ0ZXJDaGFuZ2luZ1NldHRpbmdzKCkpIHtcclxuICAgICAgICAgICAgdGhpcy51bnJlZ2lzdGVyU0NfRXZlbnQoc2NfZXZlbnQpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFJldHVybnMgYWxsIFNDX0V2ZW50cyB0aGF0IGFyZSBlbmFibGVkIGZybyB0aGlzIHNoZWxsIGNvbW1hbmQuXHJcbiAgICAgKlxyXG4gICAgICogUHJpdmF0ZSBhcyBpdCdzIGN1cnJlbnRseSBvbmx5IHVzZWQgZG9tZXN0aWNhbGx5LCBidXQgY2FuIGJlIGNoYW5nZWQgdG8gcHVibGljIGlmIG5lZWRlZC5cclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBnZXRTQ19FdmVudHMoKTogU0NfRXZlbnRbXSB7XHJcbiAgICAgICAgY29uc3QgZW5hYmxlZF9zY19ldmVudHM6IFNDX0V2ZW50W10gPSBbXTtcclxuICAgICAgICBnZXRTQ19FdmVudHModGhpcy5wbHVnaW4pLmZvckVhY2goKHNjX2V2ZW50OiBTQ19FdmVudCkgPT4ge1xyXG4gICAgICAgICAgICBpZiAodGhpcy5pc1NDX0V2ZW50RW5hYmxlZChzY19ldmVudC5zdGF0aWMoKS5nZXRDb2RlKCkpKSB7XHJcbiAgICAgICAgICAgICAgICBlbmFibGVkX3NjX2V2ZW50cy5wdXNoKHNjX2V2ZW50KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybiBlbmFibGVkX3NjX2V2ZW50cztcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFByaXZhdGUsIGlmIHlvdSBuZWVkIGFjY2VzcyBmcm9tIG91dHNpZGUsIHVzZSBlbmFibGVTQ19FdmVudCgpLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBzY19ldmVudFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSByZWdpc3RlclNDX0V2ZW50KHNjX2V2ZW50OiBTQ19FdmVudCkge1xyXG4gICAgICAgIHNjX2V2ZW50LnJlZ2lzdGVyKHRoaXMpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUHJpdmF0ZSwgaWYgeW91IG5lZWQgYWNjZXNzIGZyb20gb3V0c2lkZSwgdXNlIGRpc2FibGVTQ19FdmVudCgpLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBzY19ldmVudFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSB1bnJlZ2lzdGVyU0NfRXZlbnQoc2NfZXZlbnQ6IFNDX0V2ZW50KSB7XHJcbiAgICAgICAgc2NfZXZlbnQudW5yZWdpc3Rlcih0aGlzKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFNldCdzIHVwIGFsbCBldmVudHMgdGhhdCBhcmUgZW5hYmxlZCBmb3IgdGhpcyBzaGVsbCBjb21tYW5kLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBjYWxsZWRfYWZ0ZXJfY2hhbmdpbmdfc2V0dGluZ3MgU2V0IHRvOiB0cnVlLCBpZiB0aGlzIGhhcHBlbnMgYWZ0ZXIgY2hhbmdpbmcgY29uZmlndXJhdGlvbjsgZmFsc2UsIGlmIHRoaXMgaGFwcGVucyBkdXJpbmcgbG9hZGluZyB0aGUgcGx1Z2luLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgcmVnaXN0ZXJTQ19FdmVudHMoY2FsbGVkX2FmdGVyX2NoYW5naW5nX3NldHRpbmdzOiBib29sZWFuKSB7XHJcbiAgICAgICAgdGhpcy5nZXRTQ19FdmVudHMoKS5mb3JFYWNoKChzY19ldmVudDogU0NfRXZlbnQpID0+IHtcclxuICAgICAgICAgICAgY29uc3QgY2FuX3JlZ2lzdGVyID0gIWNhbGxlZF9hZnRlcl9jaGFuZ2luZ19zZXR0aW5ncyB8fCBzY19ldmVudC5jYW5SZWdpc3RlckFmdGVyQ2hhbmdpbmdTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICBpZiAoY2FuX3JlZ2lzdGVyKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnJlZ2lzdGVyU0NfRXZlbnQoc2NfZXZlbnQpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIHVucmVnaXN0ZXJTQ19FdmVudHMoKSB7XHJcbiAgICAgICAgdGhpcy5nZXRTQ19FdmVudHMoKS5mb3JFYWNoKChzY19ldmVudDogU0NfRXZlbnQpID0+IHtcclxuICAgICAgICAgICAgdGhpcy51bnJlZ2lzdGVyU0NfRXZlbnQoc2NfZXZlbnQpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyByZWdpc3RlclRvQ29tbWFuZFBhbGV0dGUoKTogdm9pZCB7XHJcbiAgICAgICAgLy8gVE9ETzogTW92ZSB0aGUgbG9naWMgZnJvbSBwbHVnaW4ucmVnaXN0ZXJTaGVsbENvbW1hbmQoKSB0byBoZXJlLCBidXQgc3BsaXQgdG8gbXVsdGlwbGUgbWV0aG9kcy5cclxuICAgICAgICB0aGlzLnBsdWdpbi5yZWdpc3RlclNoZWxsQ29tbWFuZCh0aGlzKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgdW5yZWdpc3RlckZyb21Db21tYW5kUGFsZXR0ZSgpOiB2b2lkIHtcclxuICAgICAgICAvLyBGSVhNRTogSSB0aGluayB0aGUgdW5yZWdpc3RlcmluZyBkb2VzIG5vdCB3b3JrLlxyXG4gICAgICAgIGRlbGV0ZSB0aGlzLnBsdWdpbi5vYnNpZGlhbl9jb21tYW5kc1t0aGlzLmdldElkKCldO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ2hlY2tzIHRoZSBjb25maWd1cmF0aW9uIGZvciBjb21tYW5kX3BhbGV0dGVfYXZhaWxhYmlsaXR5IGFuZCByZXR1cm5zOlxyXG4gICAgICogIC0gdHJ1ZSwgaWYgdGhlIHZhbHVlIGlzIFwiZW5hYmxlZFwiIG9yIFwidW5saXN0ZWRcIlxyXG4gICAgICogIC0gZmFsc2UsIGlmIHRoZSB2YWx1ZSBpcyBcImRpc2FibGVkXCJcclxuICAgICAqXHJcbiAgICAgKiBBZGRpbmcgdG8gY29tbWFuZCBwYWxldHRlIGFsc28gZW5hYmxlcyBob3RrZXlzLCB3aGljaCBpcyB3aHkgYWRkaW5nIGNhbiBiZSBwZXJtaXR0ZWQsIGJ1dCBzaG93aW5nIGRlbmllZCwgaWYgYSBzaGVsbCBjb21tYW5kIHNob3VsZCBvbmx5IGJlIGF2YWlsYWJsZSB2aWEgaG90a2V5cy5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGNhbkFkZFRvQ29tbWFuZFBhbGV0dGUoKTogYm9vbGVhbiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0Q29uZmlndXJhdGlvbigpLmNvbW1hbmRfcGFsZXR0ZV9hdmFpbGFiaWxpdHkgIT09IFwiZGlzYWJsZWRcIjtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEFub3RoZXIgbmFtZSBmb3IgY2FuQWRkVG9Db21tYW5kUGFsZXR0ZSgpLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgY2FuSGF2ZUhvdGtleXMoKTogYm9vbGVhbiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FuQWRkVG9Db21tYW5kUGFsZXR0ZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ2hlY2tzIHRoZSBjb25maWd1cmF0aW9uIGZvciBjb21tYW5kX3BhbGV0dGVfYXZhaWxhYmlsaXR5IGFuZCByZXR1cm5zOlxyXG4gICAgICogIC0gdHJ1ZSwgaWYgdGhlIHZhbHVlIGlzIFwiZW5hYmxlZFwiXHJcbiAgICAgKiAgLSBmYWxzZSwgaWYgdGhlIHZhbHVlIGlzIFwiZGlzYWJsZWRcIiBvciBcInVubGlzdGVkXCJcclxuICAgICAqL1xyXG4gICAgcHVibGljIGNhblNob3dJbkNvbW1hbmRQYWxldHRlKCk6IGJvb2xlYW4ge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmdldENvbmZpZ3VyYXRpb24oKS5jb21tYW5kX3BhbGV0dGVfYXZhaWxhYmlsaXR5ID09PSBcImVuYWJsZWRcIjtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENyZWF0ZXMgYSBuZXcgUGFyc2luZ1Byb2Nlc3MgaW5zdGFuY2UgYW5kIGRlZmluZXMgdHdvIHNldHMgb2YgdmFyaWFibGVzOlxyXG4gICAgICogIC0gRmlyc3Qgc2V0OiBBbGwgdmFyaWFibGVzIHRoYXQgYXJlIG5vdCB0aWVkIHRvIGFueSBwcmVhY3Rpb25zLlxyXG4gICAgICogIC0gU2Vjb25kIHNldDogVmFyaWFibGVzIHRoYXQgYXJlIHRpZWQgdG8gcHJlYWN0aW9ucy4gQ2FuIGJlIGFuIGVtcHR5IHNldC5cclxuICAgICAqIFlvdSBuZWVkIHRvIHN0aWxsIGNhbGwgUGFyc2luZ1Byb2Nlc3MucHJvY2VzcygpIHRvIHBhcnNlIHRoZSBmaXJzdCBzZXQuIFNoZWxsQ29tbWFuZEV4ZWN1dG9yIHRha2VzIGNhcmUgb2YgY2FsbGluZ1xyXG4gICAgICogUGFyc2luZ1Byb2Nlc3MucHJvY2Vzc1Jlc3QoKSB0byBwcm9jZXNzIGFsbCBub24tcHJvY2Vzc2VkIHNldHMuXHJcbiAgICAgKlxyXG4gICAgICogQFNlZSBQYXJzaW5nUHJvY2VzcyBjbGFzcyBmb3IgYSBkZXNjcmlwdGlvbiBvZiB0aGUgcHJvY2Vzcy5cclxuICAgICAqIEBwYXJhbSBzY19ldmVudCBOZWVkZWQgdG8gZ2V0IHt7ZXZlbnRfKn19IHZhcmlhYmxlcyBwYXJzZWQuIENhbiBiZSBsZWZ0IG91dCBpZiB3b3JraW5nIG91dHNpZGUgYW55IFNDX0V2ZW50IGNvbnRleHQsIGluIHdoaWNoIGNhc2Uge3tldmVudF8qfX0gdmFyaWFibGVzIGFyZSBpbmFjY2Vzc2libGUuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBjcmVhdGVQYXJzaW5nUHJvY2VzcyhzY19ldmVudDogU0NfRXZlbnQgfCBudWxsKTogU2hlbGxDb21tYW5kUGFyc2luZ1Byb2Nlc3Mge1xyXG4gICAgICAgIGNvbnN0IHN0ZG91dF9vdXRwdXRfd3JhcHBlciA9IHRoaXMuZ2V0T3V0cHV0V3JhcHBlcihcInN0ZG91dFwiKTsgLy8gQ2FuIGJlIG51bGxcclxuICAgICAgICBjb25zdCBzdGRlcnJfb3V0cHV0X3dyYXBwZXIgPSB0aGlzLmdldE91dHB1dFdyYXBwZXIoXCJzdGRlcnJcIik7IC8vIENhbiBiZSBudWxsXHJcbiAgICAgICAgcmV0dXJuIG5ldyBQYXJzaW5nUHJvY2VzczxzaGVsbF9jb21tYW5kX3BhcnNpbmdfbWFwPihcclxuICAgICAgICAgICAgdGhpcy5wbHVnaW4sXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIHNoZWxsX2NvbW1hbmQ6IHRoaXMuZ2V0U2hlbGxDb21tYW5kKCksXHJcbiAgICAgICAgICAgICAgICBhbGlhczogdGhpcy5nZXRBbGlhcygpLFxyXG4gICAgICAgICAgICAgICAgZW52aXJvbm1lbnRfdmFyaWFibGVfcGF0aF9hdWdtZW50YXRpb246IGdldFBBVEhBdWdtZW50YXRpb24odGhpcy5wbHVnaW4pID8/IFwiXCIsXHJcbiAgICAgICAgICAgICAgICBzdGRpbkNvbnRlbnQ6IHRoaXMuY29uZmlndXJhdGlvbi5pbnB1dF9jb250ZW50cy5zdGRpbiA/PyB1bmRlZmluZWQsXHJcbiAgICAgICAgICAgICAgICBvdXRwdXRfd3JhcHBlcl9zdGRvdXQ6IHN0ZG91dF9vdXRwdXRfd3JhcHBlciA/IHN0ZG91dF9vdXRwdXRfd3JhcHBlci5nZXRDb250ZW50KCkgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgICAgICAgICBvdXRwdXRfd3JhcHBlcl9zdGRlcnI6IHN0ZGVycl9vdXRwdXRfd3JhcHBlciA/IHN0ZGVycl9vdXRwdXRfd3JhcHBlci5nZXRDb250ZW50KCkgOiB1bmRlZmluZWQsXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIHRoaXMsXHJcbiAgICAgICAgICAgIHNjX2V2ZW50LFxyXG4gICAgICAgICAgICBbXHJcbiAgICAgICAgICAgICAgICB0aGlzLmdldE5vblByZWFjdGlvbnNEZXBlbmRlbnRWYXJpYWJsZXMoKSwgLy8gRmlyc3Qgc2V0OiBBbGwgdmFyaWFibGVzIHRoYXQgYXJlIG5vdCB0aWVkIHRvIGFueSBwcmVhY3Rpb25zLlxyXG4gICAgICAgICAgICAgICAgdGhpcy5nZXRQcmVhY3Rpb25zRGVwZW5kZW50VmFyaWFibGVzKCksIC8vIFNlY29uZCBzZXQ6IFZhcmlhYmxlcyB0aGF0IGFyZSB0aWVkIHRvIHByZWFjdGlvbnMuIENhbiBiZSBhbiBlbXB0eSBzZXQuXHJcbiAgICAgICAgICAgIF0sXHJcbiAgICAgICAgICAgIFtcclxuICAgICAgICAgICAgICAgIC8vIERvIG5vdCBlc2NhcGUgdmFyaWFibGVzIGluIHN0ZGluLCBiZWNhdXNlIHNoZWxscyB3b24ndCBpbnRlcnByZXQgc3BlY2lhbCBjaGFyYWN0ZXJzIGluIHN0ZGluLiBBbGwgY2hhcmFjdGVycyBhcmUgY29uc2lkZXJlZCBsaXRlcmFsLlxyXG4gICAgICAgICAgICAgICAgXCJzdGRpbkNvbnRlbnRcIixcclxuICAgICAgICAgICAgICAgIC8vIERvIG5vdCBlc2NhcGUgdmFyaWFibGVzIGluIG91dHB1dCB3cmFwcGVycywgYmVjYXVzZSB0aGV5IGFyZSBub3QgZ29pbmcgdGhyb3VnaCBhIHNoZWxsIGFuZCBlc2NhcGUgY2hhcmFjdGVycyB3b3VsZCBiZSB2aXNpYmxlIGluIHRoZSBlbmQgcmVzdWx0LlxyXG4gICAgICAgICAgICAgICAgJ291dHB1dF93cmFwcGVyX3N0ZG91dCcsXHJcbiAgICAgICAgICAgICAgICAnb3V0cHV0X3dyYXBwZXJfc3RkZXJyJyxcclxuICAgICAgICAgICAgXSxcclxuICAgICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBzZXRPYnNpZGlhbkNvbW1hbmQob2JzaWRpYW5fY29tbWFuZDogQ29tbWFuZCkge1xyXG4gICAgICAgIHRoaXMub2JzaWRpYW5fY29tbWFuZCA9IG9ic2lkaWFuX2NvbW1hbmQ7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldE9ic2lkaWFuQ29tbWFuZCgpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5vYnNpZGlhbl9jb21tYW5kO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogTm8gcmVuYW1pbmcgaXMgZG9uZSBpZiB0aGUgc2hlbGwgY29tbWFuZCBpcyBleGNsdWRlZCBmcm9tIHRoZSBjb21tYW5kIHBhbGV0dGUuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyByZW5hbWVPYnNpZGlhbkNvbW1hbmQoc2hlbGxfY29tbWFuZDogc3RyaW5nLCBhbGlhczogc3RyaW5nKSB7XHJcbiAgICAgICAgLy8gUmVuYW1lIHRoZSBjb21tYW5kIGluIGNvbW1hbmQgcGFsZXR0ZVxyXG4gICAgICAgIGNvbnN0IHByZWZpeCA9IHRoaXMucGx1Z2luLmdldFBsdWdpbk5hbWUoKSArIFwiOiBcIjsgLy8gTm9ybWFsbHkgT2JzaWRpYW4gcHJlZml4ZXMgYWxsIGNvbW1hbmRzIHdpdGggdGhlIHBsdWdpbiBuYW1lIGF1dG9tYXRpY2FsbHksIGJ1dCBub3cgdGhhdCB3ZSBhcmUgYWN0dWFsbHkgX2VkaXRpbmdfIGEgY29tbWFuZCBpbiB0aGUgcGFsZXR0ZSAobm90IGNyZWF0aW5nIGEgbmV3IG9uZSksIE9ic2lkaWFuIHdvbid0IGRvIHRoZSBwcmVmaXhpbmcgZm9yIHVzLlxyXG5cclxuICAgICAgICAvLyBDaGVjayB0aGF0IHRoZSBzaGVsbCBjb21tYW5kIGlzIGFjdHVhbGx5IHJlZ2lzdGVyZWQgdG8gT2JzaWRpYW4ncyBjb21tYW5kIHBhbGV0dGUuXHJcbiAgICAgICAgaWYgKHVuZGVmaW5lZCAhPT0gdGhpcy5vYnNpZGlhbl9jb21tYW5kKSB7XHJcbiAgICAgICAgICAgIC8vIFllcywgdGhlIHNoZWxsIGNvbW1hbmQgaXMgcmVnaXN0ZXJlZCBpbiBPYnNpZGlhbidzIGNvbW1hbmQgcGFsZXR0ZS5cclxuICAgICAgICAgICAgLy8gVXBkYXRlIHRoZSBjb21tYW5kIHBhbGV0dGUgbmFtZS5cclxuICAgICAgICAgICAgdGhpcy5vYnNpZGlhbl9jb21tYW5kLm5hbWUgPSBwcmVmaXggKyBnZW5lcmF0ZU9ic2lkaWFuQ29tbWFuZE5hbWUodGhpcy5wbHVnaW4sIHNoZWxsX2NvbW1hbmQsIGFsaWFzKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgLy8gSWYgdGhlIHNoZWxsIGNvbW1hbmQncyBcImNvbW1hbmRfcGFsZXR0ZV9hdmFpbGFiaWxpdHlcIiBzZXR0aW5ncyBpcyBzZXQgdG8gXCJkaXNhYmxlZFwiLCB0aGVuIHRoZSBzaGVsbCBjb21tYW5kIGlzIG5vdCBwcmVzZW50IGluIHRoaXMub2JzaWRpYW5fY29tbWFuZCBhbmQgc28gdGhlIGNvbW1hbmQgcGFsZXR0ZSBuYW1lIGRvZXMgbm90IG5lZWQgdXBkYXRpbmcuXHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDbGVhcnMgYW4gaW50ZXJuYWwgY2FjaGUgdXNlZCBieSAuZ2V0UHJlYWN0aW9ucygpLlxyXG4gICAgICogT25seSBuZWVkZWQgdG8gYmUgY2FsbGVkIGFmdGVyIGNyZWF0aW5nIG5ldyBQcmVhY3Rpb25Db25maWd1cmF0aW9ucyBvciBkZWxldGluZyBvbGQgb25lcy4gU2hvdWxkIG5vdCBuZWVkIHRvIGJlIGNhbGxlZFxyXG4gICAgICogd2hlbiBtb2RpZnlpbmcgcHJvcGVydGllcyBpbiBleGlzdGluZyBQcmVhY3Rpb25Db25maWd1cmF0aW9ucy5cclxuICAgICAqL1xyXG4gICAgcHVibGljIHJlc2V0UHJlYWN0aW9ucygpIHtcclxuICAgICAgICBkZWJ1Z0xvZyhgVFNoZWxsQ29tbWFuZCAke3RoaXMuZ2V0SWQoKX06IFJlc2V0dGluZyBwcmVhY3Rpb25zLmApO1xyXG4gICAgICAgIGRlbGV0ZSB0aGlzLmNhY2hlZF9wcmVhY3Rpb25zO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgY2FjaGVkX3ByZWFjdGlvbnM6IFByZWFjdGlvbltdIHwgdW5kZWZpbmVkO1xyXG4gICAgcHVibGljIGdldFByZWFjdGlvbnMoKTogUHJlYWN0aW9uW10ge1xyXG4gICAgICAgIGRlYnVnTG9nKGBUU2hlbGxDb21tYW5kICR7dGhpcy5nZXRJZCgpfTogR2V0dGluZyBwcmVhY3Rpb25zLmApO1xyXG4gICAgICAgIGlmICghdGhpcy5jYWNoZWRfcHJlYWN0aW9ucykge1xyXG4gICAgICAgICAgICB0aGlzLmNhY2hlZF9wcmVhY3Rpb25zID0gW107XHJcbiAgICAgICAgICAgIGxldCBwcmVhY3Rpb25fY29uZmlndXJhdGlvbjogUHJlYWN0aW9uQ29uZmlndXJhdGlvbjtcclxuICAgICAgICAgICAgZm9yIChwcmVhY3Rpb25fY29uZmlndXJhdGlvbiBvZiB0aGlzLmdldENvbmZpZ3VyYXRpb24oKS5wcmVhY3Rpb25zKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBPbmx5IGNyZWF0ZSB0aGUgcHJlYWN0aW9uIGlmIGl0J3MgZW5hYmxlZC5cclxuICAgICAgICAgICAgICAgIGlmIChwcmVhY3Rpb25fY29uZmlndXJhdGlvbi5lbmFibGVkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gWWVzLCBpdCdzIGVuYWJsZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gSW5zdGFudGlhdGUgdGhlIFByZWFjdGlvbi5cclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmNhY2hlZF9wcmVhY3Rpb25zLnB1c2goY3JlYXRlUHJlYWN0aW9uKHRoaXMucGx1Z2luLCBwcmVhY3Rpb25fY29uZmlndXJhdGlvbiwgdGhpcykpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0aGlzLmNhY2hlZF9wcmVhY3Rpb25zO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmV0dXJucyBWYXJpYWJsZXMgdGhhdCBhcmUgbm90IGRlcGVuZGVudCBvbiBhbnkgUHJlYWN0aW9uLlxyXG4gICAgICogQHByaXZhdGUgQ2FuIGJlIG1hZGUgcHVibGljIGlmIG5lZWRlZC5cclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBnZXROb25QcmVhY3Rpb25zRGVwZW5kZW50VmFyaWFibGVzKCk6IFZhcmlhYmxlU2V0IHtcclxuICAgICAgICBkZWJ1Z0xvZyhgVFNoZWxsQ29tbWFuZCAke3RoaXMuZ2V0SWQoKX06IEdldHRpbmcgbm9uIHByZWFjdGlvbnMgZGVwZW5kZW50IHZhcmlhYmxlcy5gKTtcclxuICAgICAgICBjb25zdCBhbGxfdmFyaWFibGVzID0gdGhpcy5wbHVnaW4uZ2V0VmFyaWFibGVzKCk7XHJcbiAgICAgICAgcmV0dXJuIHJlbW92ZUZyb21TZXQoYWxsX3ZhcmlhYmxlcywgdGhpcy5nZXRQcmVhY3Rpb25zRGVwZW5kZW50VmFyaWFibGVzKCkpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHByaXZhdGUgQ2FuIGJlIG1hZGUgcHVibGljIGlmIG5lZWRlZC5cclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBnZXRQcmVhY3Rpb25zRGVwZW5kZW50VmFyaWFibGVzKCk6IFZhcmlhYmxlU2V0IHtcclxuICAgICAgICBkZWJ1Z0xvZyhgVFNoZWxsQ29tbWFuZCAke3RoaXMuZ2V0SWQoKX06IEdldHRpbmcgcHJlYWN0aW9ucyBkZXBlbmRlbnQgdmFyaWFibGVzLmApO1xyXG4gICAgICAgIGxldCBkZXBlbmRlbnRfdmFyaWFibGVzID0gbmV3IFZhcmlhYmxlU2V0KCk7XHJcbiAgICAgICAgZm9yIChjb25zdCBwcmVhY3Rpb24gb2YgdGhpcy5nZXRQcmVhY3Rpb25zKCkpIHtcclxuICAgICAgICAgICAgZGVwZW5kZW50X3ZhcmlhYmxlcyA9IG1lcmdlU2V0cyhkZXBlbmRlbnRfdmFyaWFibGVzLCBwcmVhY3Rpb24uZ2V0RGVwZW5kZW50VmFyaWFibGVzKCkpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gZGVwZW5kZW50X3ZhcmlhYmxlcztcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEByZXR1cm4gUmV0dXJucyB1bmRlZmluZWQsIGlmIG5vIGNvbmZpZ3VyYXRpb24gaXMgZGVmaW5lZCBmb3IgdGhpcyB2YXJpYWJsZS5cclxuICAgICAqIEBwYXJhbSB2YXJpYWJsZVxyXG4gICAgICogQHBhcmFtIGNhbkluaGVyaXQgSWYgdHJ1ZSwgY2FuIGdldCBkZWZhdWx0IHZhbHVlIGNvbmZpZ3VyYXRpb24gZnJvbSBWYXJpYWJsZSBjb25maWd1cmF0aW9uICg9IHVwcGVyIGxldmVsIGNvbmZpZ3VyYXRpb24gaW4gdGhpcyBjYXNlKS4gQ2FuIGJlIHNldCB0byBmYWxzZSBpbiBzaXR1YXRpb25zIHdoZXJlIGl0J3MgaW1wb3J0YW50IHRvIGtub3cgd2hhdCB0aGUgc2hlbGwgY29tbWFuZCBpdHNlbGYgaGFzIGRlZmluZWQgb3Igbm90IGRlZmluZWQuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXREZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uRm9yVmFyaWFibGUodmFyaWFibGU6IFZhcmlhYmxlLCBjYW5Jbmhlcml0ID0gdHJ1ZSk6IEluaGVyaXRhYmxlVmFyaWFibGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uIHwgbnVsbCB7XHJcbiAgICAgICAgY29uc3QgZGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbjogSW5oZXJpdGFibGVWYXJpYWJsZURlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24gfCB1bmRlZmluZWQgPSB0aGlzLmNvbmZpZ3VyYXRpb24udmFyaWFibGVfZGVmYXVsdF92YWx1ZXNbdmFyaWFibGUuZ2V0SWRlbnRpZmllcigpXTtcclxuICAgICAgICBpZiAodW5kZWZpbmVkID09PSBkZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uIHx8IGRlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24udHlwZSA9PT0gXCJpbmhlcml0XCIpIHtcclxuICAgICAgICAgICAgLy8gVGhpcyBzaGVsbCBjb21tYW5kIGRvZXMgbm90IHNwZWNpZnkgYSBkZWZhdWx0IHZhbHVlLlxyXG4gICAgICAgICAgICBpZiAoY2FuSW5oZXJpdCkge1xyXG4gICAgICAgICAgICAgICAgLy8gUmV0dXJuIGEgZ2xvYmFsIGNvbmZpZ3VyYXRpb24gKGJ1dCBldmVuIHRoYXQgY2FuIGJlIHVuZGVmaW5lZCkuXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdmFyaWFibGUuZ2V0R2xvYmFsRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbigpOyAvLyBDYW4gcmV0dXJuIHVuZGVmaW5lZC5cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAvLyBJZiBpbmhlcml0aW5nIGlzIGRlbmllZCwgcGFzcyB0byByZXR1cm4gdGhlIGRlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24gdGhhdCB3ZXJlIGdvdHRlbiBmcm9tIHRoaXMuY29uZmlndXJhdGlvbi52YXJpYWJsZV9kZWZhdWx0X3ZhbHVlcy5cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGRlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb247XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIGFuIFVSSSB0aGF0IGNhbiBiZSB1c2VkIGluIGxpbmtzIChpbiBvciBvdXRzaWRlIG9mIE9ic2lkaWFuKSB0byBleGVjdXRlIHRoaXMgc2hlbGwgY29tbWFuZC4gVGhlIFVSSSBhbHNvXHJcbiAgICAgKiBjb250YWlucyBzdHVicyBmb3IgYW55IHBvc3NpYmxlIEN1c3RvbVZhcmlhYmxlcyB0aGF0IG1pZ2h0IGJlIHVzZWQgaW4gdGhlIHNoZWxsIGNvbW1hbmQgKGlmIGFueSkuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXRFeGVjdXRpb25VUkkoKSB7XHJcbiAgICAgICAgY29uc3QgZXhlY3V0aW9uX3VyaSA9IHRoaXMucGx1Z2luLmdldE9ic2lkaWFuVVJJKFNDX1BsdWdpbi5TSEVMTF9DT01NQU5EU19VUklfQUNUSU9OLCB7ZXhlY3V0ZTogdGhpcy5nZXRJZCgpfSk7XHJcblxyXG4gICAgICAgIC8vIEdldCBhIGxpc3QgQ3VzdG9tVmFyaWFibGVzIHRoYXQgdGhlIHNoZWxsIGNvbW1hbmQgdXNlcy5cclxuICAgICAgICBjb25zdCBjdXN0b21fdmFyaWFibGVzID0gbmV3IFZhcmlhYmxlU2V0KCk7XHJcbiAgICAgICAgZm9yIChjb25zdCBjdXN0b21fdmFyaWFibGUgb2YgZ2V0VXNlZFZhcmlhYmxlcyh0aGlzLnBsdWdpbiwgdGhpcy5nZXRTaGVsbENvbW1hbmQoKSkpIHtcclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhhdCB0aGUgdmFyaWFibGUgSVMgYSBDdXN0b21WYXJpYWJsZS5cclxuICAgICAgICAgICAgaWYgKGN1c3RvbV92YXJpYWJsZSBpbnN0YW5jZW9mIEN1c3RvbVZhcmlhYmxlKSB7XHJcbiAgICAgICAgICAgICAgICBjdXN0b21fdmFyaWFibGVzLmFkZChjdXN0b21fdmFyaWFibGUpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBFeGNsdWRlIHZhcmlhYmxlcyB3aG9zZSB2YWx1ZXMgd2lsbCBjb21lIGZyb20gUHJlYWN0aW9ucyAtIHRoZXkgd2lsbCBub3QgcHJvYmFibHkgYmUgbmVlZGVkIGluIHRoZSBVUkkuXHJcbiAgICAgICAgY29uc3QgY3VzdG9tX3ZhcmlhYmxlc19zdWl0YWJsZV9mb3JfdXJpID0gcmVtb3ZlRnJvbVNldChjdXN0b21fdmFyaWFibGVzLCB0aGlzLmdldFByZWFjdGlvbnNEZXBlbmRlbnRWYXJpYWJsZXMoKSk7XHJcblxyXG4gICAgICAgIC8vIEFwcGVuZCB0aGUgc3VpdGFibGUgY3VzdG9tIHZhcmlhYmxlIG5hbWVzIHRvIHRoZSB1cmkuXHJcbiAgICAgICAgbGV0IGV4ZWN1dGlvbl91cmlfd2l0aF92YXJpYWJsZXMgPSBleGVjdXRpb25fdXJpO1xyXG4gICAgICAgIGZvciAoY29uc3QgY3VzdG9tX3ZhcmlhYmxlIG9mIGN1c3RvbV92YXJpYWJsZXNfc3VpdGFibGVfZm9yX3VyaSkge1xyXG4gICAgICAgICAgICBleGVjdXRpb25fdXJpX3dpdGhfdmFyaWFibGVzICs9IFwiJlwiICsgY3VzdG9tX3ZhcmlhYmxlLnZhcmlhYmxlX25hbWUgKyBcIj1cIjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEZpbmlzaGVkLlxyXG4gICAgICAgIHJldHVybiBleGVjdXRpb25fdXJpX3dpdGhfdmFyaWFibGVzO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmV0dXJucyBhbiBhZGphY2VudCBUU2hlbGxDb21tYW5kIHRoYXQgYXBwZWFycyBuZXh0IGluIHRoZSBjb25maWd1cmF0aW9uIGxpc3QuIFJldHVybnMgdW5kZWZpbmVkLCBpZiB0aGlzIGlzIHRoZVxyXG4gICAgICogbGFzdCBUU2hlbGxDb21tYW5kLiBVc2VkIGluIHNldHRpbmdzIHRvIHN3aXRjaCBxdWlja2x5IGZyb20gb25lIFRTaGVsbENvbW1hbmQgdG8gYW5vdGhlci5cclxuICAgICAqL1xyXG4gICAgcHVibGljIG5leHRUU2hlbGxDb21tYW5kKCkge1xyXG4gICAgICAgIGNvbnN0IHRfc2hlbGxfY29tbWFuZHMgPSBPYmplY3QudmFsdWVzKHRoaXMucGx1Z2luLmdldFRTaGVsbENvbW1hbmRzKCkpO1xyXG4gICAgICAgIGNvbnN0IHRoaXNfaW5kZXggPSB0X3NoZWxsX2NvbW1hbmRzLmluZGV4T2YodGhpcyk7XHJcbiAgICAgICAgaWYgKHRoaXNfaW5kZXggPT09IHRfc2hlbGxfY29tbWFuZHMubGVuZ3RoIC0gMSkge1xyXG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdF9zaGVsbF9jb21tYW5kc1t0aGlzX2luZGV4ICsgMV07XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIGFuIGFkamFjZW50IFRTaGVsbENvbW1hbmQgdGhhdCBhcHBlYXJzIGJlZm9yZSBpbiB0aGUgY29uZmlndXJhdGlvbiBsaXN0LiBSZXR1cm5zIHVuZGVmaW5lZCwgaWYgdGhpcyBpcyB0aGVcclxuICAgICAqIGZpcnN0IFRTaGVsbENvbW1hbmQuIFVzZWQgaW4gc2V0dGluZ3MgdG8gc3dpdGNoIHF1aWNrbHkgZnJvbSBvbmUgVFNoZWxsQ29tbWFuZCB0byBhbm90aGVyLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgcHJldmlvdXNUU2hlbGxDb21tYW5kKCkge1xyXG4gICAgICAgIGNvbnN0IHRfc2hlbGxfY29tbWFuZHMgPSBPYmplY3QudmFsdWVzKHRoaXMucGx1Z2luLmdldFRTaGVsbENvbW1hbmRzKCkpO1xyXG4gICAgICAgIGNvbnN0IHRoaXNfaW5kZXggPSB0X3NoZWxsX2NvbW1hbmRzLmluZGV4T2YodGhpcyk7XHJcbiAgICAgICAgaWYgKHRoaXNfaW5kZXggPT09IDApIHtcclxuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRfc2hlbGxfY29tbWFuZHNbdGhpc19pbmRleCAtIDFdO1xyXG4gICAgfVxyXG59XHJcblxyXG4vKipcclxuICogVE9ETzogVGhlIG5hbWUgU2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdCBzb3VuZHMgbGlrZSB0aGlzIHdvdWxkIGJlIGEgc3ViLWludGVyZmFjZSBvZiBQYXJzaW5nUmVzdWx0LCBhbHRob3VnaCB0aGUgaW50ZXJmYWNlcyBhcmUgdmVyeSBkaWZmZXJlbnQuIFJlbmFtZSB0aGlzIHRvIHNvbWV0aGluZyBiZXR0ZXIuIENhbmRpZGF0ZSBuYW1lczpcclxuICogIC0gUGFyc2VkU2hlbGxDb21tYW5kUHJvcGVydGllc1xyXG4gKiAgLSBQYXJzZWRTaGVsbENvbW1hbmRTdHJpbmdzXHJcbiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIFNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQge1xyXG4gICAgc2hlbGxfY29tbWFuZDogc3RyaW5nLFxyXG4gICAgYWxpYXM6IHN0cmluZyxcclxuICAgIGVudmlyb25tZW50X3ZhcmlhYmxlX3BhdGhfYXVnbWVudGF0aW9uOiBzdHJpbmcsXHJcbiAgICBzdGRpbkNvbnRlbnQ/OiBzdHJpbmcsXHJcbiAgICBvdXRwdXRfd3JhcHBlcl9zdGRvdXQ/OiBzdHJpbmcsXHJcbiAgICBvdXRwdXRfd3JhcHBlcl9zdGRlcnI/OiBzdHJpbmcsXHJcbiAgICBzdWNjZWVkZWQ6IGJvb2xlYW47XHJcbiAgICBlcnJvcl9tZXNzYWdlczogc3RyaW5nW107XHJcbn1cclxuXHJcbmV4cG9ydCB0eXBlIFNoZWxsQ29tbWFuZFBhcnNpbmdQcm9jZXNzID0gUGFyc2luZ1Byb2Nlc3M8c2hlbGxfY29tbWFuZF9wYXJzaW5nX21hcD47XHJcblxyXG50eXBlIHNoZWxsX2NvbW1hbmRfcGFyc2luZ19tYXAgPSB7XHJcbiAgICBzaGVsbF9jb21tYW5kOiBzdHJpbmcsXHJcbiAgICBhbGlhczogc3RyaW5nLFxyXG4gICAgZW52aXJvbm1lbnRfdmFyaWFibGVfcGF0aF9hdWdtZW50YXRpb246IHN0cmluZyxcclxuICAgIHN0ZGluQ29udGVudD86IHN0cmluZyxcclxuICAgIG91dHB1dF93cmFwcGVyX3N0ZG91dD86IHN0cmluZyxcclxuICAgIG91dHB1dF93cmFwcGVyX3N0ZGVycj86IHN0cmluZyxcclxufTsiLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uLy4uL21haW5cIjtcclxuaW1wb3J0IHtcclxuICAgIEdsb2JhbFZhcmlhYmxlRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbixcclxuICAgIEluaGVyaXRhYmxlVmFyaWFibGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uLFxyXG4gICAgVmFyaWFibGUsXHJcbiAgICBWYXJpYWJsZURlZmF1bHRWYWx1ZVR5cGUsXHJcbiAgICBWYXJpYWJsZURlZmF1bHRWYWx1ZVR5cGVXaXRoSW5oZXJpdCxcclxufSBmcm9tIFwiLi4vLi4vdmFyaWFibGVzL1ZhcmlhYmxlXCI7XHJcbmltcG9ydCB7XHJcbiAgICBTZXR0aW5nLFxyXG4gICAgVGV4dEFyZWFDb21wb25lbnQsXHJcbn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7Y3JlYXRlQXV0b2NvbXBsZXRlfSBmcm9tIFwiLi9BdXRvY29tcGxldGVcIjtcclxuaW1wb3J0IHtUU2hlbGxDb21tYW5kfSBmcm9tIFwiLi4vLi4vVFNoZWxsQ29tbWFuZFwiO1xyXG5pbXBvcnQge0N1c3RvbVZhcmlhYmxlfSBmcm9tIFwiLi4vLi4vdmFyaWFibGVzL0N1c3RvbVZhcmlhYmxlXCI7XHJcbmltcG9ydCB7Z290b1VSTH0gZnJvbSBcIi4uLy4uL0NvbW1vblwiO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVZhcmlhYmxlRGVmYXVsdFZhbHVlRmllbGRzKHBsdWdpbjogU0NfUGx1Z2luLCBjb250YWluZXJFbGVtZW50OiBIVE1MRWxlbWVudCwgdGFyZ2V0T2JqZWN0OiBWYXJpYWJsZSB8IFRTaGVsbENvbW1hbmQpIHtcclxuXHJcbiAgICAvLyBBZGQgZGVmYXVsdCB2YWx1ZSBmaWVsZHMgZm9yIGVhY2ggdmFyaWFibGUgdGhhdCBjYW4gaGF2ZSBhIGRlZmF1bHQgdmFsdWUuXHJcbiAgICBmb3IgKGNvbnN0IHZhcmlhYmxlIG9mIHBsdWdpbi5nZXRWYXJpYWJsZXMoKSkge1xyXG5cclxuICAgICAgICAvLyBPbmx5IGFkZCBmaWVsZHMgZm9yIHZhcmlhYmxlcyB0aGF0IGFyZSBub3QgYWx3YXlzIGFjY2Vzc2libGUuXHJcbiAgICAgICAgaWYgKCF2YXJpYWJsZS5pc0Fsd2F5c0F2YWlsYWJsZSgpKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHNldHRpbmcgPSBjcmVhdGVWYXJpYWJsZURlZmF1bHRWYWx1ZUZpZWxkKFxyXG4gICAgICAgICAgICAgICAgcGx1Z2luLFxyXG4gICAgICAgICAgICAgICAgY29udGFpbmVyRWxlbWVudCxcclxuICAgICAgICAgICAgICAgIHZhcmlhYmxlLmdldEZ1bGxOYW1lKCksXHJcbiAgICAgICAgICAgICAgICB2YXJpYWJsZSxcclxuICAgICAgICAgICAgICAgIHRhcmdldE9iamVjdFxyXG4gICAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICAgLy8gRG9jdW1lbnRhdGlvbiBsaW5rXHJcbiAgICAgICAgICAgIGlmICghKHZhcmlhYmxlIGluc3RhbmNlb2YgQ3VzdG9tVmFyaWFibGUpKSB7XHJcbiAgICAgICAgICAgICAgICBzZXR0aW5nLmFkZEV4dHJhQnV0dG9uKGV4dHJhQnV0dG9uID0+IGV4dHJhQnV0dG9uXHJcbiAgICAgICAgICAgICAgICAgICAgLnNldEljb24oXCJoZWxwXCIpXHJcbiAgICAgICAgICAgICAgICAgICAgLnNldFRvb2x0aXAoXCJEb2N1bWVudGF0aW9uOiBcIiArIHZhcmlhYmxlLmdldEZ1bGxOYW1lKCkgKyBcIiB2YXJpYWJsZVwiKVxyXG4gICAgICAgICAgICAgICAgICAgIC5vbkNsaWNrKCgpID0+IGdvdG9VUkwodmFyaWFibGUuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSkpLFxyXG4gICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbn1cclxuXHJcbi8qKlxyXG4gKlxyXG4gKiBAcGFyYW0gcGx1Z2luXHJcbiAqIEBwYXJhbSBjb250YWluZXJFbGVtZW50XHJcbiAqIEBwYXJhbSBzZXR0aW5nTmFtZVxyXG4gKiBAcGFyYW0gdmFyaWFibGUgVGhlIHZhcmlhYmxlIHdob3NlIGRlZmF1bHQgdmFsdWUgd2lsbCBiZSBjb25maWd1cmVkIGJ5IHRoZSBjcmVhdGVkIHNldHRpbmcgZmllbGQuXHJcbiAqIEBwYXJhbSB0YXJnZXRPYmplY3QgSW4gd2hpY2ggb2JqZWN0J3MgY29uZmlndXJhdGlvbiB0aGUgZGVmYXVsdCB2YWx1ZSBzZXR0aW5ncyBzaG91bGQgYmUgc3RvcmVkLiBDYW4gYmUgYSBUU2hlbGxDb21tYW5kIG9yIGEgVmFyaWFibGUgKGVpdGhlciBDdXN0b21WYXJpYWJsZSBvciBhIGJ1aWx0LWluIG9uZSkuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlVmFyaWFibGVEZWZhdWx0VmFsdWVGaWVsZChcclxuICAgICAgICBwbHVnaW46IFNDX1BsdWdpbixcclxuICAgICAgICBjb250YWluZXJFbGVtZW50OiBIVE1MRWxlbWVudCxcclxuICAgICAgICBzZXR0aW5nTmFtZTogc3RyaW5nLFxyXG4gICAgICAgIHZhcmlhYmxlOiBWYXJpYWJsZSxcclxuICAgICAgICB0YXJnZXRPYmplY3Q/OiBWYXJpYWJsZSB8IFRTaGVsbENvbW1hbmQsXHJcbiAgICApOiBTZXR0aW5nIHtcclxuXHJcbiAgICBpZiAodW5kZWZpbmVkID09PSB0YXJnZXRPYmplY3QpIHtcclxuICAgICAgICAvLyBObyBjb25maWd1cmF0aW9uIHRhcmdldCBpcyBkZWZpbmVkLCBzbyB1c2UgdGhlIHZhcmlhYmxlIGFzIGEgdGFyZ2V0LlxyXG4gICAgICAgIHRhcmdldE9iamVjdCA9IHZhcmlhYmxlO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHRhcmdldFR5cGUgPVxyXG4gICAgICAgIHRhcmdldE9iamVjdCBpbnN0YW5jZW9mIFRTaGVsbENvbW1hbmRcclxuICAgICAgICAgICAgPyAndFNoZWxsQ29tbWFuZCdcclxuICAgICAgICAgICAgOiB0YXJnZXRPYmplY3QgaW5zdGFuY2VvZiBDdXN0b21WYXJpYWJsZVxyXG4gICAgICAgICAgICAgICAgPyAnY3VzdG9tVmFyaWFibGUnXHJcbiAgICAgICAgICAgICAgICA6ICdidWlsdGluVmFyaWFibGUnXHJcbiAgICA7XHJcblxyXG4gICAgaWYgKFwiY3VzdG9tVmFyaWFibGVcIiA9PT0gdGFyZ2V0VHlwZSB8fCBcImJ1aWx0aW5WYXJpYWJsZVwiID09PSB0YXJnZXRUeXBlKSB7XHJcbiAgICAgICAgaWYgKHRhcmdldE9iamVjdCAhPT0gdmFyaWFibGUpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSWYgZGVmaW5pbmcgJ3RhcmdldE9iamVjdCcgYXJndW1lbnQgYXMgYSBWYXJpYWJsZSwgaXQgc2hvdWxkIGJlIHRoZSBzYW1lIGFzIHRoZSAndmFyaWFibGUnIGFyZ3VtZW50LlwiKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IGFuIGlkZW50aWZpZXIgZm9yIGEgdmFyaWFibGUgKGFuIGlkLCBpZiBpdCdzIGEgQ3VzdG9tVmFyaWFibGUsIG90aGVyd2lzZSB0aGUgdmFyaWFibGUncyBuYW1lKS5cclxuICAgIGNvbnN0IHZhcmlhYmxlSWRlbnRpZmllciA9IHZhcmlhYmxlLmdldElkZW50aWZpZXIoKTtcclxuXHJcbiAgICAvLyBJZiBhIGRlZmF1bHQgdmFsdWUgaGFzIGJlZW4gZGVmaW5lZCBmb3IgdGhpcyB2YXJpYWJsZSAoYW5kIHRoaXMgdGFyZ2V0T2JqZWN0KSwgcmV0cmlldmUgdGhlIGNvbmZpZ3VyYXRpb24uXHJcbiAgICBsZXQgZGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbjogR2xvYmFsVmFyaWFibGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uIHwgSW5oZXJpdGFibGVWYXJpYWJsZURlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24gfCBudWxsO1xyXG4gICAgc3dpdGNoICh0YXJnZXRUeXBlKSB7XHJcbiAgICAgICAgY2FzZSBcInRTaGVsbENvbW1hbmRcIjpcclxuICAgICAgICAgICAgZGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbiA9ICh0YXJnZXRPYmplY3QgYXMgVFNoZWxsQ29tbWFuZCkuZ2V0RGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbkZvclZhcmlhYmxlKHZhcmlhYmxlLCBmYWxzZSk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIGNhc2UgXCJidWlsdGluVmFyaWFibGVcIjogLy8gQm90aCBjbGFzc2VzIGhhdmUuLi5cclxuICAgICAgICBjYXNlIFwiY3VzdG9tVmFyaWFibGVcIjogIC8vIC4uLiB0aGUgZ2V0R2xvYmFsRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbigpIG1ldGhvZC5cclxuICAgICAgICAgICAgZGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbiA9ICh0YXJnZXRPYmplY3QgYXMgVmFyaWFibGUgfCBDdXN0b21WYXJpYWJsZSkuZ2V0R2xvYmFsRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbigpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgIH1cclxuXHJcbiAgICAvLyBBIGZ1bmN0aW9uIGZvciBjcmVhdGluZyBjb25maWd1cmF0aW9uIGluIG9uQ2hhbmdlKCkgY2FsbGJhY2tzIGlmIHRoZSB2YXJpYWJsZSBkb2VzIG5vdCB5ZXQgaGF2ZSBvbmUgZm9yIHRoaXMgY29uZmlndXJhdGlvbi5cclxuICAgIGNvbnN0IGNyZWF0ZURlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24gPSAoKSA9PiB7XHJcbiAgICAgICAgY29uc3QgY29uZmlndXJhdGlvbjogR2xvYmFsVmFyaWFibGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uIC8qIFRoaXMgdHlwZSBzaG91bGQgYmUgY29tcGF0aWJsZSBhbHNvIHdoZW4gYXNzaWduaW5nIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgVFNoZWxsQ29tbWFuZCwgd2hpY2ggYWN0dWFsbHkgdXNlcyBJbmhlcml0YWJsZVZhcmlhYmxlRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbiBpbnN0ZWFkIG9mIEdsb2JhbCouICovID0ge1xyXG4gICAgICAgICAgICB0eXBlOiBcInNob3ctZXJyb3JzXCIsXHJcbiAgICAgICAgICAgIHZhbHVlOiBcIlwiLFxyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIC8vIFN0b3JlIHRoZSBjb25maWd1cmF0aW9uIHRvIHRoZSB0YXJnZXQgb2JqZWN0J3MgY29uZmlndXJhdGlvbi5cclxuICAgICAgICBzd2l0Y2ggKHRhcmdldFR5cGUpIHtcclxuICAgICAgICAgICAgY2FzZSBcInRTaGVsbENvbW1hbmRcIjpcclxuICAgICAgICAgICAgICAgICh0YXJnZXRPYmplY3QgYXMgVFNoZWxsQ29tbWFuZCkuZ2V0Q29uZmlndXJhdGlvbigpLnZhcmlhYmxlX2RlZmF1bHRfdmFsdWVzW3ZhcmlhYmxlSWRlbnRpZmllcl0gPSBjb25maWd1cmF0aW9uO1xyXG4gICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgIGNhc2UgXCJidWlsdGluVmFyaWFibGVcIjpcclxuICAgICAgICAgICAgICAgIGlmICh1bmRlZmluZWQgPT09IHBsdWdpbi5zZXR0aW5ncy5idWlsdGluX3ZhcmlhYmxlc1t2YXJpYWJsZUlkZW50aWZpZXJdKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gQ3JlYXRlIGEgY29uZmlnIG9iamVjdCBmb3IgdGhpcyB2YXJpYWJsZSBpZiBpdCBkb2VzIG5vdCBleGlzdCB5ZXQuXHJcbiAgICAgICAgICAgICAgICAgICAgcGx1Z2luLnNldHRpbmdzLmJ1aWx0aW5fdmFyaWFibGVzW3ZhcmlhYmxlSWRlbnRpZmllcl0gPSB7ZGVmYXVsdF92YWx1ZTogbnVsbH07XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBwbHVnaW4uc2V0dGluZ3MuYnVpbHRpbl92YXJpYWJsZXNbdmFyaWFibGVJZGVudGlmaWVyXS5kZWZhdWx0X3ZhbHVlID0gY29uZmlndXJhdGlvbjtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICBjYXNlIFwiY3VzdG9tVmFyaWFibGVcIjpcclxuICAgICAgICAgICAgICAgICh0YXJnZXRPYmplY3QgYXMgQ3VzdG9tVmFyaWFibGUpLmdldENvbmZpZ3VyYXRpb24oKS5kZWZhdWx0X3ZhbHVlID0gY29uZmlndXJhdGlvbjtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gY29uZmlndXJhdGlvbjtcclxuICAgIH07XHJcblxyXG4gICAgbGV0IHRleHRhcmVhQ29tcG9uZW50OiBUZXh0QXJlYUNvbXBvbmVudDtcclxuXHJcbiAgICAvLyBBIGZ1bmN0aW9uIGZvciB1cGRhdGluZyB0ZXh0YXJlYUNvbXBvbmVudCB2aXNpYmlsaXR5LlxyXG4gICAgY29uc3QgdXBkYXRlVGV4dGFyZWFDb21wb25lbnRWaXNpYmlsaXR5ID0gKHR5cGU6IHN0cmluZykgPT4ge1xyXG4gICAgICAgIGlmIChcInZhbHVlXCIgPT09IHR5cGUpIHtcclxuICAgICAgICAgICAgdGV4dGFyZWFDb21wb25lbnQuaW5wdXRFbC5yZW1vdmVDbGFzcyhcIlNDLWhpZGVcIik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGV4dGFyZWFDb21wb25lbnQuaW5wdXRFbC5hZGRDbGFzcyhcIlNDLWhpZGVcIik7XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBEZWZpbmUgYSBzZXQgb2Ygb3B0aW9ucyBmb3IgZGVmYXVsdCB2YWx1ZSB0eXBlXHJcbiAgICBjb25zdCBkZWZhdWx0VmFsdWVUeXBlT3B0aW9ucyA9IHtcclxuICAgICAgICBcImluaGVyaXRcIjogXCJcIiwgLy8gV2lsbCBiZSB1cGRhdGVkIG9yIGRlbGV0ZWQgYmVsb3cuXHJcbiAgICAgICAgXCJzaG93LWVycm9yc1wiOiBcIkNhbmNlbCBleGVjdXRpb24gYW5kIHNob3cgZXJyb3JzXCIsXHJcbiAgICAgICAgXCJjYW5jZWwtc2lsZW50bHlcIjogXCJDYW5jZWwgZXhlY3V0aW9uIHNpbGVudGx5XCIsXHJcbiAgICAgICAgXCJ2YWx1ZVwiOiBcIkV4ZWN1dGUgd2l0aCB2YWx1ZTpcIixcclxuICAgIH07XHJcbiAgICBzd2l0Y2ggKHRhcmdldFR5cGUpIHtcclxuICAgICAgICBjYXNlIFwidFNoZWxsQ29tbWFuZFwiOiB7XHJcbiAgICAgICAgICAgIC8vIFNoZWxsIGNvbW1hbmRzIGNhbiBoYXZlIHRoZSBcImluaGVyaXRcIiB0eXBlLlxyXG4gICAgICAgICAgICBjb25zdCBnbG9iYWxEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uOiBHbG9iYWxWYXJpYWJsZURlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24gfCBudWxsID0gdmFyaWFibGUuZ2V0R2xvYmFsRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbigpO1xyXG4gICAgICAgICAgICBjb25zdCBnbG9iYWxEZWZhdWx0VmFsdWVUeXBlOiBWYXJpYWJsZURlZmF1bHRWYWx1ZVR5cGUgPSBnbG9iYWxEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uID8gZ2xvYmFsRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbi50eXBlIDogXCJzaG93LWVycm9yc1wiO1xyXG4gICAgICAgICAgICBkZWZhdWx0VmFsdWVUeXBlT3B0aW9ucy5pbmhlcml0ID0gXCJJbmhlcml0OiBcIiArIGRlZmF1bHRWYWx1ZVR5cGVPcHRpb25zW2dsb2JhbERlZmF1bHRWYWx1ZVR5cGVdO1xyXG4gICAgICAgICAgICBpZiAoXCJ2YWx1ZVwiID09PSBnbG9iYWxEZWZhdWx0VmFsdWVUeXBlKSB7XHJcbiAgICAgICAgICAgICAgICBkZWZhdWx0VmFsdWVUeXBlT3B0aW9ucy5pbmhlcml0ICs9IFwiIFwiICsgZ2xvYmFsRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbj8udmFsdWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNhc2UgXCJidWlsdGluVmFyaWFibGVcIjpcclxuICAgICAgICBjYXNlIFwiY3VzdG9tVmFyaWFibGVcIjoge1xyXG4gICAgICAgICAgICAvLyBWYXJpYWJsZXMgZG8gbm90IGhhdmUgdGhlIFwiaW5oZXJpdFwiIHR5cGUuXHJcbiAgICAgICAgICAgIC8vIEB0cy1pZ25vcmUgRG9uJ3QgeWVsbCBhYm91dCByZW1vdmluZyBhIG5vbi1vcHRpb25hbCBwcm9wZXJ0eSBcImluaGVyaXRcIi5cclxuICAgICAgICAgICAgZGVsZXRlIGRlZmF1bHRWYWx1ZVR5cGVPcHRpb25zLmluaGVyaXQ7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgZGVmYXVsdCB2YWx1ZSBzZXR0aW5nXHJcbiAgICBjb25zdCBkZWZhdWx0VmFsdWVTZXR0aW5nOiBTZXR0aW5nID0gbmV3IFNldHRpbmcoY29udGFpbmVyRWxlbWVudClcclxuICAgICAgICAuc2V0TmFtZShzZXR0aW5nTmFtZSlcclxuICAgICAgICAuc2V0RGVzYyhcIklmIG5vdCBhdmFpbGFibGUsIHRoZW46XCIpXHJcbiAgICAgICAgLnNldFRvb2x0aXAodmFyaWFibGUuZ2V0QXZhaWxhYmlsaXR5VGV4dFBsYWluKCkpXHJcbiAgICAgICAgLmFkZERyb3Bkb3duKGRyb3Bkb3duID0+IGRyb3Bkb3duXHJcbiAgICAgICAgICAgIC5hZGRPcHRpb25zKGRlZmF1bHRWYWx1ZVR5cGVPcHRpb25zKVxyXG4gICAgICAgICAgICAuc2V0VmFsdWUoXHJcbiAgICAgICAgICAgICAgICBkZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uXHJcbiAgICAgICAgICAgICAgICA/IGRlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24udHlwZVxyXG4gICAgICAgICAgICAgICAgOiBcInRTaGVsbENvbW1hbmRcIiA9PT0gdGFyZ2V0VHlwZVxyXG4gICAgICAgICAgICAgICAgICAgID8gXCJpbmhlcml0XCIgICAgIC8vIElmIGNvbmZpZ3VyaW5nIGEgVFNoZWxsQ29tbWFuZCwgdGhlbiBkZWZhdWx0IGNvbmZpZyB0eXBlIHNob3VsZCBiZSBcImluaGVyaXRcIi5cclxuICAgICAgICAgICAgICAgICAgICA6IFwic2hvdy1lcnJvcnNcIiAvLyBJZiBjb25maWd1cmluZyBhIFZhcmlhYmxlLCB0aGVuIGRlZmF1bHQgY29uZmlnIHR5cGUgc2hvdWxkIGJlIFwic2hvdy1lcnJvcnNcIiwgYmVjYXVzZSBcImluaGVyaXRcIiBpcyBub3QgYXZhaWxhYmxlLlxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAobmV3VHlwZTogVmFyaWFibGVEZWZhdWx0VmFsdWVUeXBlV2l0aEluaGVyaXQpID0+IHtcclxuICAgICAgICAgICAgICAgIGlmICghZGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbikge1xyXG4gICAgICAgICAgICAgICAgICAgIGRlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24gPSBjcmVhdGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uKCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gU2V0IHRoZSBuZXcgdHlwZVxyXG4gICAgICAgICAgICAgICAgZGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbi50eXBlID0gbmV3VHlwZTtcclxuICAgICAgICAgICAgICAgIGlmICh0YXJnZXRUeXBlID09PSBcInRTaGVsbENvbW1hbmRcIikge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFNoZWxsIGNvbW1hbmRzOlxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChcImluaGVyaXRcIiA9PT0gbmV3VHlwZSAmJiBkZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uLnZhbHVlID09PSBcIlwiKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIFwiaW5oZXJpdFwiIGlzIHNlbGVjdGVkIGFuZCBubyB0ZXh0IHZhbHVlIGlzIHR5cGVkLCB0aGUgY29uZmlndXJhdGlvbiBmaWxlIGNhbiBiZSBjbGVhbmVkIHVwIGJ5IHJlbW92aW5nIHRoaXMgY29uZmlndXJhdGlvbiBvYmplY3QgY29tcGxldGVseS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUHJldmVudCBkZWxldGluZywgaWYgYSB0ZXh0IHZhbHVlIGlzIHByZXNlbnQsIGJlY2F1c2UgdGhlIHVzZXIgbWlnaHQgd2FudCB0byBrZWVwIGl0IGlmIHRoZXkgd2lsbCBsYXRlciBjaGFuZ2UgJ3R5cGUnIHRvICd2YWx1ZScuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSAodGFyZ2V0T2JqZWN0IGFzIFRTaGVsbENvbW1hbmQpLmdldENvbmZpZ3VyYXRpb24oKS52YXJpYWJsZV9kZWZhdWx0X3ZhbHVlc1t2YXJpYWJsZUlkZW50aWZpZXJdO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVmFyaWFibGVzOlxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChcInNob3ctZXJyb3JzXCIgPT09IG5ld1R5cGUgJiYgZGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbi52YWx1ZSA9PT0gXCJcIikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBcInNob3ctZXJyb3JzXCIgaXMgc2VsZWN0ZWQgYW5kIG5vIHRleHQgdmFsdWUgaXMgdHlwZWQsIHRoZSBjb25maWd1cmF0aW9uIGZpbGUgY2FuIGJlIGNsZWFuZWQgdXAgYnkgcmVtb3ZpbmcgdGhpcyBjb25maWd1cmF0aW9uIG9iamVjdCBjb21wbGV0ZWx5LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBQcmV2ZW50IGRlbGV0aW5nLCBpZiBhIHRleHQgdmFsdWUgaXMgcHJlc2VudCwgYmVjYXVzZSB0aGUgdXNlciBtaWdodCB3YW50IHRvIGtlZXAgaXQgaWYgdGhleSB3aWxsIGxhdGVyIGNoYW5nZSAndHlwZScgdG8gJ3ZhbHVlJy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoICh0YXJnZXRUeXBlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiYnVpbHRpblZhcmlhYmxlXCI6XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGx1Z2luLnNldHRpbmdzLmJ1aWx0aW5fdmFyaWFibGVzW3ZhcmlhYmxlSWRlbnRpZmllcl0uZGVmYXVsdF92YWx1ZSA9IG51bGw7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwiY3VzdG9tVmFyaWFibGVcIjpcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGFyZ2V0T2JqZWN0IGFzIEN1c3RvbVZhcmlhYmxlKS5nZXRDb25maWd1cmF0aW9uKCkuZGVmYXVsdF92YWx1ZSA9IG51bGw7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gU2hvdy9oaWRlIHRoZSB0ZXh0YXJlYVxyXG4gICAgICAgICAgICAgICAgdXBkYXRlVGV4dGFyZWFDb21wb25lbnRWaXNpYmlsaXR5KG5ld1R5cGUpO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIFNhdmUgdGhlIHNldHRpbmdzXHJcbiAgICAgICAgICAgICAgICBhd2FpdCBwbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgIH0pLFxyXG4gICAgICAgIClcclxuICAgICAgICAuYWRkVGV4dEFyZWEodGV4dGFyZWEgPT4gdGV4dGFyZWFDb21wb25lbnQgPSB0ZXh0YXJlYVxyXG4gICAgICAgICAgICAuc2V0VmFsdWUoZGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbiA/IGRlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24udmFsdWUgOiBcIlwiKVxyXG4gICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKG5ld1ZhbHVlOiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgICAgIGlmICghZGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbikge1xyXG4gICAgICAgICAgICAgICAgICAgIGRlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb24gPSBjcmVhdGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uKCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gU2V0IHRoZSBuZXcgdGV4dCB2YWx1ZVxyXG4gICAgICAgICAgICAgICAgZGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbi52YWx1ZSA9IG5ld1ZhbHVlO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIFNhdmUgdGhlIHNldHRpbmdzXHJcbiAgICAgICAgICAgICAgICBhd2FpdCBwbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgIH0pLnRoZW4oKHRleHRhcmVhQ29tcG9uZW50KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAvLyBBdXRvY29tcGxldGUgZm9yIHRoZSB0ZXh0YXJlYS5cclxuICAgICAgICAgICAgICAgIGlmIChwbHVnaW4uc2V0dGluZ3Muc2hvd19hdXRvY29tcGxldGVfbWVudSkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZUF1dG9jb21wbGV0ZShwbHVnaW4sIHRleHRhcmVhQ29tcG9uZW50LmlucHV0RWwsICgpID0+IHRleHRhcmVhQ29tcG9uZW50Lm9uQ2hhbmdlZCgpKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSksXHJcbiAgICAgICAgKVxyXG4gICAgO1xyXG4gICAgdXBkYXRlVGV4dGFyZWFDb21wb25lbnRWaXNpYmlsaXR5KFxyXG4gICAgICAgIGRlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb25cclxuICAgICAgICAgICAgPyBkZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uLnR5cGVcclxuICAgICAgICAgICAgOiB0YXJnZXRUeXBlID09PSBcInRTaGVsbENvbW1hbmRcIlxyXG4gICAgICAgICAgICAgICAgPyBcInNob3ctZXJyb3JzXCIgLy8gSXQgZG9lcyBub3QgcmVhbGx5IG1hdHRlciBpZiBwYXNzaW5nIFwic2hvdy1lcnJvcnNcIiAuLi4uXHJcbiAgICAgICAgICAgICAgICA6IFwiaW5oZXJpdFwiLCAgICAvLyAuLi4gb3IgXCJpbmhlcml0XCIsIGJvdGggd2lsbCBoYXZlIHRoZSBzYW1lIGVmZmVjdCAoPSBoaWRlIGEgdGV4dGFyZWEpLCBidXQgdGhpcyBpcyBtb3JlIGZ1dHVyZS1wcm9vZi5cclxuICAgICk7XHJcblxyXG4gICAgcmV0dXJuIGRlZmF1bHRWYWx1ZVNldHRpbmc7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U2V0dGluZ30gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7U0NfTWFpblNldHRpbmdzfSBmcm9tIFwiLi4vLi4vc2V0dGluZ3MvU0NfTWFpblNldHRpbmdzXCI7XHJcbmltcG9ydCB7Q3VzdG9tVmFyaWFibGVJbnN0YW5jZX0gZnJvbSBcIi4vQ3VzdG9tVmFyaWFibGVJbnN0YW5jZVwiO1xyXG5pbXBvcnQge1xyXG4gICAgZ2V0SURHZW5lcmF0b3IsXHJcbiAgICBNb2RlbCxcclxuICAgIFBhcmVudE1vZGVsT25lVG9NYW55SWRSZWxhdGlvbixcclxufSBmcm9tIFwiLi4vLi4vaW1wb3J0c1wiO1xyXG5pbXBvcnQge2RlYnVnTG9nfSBmcm9tIFwiLi4vLi4vRGVidWdcIjtcclxuaW1wb3J0IHtcclxuICAgIEdsb2JhbFZhcmlhYmxlRGVmYXVsdFZhbHVlQ29uZmlndXJhdGlvbixcclxufSBmcm9tIFwiLi4vLi4vdmFyaWFibGVzL1ZhcmlhYmxlXCI7XHJcbmltcG9ydCB7Y3JlYXRlVmFyaWFibGVEZWZhdWx0VmFsdWVGaWVsZH0gZnJvbSBcIi4uLy4uL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvY3JlYXRlVmFyaWFibGVEZWZhdWx0VmFsdWVGaWVsZHNcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBDdXN0b21WYXJpYWJsZU1vZGVsIGV4dGVuZHMgTW9kZWwge1xyXG5cclxuICAgIHByaXZhdGUgY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlczogQ3VzdG9tVmFyaWFibGVJbnN0YW5jZU1hcCA9IG5ldyBDdXN0b21WYXJpYWJsZUluc3RhbmNlTWFwO1xyXG5cclxuICAgIHB1YmxpYyBnZXRTaW5ndWxhck5hbWUoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gXCJDdXN0b20gdmFyaWFibGVcIjtcclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgZGVmaW5lUGFyZW50Q29uZmlndXJhdGlvblJlbGF0aW9uKGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZTogQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSk6IFBhcmVudE1vZGVsT25lVG9NYW55SWRSZWxhdGlvbiB7XHJcbiAgICAgICAgZGVidWdMb2coYEN1c3RvbVZhcmlhYmxlTW9kZWw6IERlZmluaW5nIHBhcmVudCBjb25maWd1cmF0aW9uIHJlbGF0aW9uIGZvciBDdXN0b21WYXJpYWJsZUluc3RhbmNlICR7Y3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlLmdldElEKCl9LmApO1xyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIHR5cGU6IFwib25lLXRvLW1hbnktaWRcIixcclxuICAgICAgICAgICAga2V5OiBcImN1c3RvbV92YXJpYWJsZXNcIixcclxuICAgICAgICAgICAgaWQ6IGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZS5nZXRJRCgpLFxyXG4gICAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGxvYWRJbnN0YW5jZXMocGFyZW50X2NvbmZpZ3VyYXRpb246IFNDX01haW5TZXR0aW5ncyk6IEN1c3RvbVZhcmlhYmxlSW5zdGFuY2VNYXAge1xyXG4gICAgICAgIGRlYnVnTG9nKGBDdXN0b21WYXJpYWJsZU1vZGVsOiBMb2FkaW5nIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2VzLmApO1xyXG4gICAgICAgIHRoaXMuY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlcy5jbGVhcigpO1xyXG4gICAgICAgIHBhcmVudF9jb25maWd1cmF0aW9uLmN1c3RvbV92YXJpYWJsZXMuZm9yRWFjaCgoY3VzdG9tX3ZhcmlhYmxlX2NvbmZpZ3VyYXRpb246IEN1c3RvbVZhcmlhYmxlQ29uZmlndXJhdGlvbikgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLmN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZXMuc2V0KFxyXG4gICAgICAgICAgICAgICAgY3VzdG9tX3ZhcmlhYmxlX2NvbmZpZ3VyYXRpb24uaWQsXHJcbiAgICAgICAgICAgICAgICBuZXcgQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSh0aGlzLCBjdXN0b21fdmFyaWFibGVfY29uZmlndXJhdGlvbiwgcGFyZW50X2NvbmZpZ3VyYXRpb24pXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlcztcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgbmV3SW5zdGFuY2UocGFyZW50X2NvbmZpZ3VyYXRpb246IFNDX01haW5TZXR0aW5ncyk6IEN1c3RvbVZhcmlhYmxlSW5zdGFuY2Uge1xyXG4gICAgICAgIGRlYnVnTG9nKGBDdXN0b21WYXJpYWJsZU1vZGVsOiBDcmVhdGluZyBhIG5ldyBDdXN0b21WYXJpYWJsZUluc3RhbmNlLmApO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0XHJcbiAgICAgICAgY29uc3QgY3VzdG9tX3ZhcmlhYmxlX2NvbmZpZ3VyYXRpb246IEN1c3RvbVZhcmlhYmxlQ29uZmlndXJhdGlvbiA9IHRoaXMuZ2V0RGVmYXVsdENvbmZpZ3VyYXRpb24oKTtcclxuICAgICAgICBwYXJlbnRfY29uZmlndXJhdGlvbi5jdXN0b21fdmFyaWFibGVzLnB1c2goY3VzdG9tX3ZhcmlhYmxlX2NvbmZpZ3VyYXRpb24pO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBDdXN0b21WYXJpYWJsZUluc3RhbmNlIGZvciBoYW5kbGluZyB0aGUgY29uZmlndXJhdGlvblxyXG4gICAgICAgIGNvbnN0IGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZSA9IG5ldyBDdXN0b21WYXJpYWJsZUluc3RhbmNlKHRoaXMsIGN1c3RvbV92YXJpYWJsZV9jb25maWd1cmF0aW9uLCBwYXJlbnRfY29uZmlndXJhdGlvbik7XHJcbiAgICAgICAgdGhpcy5jdXN0b21fdmFyaWFibGVfaW5zdGFuY2VzLnNldChjdXN0b21fdmFyaWFibGVfY29uZmlndXJhdGlvbi5pZCwgY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlKTtcclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGFuIG9wZXJhdGlvbmFsIHZhcmlhYmxlLlxyXG4gICAgICAgIHRoaXMucGx1Z2luLmdldFZhcmlhYmxlcygpLmFkZChjdXN0b21fdmFyaWFibGVfaW5zdGFuY2UuY3JlYXRlQ3VzdG9tVmFyaWFibGUoKSk7XHJcblxyXG4gICAgICAgIHJldHVybiBjdXN0b21fdmFyaWFibGVfaW5zdGFuY2U7XHJcbiAgICAgICAgLy8gVE9ETzogTW92ZSB0aGlzIGxvZ2ljIHRvIHRoZSBiYXNlIE1vZGVsIGNsYXNzLlxyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBfY3JlYXRlU2V0dGluZ0ZpZWxkcyhpbnN0YW5jZTogQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSwgY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KTogU2V0dGluZyB7XHJcbiAgICAgICAgZGVidWdMb2coYEN1c3RvbVZhcmlhYmxlTW9kZWw6IENyZWF0aW5nIHNldHRpbmcgZmllbGRzIGZvciBDdXN0b21WYXJpYWJsZUluc3RhbmNlICR7aW5zdGFuY2UuZ2V0SUQoKX0uYCk7XHJcblxyXG4gICAgICAgIC8vIE1ha2UgdGhlIGZpZWxkcyBhcHBlYXIgY2xvc2VyIHRvZ2V0aGVyLlxyXG4gICAgICAgIGNvbnRhaW5lcl9lbGVtZW50LmFkZENsYXNzKFwiU0Mtc2V0dGluZy1ncm91cFwiKTtcclxuXHJcbiAgICAgICAgLy8gSGVhZGluZyBzZXR0aW5nXHJcbiAgICAgICAgY29uc3QgaGVhZGluZ19zZXR0aW5nID0gbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKGluc3RhbmNlLmdldEZ1bGxOYW1lKCkpXHJcbiAgICAgICAgICAgIC5zZXRIZWFkaW5nKClcclxuICAgICAgICA7XHJcblxyXG4gICAgICAgIC8vIE5hbWUgc2V0dGluZ1xyXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0TmFtZShcIlZhcmlhYmxlIG5hbWVcIilcclxuICAgICAgICAgICAgLnNldERlc2MoXCJNdXN0IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGNoYXJhY3Rlci4gQWxsb3dlZCBjaGFyYWN0ZXJzIGFyZSBsZXR0ZXJzIGEteiwgbnVtYmVycyAwLTkgYW5kIGFuIHVuZGVyc2NvcmUgX1wiKVxyXG4gICAgICAgICAgICAuc2V0Q2xhc3MoXCJTQy1jdXN0b20tdmFyaWFibGUtbmFtZS1zZXR0aW5nXCIpXHJcbiAgICAgICAgICAgIC5hZGRUZXh0KHRleHQgPT4gdGV4dFxyXG4gICAgICAgICAgICAgICAgLnNldFZhbHVlKGluc3RhbmNlLmNvbmZpZ3VyYXRpb24ubmFtZSlcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZSgobmV3X25hbWU6IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IEZpbmQgYSB3YXkgdG8gY3JlYXRlIHRoaXMga2luZCBvZiB0cml2aWFsIG9uQ2hhbmdlKCkgZnVuY3Rpb25zIGluIHRoZSBNb2RlbCBiYXNlIGNsYXNzLlxyXG4gICAgICAgICAgICAgICAgICAgIGluc3RhbmNlLnNldElmVmFsaWQoXCJuYW1lXCIsIG5ld19uYW1lKS50aGVuKGFzeW5jICgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVmFsaWRcclxuICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGluZ19zZXR0aW5nLnNldE5hbWUoaW5zdGFuY2UuZ2V0RnVsbE5hbWUoKSk7IC8vIEFsc28gcmVtb3ZlcyBhIHBvc3NpYmxlIHdhcm5pbmcgbWVzc2FnZS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaW5zdGFuY2UuZ2V0Q3VzdG9tVmFyaWFibGUoKS51cGRhdGVQcm9wZXJ0aWVzKCk7IC8vIFVwZGF0ZSB0aGUgbmFtZSBhbHNvIHRvIHRoZSBvcGVyYXRpb25hbCB2YXJpYWJsZSwgbm90IG9ubHkgaW4gY29uZmlndXJhdGlvbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnVwZGF0ZUN1c3RvbVZhcmlhYmxlVmlld3MoKTtcclxuICAgICAgICAgICAgICAgICAgICB9LCAocmVhc29uOiBzdHJpbmcgfCB1bmtub3duKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5vdCB2YWxpZFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHJlYXNvbiA9PT0gXCJzdHJpbmdcIikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyBpcyBhIHZhbGlkYXRpb24gZXJyb3IgbWVzc2FnZS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERpc3BsYXkgYSB3YXJuaW5nIG1lc3NhZ2UuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkaW5nX3NldHRpbmcuc2V0TmFtZShyZWFzb24gKyBcIiBUaGUgbmFtZSB3YXMgbm90IHNhdmVkLlwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvbWUgb3RoZXIgcnVudGltZSBlcnJvciBoYXMgb2NjdXJyZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyByZWFzb247XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG5cclxuICAgICAgICAvLyBEZXNjcmlwdGlvbiBzZXR0aW5nXHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKFwiRGVzY3JpcHRpb25cIilcclxuICAgICAgICAgICAgLnNldERlc2MoXCJBcHBlYXJzIGluIGF1dG9jb21wbGV0ZSBsaXN0cyBhbG9uZyB3aXRoIHRoZSB2YXJpYWJsZSBuYW1lLCBhbmQgYWxzbyBpbiB0aGUgJ0N1c3RvbSB2YXJpYWJsZXMnIHBhbmUsIGlmIHlvdSB1c2UgaXQuXCIpXHJcbiAgICAgICAgICAgIC5hZGRUZXh0KHRleHQgPT4gdGV4dFxyXG4gICAgICAgICAgICAgICAgLnNldFZhbHVlKGluc3RhbmNlLmNvbmZpZ3VyYXRpb24uZGVzY3JpcHRpb24pXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKG5ld19kZXNjcmlwdGlvbjogc3RyaW5nKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVE9ETzogRmluZCBhIHdheSB0byBjcmVhdGUgdGhpcyBraW5kIG9mIHRyaXZpYWwgb25DaGFuZ2UoKSBmdW5jdGlvbnMgaW4gdGhlIE1vZGVsIGJhc2UgY2xhc3MuXHJcbiAgICAgICAgICAgICAgICAgICAgaW5zdGFuY2UuY29uZmlndXJhdGlvbi5kZXNjcmlwdGlvbiA9IG5ld19kZXNjcmlwdGlvbjtcclxuICAgICAgICAgICAgICAgICAgICBpbnN0YW5jZS5nZXRDdXN0b21WYXJpYWJsZSgpLnVwZGF0ZVByb3BlcnRpZXMoKTsgLy8gVXBkYXRlIHRoZSBkZXNjcmlwdGlvbiBhbHNvIHRvIHRoZSBvcGVyYXRpb25hbCB2YXJpYWJsZSwgbm90IG9ubHkgaW4gY29uZmlndXJhdGlvbi5cclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi51cGRhdGVDdXN0b21WYXJpYWJsZVZpZXdzKCk7XHJcbiAgICAgICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgIDtcclxuXHJcbiAgICAgICAgLy8gRGVmYXVsdCB2YWx1ZSBzZXR0aW5nXHJcbiAgICAgICAgY3JlYXRlVmFyaWFibGVEZWZhdWx0VmFsdWVGaWVsZChcclxuICAgICAgICAgICAgdGhpcy5wbHVnaW4sXHJcbiAgICAgICAgICAgIGNvbnRhaW5lcl9lbGVtZW50LFxyXG4gICAgICAgICAgICBcIkRlZmF1bHQgdmFsdWVcIixcclxuICAgICAgICAgICAgaW5zdGFuY2UuZ2V0Q3VzdG9tVmFyaWFibGUoKSxcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICByZXR1cm4gaGVhZGluZ19zZXR0aW5nO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyB2YWxpZGF0ZVZhbHVlKGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZTogQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSwgZmllbGQ6IGtleW9mIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2VbXCJjb25maWd1cmF0aW9uXCJdLCBjdXN0b21fdmFyaWFibGVfbmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgZGVidWdMb2coYEN1c3RvbVZhcmlhYmxlTW9kZWw6IFZhbGlkYXRpbmcgJHtmaWVsZH0gdmFsdWUgJHtjdXN0b21fdmFyaWFibGVfbmFtZX0gZm9yIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UgJHtjdXN0b21fdmFyaWFibGVfaW5zdGFuY2UuZ2V0SUQoKX0uYCk7XHJcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgICAgICAgICAgc3dpdGNoIChmaWVsZCkge1xyXG4gICAgICAgICAgICAgICAgY2FzZSBcIm5hbWVcIjpcclxuICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayB0aGF0IHRoZSBuYW1lIGNvbnRhaW5zIG9ubHkgY2hhcmFjdGVycyBhLXosIDAtOSBhbmQvb3IgdW5kZXJsaW5lIF9cclxuICAgICAgICAgICAgICAgICAgICBpZiAoIWN1c3RvbV92YXJpYWJsZV9uYW1lLm1hdGNoKC9eW1xcd1xcZF0rJC91KSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJbmNvcnJlY3QgZm9ybWF0LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoYFRoZSBuYW1lIHt7XyR7Y3VzdG9tX3ZhcmlhYmxlX25hbWV9fX0gZG9lcyBub3QgbWVldCB0aGUgbmFtaW5nIHJlcXVpcmVtZW50cy5gKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIG5hbWUgaXMgYSBkdXBsaWNhdGUuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuaXNDdXN0b21WYXJpYWJsZU5hbWVEdXBsaWNhdGUoY3VzdG9tX3ZhcmlhYmxlX25hbWUsIGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZSkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSXQncyBhIGR1cGxpY2F0ZS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGBUaGUgbmFtZSB7e18ke2N1c3RvbV92YXJpYWJsZV9uYW1lfX19IGlzIGFscmVhZHkgcmVzZXJ2ZWQuYCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSXQncyB1bmlxdWUuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgICAgICAgICAvLyBPdGhlciBmaWVsZHMgZG8gbm90IG5lZWQgdmFsaWRhdGlvbi5cclxuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldERlZmF1bHRDb25maWd1cmF0aW9uKCk6IEN1c3RvbVZhcmlhYmxlQ29uZmlndXJhdGlvbiB7XHJcbiAgICAgICAgLy8gR2VuZXJhdGUgYSB1bmlxdWUgbmFtZSBmb3IgdGhlIHZhcmlhYmxlIGJ5IHVzaW5nIGEgc2VxdWVudGlhbCBudW1iZXIuXHJcbiAgICAgICAgbGV0IHNlcXVlbnRpYWxfbnVtYmVyID0gMTtcclxuICAgICAgICB3aGlsZSAodGhpcy5pc0N1c3RvbVZhcmlhYmxlTmFtZUR1cGxpY2F0ZShTdHJpbmcoc2VxdWVudGlhbF9udW1iZXIpKSkge1xyXG4gICAgICAgICAgICBzZXF1ZW50aWFsX251bWJlcisrO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGEgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgaWQ6IGdldElER2VuZXJhdG9yKCkuZ2VuZXJhdGVJRCgpLFxyXG4gICAgICAgICAgICBuYW1lOiBTdHJpbmcoc2VxdWVudGlhbF9udW1iZXIpLFxyXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJcIixcclxuICAgICAgICAgICAgZGVmYXVsdF92YWx1ZTogbnVsbCxcclxuICAgICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBhc3luYyBfZGVsZXRlSW5zdGFuY2UoY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlOiBDdXN0b21WYXJpYWJsZUluc3RhbmNlKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgZGVidWdMb2coYEN1c3RvbVZhcmlhYmxlTW9kZWw6IERlbGV0aW5nIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UgJHtjdXN0b21fdmFyaWFibGVfaW5zdGFuY2UuZ2V0SUQoKX0uYCk7XHJcblxyXG4gICAgICAgIC8vIFJlbW92ZSB0aGUgQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSBmcm9tIGFsbCBQcm9tcHRGaWVsZHMgdGhhdCB1c2UgaXQuXHJcbiAgICAgICAgZm9yIChjb25zdCBwcm9tcHQgb2YgdGhpcy5wbHVnaW4uZ2V0UHJvbXB0cygpLnZhbHVlcygpKSB7XHJcbiAgICAgICAgICAgIGZvciAoY29uc3QgcHJvbXB0X2ZpZWxkIG9mIHByb21wdC5wcm9tcHRfZmllbGRzKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlLmdldElEKCkgPT09IHByb21wdF9maWVsZC5jb25maWd1cmF0aW9uLnRhcmdldF92YXJpYWJsZV9pZCkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFRoaXMgcHJvbXB0IGZpZWxkIHVzZXMgdGhpcyBDdXN0b21WYXJpYWJsZUluc3RhbmNlLlxyXG4gICAgICAgICAgICAgICAgICAgIC8vIFJlbW92ZSB0aGUgdmFyaWFibGUgZnJvbSB1c2UuXHJcbiAgICAgICAgICAgICAgICAgICAgcHJvbXB0X2ZpZWxkLmNvbmZpZ3VyYXRpb24udGFyZ2V0X3ZhcmlhYmxlX2lkID0gXCJcIjtcclxuICAgICAgICAgICAgICAgICAgICAvLyBTYXZpbmcgaXMgZG9uZSBsYXRlciwgYWZ0ZXIgdGhlIF9kZWxldGVJbnN0YW5jZSgpIGNhbGwuXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIERlbGV0ZSBDdXN0b21WYXJpYWJsZVxyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHRoaXMucGx1Z2luLmdldFZhcmlhYmxlcygpLmRlbGV0ZShjdXN0b21fdmFyaWFibGVfaW5zdGFuY2UuZ2V0Q3VzdG9tVmFyaWFibGUoKSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgLy8gSWYgY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlLmdldEN1c3RvbVZhcmlhYmxlKCkgZmFpbGVkLCBubyBuZWVkIHRvIGRvIGFueXRoaW5nLiBJdCBqdXN0IG1lYW5zIHRoZXJlIGlzIG5vIEN1c3RvbVZhcmlhYmxlLCBzbyB0aGVyZSdzIG5vdGhpbmcgdG8gZGVsZXRlLlxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRGVsZXRlIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2VcclxuICAgICAgICB0aGlzLmN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZXMuZGVsZXRlKGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZS5nZXRJRCgpKTtcclxuXHJcbiAgICAgICAgLy8gcmVtb3ZlIHRoZSB2YXJpYWJsZSBmcm9tIGN1c3RvbSB2YXJpYWJsZSBzaWRlIHBhbmVzLlxyXG4gICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnVwZGF0ZUN1c3RvbVZhcmlhYmxlVmlld3MoKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENhbiBiZSBjaGFuZ2VkIHRvIHB1YmxpYyBpZiBuZWVkZWQuXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgaXNDdXN0b21WYXJpYWJsZU5hbWVEdXBsaWNhdGUoY3VzdG9tX3ZhcmlhYmxlX25hbWU6IHN0cmluZywgaWdub3JlX2N1c3RvbV92YXJpYWJsZV9pbnN0YW5jZT86IEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UpOiBib29sZWFuIHtcclxuICAgICAgICBsZXQgaXNfZHVwbGljYXRlID0gZmFsc2U7XHJcbiAgICAgICAgdGhpcy5jdXN0b21fdmFyaWFibGVfaW5zdGFuY2VzLmZvckVhY2goKGN1c3RvbV92YXJpYWJsZTJfaW5zdGFuY2U6IEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UsIGN1c3RvbV92YXJpYWJsZV9pZDogc3RyaW5nKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIEZpcnN0IGNoZWNrIGNhbiB0aGUgY3VycmVudCBjdXN0b20gdmFyaWFibGUgYXR0ZW5kIHRvIHRoZSBkdXBsaWNhdGUgdGVzdC5cclxuICAgICAgICAgICAgaWYgKGlnbm9yZV9jdXN0b21fdmFyaWFibGVfaW5zdGFuY2UgJiYgY3VzdG9tX3ZhcmlhYmxlX2lkID09PSBpZ25vcmVfY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlLmdldElEKCkpIHtcclxuICAgICAgICAgICAgICAgIC8vIERvbid0IGNoZWNrIHRoaXMgaW5zdGFuY2UuIFRoaXMgc2tpcHBpbmcgaXMgdXNlZCBmb3IgdGhlIGN1cnJlbnQgb3duZXIgb2YgdGhlIG5hbWUuXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIE5vdyBkbyB0aGUgYWN0dWFsIGR1cGxpY2F0ZSB0ZXN0LlxyXG4gICAgICAgICAgICBpZiAoY3VzdG9tX3ZhcmlhYmxlX25hbWUudG9Mb2NhbGVMb3dlckNhc2UoKSA9PT0gY3VzdG9tX3ZhcmlhYmxlMl9pbnN0YW5jZS5jb25maWd1cmF0aW9uLm5hbWUudG9Mb2NhbGVMb3dlckNhc2UoKSkge1xyXG4gICAgICAgICAgICAgICAgaXNfZHVwbGljYXRlID0gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybiBpc19kdXBsaWNhdGU7XHJcbiAgICB9XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgQ3VzdG9tVmFyaWFibGVDb25maWd1cmF0aW9uIHtcclxuICAgIGlkOiBzdHJpbmcsXHJcbiAgICBuYW1lOiBzdHJpbmcsXHJcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nLFxyXG4gICAgZGVmYXVsdF92YWx1ZTogR2xvYmFsVmFyaWFibGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uIHwgbnVsbCxcclxufVxyXG5cclxuZXhwb3J0IGNsYXNzIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2VNYXAgZXh0ZW5kcyBNYXA8c3RyaW5nLCBDdXN0b21WYXJpYWJsZUluc3RhbmNlPiB7fSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtTQ19Nb2RhbH0gZnJvbSBcIi4uLy4uL1NDX01vZGFsXCI7XHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uLy4uL21haW5cIjtcclxuaW1wb3J0IHtcclxuICAgIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UsXHJcbiAgICBDdXN0b21WYXJpYWJsZU1vZGVsLFxyXG4gICAgZ2V0TW9kZWwsXHJcbn0gZnJvbSBcIi4uLy4uL2ltcG9ydHNcIjtcclxuaW1wb3J0IHtTZXR0aW5nfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBDdXN0b21WYXJpYWJsZVNldHRpbmdzTW9kYWwgZXh0ZW5kcyBTQ19Nb2RhbCB7XHJcblxyXG4gICAgcHJpdmF0ZSBjcmVhdGVkID0gZmFsc2U7XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBjdXN0b21fdmFyaWFibGVfaW5zdGFuY2U6IEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UsXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBvbl9hZnRlcl9jcmVhdGlvbjogKCkgPT4gdm9pZCxcclxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IG9uX2FmdGVyX2NhbmNlbGxpbmc6ICgpID0+IHZvaWQsXHJcbiAgICApIHtcclxuICAgICAgICBzdXBlcihwbHVnaW4pO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbk9wZW4oKTogdm9pZCB7XHJcbiAgICAgICAgc3VwZXIub25PcGVuKCk7XHJcblxyXG4gICAgICAgIGNvbnN0IG1vZGVsID0gZ2V0TW9kZWw8Q3VzdG9tVmFyaWFibGVNb2RlbD4oQ3VzdG9tVmFyaWFibGVNb2RlbC5uYW1lKTtcclxuICAgICAgICBtb2RlbC5jcmVhdGVTZXR0aW5nRmllbGRzKHRoaXMuY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlLCB0aGlzLm1vZGFsRWwsIGZhbHNlKTtcclxuXHJcbiAgICAgICAgbmV3IFNldHRpbmcodGhpcy5tb2RhbEVsKVxyXG4gICAgICAgICAgICAuYWRkQnV0dG9uKGJ1dHRvbiA9PiBidXR0b25cclxuICAgICAgICAgICAgICAgIC5zZXRCdXR0b25UZXh0KFwiQ3JlYXRlXCIpXHJcbiAgICAgICAgICAgICAgICAub25DbGljaygoKSA9PiB0aGlzLmFwcHJvdmUoKSksXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGFwcHJvdmUoKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5jcmVhdGVkID0gdHJ1ZTtcclxuICAgICAgICB0aGlzLm9uX2FmdGVyX2NyZWF0aW9uKCk7XHJcbiAgICAgICAgdGhpcy5jbG9zZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbkNsb3NlKCk6IHZvaWQge1xyXG4gICAgICAgIHN1cGVyLm9uQ2xvc2UoKTtcclxuXHJcbiAgICAgICAgaWYgKCF0aGlzLmNyZWF0ZWQpIHtcclxuICAgICAgICAgICAgdGhpcy5vbl9hZnRlcl9jYW5jZWxsaW5nKCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1xyXG4gICAgSXRlbVZpZXcsXHJcbiAgICBXb3Jrc3BhY2VMZWFmLFxyXG59IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi8uLi9tYWluXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgQ3VzdG9tVmFyaWFibGVWaWV3IGV4dGVuZHMgSXRlbVZpZXcge1xyXG5cclxuICAgIHB1YmxpYyBzdGF0aWMgVmlld1R5cGUgPSBcIlNDLWN1c3RvbS12YXJpYWJsZXMtdmlld1wiO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIHByaXZhdGUgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgbGVhZjogV29ya3NwYWNlTGVhZlxyXG4gICAgKSB7XHJcbiAgICAgICAgc3VwZXIobGVhZik7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldERpc3BsYXlUZXh0KCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIFwiQ3VzdG9tIHZhcmlhYmxlc1wiO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRWaWV3VHlwZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBDdXN0b21WYXJpYWJsZVZpZXcuVmlld1R5cGU7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldEljb24oKSB7XHJcbiAgICAgICAgcmV0dXJuIFwiY29kZS1nbHlwaFwiO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxEaXZFbGVtZW50O1xyXG4gICAgcHJvdGVjdGVkIGFzeW5jIG9uT3BlbigpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICB0aGlzLmNvbnRhaW5lcl9lbGVtZW50ID0gdGhpcy5jb250YWluZXJFbC5jaGlsZHJlblsxXS5jcmVhdGVEaXYoKTsgLy8gSSBkb24ndCBrbm93IHdoeSBJIGNhbm5vdCBjcmVhdGUgZWxlbWVudHMgZGlyZWN0bHkgdW5kZXIgdGhpcy5jb250YWluZXJFbCAodGhleSB3b3VsZG4ndCBzaG93IHVwKS4gSSBkaWQgdGhlIHNhbWUgdGhpbmcgYXMgd2FzIGRvbmUgaGVyZTogaHR0cHM6Ly9tYXJjdXMuc2UubmV0L29ic2lkaWFuLXBsdWdpbi1kb2NzL2d1aWRlcy9jdXN0b20tdmlld3MgKHJlZmVyZW5jZWQgMjAyMi0wMy0yMykuXHJcbiAgICAgICAgdGhpcy5jb250YWluZXJfZWxlbWVudC5hZGRDbGFzcyhcImNvbnRhaW5lclwiKTtcclxuXHJcbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGVDb250ZW50KCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGFzeW5jIHVwZGF0ZUNvbnRlbnQoKSB7XHJcbiAgICAgICAgdGhpcy5jb250YWluZXJfZWxlbWVudC5lbXB0eSgpO1xyXG4gICAgICAgIHRoaXMuY29udGFpbmVyX2VsZW1lbnQuY3JlYXRlRWwoXCJoM1wiLCB7dGV4dDogXCJDdXN0b20gdmFyaWFibGVzXCJ9KTtcclxuICAgICAgICBjb25zdCB2YXJpYWJsZUxpc3RFbGVtZW50OiBIVE1MVUxpc3RFbGVtZW50ID0gdGhpcy5jb250YWluZXJfZWxlbWVudC5jcmVhdGVFbChcInVsXCIpO1xyXG4gICAgICAgIGZvciAoY29uc3QgY3VzdG9tVmFyaWFibGVJbnN0YW5jZSBvZiB0aGlzLnBsdWdpbi5nZXRDdXN0b21WYXJpYWJsZUluc3RhbmNlcygpLnZhbHVlcygpKSB7XHJcbiAgICAgICAgICAgIGxldCBjdXN0b21WYXJpYWJsZVZhbHVlOiBzdHJpbmcgfCBudWxsID0gKGF3YWl0IGN1c3RvbVZhcmlhYmxlSW5zdGFuY2UuZ2V0Q3VzdG9tVmFyaWFibGUoKS5nZXRWYWx1ZSgpKS52YWx1ZTtcclxuICAgICAgICAgICAgbGV0IGN1c3RvbVZhcmlhYmxlU3RhdGU6IHN0cmluZyB8IG51bGwgPSBudWxsO1xyXG4gICAgICAgICAgICBpZiAobnVsbCA9PT0gY3VzdG9tVmFyaWFibGVWYWx1ZSkge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhlIHZhcmlhYmxlIGhhcyBubyB2YWx1ZSB5ZXQuXHJcbiAgICAgICAgICAgICAgICBpZiAoXCJ2YWx1ZVwiID09PSBjdXN0b21WYXJpYWJsZUluc3RhbmNlLmNvbmZpZ3VyYXRpb24uZGVmYXVsdF92YWx1ZT8udHlwZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIEluZGljYXRlIHRoYXQgdGhlIHZhcmlhYmxlIGhhcyBhIGRlZmF1bHQgdmFsdWUgZGVmaW5lZCwgd2hpY2ggd2lsbCBwcmFjdGljYWxseSBiZSB1c2VkIGFzIGxvbmcgYXMgbm8gb3ZlcnJpZGluZyB2YWx1ZSBpcyBzZXQuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKFwiXCIgPT09IGN1c3RvbVZhcmlhYmxlSW5zdGFuY2UuY29uZmlndXJhdGlvbi5kZWZhdWx0X3ZhbHVlLnZhbHVlLnRyaW0oKSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjdXN0b21WYXJpYWJsZVN0YXRlID0gXCJObyB2YWx1ZSB5ZXQsIGJ1dCBkZWZhdWx0cyB0bzogQW4gZW1wdHkgdGV4dC5cIjtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjdXN0b21WYXJpYWJsZVN0YXRlID0gXCJObyB2YWx1ZSB5ZXQsIGJ1dCBkZWZhdWx0cyB0bzogXCI7IC8vIFRoZSB2YWx1ZSB3aWxsIGFwcGVhciBuZXh0IHRvIHRoZSBzdGF0ZSB0ZXh0IGxhdGVyIGJlbG93LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBjdXN0b21WYXJpYWJsZVZhbHVlID0gY3VzdG9tVmFyaWFibGVJbnN0YW5jZS5jb25maWd1cmF0aW9uLmRlZmF1bHRfdmFsdWUudmFsdWU7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBObyBkZWZhdWx0IHZhbHVlIGlzIGRlZmluZWQsIHNvIG5vIHZhbHVlIGlzIGFjY2Vzc2libGUuXHJcbiAgICAgICAgICAgICAgICAgICAgY3VzdG9tVmFyaWFibGVTdGF0ZSA9IFwiTm8gdmFsdWUgeWV0LlwiO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKFwiXCIgPT09IGN1c3RvbVZhcmlhYmxlVmFsdWUpIHtcclxuICAgICAgICAgICAgICAgIGN1c3RvbVZhcmlhYmxlU3RhdGUgPSBcIkFuIGVtcHR5IHRleHQuXCI7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgY29uc3QgdmFyaWFibGVMaXN0SXRlbUVsZW1lbnQgPSB2YXJpYWJsZUxpc3RFbGVtZW50LmNyZWF0ZUVsKFwibGlcIiwge1xyXG4gICAgICAgICAgICAgICAgdGV4dDogY3VzdG9tVmFyaWFibGVJbnN0YW5jZS5nZXRGdWxsTmFtZSgpLFxyXG4gICAgICAgICAgICAgICAgYXR0cjoge1xyXG4gICAgICAgICAgICAgICAgICAgIFwiYXJpYS1sYWJlbFwiOiBjdXN0b21WYXJpYWJsZUluc3RhbmNlLmNvbmZpZ3VyYXRpb24uZGVzY3JpcHRpb24sXHJcbiAgICAgICAgICAgICAgICAgICAgXCJjbGFzc1wiOiBcIlNDLWN1c3RvbS12YXJpYWJsZS12aWV3LWxpc3QtaXRlbVwiLFxyXG4gICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIHZhcmlhYmxlTGlzdEl0ZW1FbGVtZW50LmNyZWF0ZUVsKFwiYnJcIik7XHJcbiAgICAgICAgICAgIGlmIChudWxsICE9PSBjdXN0b21WYXJpYWJsZVN0YXRlKSB7XHJcbiAgICAgICAgICAgICAgICB2YXJpYWJsZUxpc3RJdGVtRWxlbWVudC5jcmVhdGVFbChcImVtXCIpLmluc2VydEFkamFjZW50VGV4dChcImJlZm9yZWVuZFwiLCBjdXN0b21WYXJpYWJsZVN0YXRlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBpZiAobnVsbCAhPT0gY3VzdG9tVmFyaWFibGVWYWx1ZSkge1xyXG4gICAgICAgICAgICAgICAgLy8gQm9sZCBub3JtYWwgdmFsdWVzIHRvIG1ha2UgdGhlbSBtb3JlIHByb21pbmVudCBpbiBjb250cmFzdCB0byB2YXJpYWJsZSBuYW1lcyBhbmQgXCJObyB2YWx1ZSB5ZXQuXCIvXCJBbiBlbXB0eSB0ZXh0LlwiIHRleHRzLlxyXG4gICAgICAgICAgICAgICAgdmFyaWFibGVMaXN0SXRlbUVsZW1lbnQuY3JlYXRlRWwoXCJzdHJvbmdcIikuaW5zZXJ0QWRqYWNlbnRUZXh0KFwiYmVmb3JlZW5kXCIsIGN1c3RvbVZhcmlhYmxlVmFsdWUpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi4vbWFpblwiO1xyXG5pbXBvcnQge1NoZWxsQ29tbWFuZFBhcnNpbmdQcm9jZXNzLCBUU2hlbGxDb21tYW5kfSBmcm9tIFwiLi4vVFNoZWxsQ29tbWFuZFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50fSBmcm9tIFwiLi4vZXZlbnRzL1NDX0V2ZW50XCI7XHJcbmltcG9ydCB7VmFyaWFibGVTZXR9IGZyb20gXCIuLi92YXJpYWJsZXMvbG9hZFZhcmlhYmxlc1wiO1xyXG5pbXBvcnQge1xyXG4gICAgUHJlYWN0aW9uX1Byb21wdCxcclxuICAgIFByZWFjdGlvbl9Qcm9tcHRfQ29uZmlndXJhdGlvbixcclxufSBmcm9tIFwiLi4vaW1wb3J0c1wiO1xyXG5cclxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFByZWFjdGlvbiB7XHJcblxyXG4gICAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIHByb3RlY3RlZCByZWFkb25seSBwbHVnaW46IFNDX1BsdWdpbixcclxuICAgICAgICBwdWJsaWMgcmVhZG9ubHkgY29uZmlndXJhdGlvbjogUHJlYWN0aW9uQ29uZmlndXJhdGlvbixcclxuICAgICAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kLFxyXG4gICAgKSB7fVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmV0dXJucyBhIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBwaXBlbGluZSBvZiBwcmVhY3Rpb25zIGNhbiBwcm9jZWVkIHRvIHRoZSBuZXh0IHByZWFjdGlvbi4gRmFsc2UgaW5kaWNhdGVzXHJcbiAgICAgKiB0byBjYW5jZWwgcnVubmluZyBhbnkgcG9zc2libGUgbGF0ZXIgcHJlYWN0aW9ucywgYW5kIGFsc28gY2FuY2VscyBleGVjdXRpb24gb2YgdGhlIHNoZWxsIGNvbW1hbmQuIElmIGFsbCBwcmVhY3Rpb25zJ1xyXG4gICAgICogcHJvbWlzZXMgcmV0dXJuIHRydWUsIHRoZSBzaGVsbCBjb21tYW5kIHdpbGwgYmUgZXhlY3V0ZWQuXHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCBkb1ByZWFjdGlvbihwYXJzaW5nX3Byb2Nlc3M6IFNoZWxsQ29tbWFuZFBhcnNpbmdQcm9jZXNzLCBzY19ldmVudDogU0NfRXZlbnQgfCBudWxsKTogUHJvbWlzZTxib29sZWFuPjtcclxuXHJcbiAgICAvKipcclxuICAgICAqIE1heWJlIHRoaXMgd3JhcHBlciBtZXRob2QgaXMgdW5uZWVkZWQsIGJ1dCBoYXZlIGl0IGZvciBhIHdoaWxlIGF0IGxlYXN0LlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgcGVyZm9ybShwYXJzaW5nX3Byb2Nlc3M6IFNoZWxsQ29tbWFuZFBhcnNpbmdQcm9jZXNzLCBzY19ldmVudDogU0NfRXZlbnQgfCBudWxsKTogUHJvbWlzZTxib29sZWFuPiB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuZG9QcmVhY3Rpb24ocGFyc2luZ19wcm9jZXNzLCBzY19ldmVudCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGdldERlZmF1bHRDb25maWd1cmF0aW9uKCk6IFByZWFjdGlvbkNvbmZpZ3VyYXRpb247IC8vIFRPRE86IFJlbW92ZSBpZiB0aGlzIHdvbid0IGJlIHVzZWQuXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIHZhcmlhYmxlcyB0aGF0IGFyZSBkZXBlbmRlbnQgb2YgdGhpcyBQcmVhY3Rpb24sIGkuZS4gdmFyaWFibGVzIHdob3NlIHZhbHVlIGlzIHNldCBieSB0aGlzIFByZWFjdGlvbi5cclxuICAgICAqIElmIGEgdmFyaWFibGUgaXMgUkVBRCBieSBhIFByZWFjdGlvbiwgaXQgaXMgTk9UIGNvbnNpZGVyZWQgdG8gYmUgX2RlcGVuZGVudF8gb2YgdGhlIFByZWFjdGlvbiwgYXMgbG9uZyBhcyB0aGUgdmFyaWFibGUnc1xyXG4gICAgICogdmFsdWUgaXMgbm90IGNoYW5nZWQgYnkgdGhlIFByZWFjdGlvbi5cclxuICAgICAqXHJcbiAgICAgKiBCeSBkZWZhdWx0LCBpdCByZXR1cm5zIGFuIGVtcHR5IFZhcmlhYmxlU2V0LCBiZWNhdXNlIG5vdCBhbGwgUHJlYWN0aW9ucyB3aWxsIHVzZSB2YXJpYWJsZXMgYXQgYWxsLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZ2V0RGVwZW5kZW50VmFyaWFibGVzKCk6IFZhcmlhYmxlU2V0IHtcclxuICAgICAgICByZXR1cm4gbmV3IFZhcmlhYmxlU2V0KCk7XHJcbiAgICB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQcmVhY3Rpb24ocGx1Z2luOiBTQ19QbHVnaW4sIHByZWFjdGlvbl9jb25maWd1cmF0aW9uOiBQcmVhY3Rpb25Db25maWd1cmF0aW9uLCB0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQpOiBQcmVhY3Rpb24ge1xyXG4gICAgc3dpdGNoIChwcmVhY3Rpb25fY29uZmlndXJhdGlvbi50eXBlKSB7XHJcbiAgICAgICAgY2FzZSBcInByb21wdFwiOlxyXG4gICAgICAgICAgICByZXR1cm4gbmV3IFByZWFjdGlvbl9Qcm9tcHQocGx1Z2luLCAocHJlYWN0aW9uX2NvbmZpZ3VyYXRpb24gYXMgUHJlYWN0aW9uX1Byb21wdF9Db25maWd1cmF0aW9uKSwgdF9zaGVsbF9jb21tYW5kKTtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBQcmVhY3Rpb25Db25maWd1cmF0aW9uIHtcclxuICAgIHR5cGU6IFwicHJvbXB0XCI7XHJcbiAgICBlbmFibGVkOiBib29sZWFuO1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1NDX0V2ZW50fSBmcm9tIFwiLi4vZXZlbnRzL1NDX0V2ZW50XCI7XHJcbmltcG9ydCB7VmFyaWFibGVTZXR9IGZyb20gXCIuLi92YXJpYWJsZXMvbG9hZFZhcmlhYmxlc1wiO1xyXG5pbXBvcnQge1xyXG4gICAgUHJlYWN0aW9uLFxyXG4gICAgUHJlYWN0aW9uQ29uZmlndXJhdGlvbixcclxuICAgIFByb21wdCxcclxufSBmcm9tIFwiLi4vaW1wb3J0c1wiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi9tYWluXCI7XHJcbmltcG9ydCB7U2hlbGxDb21tYW5kUGFyc2luZ1Byb2Nlc3MsIFRTaGVsbENvbW1hbmR9IGZyb20gXCIuLi9UU2hlbGxDb21tYW5kXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgUHJlYWN0aW9uX1Byb21wdCBleHRlbmRzIFByZWFjdGlvbiB7XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgcHVibGljIHJlYWRvbmx5IGNvbmZpZ3VyYXRpb246IFByZWFjdGlvbl9Qcm9tcHRfQ29uZmlndXJhdGlvbixcclxuICAgICAgICB0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQsXHJcbiAgICApIHtcclxuICAgICAgICBzdXBlcihwbHVnaW4sIGNvbmZpZ3VyYXRpb24sIHRfc2hlbGxfY29tbWFuZCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGRvUHJlYWN0aW9uKHBhcnNpbmdfcHJvY2VzczogU2hlbGxDb21tYW5kUGFyc2luZ1Byb2Nlc3MsIHNjX2V2ZW50OiBTQ19FdmVudCk6IFByb21pc2U8Ym9vbGVhbj4ge1xyXG4gICAgICAgIC8vIFRPRE86IE5vdyB0aGF0IGRvUHJlYWN0aW9uKCkgcmV0dXJucyBhIHNpbWlsYXIgUHJvbWlzZSBhcyBpcyByZWNlaXZlZCBmcm9tIG9wZW5Qcm9tcHQoKSwgY29uc2lkZXIganVzdCByZXR1cm5pbmcgdGhlIHNhbWUgUHJvbWlzZSBpbnN0ZWFkIG9mIGNyZWF0aW5nIGEgbmV3IG9uZS5cclxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2U8Ym9vbGVhbj4oKHJlc29sdmUpID0+IHtcclxuICAgICAgICAgICAgdGhpcy5nZXRQcm9tcHQoKS5vcGVuUHJvbXB0KHRoaXMudF9zaGVsbF9jb21tYW5kLCBwYXJzaW5nX3Byb2Nlc3MsIHNjX2V2ZW50KS50aGVuKChleGVjdXRpb25fY29uZmlybWVkOiBib29sZWFuKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGUgUHJvbXB0TW9kYWwgaGFzIGJlZW4gY2xvc2VkLlxyXG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdXNlciB3YW50ZWQgdG8gZXhlY3V0ZSB0aGUgc2hlbGwgY29tbWFuZCBvciBjYW5jZWwuXHJcbiAgICAgICAgICAgICAgICBpZiAoZXhlY3V0aW9uX2NvbmZpcm1lZCkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFVzZXIgd2FudHMgdG8gZXhlY3V0ZS5cclxuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHRydWUpO1xyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBVc2VyIHdhbnRzIHRvIGNhbmNlbC5cclxuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKGZhbHNlKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIGFsbCB0aGUgQ3VzdG9tVmFyaWFibGVzIHdob3NlIHZhbHVlcyB0aGlzIFByZWFjdGlvbidzIFByb21wdCBzZXRzLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZ2V0RGVwZW5kZW50VmFyaWFibGVzKCk6IFZhcmlhYmxlU2V0IHtcclxuICAgICAgICBjb25zdCB2YXJpYWJsZXMgPSBuZXcgVmFyaWFibGVTZXQoKTtcclxuICAgICAgICBmb3IgKGNvbnN0IHByb21wdF9maWVsZCBvZiB0aGlzLmdldFByb21wdCgpLnByb21wdF9maWVsZHMpIHtcclxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhhdCB0aGUgUHJvbXB0RmllbGQgaGFzIGEgdGFyZ2V0IHZhcmlhYmxlIGRlZmluZWQuIE90aGVyd2lzZSBnZXRUYXJnZXRWYXJpYWJsZSgpIHdvdWxkIGNhdXNlIGEgY3Jhc2guXHJcbiAgICAgICAgICAgIGlmIChcIlwiICE9PSBwcm9tcHRfZmllbGQuY29uZmlndXJhdGlvbi50YXJnZXRfdmFyaWFibGVfaWQpIHtcclxuICAgICAgICAgICAgICAgIHZhcmlhYmxlcy5hZGQocHJvbXB0X2ZpZWxkLmdldFRhcmdldFZhcmlhYmxlKCkpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YXJpYWJsZXM7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUT0RPOiBSZW1vdmUuXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBnZXREZWZhdWx0Q29uZmlndXJhdGlvbigpOiBQcmVhY3Rpb25fUHJvbXB0X0NvbmZpZ3VyYXRpb24ge1xyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIHR5cGU6IFwicHJvbXB0XCIsXHJcbiAgICAgICAgICAgIGVuYWJsZWQ6IGZhbHNlLFxyXG4gICAgICAgICAgICBwcm9tcHRfaWQ6IFwiXCIsXHJcbiAgICAgICAgfTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGdldFByb21wdCgpOiBQcm9tcHQge1xyXG4gICAgICAgIGNvbnN0IHByb21wdElkOiBzdHJpbmcgfCB1bmRlZmluZWQgPSB0aGlzLmNvbmZpZ3VyYXRpb24ucHJvbXB0X2lkO1xyXG4gICAgICAgIGlmICh1bmRlZmluZWQgPT09IHByb21wdElkKSB7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlByb21wdCBpZCBpcyB1bmRlZmluZWQgaW4gY29uZmlndXJhdGlvbi5cIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IHByb21wdDogUHJvbXB0IHwgdW5kZWZpbmVkID0gdGhpcy5wbHVnaW4uZ2V0UHJvbXB0cygpLmdldChwcm9tcHRJZCk7XHJcbiAgICAgICAgaWYgKHVuZGVmaW5lZCA9PT0gcHJvbXB0KSB7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlByb21wdCB3aXRoIGlkICdcIiArIHByb21wdElkICsgXCInIGRvZXMgbm90IGV4aXN0XCIpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gcHJvbXB0O1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZ2V0RGVmYXVsdFByZWFjdGlvbl9Qcm9tcHRfQ29uZmlndXJhdGlvbigpOiBQcmVhY3Rpb25fUHJvbXB0X0NvbmZpZ3VyYXRpb24ge1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgICB0eXBlOiBcInByb21wdFwiLFxyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlLFxyXG4gICAgICAgIHByb21wdF9pZDogXCJcIixcclxuICAgIH07XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgUHJlYWN0aW9uX1Byb21wdF9Db25maWd1cmF0aW9uIGV4dGVuZHMgUHJlYWN0aW9uQ29uZmlndXJhdGlvbiB7XHJcbiAgICB0eXBlOiBcInByb21wdFwiO1xyXG4gICAgcHJvbXB0X2lkOiBzdHJpbmcgfCB1bmRlZmluZWQ7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U2V0dGluZ30gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7U0NfRXZlbnR9IGZyb20gXCIuLi8uLi8uLi9ldmVudHMvU0NfRXZlbnRcIjtcclxuaW1wb3J0IHtwYXJzZVZhcmlhYmxlc30gZnJvbSBcIi4uLy4uLy4uL3ZhcmlhYmxlcy9wYXJzZVZhcmlhYmxlc1wiO1xyXG5pbXBvcnQge1RTaGVsbENvbW1hbmR9IGZyb20gXCIuLi8uLi8uLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7XHJcbiAgICBDdXN0b21WYXJpYWJsZSxcclxuICAgIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UsXHJcbiAgICBJbnN0YW5jZSxcclxuICAgIFByb21wdCxcclxuICAgIFByb21wdENvbmZpZ3VyYXRpb24sXHJcbiAgICBQcm9tcHRGaWVsZE1vZGVsLFxyXG59IGZyb20gXCIuLi8uLi8uLi9pbXBvcnRzXCI7XHJcblxyXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgUHJvbXB0RmllbGQgZXh0ZW5kcyBJbnN0YW5jZSB7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDb250YWlucyBhIHZhbHVlIHByZXZpZXcgZWxlbWVudC5cclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHByZXZpZXdfc2V0dGluZzogU2V0dGluZztcclxuXHJcbiAgICBwcml2YXRlIHBhcnNlZF92YWx1ZTogc3RyaW5nIHwgbnVsbDtcclxuICAgIHByaXZhdGUgcGFyc2luZ19lcnJvcnM6IHN0cmluZ1tdID0gW107XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcHVibGljIG1vZGVsOiBQcm9tcHRGaWVsZE1vZGVsLFxyXG4gICAgICAgIHB1YmxpYyBwcm9tcHQ6IFByb21wdCxcclxuICAgICAgICBwdWJsaWMgY29uZmlndXJhdGlvbjogUHJvbXB0RmllbGRDb25maWd1cmF0aW9uLFxyXG4gICAgICAgIHB1YmxpYyBwcm9tcHRfZmllbGRfaW5kZXg6IGtleW9mIFByb21wdENvbmZpZ3VyYXRpb25bXCJmaWVsZHNcIl0sIC8vIFRPRE86ICdrZXlvZicgaXMga2luZCBvZiBpbmNvcnJlY3QgaGVyZSwgJ2tleW9mJyBpcyBmb3Igb2JqZWN0cywgYnV0ICdTQ19NYWluU2V0dGluZ3NbXCJjdXN0b21fdmFyaWFibGVzXCJdJyBpcyBhbiBhcnJheSB3aXRoIG51bWVyaWMgaW5kZXhlcy5cclxuICAgICkge1xyXG4gICAgICAgIHN1cGVyKG1vZGVsLCBjb25maWd1cmF0aW9uLCBwcm9tcHQuY29uZmlndXJhdGlvbik7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIGNvbnRhaW5lcl9lbGVtZW50XHJcbiAgICAgKiBAcGFyYW0gdF9zaGVsbF9jb21tYW5kXHJcbiAgICAgKiBAcGFyYW0gc2NfZXZlbnQgVXNlZCB3aGVuIHBhcnNpbmcgdmFyaWFibGVzIGZvciBkZWZhdWx0X3ZhbHVlIGFuZCB0aGUgaW5wdXR0ZWQgdmFsdWUuIE5lZWRlZCBzbyB0aGF0IGFsc28ge3tldmVudF8qfX0gdmFyaWFibGVzIGNhbiBiZSB1c2VkIGluIHByb21wdHMuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBhc3luYyBjcmVhdGVGaWVsZChjb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQsIHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCB8IG51bGwsIHNjX2V2ZW50OiBTQ19FdmVudCB8IG51bGwpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICBhd2FpdCB0aGlzLl9jcmVhdGVGaWVsZChjb250YWluZXJfZWxlbWVudCwgdF9zaGVsbF9jb21tYW5kLCBzY19ldmVudCk7XHJcblxyXG4gICAgICAgIC8vIENyZWF0ZSBhIHByZXZpZXcgc2V0dGluZyBlbGVtZW50LiBJdCB3aWxsIG5vdCBjb250YWluIGFueSBhY3R1YWwgc2V0dGluZyBlbGVtZW50cywganVzdCB0ZXh0LlxyXG4gICAgICAgIHRoaXMucHJldmlld19zZXR0aW5nID0gbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpO1xyXG5cclxuICAgICAgICAvLyBQYXJzZSB2YXJpYWJsZXMgaW4gdGhlIGRlZmF1bHQgdmFsdWUgYW5kIGluc2VydCBpdCB0byB0aGUgZmllbGQuXHJcbiAgICAgICAgLy8gTm90ZSB0aGF0IHRoaXMgaXMgYSBkaWZmZXJlbnQgXCJkZWZhdWx0IHZhbHVlXCIgdGhhbiB3aGF0IFRTaGVsbENvbW1hbmQgY29uc2lkZXJzIGFzIHZhcmlhYmxlcycgZGVmYXVsdCB2YWx1ZXMhIFRoaXMgaXMgYWJvdXQgYSBfZmllbGQnc18gZGVmYXVsdCB2YWx1ZSwgbm90IGEgdmFyaWFibGUncyBkZWZhdWx0IHZhbHVlLiB0X3NoZWxsX2NvbW1hbmQgaXMgcGFzc2VkIGluIG9yZGVyIHRvIGFsbG93IGFueSBwb3NzaWJsZSB2YXJpYWJsZXMgaW4gdGhlIGZpZWxkJ3MgZGVmYXVsdCB2YWx1ZSB0byBhY2Nlc3MgdGhlIHZhcmlhYmxlcycgZGVmYXVsdCB2YWx1ZXMgKHdoaWNoIGNvbWUgZnJvbSBUU2hlbGxDb21tYW5kKS5cclxuICAgICAgICBhd2FpdCB0aGlzLmFwcGx5RGVmYXVsdFZhbHVlKHRfc2hlbGxfY29tbWFuZCwgc2NfZXZlbnQpO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCBfY3JlYXRlRmllbGQoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50LCB0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQgfCBudWxsLCBzY19ldmVudDogU0NfRXZlbnQgfCBudWxsKTogUHJvbWlzZTx2b2lkPjtcclxuXHJcbiAgICBwdWJsaWMgZ2V0VGl0bGUoKTogc3RyaW5nIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmF0aW9uLmxhYmVsID09PSBcIlwiID8gXCJVbmxhYmVsbGVkIGZpZWxkXCIgOiB0aGlzLmNvbmZpZ3VyYXRpb24ubGFiZWw7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXRzIGEgdmFsdWUgZnJvbSB0aGUgZm9ybSBmaWVsZC5cclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGdldFZhbHVlKCk6IHN0cmluZztcclxuXHJcbiAgICAvKipcclxuICAgICAqIFNldHMgYSB2YWx1ZSB0byB0aGUgZm9ybSBmaWVsZC5cclxuICAgICAqIEBwYXJhbSB2YWx1ZVxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgYWJzdHJhY3Qgc2V0VmFsdWUodmFsdWU6IHN0cmluZyk6IHZvaWQ7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBQYXJzZXMgdGhlIGRlZmF1bHQgdmFsdWUgYW5kIHNldHMgaXQgdG8gdGhlIGZvcm0gZWxlbWVudC5cclxuICAgICAqIEBwYXJhbSB0X3NoZWxsX2NvbW1hbmRcclxuICAgICAqIEBwYXJhbSBzY19ldmVudFxyXG4gICAgICogQHByaXZhdGVcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBhc3luYyBhcHBseURlZmF1bHRWYWx1ZSh0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQgfCBudWxsLCBzY19ldmVudDogU0NfRXZlbnQgfCBudWxsKSB7XHJcbiAgICAgICAgY29uc3QgZGVmYXVsdF92YWx1ZSA9IHRoaXMuY29uZmlndXJhdGlvbi5kZWZhdWx0X3ZhbHVlO1xyXG4gICAgICAgIGNvbnN0IHBhcnNpbmdfcmVzdWx0ID0gYXdhaXQgcGFyc2VWYXJpYWJsZXModGhpcy5wcm9tcHQubW9kZWwucGx1Z2luLCBkZWZhdWx0X3ZhbHVlLCBudWxsLCB0X3NoZWxsX2NvbW1hbmQsIHNjX2V2ZW50KTtcclxuICAgICAgICBpZiAoIXBhcnNpbmdfcmVzdWx0LnN1Y2NlZWRlZCkge1xyXG4gICAgICAgICAgICAvLyBQYXJzaW5nIGZhaWxlZC5cclxuICAgICAgICAgICAgdGhpcy5zZXRWYWx1ZShkZWZhdWx0X3ZhbHVlKTsgLy8gVXNlIHRoZSB1bnBhcnNlZCB2YWx1ZS4gSWYgZGVmYXVsdCB2YWx1ZSBjb250YWlucyBhIHZhcmlhYmxlIHRoYXQgY2Fubm90IGJlIHBhcnNlZCwgYSB1c2VyIGNhbiBzZWUgdGhlIHZhcmlhYmxlIGluIHRoZSBwcm9tcHQgbW9kYWwgYW5kIGVpdGhlciBmaXggaXQgb3IgY2hhbmdlIGl0IHRvIHNvbWV0aGluZyBlbHNlLlxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIFBhcnNpbmcgc3VjY2VlZGVkLlxyXG4gICAgICAgICAgICB0aGlzLnNldFZhbHVlKHBhcnNpbmdfcmVzdWx0LnBhcnNlZF9jb250ZW50IGFzIHN0cmluZyk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGF3YWl0IHRoaXMudmFsdWVIYXNDaGFuZ2VkKHRfc2hlbGxfY29tbWFuZCwgc2NfZXZlbnQpO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRQYXJzZWRWYWx1ZSgpOiBzdHJpbmcgfCBudWxsIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5wYXJzZWRfdmFsdWU7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUcmllcyB0byBnZXQgYSBwYXJzZWQgdmFsdWUsIGJ1dCBpZiBpdCdzIG5vdCBhdmFpbGFibGUgKHByb2JhYmx5IGR1ZSB0byBpbmNvcnJlY3QgdXNhZ2Ugb2YgdmFyaWFibGVzKSwgcmV0dXJucyBhblxyXG4gICAgICogdW5wYXJzZWQgdmFsdWUgaW5zdGVhZCgpLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZ2V0UGFyc2VkT3JSYXdWYWx1ZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnBhcnNlZF92YWx1ZSA/PyB0aGlzLmdldFZhbHVlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldFBhcnNpbmdFcnJvcnMoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMucGFyc2luZ19lcnJvcnM7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBVcGRhdGVzIHRoaXMucGFyc2VkX3ZhbHVlLCB0aGlzLnBhcnNpbmdfZXJyb3JzIGFuZCB0aGlzLnByZXZpZXdfc2V0dGluZyAuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHRfc2hlbGxfY29tbWFuZFxyXG4gICAgICogQHBhcmFtIHNjX2V2ZW50XHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBhc3luYyB2YWx1ZUhhc0NoYW5nZWQodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kIHwgbnVsbCwgc2NfZXZlbnQ6IFNDX0V2ZW50IHwgbnVsbCkge1xyXG4gICAgICAgIGxldCBwcmV2aWV3OiBzdHJpbmc7XHJcblxyXG4gICAgICAgIC8vIFBhcnNlIHZhcmlhYmxlcyBpbiB0aGUgdmFsdWUuXHJcbiAgICAgICAgY29uc3QgcGFyc2luZ19yZXN1bHQgPSBhd2FpdCBwYXJzZVZhcmlhYmxlcyh0aGlzLnByb21wdC5tb2RlbC5wbHVnaW4sIHRoaXMuZ2V0VmFsdWUoKSwgbnVsbCwgdF9zaGVsbF9jb21tYW5kLCBzY19ldmVudCk7XHJcbiAgICAgICAgaWYgKCFwYXJzaW5nX3Jlc3VsdC5zdWNjZWVkZWQpIHtcclxuICAgICAgICAgICAgLy8gUGFyc2luZyBmYWlsZWQuXHJcbiAgICAgICAgICAgIHRoaXMucGFyc2VkX3ZhbHVlID0gbnVsbDtcclxuICAgICAgICAgICAgaWYgKHBhcnNpbmdfcmVzdWx0LmVycm9yX21lc3NhZ2VzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgIC8vIERpc3BsYXkgdGhlIGZpcnN0IGVycm9yIG1lc3NhZ2UuIElmIHRoZXJlIGFyZSBtb3JlLCBvdGhlcnMgY2FuIGJlIG9taXR0ZWQuXHJcbiAgICAgICAgICAgICAgICBwcmV2aWV3ID0gcGFyc2luZ19yZXN1bHQuZXJyb3JfbWVzc2FnZXNbMF07XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBJZiB0aGVyZSBhcmUgbm8gZXJyb3IgbWVzc2FnZXMsIHRoZW4gZXJyb3JzIGFyZSBzaWxlbnRseSBpZ25vcmVkIGJ5IHVzZXIncyB2YXJpYWJsZSBjb25maWd1cmF0aW9uLCBpbiB3aGljaCBjYXNlIGp1c3Qgc2hvdyB0aGUgb3JpZ2luYWwgY29udGVudC5cclxuICAgICAgICAgICAgICAgIHByZXZpZXcgPSBwYXJzaW5nX3Jlc3VsdC5vcmlnaW5hbF9jb250ZW50O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHRoaXMucGFyc2luZ19lcnJvcnMgPSBwYXJzaW5nX3Jlc3VsdC5lcnJvcl9tZXNzYWdlcztcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBQYXJzaW5nIHN1Y2NlZWRlZFxyXG4gICAgICAgICAgICB0aGlzLnBhcnNlZF92YWx1ZSA9IHBhcnNpbmdfcmVzdWx0LnBhcnNlZF9jb250ZW50O1xyXG4gICAgICAgICAgICBwcmV2aWV3ID0gcGFyc2luZ19yZXN1bHQucGFyc2VkX2NvbnRlbnQgYXMgc3RyaW5nO1xyXG4gICAgICAgICAgICB0aGlzLnBhcnNpbmdfZXJyb3JzID0gW107IC8vIE5vIGVycm9ycy5cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFVwZGF0ZSB0aGUgcHJldmlldyBlbGVtZW50LlxyXG4gICAgICAgIGlmICgwID09PSBwYXJzaW5nX3Jlc3VsdC5jb3VudF9wYXJzZWRfdmFyaWFibGVzKSB7XHJcbiAgICAgICAgICAgICAvLyBJZiBubyB2YXJpYWJsZXMgd2VyZSB1c2VkLCBoaWRlIHRoZSBkZXNjcmlwdGlvbiBhcyBpdCdzIG5vdCBuZWVkZWQgdG8gcmVwZWF0IHRoZSB2YWx1ZSB0aGF0IGFscmVhZHkgc2hvd3MgdXAgaW4gdGhlIGZvcm0gZmllbGQuXHJcbiAgICAgICAgICAgIHByZXZpZXcgPSBcIlwiO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnByZXZpZXdfc2V0dGluZy5zZXREZXNjKHByZXZpZXcpO1xyXG5cclxuICAgICAgICAvLyBDYWxsIGEgcG9zc2libGUgZXh0ZXJuYWwgY2FsbGJhY2tcclxuICAgICAgICBpZiAodGhpcy5vbl9jaGFuZ2VfY2FsbGJhY2spIHtcclxuICAgICAgICAgICAgdGhpcy5vbl9jaGFuZ2VfY2FsbGJhY2soKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBAcGFyYW0gb25fY2hhbmdlX2NhbGxiYWNrIEEgY2FsbGJhY2sgdGhhdCB3aWxsIGJlIGNhbGxlZCB3aGVuZXZlciB0aGUgZmllbGQncyB2YWx1ZSBpcyBjaGFuZ2VkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgb25DaGFuZ2Uob25fY2hhbmdlX2NhbGxiYWNrOiAoKSA9PiB2b2lkKSB7XHJcbiAgICAgICAgdGhpcy5vbl9jaGFuZ2VfY2FsbGJhY2sgPSBvbl9jaGFuZ2VfY2FsbGJhY2s7XHJcbiAgICB9XHJcbiAgICBwcml2YXRlIG9uX2NoYW5nZV9jYWxsYmFjaz86ICgpID0+IHZvaWQ7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBAcGFyYW0gb25fZm9jdXNfY2FsbGJhY2sgQSBjYWxsYmFjayB0aGF0IHdpbGwgYmUgY2FsbGVkIHdoZW5ldmVyIHRoZSBmaWVsZCBpcyBmb2N1c2VkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgb25Gb2N1cyhvbl9mb2N1c19jYWxsYmFjazogKHByb21wdF9maWVsZDogUHJvbXB0RmllbGQpID0+IHZvaWQpIHtcclxuICAgICAgICB0aGlzLm9uX2ZvY3VzX2NhbGxiYWNrID0gb25fZm9jdXNfY2FsbGJhY2s7XHJcbiAgICB9XHJcbiAgICBwcml2YXRlIG9uX2ZvY3VzX2NhbGxiYWNrPzogKHByb21wdF9maWVsZDogUHJvbXB0RmllbGQpID0+IHZvaWQ7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTaG91bGQgYmUgY2FsbGVkIGJ5IHRoZSBzdWJjbGFzcyB3aGVuIHRoZSBmaWVsZCBoYXMgZ290dGVuIGZvY3VzLlxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgaGFzR290dGVuRm9jdXMoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMub25fZm9jdXNfY2FsbGJhY2spIHtcclxuICAgICAgICAgICAgdGhpcy5vbl9mb2N1c19jYWxsYmFjayh0aGlzKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBGb3JjZXMgZm9jdXMgb24gdGhlIGZpZWxkLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgYWJzdHJhY3Qgc2V0Rm9jdXMoKTogdm9pZDtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEVuc3VyZXMgdGhhdCB0aGUgZmllbGQgaXMgZmlsbGVkLCBpZiBpdCdzIG1hbmRhdG9yeS4gSWYgdGhlIGZpZWxkIGlzIG5vdCBtYW5kYXRvcnksIGl0J3MgYWx3YXlzIHZhbGlkLlxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm4gVHJ1ZSB3aGVuIHZhbGlkLCBmYWxzZSB3aGVuIG5vdCB2YWxpZC5cclxuICAgICAqL1xyXG4gICAgcHVibGljIHZhbGlkYXRlKCkge1xyXG4gICAgICAgIGlmICghdGhpcy5jb25maWd1cmF0aW9uLnJlcXVpcmVkKSB7XHJcbiAgICAgICAgICAgIC8vIE5vIG5lZWQgdG8gdmFsaWRhdGUsIGJlY2F1c2UgdGhlIGZpZWxkIGlzIG5vdCBtYW5kYXRvcnkuXHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRW5zdXJlIHRoZSBmaWVsZCBpcyBmaWxsZWRcclxuICAgICAgICByZXR1cm4gdGhpcy5pc0ZpbGxlZCgpO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCBpc0ZpbGxlZCgpOiBib29sZWFuO1xyXG5cclxuICAgIHB1YmxpYyBnZXRUYXJnZXRWYXJpYWJsZUluc3RhbmNlKCk6IEN1c3RvbVZhcmlhYmxlSW5zdGFuY2Uge1xyXG4gICAgICAgIGNvbnN0IHRhcmdldF92YXJpYWJsZV9pZCA9IHRoaXMuY29uZmlndXJhdGlvbi50YXJnZXRfdmFyaWFibGVfaWQ7XHJcbiAgICAgICAgY29uc3QgY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlOiBDdXN0b21WYXJpYWJsZUluc3RhbmNlIHwgdW5kZWZpbmVkID0gdGhpcy5wcm9tcHQubW9kZWwucGx1Z2luLmdldEN1c3RvbVZhcmlhYmxlSW5zdGFuY2VzKCkuZ2V0KHRhcmdldF92YXJpYWJsZV9pZCk7XHJcbiAgICAgICAgaWYgKCFjdXN0b21fdmFyaWFibGVfaW5zdGFuY2UpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMuY29uc3RydWN0b3IubmFtZSArIFwiLmdldFRhcmdldFZhcmlhYmxlSW5zdGFuY2UoKTogQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSB3aXRoIElEICdcIiArIHRhcmdldF92YXJpYWJsZV9pZCArIFwiJyB3YXMgbm90IGZvdW5kXCIpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRUYXJnZXRWYXJpYWJsZSgpOiBDdXN0b21WYXJpYWJsZSB7XHJcbiAgICAgICAgY29uc3QgY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlID0gdGhpcy5nZXRUYXJnZXRWYXJpYWJsZUluc3RhbmNlKCk7XHJcbiAgICAgICAgcmV0dXJuIGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZS5nZXRDdXN0b21WYXJpYWJsZSgpO1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFByb21wdEZpZWxkQ29uZmlndXJhdGlvbiB7XHJcbiAgICAvLyB0eXBlOiBcInRleHRcIjsgLy8gVE9ETzogVW5jb21tZW50IHdoZW4gaW1wbGVtZW50aW5nIG1vcmUgdmFsdWVzIHRoYW4ganVzdCBcInRleHRcIi4gTm8gbmVlZCB0byBkZWNpZGUgdGhlIHZhbHVlIFwidGV4dFwiIG5vdywgaXQgY2FuIGJlIGNoYW5nZWQgdG8gXCJzaW5nbGUtbGluZS10ZXh0XCIgb3Igc29tZXRoaW5nIGVsc2UsIHRvby5cclxuICAgIGxhYmVsOiBzdHJpbmc7XHJcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nO1xyXG4gICAgZGVmYXVsdF92YWx1ZTogc3RyaW5nO1xyXG4gICAgLy8gIFRPRE86IEFkZCAncGxhY2Vob2xkZXInLlxyXG4gICAgdGFyZ2V0X3ZhcmlhYmxlX2lkOiBzdHJpbmc7XHJcbiAgICByZXF1aXJlZDogYm9vbGVhbjtcclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtcclxuICAgIFNldHRpbmcsXHJcbiAgICBUZXh0Q29tcG9uZW50LFxyXG59IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQge3JhbmRvbUludGVnZXJ9IGZyb20gXCIuLi8uLi8uLi9Db21tb25cIjtcclxuaW1wb3J0IHtjcmVhdGVBdXRvY29tcGxldGV9IGZyb20gXCIuLi8uLi8uLi9zZXR0aW5ncy9zZXR0aW5nX2VsZW1lbnRzL0F1dG9jb21wbGV0ZVwiO1xyXG5pbXBvcnQge1xyXG4gICAgQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSxcclxuICAgIEN1c3RvbVZhcmlhYmxlTW9kZWwsXHJcbiAgICBDdXN0b21WYXJpYWJsZVNldHRpbmdzTW9kYWwsXHJcbiAgICBnZXRNb2RlbCxcclxuICAgIE1vZGVsLFxyXG4gICAgUGFyZW50TW9kZWxPbmVUb01hbnlJbmRleFJlbGF0aW9uLFxyXG4gICAgUHJvbXB0LFxyXG4gICAgUHJvbXB0RmllbGQsXHJcbiAgICBQcm9tcHRGaWVsZF9UZXh0LFxyXG4gICAgUHJvbXB0RmllbGRDb25maWd1cmF0aW9uLFxyXG59IGZyb20gXCIuLi8uLi8uLi9pbXBvcnRzXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgUHJvbXB0RmllbGRNb2RlbCBleHRlbmRzIE1vZGVsIHtcclxuXHJcbiAgICBwdWJsaWMgZ2V0U2luZ3VsYXJOYW1lKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIFwiRmllbGRcIjtcclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgZGVmaW5lUGFyZW50Q29uZmlndXJhdGlvblJlbGF0aW9uKHByb21wdF9maWVsZDogUHJvbXB0RmllbGQpOiBQYXJlbnRNb2RlbE9uZVRvTWFueUluZGV4UmVsYXRpb24ge1xyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIHR5cGU6IFwib25lLXRvLW1hbnktaW5kZXhcIixcclxuICAgICAgICAgICAga2V5OiBcImZpZWxkc1wiLFxyXG4gICAgICAgICAgICBpbmRleDogcHJvbXB0X2ZpZWxkLnByb21wdF9maWVsZF9pbmRleCBhcyBudW1iZXIsXHJcbiAgICAgICAgfTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgbG9hZEluc3RhbmNlcyhwcm9tcHQ6IFByb21wdCk6IFByb21wdEZpZWxkU2V0IHtcclxuICAgICAgICBjb25zdCBwcm9tcHRfZmllbGRzID0gbmV3IFByb21wdEZpZWxkU2V0O1xyXG4gICAgICAgIHByb21wdC5jb25maWd1cmF0aW9uLmZpZWxkcy5mb3JFYWNoKChmaWVsZF9jb25maWd1cmF0aW9uOiBQcm9tcHRGaWVsZENvbmZpZ3VyYXRpb24sIGluZGV4KSA9PiB7XHJcbiAgICAgICAgICAgIHByb21wdF9maWVsZHMuYWRkKFxyXG4gICAgICAgICAgICAgICAgdGhpcy5jcmVhdGVJbnN0YW5jZShwcm9tcHQsIGZpZWxkX2NvbmZpZ3VyYXRpb24sIGluZGV4KVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybiBwcm9tcHRfZmllbGRzO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBuZXdJbnN0YW5jZShwcm9tcHQ6IFByb21wdCk6IFByb21wdEZpZWxkIHtcclxuICAgICAgICAvLyBUT0RPOiBNb3ZlIHRoaXMgbG9naWMgdG8gdGhlIGJhc2UgTW9kZWwgY2xhc3MuXHJcblxyXG4gICAgICAgIC8vIFNldHVwIGEgZGVmYXVsdCBjb25maWd1cmF0aW9uXHJcbiAgICAgICAgY29uc3QgcHJvbXB0X2ZpZWxkX2NvbmZpZ3VyYXRpb24gPSB0aGlzLmdldERlZmF1bHRDb25maWd1cmF0aW9uKCk7XHJcblxyXG4gICAgICAgIC8vIEluc3RhbnRpYXRlIGEgUHJvbXB0RmllbGRcclxuICAgICAgICBjb25zdCBwcm9tcHRfZmllbGQgPSB0aGlzLmNyZWF0ZUluc3RhbmNlKHByb21wdCwgcHJvbXB0X2ZpZWxkX2NvbmZpZ3VyYXRpb24sIHByb21wdC5jb25maWd1cmF0aW9uLmZpZWxkcy5sZW5ndGgpO1xyXG5cclxuICAgICAgICAvLyBTdG9yZSB0aGUgY29uZmlndXJhdGlvbiBpbnRvIHRoZSBwcm9tcHQncyBjb25maWd1cmF0aW9uXHJcbiAgICAgICAgcHJvbXB0LmNvbmZpZ3VyYXRpb24uZmllbGRzLnB1c2gocHJvbXB0X2ZpZWxkX2NvbmZpZ3VyYXRpb24pO1xyXG5cclxuICAgICAgICAvLyBTdG9yZSB0aGUgUHJvbXB0RmllbGQgaW5zdGFuY2UgaW50byBpdHMgcGFyZW50IFByb21wdCdzIGxpc3Qgb2YgZmllbGRzLlxyXG4gICAgICAgIHByb21wdC5wcm9tcHRfZmllbGRzLmFkZChwcm9tcHRfZmllbGQpO1xyXG5cclxuICAgICAgICAvLyBSZXR1cm4gdGhlIFByb21wdEZpZWxkXHJcbiAgICAgICAgcmV0dXJuIHByb21wdF9maWVsZDtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGNyZWF0ZUluc3RhbmNlKHByb21wdDogUHJvbXB0LCBwcm9tcHRfZmllbGRfY29uZmlndXJhdGlvbjogUHJvbXB0RmllbGRDb25maWd1cmF0aW9uLCBwcm9tcHRfZmllbGRfaW5kZXg6IG51bWJlcik6IFByb21wdEZpZWxkIHtcclxuICAgICAgICAvLyBUT0RPOiBXaGVuIHRoZSAndHlwZScgZmllbGQgZ2V0cyBpbXBsZW1lbnRlZCBvbiBQcm9tcHRGaWVsZENvbmZpZ3VyYXRpb24sIGltcGxlbWVudCBzb21lIGtpbmQgb2Ygc3dpdGNoIHN0cnVjdHVyZSBoZXJlIHRvIGNyZWF0ZSBkaWZmZXJlbnQgdHlwZXMgb2YgUHJvbXB0RmllbGRzLlxyXG4gICAgICAgIHJldHVybiBuZXcgUHJvbXB0RmllbGRfVGV4dCh0aGlzLCBwcm9tcHQsIHByb21wdF9maWVsZF9jb25maWd1cmF0aW9uLCBwcm9tcHRfZmllbGRfaW5kZXgpO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBfY3JlYXRlU2V0dGluZ0ZpZWxkcyhwcm9tcHRfZmllbGQ6IFByb21wdEZpZWxkLCBjb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQpOiBTZXR0aW5nIHtcclxuICAgICAgICBjb25zdCBsYWJlbF9wbGFjZWhvbGRlcnMgPSBbXHJcbiAgICAgICAgICAgIFwiV2hhdCBpcyB5b3VyIG5hbWU/XCIsXHJcbiAgICAgICAgICAgIFwiSG93IGJpZyBpcyB0aGUgdW5pdmVyc2U/XCIsXHJcbiAgICAgICAgICAgIFwiSG93IGxvbmcgaXMgZXRlcm5pdHk/XCIsXHJcbiAgICAgICAgICAgIFwiV2hhdCBpcyB5b3VyIGx1Y2t5IG51bWJlcj9cIixcclxuICAgICAgICAgICAgXCJXaGF0IGlzIHlvdXIgZmF2b3JpdGUgc29uZz9cIixcclxuICAgICAgICAgICAgXCJXaGF0IGlzIHlvdXIgZmF2b3JpdGUgY29sb3I/XCIsXHJcbiAgICAgICAgICAgIFwiSG93IG1hbnkgYm9va3MgaGF2ZSB5b3UgcmVhZD9cIixcclxuICAgICAgICAgICAgXCJXaGF0IGlzIHRoZSBwdXJwb3NlIG9mIGxpZmU/XCIsXHJcbiAgICAgICAgXTtcclxuICAgICAgICBjb25zdCBkZWZhdWx0X3ZhbHVlX3BsYWNlaG9sZGVycyA9IFtcclxuICAgICAgICAgICAgW1wiQm9uZCwgSmFtZXMgQm9uZFwiLCBcIkpvaG4gRG9lXCIsIFwiSmFuZSBEb2VcIiwgXCJNci4gQmVhblwiXSxcclxuICAgICAgICAgICAgW1wiVmVyeSBiaWcsIGFuZCBzdGlsbCBleHBhbmRpbmdcIiwgXCI5MyBiaWxsaW9uIGxpZ2h0LXllYXJzXCJdLFxyXG4gICAgICAgICAgICBbXCJJbmZpbml0ZVwiLCBcIlRvbyBsb25nIHRvIHdhaXQgZm9yXCJdLFxyXG4gICAgICAgICAgICBbU3RyaW5nKHJhbmRvbUludGVnZXIoMCwgOSkpLCBcIkkgZG9uJ3QgaGF2ZSBvbmVcIl0sXHJcbiAgICAgICAgICAgIFtcIldlIGFyZSB0aGUgd29ybGQgKFVTQSBmb3IgQWZyaWNhKVwiLCBcIkhlYWwgdGhlIHdvcmxkIChNaWNoYWVsIEphY2tzb24pXCIsIFwiSW1hZ2luZSAoSm9obiBMZW5ub24pXCIsIFwiQ2lyY2xlIG9mIGxpZmUgKEVsdG9uIEpvaG4pXCJdLFxyXG4gICAgICAgICAgICBbXCJCbHVlIGFzIGRlZXAgYXMgYW4gb2NlYW5cIiwgXCJSZWQgYXMgbG92ZVwiLCBcIkdyYXNzLWdyZWVuXCIsIFwiU25vdy13aGl0ZVwiXSxcclxuICAgICAgICAgICAgW1wiVGhvdXNhbmRzXCIsIFwiTWFueVwiLCBcIkNvdW50bGVzc1wiLCBcIk5vbmVcIl0sXHJcbiAgICAgICAgICAgIFtcIlRoaW5raW5nXCIsIFwiQmVpbmcgYSBiZWluZ1wiLCBcIjQyXCJdLFxyXG4gICAgICAgIF07XHJcbiAgICAgICAgY29uc3QgbGFiZWxfcGxhY2Vob2xkZXJfaW5kZXg6IG51bWJlciA9IHJhbmRvbUludGVnZXIoMCwgbGFiZWxfcGxhY2Vob2xkZXJzLmxlbmd0aCAtIDEpO1xyXG4gICAgICAgIGNvbnN0IGRlZmF1bHRfdmFsdWVfcGxhY2Vob2xkZXJzX3N1YnNldDogc3RyaW5nW10gPSBkZWZhdWx0X3ZhbHVlX3BsYWNlaG9sZGVyc1tsYWJlbF9wbGFjZWhvbGRlcl9pbmRleF07XHJcblxyXG4gICAgICAgIC8vIENyZWF0ZSBhIGxpc3Qgb2YgY3VzdG9tIHZhcmlhYmxlc1xyXG4gICAgICAgIGNvbnN0IGN1c3RvbV92YXJpYWJsZV9vcHRpb25zOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfSA9IHt9O1xyXG4gICAgICAgIHRoaXMucGx1Z2luLmdldEN1c3RvbVZhcmlhYmxlSW5zdGFuY2VzKCkuZm9yRWFjaCgoY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlOiBDdXN0b21WYXJpYWJsZUluc3RhbmNlLCBjdXN0b21fdmFyaWFibGVfaWQ6IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICBjdXN0b21fdmFyaWFibGVfb3B0aW9uc1tjdXN0b21fdmFyaWFibGVfaWRdID0gY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlLmdldEZ1bGxOYW1lKCk7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIGNvbnN0IG9uX2RlZmF1bHRfdmFsdWVfc2V0dGluZ19jaGFuZ2UgPSBhc3luYyAobmV3X2RlZmF1bHRfdmFsdWU6IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICBwcm9tcHRfZmllbGQuY29uZmlndXJhdGlvbi5kZWZhdWx0X3ZhbHVlID0gbmV3X2RlZmF1bHRfdmFsdWU7XHJcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgc2V0dGluZyBmaWVsZHNcclxuICAgICAgICBjb25zdCBzZXR0aW5nX2dyb3VwX2VsZW1lbnQgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVEaXYoe2F0dHI6IHtjbGFzczogXCJTQy1zZXR0aW5nLWdyb3VwXCJ9fSk7XHJcbiAgICAgICAgbGV0IGxhYmVsX3NldHRpbmdfY29tcG9uZW50OiBUZXh0Q29tcG9uZW50O1xyXG4gICAgICAgIGxldCBkZXNjcmlwdGlvbl9zZXR0aW5nX2NvbXBvbmVudDogVGV4dENvbXBvbmVudDtcclxuICAgICAgICBjb25zdCBzZXR0aW5nX2dyb3VwOiBQcm9tcHRGaWVsZFNldHRpbmdHcm91cCA9IHtcclxuICAgICAgICAgICAgaGVhZGluZ19zZXR0aW5nOiBuZXcgU2V0dGluZyhzZXR0aW5nX2dyb3VwX2VsZW1lbnQpXHJcbiAgICAgICAgICAgICAgICAuc2V0TmFtZShcIlwiKSAvLyBUaGlzIHdpbGwgYmUgc2V0IGRvd24gYmVsb3cuXHJcbiAgICAgICAgICAgICAgICAuc2V0SGVhZGluZygpXHJcbiAgICAgICAgICAgICxcclxuICAgICAgICAgICAgbGFiZWxfc2V0dGluZzogbmV3IFNldHRpbmcoc2V0dGluZ19ncm91cF9lbGVtZW50KVxyXG4gICAgICAgICAgICAgICAgLnNldE5hbWUoXCJGaWVsZCBsYWJlbFwiKVxyXG4gICAgICAgICAgICAgICAgLmFkZFRleHQodGV4dCA9PiBsYWJlbF9zZXR0aW5nX2NvbXBvbmVudCA9IHRleHRcclxuICAgICAgICAgICAgICAgICAgICAuc2V0VmFsdWUocHJvbXB0X2ZpZWxkLmNvbmZpZ3VyYXRpb24ubGFiZWwpXHJcbiAgICAgICAgICAgICAgICAgICAgLnNldFBsYWNlaG9sZGVyKGxhYmVsX3BsYWNlaG9sZGVyc1tsYWJlbF9wbGFjZWhvbGRlcl9pbmRleF0pXHJcbiAgICAgICAgICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jIChuZXdfbGFiZWw6IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBwcm9tcHRfZmllbGQuY29uZmlndXJhdGlvbi5sYWJlbCA9IG5ld19sYWJlbDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgX3VwZGF0ZV9oZWFkaW5nKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICxcclxuICAgICAgICAgICAgZGVmYXVsdF92YWx1ZV9zZXR0aW5nOiBuZXcgU2V0dGluZyhzZXR0aW5nX2dyb3VwX2VsZW1lbnQpXHJcbiAgICAgICAgICAgICAgICAuc2V0TmFtZShcIkRlZmF1bHQgdmFsdWVcIilcclxuICAgICAgICAgICAgICAgIC5hZGRUZXh0KHRleHQgPT4gdGV4dFxyXG4gICAgICAgICAgICAgICAgICAgIC5zZXRWYWx1ZShwcm9tcHRfZmllbGQuY29uZmlndXJhdGlvbi5kZWZhdWx0X3ZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICAgIC5zZXRQbGFjZWhvbGRlcihcclxuICAgICAgICAgICAgICAgICAgICAgICAgcHJvbXB0X2ZpZWxkLmNvbmZpZ3VyYXRpb24ubGFiZWwgPyBcIlwiIC8vIElmIHRoZSBsYWJlbCBpcyBkZWZpbmVkLCBkbyBub3QgYWRkIGEgcGxhY2Vob2xkZXIgaGVyZSwgYXMgdGhlIGxhYmVsJ3MgcGxhY2Vob2xkZXIgaXMgbm90IHZpc2libGUsIHNvIHRoaXMgcGxhY2Vob2xkZXIgd291bGQgbm90IG1ha2Ugc2Vuc2UuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IGRlZmF1bHRfdmFsdWVfcGxhY2Vob2xkZXJzX3N1YnNldFtyYW5kb21JbnRlZ2VyKDAsIGRlZmF1bHRfdmFsdWVfcGxhY2Vob2xkZXJzX3N1YnNldC5sZW5ndGggLSAxKV1cclxuICAgICAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgICAgICAgLm9uQ2hhbmdlKG9uX2RlZmF1bHRfdmFsdWVfc2V0dGluZ19jaGFuZ2UpXHJcbiAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICxcclxuICAgICAgICAgICAgZGVzY3JpcHRpb25fc2V0dGluZzogbmV3IFNldHRpbmcoc2V0dGluZ19ncm91cF9lbGVtZW50KVxyXG4gICAgICAgICAgICAgICAgLnNldE5hbWUoXCJEZXNjcmlwdGlvblwiKVxyXG4gICAgICAgICAgICAgICAgLmFkZFRleHQodGV4dCA9PiBkZXNjcmlwdGlvbl9zZXR0aW5nX2NvbXBvbmVudCA9IHRleHRcclxuICAgICAgICAgICAgICAgICAgICAuc2V0VmFsdWUocHJvbXB0X2ZpZWxkLmNvbmZpZ3VyYXRpb24uZGVzY3JpcHRpb24pXHJcbiAgICAgICAgICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jIChuZXdfZGVzY3JpcHRpb246IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBwcm9tcHRfZmllbGQuY29uZmlndXJhdGlvbi5kZXNjcmlwdGlvbiA9IG5ld19kZXNjcmlwdGlvbjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICxcclxuICAgICAgICAgICAgdGFyZ2V0X3ZhcmlhYmxlX3NldHRpbmc6IG5ldyBTZXR0aW5nKHNldHRpbmdfZ3JvdXBfZWxlbWVudClcclxuICAgICAgICAgICAgICAgIC5zZXROYW1lKFwiVGFyZ2V0IHZhcmlhYmxlXCIpXHJcbiAgICAgICAgICAgICAgICAuc2V0RGVzYyhcIldoZXJlIHRoZSBpbnB1dHRlZCB2YWx1ZSB3aWxsIGJlIHN0b3JlZCBpbi4gWW91IGNhbiB1c2UgdGhlIHZhcmlhYmxlIGluIGEgc2hlbGwgY29tbWFuZC5cIilcclxuICAgICAgICAgICAgICAgIC5hZGREcm9wZG93bihkcm9wZG93biA9PiBkcm9wZG93blxyXG4gICAgICAgICAgICAgICAgICAgIC5hZGRPcHRpb24oXCJcIiwgXCJcIikgLy8gQW4gb3B0aW9uIGZvciBhIHNpdHVhdGlvbiB3aGVuIG5vdGhpbmcgaXMgc2VsZWN0ZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgLmFkZE9wdGlvbnMoY3VzdG9tX3ZhcmlhYmxlX29wdGlvbnMpXHJcbiAgICAgICAgICAgICAgICAgICAgLmFkZE9wdGlvbihcIm5ld1wiLCBcIkNyZWF0ZSBhIG5ldyBjdXN0b20gdmFyaWFibGVcIilcclxuICAgICAgICAgICAgICAgICAgICAuc2V0VmFsdWUocHJvbXB0X2ZpZWxkLmNvbmZpZ3VyYXRpb24udGFyZ2V0X3ZhcmlhYmxlX2lkKVxyXG4gICAgICAgICAgICAgICAgICAgIC5vbkNoYW5nZSgobmV3X3RhcmdldF92YXJpYWJsZV9pZDogc3RyaW5nKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChcIm5ld1wiID09PSBuZXdfdGFyZ2V0X3ZhcmlhYmxlX2lkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDcmVhdGUgYSBuZXcgY3VzdG9tIHZhcmlhYmxlLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbW9kZWwgPSBnZXRNb2RlbDxDdXN0b21WYXJpYWJsZU1vZGVsPihDdXN0b21WYXJpYWJsZU1vZGVsLm5hbWUpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlID0gbW9kZWwubmV3SW5zdGFuY2UodGhpcy5wbHVnaW4uc2V0dGluZ3MpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCkudGhlbigoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbW9kYWwgPSBuZXcgQ3VzdG9tVmFyaWFibGVTZXR0aW5nc01vZGFsKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VzdG9tX3ZhcmlhYmxlX2luc3RhbmNlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBWYXJpYWJsZSBpcyBjcmVhdGVkLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJvcGRvd24uYWRkT3B0aW9uKGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZS5nZXRJRCgpLCBjdXN0b21fdmFyaWFibGVfaW5zdGFuY2UuZ2V0VGl0bGUoKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcm9wZG93bi5zZXRWYWx1ZShjdXN0b21fdmFyaWFibGVfaW5zdGFuY2UuZ2V0SUQoKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9tcHRfZmllbGQuY29uZmlndXJhdGlvbi50YXJnZXRfdmFyaWFibGVfaWQgPSBjdXN0b21fdmFyaWFibGVfaW5zdGFuY2UuZ2V0SUQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcm9wZG93bi5zZXRWYWx1ZShwcm9tcHRfZmllbGQuY29uZmlndXJhdGlvbi50YXJnZXRfdmFyaWFibGVfaWQpOyAvLyBSZXNldCB0aGUgZHJvcGRvd24gc2VsZWN0aW9uLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVmFyaWFibGUgY3JlYXRpb24gd2FzIGNhbmNlbGxlZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmRlbGV0ZUluc3RhbmNlKGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGFsLm9wZW4oKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVXNlIGFuIGV4aXN0aW5nIHRhcmdldCB2YXJpYWJsZSAob3IgYW4gZW1wdHkgaWQgXCJcIikuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayB0aGF0IHRoaXMgdGFyZ2V0IHZhcmlhYmxlIGlzIG5vdCByZXNlcnZlZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb21wdF9maWVsZC5zZXRJZlZhbGlkKFwidGFyZ2V0X3ZhcmlhYmxlX2lkXCIsIG5ld190YXJnZXRfdmFyaWFibGVfaWQpLnRoZW4oYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEl0IGNhbiBiZSB1c2VkLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwgKGVycm9yX21lc3NhZ2U6IHN0cmluZyB8IHVua25vd24pID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGVycm9yX21lc3NhZ2UgPT09IFwic3RyaW5nXCIpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyBpcyBhIHZhbGlkYXRpb24gZXJyb3IgbWVzc2FnZS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhlIHRhcmdldCB2YXJpYWJsZSBpcyByZXNlcnZlZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJvcGRvd24uc2V0VmFsdWUocHJvbXB0X2ZpZWxkLmNvbmZpZ3VyYXRpb24udGFyZ2V0X3ZhcmlhYmxlX2lkKTsgLy8gUmVzZXQgdGhlIGRyb3Bkb3duIHNlbGVjdGlvbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3Tm90aWZpY2F0aW9uKGVycm9yX21lc3NhZ2UpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvbWUgb3RoZXIgcnVudGltZSBlcnJvciBoYXMgb2NjdXJyZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGVycm9yX21lc3NhZ2U7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAsXHJcbiAgICAgICAgICAgIHJlcXVpcmVkX3NldHRpbmc6IG5ldyBTZXR0aW5nKHNldHRpbmdfZ3JvdXBfZWxlbWVudClcclxuICAgICAgICAgICAgICAgIC5zZXROYW1lKFwiSXMgcmVxdWlyZWRcIilcclxuICAgICAgICAgICAgICAgIC5zZXREZXNjKFwiSWYgb24sIHRoZSBmaWVsZCBuZWVkcyB0byBiZSBmaWxsZWQgYmVmb3JlIHRoZSBwcm9tcHQgY2FuIGJlIHN1Ym1pdHRlZC5cIilcclxuICAgICAgICAgICAgICAgIC5hZGRUb2dnbGUodG9nZ2xlID0+IHRvZ2dsZVxyXG4gICAgICAgICAgICAgICAgICAgIC5zZXRWYWx1ZShwcm9tcHRfZmllbGQuY29uZmlndXJhdGlvbi5yZXF1aXJlZClcclxuICAgICAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKG5ld19yZXF1aXJlZDogYm9vbGVhbikgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBwcm9tcHRfZmllbGQuY29uZmlndXJhdGlvbi5yZXF1aXJlZCA9IG5ld19yZXF1aXJlZDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgLFxyXG4gICAgICAgIH07XHJcbiAgICAgICAgX3VwZGF0ZV9oZWFkaW5nKCk7XHJcblxyXG4gICAgICAgIGZ1bmN0aW9uIF91cGRhdGVfaGVhZGluZygpIHtcclxuICAgICAgICAgICAgc2V0dGluZ19ncm91cC5oZWFkaW5nX3NldHRpbmcuc2V0TmFtZShwcm9tcHRfZmllbGQuZ2V0VGl0bGUoKSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBBdXRvY29tcGxldGUgbWVudVxyXG4gICAgICAgIGlmICh0aGlzLnBsdWdpbi5zZXR0aW5ncy5zaG93X2F1dG9jb21wbGV0ZV9tZW51KSB7XHJcbiAgICAgICAgICAgIC8vIFNob3cgYXV0b2NvbXBsZXRlIG1lbnUgKD0gYSBsaXN0IG9mIGF2YWlsYWJsZSB2YXJpYWJsZXMpLlxyXG4gICAgICAgICAgICBjb25zdCBsYWJlbF9pbnB1dF9lbGVtZW50ID0gc2V0dGluZ19ncm91cC5sYWJlbF9zZXR0aW5nLmNvbnRyb2xFbC5maW5kKFwiaW5wdXRcIikgYXMgSFRNTElucHV0RWxlbWVudDtcclxuICAgICAgICAgICAgY3JlYXRlQXV0b2NvbXBsZXRlKHRoaXMucGx1Z2luLCBsYWJlbF9pbnB1dF9lbGVtZW50LCAoKSA9PiBsYWJlbF9zZXR0aW5nX2NvbXBvbmVudC5vbkNoYW5nZWQoKSk7XHJcbiAgICAgICAgICAgIGNvbnN0IGRlZmF1bHRfdmFsdWVfaW5wdXRfZWxlbWVudCA9IHNldHRpbmdfZ3JvdXAuZGVmYXVsdF92YWx1ZV9zZXR0aW5nLmNvbnRyb2xFbC5maW5kKFwiaW5wdXRcIikgYXMgSFRNTElucHV0RWxlbWVudDtcclxuICAgICAgICAgICAgY3JlYXRlQXV0b2NvbXBsZXRlKHRoaXMucGx1Z2luLCBkZWZhdWx0X3ZhbHVlX2lucHV0X2VsZW1lbnQsIG9uX2RlZmF1bHRfdmFsdWVfc2V0dGluZ19jaGFuZ2UpO1xyXG4gICAgICAgICAgICBjb25zdCBkZXNjcmlwdGlvbl9pbnB1dF9lbGVtZW50ID0gc2V0dGluZ19ncm91cC5kZXNjcmlwdGlvbl9zZXR0aW5nLmNvbnRyb2xFbC5maW5kKFwiaW5wdXRcIikgYXMgSFRNTElucHV0RWxlbWVudDtcclxuICAgICAgICAgICAgY3JlYXRlQXV0b2NvbXBsZXRlKHRoaXMucGx1Z2luLCBkZXNjcmlwdGlvbl9pbnB1dF9lbGVtZW50LCAoKSA9PiBkZXNjcmlwdGlvbl9zZXR0aW5nX2NvbXBvbmVudC5vbkNoYW5nZWQoKSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gc2V0dGluZ19ncm91cC5oZWFkaW5nX3NldHRpbmc7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIHZhbGlkYXRlVmFsdWUocHJvbXB0X2ZpZWxkOiBQcm9tcHRGaWVsZCwgZmllbGQ6IGtleW9mIFByb21wdEZpZWxkQ29uZmlndXJhdGlvbiwgdmFsdWU6IHVua25vd24pOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgICAgICBzd2l0Y2ggKGZpZWxkKSB7XHJcbiAgICAgICAgICAgIGNhc2UgXCJ0YXJnZXRfdmFyaWFibGVfaWRcIjoge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgbmV3X3RhcmdldF92YXJpYWJsZV9pZDogc3RyaW5nID0gdmFsdWUgYXMgc3RyaW5nOyAvLyBBIG1vcmUgZGVzY3JpcHRpdmUgbmFtZSBmb3IgJ3ZhbHVlJy5cclxuXHJcbiAgICAgICAgICAgICAgICAvLyBBbHdheXMgYWxsb3cgYW4gZW1wdHkgdGFyZ2V0X3ZhcmlhYmxlX2lkLiBBIFByb21wdCBjYW5ub3QgYmUgb3BlbmVkIGlmIGEgZmllbGQgbGFja3MgYSB0YXJnZXRfdmFyaWFibGVfaWQsIGJ1dCBpdCdzIGFsbG93ZWQgdG8gYmUgc3RvcmVkIGluIHRoZSBjb25maWd1cmF0aW9uLCBiZWNhdXNlIG5ldyBQcm9tcHRzIGNhbm5vdCBoYXZlIGEgZGVmYXVsdCBzZWxlY3RlZCB0YXJnZXQgdmFyaWFibGUuXHJcbiAgICAgICAgICAgICAgICBpZiAoXCJcIiA9PT0gbmV3X3RhcmdldF92YXJpYWJsZV9pZCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAvLyBDaGVjayB0aGF0IHRoZSB0YXJnZXQgdmFyaWFibGUgaXMgbm90IHVzZWQgYnkgb3RoZXIgZmllbGRzIG9mIHRoZSBzYW1lIFByb21wdC5cclxuICAgICAgICAgICAgICAgIGZvciAoY29uc3Qgb3RoZXJfcHJvbXB0X2ZpZWxkIG9mIHByb21wdF9maWVsZC5wcm9tcHQucHJvbXB0X2ZpZWxkcykge1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChwcm9tcHRfZmllbGQgIT09IG90aGVyX3Byb21wdF9maWVsZCkgeyAvLyBEbyBub3QgY2hlY2sgdGhlIHNhbWUgZmllbGQuIE9ubHkgY2hlY2sgb3RoZXIgZmllbGRzLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBpZiB0aGlzIG90aGVyIGZpZWxkIGhhcyB0aGUgc2FtZSB0YXJnZXQgdmFyaWFibGUuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChuZXdfdGFyZ2V0X3ZhcmlhYmxlX2lkID09PSBvdGhlcl9wcm9tcHRfZmllbGQuY29uZmlndXJhdGlvbi50YXJnZXRfdmFyaWFibGVfaWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZXkgaGF2ZSB0aGUgc2FtZSB0YXJnZXRfdmFyaWFibGVfaWQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBSZXR1cm4gYW4gZXJyb3IgbWVzc2FnZS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHRhcmdldFZhcmlhYmxlSW5zdGFuY2U6IEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UgfCB1bmRlZmluZWQgPSB0aGlzLnBsdWdpbi5nZXRDdXN0b21WYXJpYWJsZUluc3RhbmNlcygpLmdldChuZXdfdGFyZ2V0X3ZhcmlhYmxlX2lkKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh1bmRlZmluZWQgPT09IHRhcmdldFZhcmlhYmxlSW5zdGFuY2UpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZCBub3QgZmluZCB0YXJnZXQgdmFyaWFibGUgd2l0aCBpZCBcIiArIG5ld190YXJnZXRfdmFyaWFibGVfaWQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0X3ZhcmlhYmxlX25hbWUgPSB0YXJnZXRWYXJpYWJsZUluc3RhbmNlLmdldEZ1bGxOYW1lKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QoYFRhcmdldCB2YXJpYWJsZSAke3RhcmdldF92YXJpYWJsZV9uYW1lfSBpcyBhbHJlYWR5IHVzZWQgYnkgYW5vdGhlciBmaWVsZCBpbiB0aGUgc2FtZSBwcm9tcHQuIFNlbGVjdCBhbm90aGVyIHZhcmlhYmxlLmApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgLy8gQWxsIGZpZWxkcyBoYXZlIGJlZW4gY2hlY2tlZCBhbmQgbm8gY29sbGlzaW9ucyB3ZXJlIGZvdW5kLlxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xyXG4gICAgICAgICAgICB9IGRlZmF1bHQ6IHtcclxuICAgICAgICAgICAgICAgIC8vIE5vIHZhbGlkYXRpb24gZm9yIG90aGVyIGZpZWxkcy5cclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzLmNvbnN0cnVjdG9yLm5hbWUgKyBcIi52YWxpZGF0ZVZhbHVlKCk6IE5vIHZhbGlkYXRpb24gaXMgaW1wbGVtZW50ZWQgZm9yIG90aGVyIGZpZWxkcy5cIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldERlZmF1bHRDb25maWd1cmF0aW9uKCk6IFByb21wdEZpZWxkQ29uZmlndXJhdGlvbiB7XHJcbiAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgLy8gdHlwZTogXCJ0ZXh0XCIsXHJcbiAgICAgICAgICAgIGxhYmVsOiBcIlwiLFxyXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJcIixcclxuICAgICAgICAgICAgZGVmYXVsdF92YWx1ZTogXCJcIixcclxuICAgICAgICAgICAgLy8gIFRPRE86IEFkZCAncGxhY2Vob2xkZXInLlxyXG4gICAgICAgICAgICB0YXJnZXRfdmFyaWFibGVfaWQ6IFwiXCIsXHJcbiAgICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIF9kZWxldGVJbnN0YW5jZShwcm9tcHRfZmllbGQ6IFByb21wdEZpZWxkKTogdm9pZCB7XHJcbiAgICAgICAgcHJvbXB0X2ZpZWxkLnByb21wdC5wcm9tcHRfZmllbGRzLmRlbGV0ZShwcm9tcHRfZmllbGQpO1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgY2xhc3MgUHJvbXB0RmllbGRTZXQgZXh0ZW5kcyBTZXQ8UHJvbXB0RmllbGQ+IHt9XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFByb21wdEZpZWxkU2V0dGluZ0dyb3VwIHtcclxuICAgIGhlYWRpbmdfc2V0dGluZzogU2V0dGluZztcclxuICAgIGxhYmVsX3NldHRpbmc6IFNldHRpbmc7XHJcbiAgICBkZWZhdWx0X3ZhbHVlX3NldHRpbmc6IFNldHRpbmc7XHJcbiAgICBkZXNjcmlwdGlvbl9zZXR0aW5nOiBTZXR0aW5nO1xyXG4gICAgdGFyZ2V0X3ZhcmlhYmxlX3NldHRpbmc6IFNldHRpbmdcclxuICAgIHJlcXVpcmVkX3NldHRpbmc6IFNldHRpbmc7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7XHJcbiAgICBTZXR0aW5nLFxyXG4gICAgVGV4dENvbXBvbmVudCxcclxufSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHtjcmVhdGVBdXRvY29tcGxldGV9IGZyb20gXCIuLi8uLi8uLi9zZXR0aW5ncy9zZXR0aW5nX2VsZW1lbnRzL0F1dG9jb21wbGV0ZVwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi8uLi8uLi9tYWluXCI7XHJcbmltcG9ydCB7U0NfRXZlbnR9IGZyb20gXCIuLi8uLi8uLi9ldmVudHMvU0NfRXZlbnRcIjtcclxuaW1wb3J0IHtwYXJzZVZhcmlhYmxlc30gZnJvbSBcIi4uLy4uLy4uL3ZhcmlhYmxlcy9wYXJzZVZhcmlhYmxlc1wiO1xyXG5pbXBvcnQge1RTaGVsbENvbW1hbmR9IGZyb20gXCIuLi8uLi8uLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7XHJcbiAgICBQcm9tcHRGaWVsZCxcclxufSBmcm9tIFwiLi4vLi4vLi4vaW1wb3J0c1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFByb21wdEZpZWxkX1RleHQgZXh0ZW5kcyBQcm9tcHRGaWVsZCB7XHJcblxyXG4gICAgcHJpdmF0ZSB0ZXh0X2NvbXBvbmVudDogVGV4dENvbXBvbmVudDtcclxuXHJcbiAgICBwcm90ZWN0ZWQgYXN5bmMgX2NyZWF0ZUZpZWxkKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCwgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kIHwgbnVsbCwgc2NfZXZlbnQ6IFNDX0V2ZW50IHwgbnVsbCkge1xyXG4gICAgICAgIGNvbnN0IHBsdWdpbjogU0NfUGx1Z2luID0gdGhpcy5wcm9tcHQubW9kZWwucGx1Z2luO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgdGhlIGZpZWxkXHJcbiAgICAgICAgY29uc3Qgb25fY2hhbmdlID0gKCkgPT4gdGhpcy52YWx1ZUhhc0NoYW5nZWQodF9zaGVsbF9jb21tYW5kLCBzY19ldmVudCk7XHJcbiAgICAgICAgY29uc3QgbGFiZWxfcGFyc2luZ19yZXN1bHQgPSBhd2FpdCBwYXJzZVZhcmlhYmxlcyh0aGlzLnByb21wdC5tb2RlbC5wbHVnaW4sIHRoaXMuY29uZmlndXJhdGlvbi5sYWJlbCwgbnVsbCwgdF9zaGVsbF9jb21tYW5kLCBzY19ldmVudCk7XHJcbiAgICAgICAgY29uc3QgZGVzY3JpcHRpb25fcGFyc2luZ19yZXN1bHQgPSBhd2FpdCBwYXJzZVZhcmlhYmxlcyh0aGlzLnByb21wdC5tb2RlbC5wbHVnaW4sIHRoaXMuY29uZmlndXJhdGlvbi5kZXNjcmlwdGlvbiwgbnVsbCwgdF9zaGVsbF9jb21tYW5kLCBzY19ldmVudCk7XHJcbiAgICAgICAgY29uc3Qgc2V0dGluZyA9IG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0TmFtZShsYWJlbF9wYXJzaW5nX3Jlc3VsdC5zdWNjZWVkZWQgPyBsYWJlbF9wYXJzaW5nX3Jlc3VsdC5wYXJzZWRfY29udGVudCBhcyBzdHJpbmcgOiBsYWJlbF9wYXJzaW5nX3Jlc3VsdC5vcmlnaW5hbF9jb250ZW50KVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhkZXNjcmlwdGlvbl9wYXJzaW5nX3Jlc3VsdC5zdWNjZWVkZWQgPyBkZXNjcmlwdGlvbl9wYXJzaW5nX3Jlc3VsdC5wYXJzZWRfY29udGVudCBhcyBzdHJpbmcgOiBkZXNjcmlwdGlvbl9wYXJzaW5nX3Jlc3VsdC5vcmlnaW5hbF9jb250ZW50KVxyXG4gICAgICAgICAgICAuYWRkVGV4dCgodGV4dF9jb21wb25lbnQpID0+IHtcclxuICAgICAgICAgICAgICAgIHRoaXMudGV4dF9jb21wb25lbnQgPSB0ZXh0X2NvbXBvbmVudDtcclxuICAgICAgICAgICAgICAgIHRleHRfY29tcG9uZW50Lm9uQ2hhbmdlKG9uX2NoYW5nZSk7XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgO1xyXG5cclxuICAgICAgICAvLyBTZXQgdXAgb25Gb2N1cyBob29rLlxyXG4gICAgICAgIHRoaXMudGV4dF9jb21wb25lbnQuaW5wdXRFbC5vbmZvY3VzID0gKCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLmhhc0dvdHRlbkZvY3VzKCk7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgLy8gU2hvdyBhdXRvY29tcGxldGUgbWVudSAoaWYgZW5hYmxlZClcclxuICAgICAgICBpZiAocGx1Z2luLnNldHRpbmdzLnNob3dfYXV0b2NvbXBsZXRlX21lbnUpIHtcclxuICAgICAgICAgICAgY29uc3QgaW5wdXRfZWxlbWVudCA9IHNldHRpbmcuY29udHJvbEVsLmZpbmQoXCJpbnB1dFwiKSBhcyBIVE1MSW5wdXRFbGVtZW50O1xyXG4gICAgICAgICAgICBjcmVhdGVBdXRvY29tcGxldGUocGx1Z2luLCBpbnB1dF9lbGVtZW50LCBvbl9jaGFuZ2UpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwcm90ZWN0ZWQgc2V0VmFsdWUodmFsdWU6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMudGV4dF9jb21wb25lbnQuc2V0VmFsdWUodmFsdWUpO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBnZXRWYWx1ZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiB0aGlzLnRleHRfY29tcG9uZW50LmdldFZhbHVlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIHNldEZvY3VzKCk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMudGV4dF9jb21wb25lbnQuaW5wdXRFbC5mb2N1cygpO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBpc0ZpbGxlZCgpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5nZXRWYWx1ZSgpLmxlbmd0aCA+IDA7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uLy4uL21haW5cIjtcclxuaW1wb3J0IHtTaGVsbENvbW1hbmRQYXJzaW5nUHJvY2VzcywgVFNoZWxsQ29tbWFuZH0gZnJvbSBcIi4uLy4uL1RTaGVsbENvbW1hbmRcIjtcclxuaW1wb3J0IHtTQ19NYWluU2V0dGluZ3N9IGZyb20gXCIuLi8uLi9zZXR0aW5ncy9TQ19NYWluU2V0dGluZ3NcIjtcclxuaW1wb3J0IHtTQ19FdmVudH0gZnJvbSBcIi4uLy4uL2V2ZW50cy9TQ19FdmVudFwiO1xyXG5pbXBvcnQge1xyXG4gICAgZ2V0TW9kZWwsXHJcbiAgICBJbnN0YW5jZSxcclxuICAgIFByb21wdEZpZWxkLFxyXG4gICAgUHJvbXB0RmllbGRDb25maWd1cmF0aW9uLFxyXG4gICAgUHJvbXB0RmllbGRTZXQsXHJcbiAgICBQcm9tcHRGaWVsZE1vZGVsLFxyXG4gICAgUHJvbXB0TW9kYWwsXHJcbiAgICBQcm9tcHRNb2RlbCxcclxuICAgIGdldElER2VuZXJhdG9yLFxyXG59IGZyb20gXCIuLi8uLi9pbXBvcnRzXCI7XHJcbmltcG9ydCB7ZGVidWdMb2d9IGZyb20gXCIuLi8uLi9EZWJ1Z1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFByb21wdCBleHRlbmRzIEluc3RhbmNlIHtcclxuXHJcbiAgICBwdWJsaWMgcHJvbXB0X2ZpZWxkczogUHJvbXB0RmllbGRTZXQgPSBuZXcgUHJvbXB0RmllbGRTZXQoKTtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihcclxuICAgICAgICBwdWJsaWMgbW9kZWw6IFByb21wdE1vZGVsLFxyXG4gICAgICAgIHByb3RlY3RlZCBwbHVnaW46IFNDX1BsdWdpbixcclxuICAgICAgICBwdWJsaWMgY29uZmlndXJhdGlvbjogUHJvbXB0Q29uZmlndXJhdGlvbixcclxuICAgICAgICBwdWJsaWMgcGFyZW50X2NvbmZpZ3VyYXRpb246IFNDX01haW5TZXR0aW5ncyxcclxuICAgICkge1xyXG4gICAgICAgIHN1cGVyKG1vZGVsLCBjb25maWd1cmF0aW9uLCBwYXJlbnRfY29uZmlndXJhdGlvbik7XHJcblxyXG4gICAgICAgIC8vIEludHJvZHVjZSB0aGUgSUQgdG8gYW4gSUQgZ2VuZXJhdG9yIHNvIHRoYXQgaXQgd29uJ3QgYWNjaWRlbnRhbGx5IGdlbmVyYXRlIHRoZSBzYW1lIElEIGFnYWluIHdoZW4gY3JlYXRpbmcgbmV3IFByb21wdHMuXHJcbiAgICAgICAgZ2V0SURHZW5lcmF0b3IoKS5hZGRSZXNlcnZlZElEKGNvbmZpZ3VyYXRpb24uaWQpO1xyXG5cclxuICAgICAgICB0aGlzLmNyZWF0ZUZpZWxkcygpO1xyXG4gICAgfVxyXG5cclxuXHJcbiAgICBwdWJsaWMgZ2V0SUQoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbi5pZDtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0VGl0bGUoKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbi50aXRsZTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0Q29uZmlndXJhdGlvbigpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmF0aW9uO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRDU1NDbGFzcygpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiBQcm9tcHQuZ2V0Q1NTQmFzZUNsYXNzKCkgKyBcIi1cIiArIHRoaXMuZ2V0SUQoKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgc3RhdGljIGdldENTU0Jhc2VDbGFzcygpIHtcclxuICAgICAgICByZXR1cm4gXCJTQy1wcm9tcHQtbW9kYWxcIjtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgZ2V0Q1NTQ2xhc3NlcygpIHtcclxuICAgICAgICByZXR1cm4gW1xyXG4gICAgICAgICAgICBQcm9tcHQuZ2V0Q1NTQmFzZUNsYXNzKCksXHJcbiAgICAgICAgICAgIHRoaXMuZ2V0Q1NTQ2xhc3MoKSxcclxuICAgICAgICBdO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHRfc2hlbGxfY29tbWFuZCBDYW4gYmUgbnVsbCwgaWYgd2FudGVkIHRvIGp1c3QgcHJldmlldyB0aGUgUHJvbXB0IG1vZGFsIHdpdGhvdXQgcmVhbGx5IGV4ZWN1dGluZyBhIHNoZWxsIGNvbW1hbmQuIElucHV0dGVkIHZhbHVlcyB3aWxsIHN0aWxsIGJlIGFzc2lnbmVkIHRvIHRhcmdldCB2YXJpYWJsZXMuXHJcbiAgICAgKiBAcGFyYW0gcGFyc2luZ19wcm9jZXNzXHJcbiAgICAgKiBAcGFyYW0gc2NfZXZlbnRcclxuICAgICAqIEByZXR1cm4gUHJvbWlzZSBUaGUgYm9vbGVhbiB2YWx1ZSB0ZWxscyB3aGV0aGVyIHRoZSB1c2VyIHdhbnRzIHRvIGV4ZWN1dGUgYSBzaGVsbCBjb21tYW5kICh0cnVlKSBvciBjYW5jZWwgKGZhbHNlKS5cclxuICAgICAqL1xyXG4gICAgcHVibGljIG9wZW5Qcm9tcHQodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kIHwgbnVsbCwgcGFyc2luZ19wcm9jZXNzOiBTaGVsbENvbW1hbmRQYXJzaW5nUHJvY2VzcyB8IG51bGwsIHNjX2V2ZW50OiBTQ19FdmVudCB8IG51bGwpOiBQcm9taXNlPGJvb2xlYW4+IHtcclxuICAgICAgICBjb25zdCBjYW5fb3Blbl9wcm9tcHRfcmVzdWx0ID0gdGhpcy5jYW5PcGVuUHJvbXB0KCk7XHJcbiAgICAgICAgaWYgKHRydWUgIT09IGNhbl9vcGVuX3Byb21wdF9yZXN1bHQpIHtcclxuICAgICAgICAgICAgLy8gU29tZSBlcnJvciBpcyBwcmV2ZW50aW5nIG9wZW5pbmcgdGhlIHByb21wdC5cclxuICAgICAgICAgICAgLy8gQSBodW1hbi1yZWFkYWJsZSBlcnJvciBtZXNzYWdlIGlzIGNvbnRhaW5lZCBpbiBjYW5fb3Blbl9wcm9tcHRfcmVzdWx0LlxyXG4gICAgICAgICAgICBkZWJ1Z0xvZyhcIkNvdWxkIG5vdCBvcGVuIFByb21wdCBcIiArIHRoaXMuZ2V0SUQoKSArIFwiIGJlY2F1c2Ugb2YgZXJyb3I6IFwiICsgY2FuX29wZW5fcHJvbXB0X3Jlc3VsdCk7XHJcbiAgICAgICAgICAgIHRoaXMucGx1Z2luLm5ld0Vycm9yKGNhbl9vcGVuX3Byb21wdF9yZXN1bHQpO1xyXG4gICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTsgLy8gZmFsc2U6IENhbmNlbCBleGVjdXRpb24gKHByZXRlbmRzIHRoYXQgYSB1c2VyIGNhbmNlbGxlZCBpdCwgYnV0IGl0J3Mgb2spLlxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgZGVidWdMb2coXCJPcGVuaW5nIFByb21wdCBcIiArIHRoaXMuZ2V0SUQoKSk7XHJcblxyXG4gICAgICAgIGNvbnN0IG1vZGFsID0gbmV3IFByb21wdE1vZGFsKFxyXG4gICAgICAgICAgICB0aGlzLnBsdWdpbixcclxuICAgICAgICAgICAgdGhpcy5wcm9tcHRfZmllbGRzLFxyXG4gICAgICAgICAgICB0X3NoZWxsX2NvbW1hbmQsXHJcbiAgICAgICAgICAgIHBhcnNpbmdfcHJvY2VzcyxcclxuICAgICAgICAgICAgdGhpcyxcclxuICAgICAgICAgICAgc2NfZXZlbnQsXHJcbiAgICAgICAgICAgICgpID0+IHtyZXR1cm4gdGhpcy52YWxpZGF0ZUZpZWxkcygpO31cclxuICAgICAgICApO1xyXG4gICAgICAgIG1vZGFsLm9wZW4oKTtcclxuICAgICAgICByZXR1cm4gbW9kYWwucHJvbWlzZTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGNhbk9wZW5Qcm9tcHQoKTogdHJ1ZSB8IHN0cmluZyB7XHJcblxyXG4gICAgICAgIC8vIENoZWNrIHRoYXQgYWxsIFByb21wdEZpZWxkcyBoYXZlIGEgdGFyZ2V0IHZhcmlhYmxlIGRlZmluZWQuXHJcbiAgICAgICAgZm9yIChjb25zdCBwcm9tcHRfZmllbGQgb2YgdGhpcy5wcm9tcHRfZmllbGRzKSB7XHJcbiAgICAgICAgICAgIGlmICghcHJvbXB0X2ZpZWxkLmNvbmZpZ3VyYXRpb24udGFyZ2V0X3ZhcmlhYmxlX2lkKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gYENhbm5vdCBvcGVuIHByb21wdCAnJHt0aGlzLmdldFRpdGxlKCl9JzogRmllbGQgJyR7cHJvbXB0X2ZpZWxkLmdldFRpdGxlKCl9JyBkb2VzIG5vdCBoYXZlIGEgdGFyZ2V0IHZhcmlhYmxlLmA7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgICAgIHByb21wdF9maWVsZC5nZXRUYXJnZXRWYXJpYWJsZUluc3RhbmNlKCk7IC8vIEp1c3QgdHJ5IHRvIGdldCBhIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UuIE5vIG5lZWQgdG8gdXNlIGl0IGhlcmUsIGJ1dCBpZiB0aGlzIGZhaWxzLCB3ZSBrbm93IHRoZSB2YXJpYWJsZSBpcyByZW1vdmVkLlxyXG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYENhbm5vdCBvcGVuIHByb21wdCAnJHt0aGlzLmdldFRpdGxlKCl9JzogRmllbGQgJyR7cHJvbXB0X2ZpZWxkLmdldFRpdGxlKCl9JyB1c2VzIGEgdGFyZ2V0IHZhcmlhYmxlIHdoaWNoIGRvZXMgbm90IGV4aXN0IGFueW1vcmUuYDtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQWxsIG9rLlxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBQcm9tcHRGaWVsZCBpbnN0YW5jZXMsIE5PVCBzZXR0aW5nIGZpZWxkcyFcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBjcmVhdGVGaWVsZHMoKSB7XHJcbiAgICAgICAgZGVidWdMb2coXCJDcmVhdGluZyBmaWVsZHMgZm9yIFByb21wdCBcIiArIHRoaXMuZ2V0SUQoKSk7XHJcbiAgICAgICAgY29uc3QgcHJvbXB0X2ZpZWxkX21vZGVsID0gZ2V0TW9kZWw8UHJvbXB0RmllbGRNb2RlbD4oUHJvbXB0RmllbGRNb2RlbC5uYW1lKTtcclxuICAgICAgICB0aGlzLnByb21wdF9maWVsZHMgPSBwcm9tcHRfZmllbGRfbW9kZWwubG9hZEluc3RhbmNlcyh0aGlzKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFZhbGlkYXRlcyB2YWx1ZXMgaW4gUHJvbXB0RmllbGQgaW5zdGFuY2VzLCBOT1Qgc2V0dGluZyBmaWVsZHMhXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgdmFsaWRhdGVGaWVsZHMoKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgZGVidWdMb2coXCJWYWxpZGF0aW5nIGZpZWxkcyBmb3IgUHJvbXB0IFwiICsgdGhpcy5nZXRJRCgpKTtcclxuXHJcbiAgICAgICAgLy8gSXRlcmF0ZSBhbGwgZmllbGRzIGFuZCBjaGVjayB0aGVpciB2YWxpZGl0eS5cclxuICAgICAgICBjb25zdCBlcnJvcl9tZXNzYWdlczogc3RyaW5nW10gPSBbXTtcclxuICAgICAgICB0aGlzLnByb21wdF9maWVsZHMuZm9yRWFjaCgocHJvbXB0X2ZpZWxkOiBQcm9tcHRGaWVsZCkgPT4ge1xyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGZpZWxkIGhhcyBwYXJzaW5nIGVycm9ycy5cclxuICAgICAgICAgICAgY29uc3QgcGFyc2luZ19lcnJvcnM6IHN0cmluZ1tdID0gcHJvbXB0X2ZpZWxkLmdldFBhcnNpbmdFcnJvcnMoKTtcclxuICAgICAgICAgICAgZm9yIChjb25zdCBwYXJzaW5nX2Vycm9yIG9mIHBhcnNpbmdfZXJyb3JzKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGlzIGZpZWxkIGhhcyBwYXJzaW5nIGVycm9yKHMpLlxyXG4gICAgICAgICAgICAgICAgZXJyb3JfbWVzc2FnZXMucHVzaChgJyR7cHJvbXB0X2ZpZWxkLmdldFRpdGxlKCl9JzogYCArIHBhcnNpbmdfZXJyb3IpO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBvdGhlciB2YWxpZGl0eS5cclxuICAgICAgICAgICAgaWYgKCFwcm9tcHRfZmllbGQudmFsaWRhdGUoKSkge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhpcyBmaWVsZCBmYWlsZWQgdG8gdmFsaWRhdGUuXHJcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiBDaGFuZ2UgdGhpcyBzbyB0aGF0IHRoZSBtZXNzYWdlIHdpbGwgY29tZSBmcm9tIHByb21wdF9maWVsZC52YWxpZGF0ZSgpLlxyXG4gICAgICAgICAgICAgICAgZXJyb3JfbWVzc2FnZXMucHVzaChgJyR7cHJvbXB0X2ZpZWxkLmdldFRpdGxlKCl9JyBuZWVkcyB0byBiZSBmaWxsZWQuYCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gUmV0dXJuIHRoZSByZXN1bHQuXHJcbiAgICAgICAgaWYgKDAgPT09IGVycm9yX21lc3NhZ2VzLmxlbmd0aCkge1xyXG4gICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGVycm9yX21lc3NhZ2VzKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBXaGVuIHByZXZpZXdpbmcgYSBQcm9tcHRNb2RhbCwgdGhlcmUgaXMgbm8gcmVhbCBzaGVsbCBjb21tYW5kIGF2YWlsYWJsZSAoYmVjYXVzZSBubyBzaGVsbCBjb21tYW5kIGhhcyB0cmlnZ2VyZWQgdGhlXHJcbiAgICAgKiBQcm9tcHRNb2RhbCkuIFRoaXMgbWV0aG9kIGNyZWF0ZXMganVzdCBhIGR1bW15IHNoZWxsIGNvbW1hbmQgc3RyaW5nIHRoYXQgaW1pdGF0ZXMgYSBjb21tYW5kIHRoYXQgd291bGQgZWNobyB2YXJpYWJsZSB2YWx1ZXMuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXRFeGFtcGxlU2hlbGxDb21tYW5kKCk6IHN0cmluZyB7XHJcbiAgICAgICAgY29uc3QgdmFyaWFibGVfbmFtZXM6IHN0cmluZ1tdID0gW107XHJcbiAgICAgICAgZm9yIChjb25zdCBwcm9tcHRfZmllbGQgb2YgdGhpcy5wcm9tcHRfZmllbGRzKSB7XHJcbiAgICAgICAgICAgIHZhcmlhYmxlX25hbWVzLnB1c2gocHJvbXB0X2ZpZWxkLmdldFRhcmdldFZhcmlhYmxlSW5zdGFuY2UoKS5nZXRGdWxsTmFtZSgpKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIFwiZWNobyBcIit2YXJpYWJsZV9uYW1lcy5qb2luKFwiIFwiKTtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBQcm9tcHRDb25maWd1cmF0aW9uIHtcclxuICAgIGlkOiBzdHJpbmc7XHJcbiAgICB0aXRsZTogc3RyaW5nO1xyXG4gICAgZGVzY3JpcHRpb246IHN0cmluZztcclxuICAgIHByZXZpZXdfc2hlbGxfY29tbWFuZDogYm9vbGVhbjtcclxuICAgIGZpZWxkczogUHJvbXB0RmllbGRDb25maWd1cmF0aW9uW107XHJcbiAgICBleGVjdXRlX2J1dHRvbl90ZXh0OiBzdHJpbmc7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U0NfTW9kYWx9IGZyb20gXCIuLi8uLi9TQ19Nb2RhbFwiO1xyXG5pbXBvcnQge1NoZWxsQ29tbWFuZFBhcnNpbmdQcm9jZXNzLCBUU2hlbGxDb21tYW5kfSBmcm9tIFwiLi4vLi4vVFNoZWxsQ29tbWFuZFwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi8uLi9tYWluXCI7XHJcbmltcG9ydCB7U2V0dGluZ30gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7U0NfRXZlbnR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRcIjtcclxuaW1wb3J0IHtjcmVhdGVNdWx0aWxpbmVUZXh0RWxlbWVudH0gZnJvbSBcIi4uLy4uL0NvbW1vblwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlLCBWYXJpYWJsZVZhbHVlUmVzdWx0fSBmcm9tIFwiLi4vLi4vdmFyaWFibGVzL1ZhcmlhYmxlXCI7XHJcbmltcG9ydCB7XHJcbiAgICBQcm9tcHQsXHJcbiAgICBQcm9tcHRGaWVsZCxcclxuICAgIFByb21wdEZpZWxkU2V0LFxyXG59IGZyb20gXCIuLi8uLi9pbXBvcnRzXCI7XHJcbmltcG9ydCB7XHJcbiAgICBwYXJzZVZhcmlhYmxlcyxcclxuICAgIFBhcnNpbmdSZXN1bHQsXHJcbn0gZnJvbSBcIi4uLy4uL3ZhcmlhYmxlcy9wYXJzZVZhcmlhYmxlc1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFByb21wdE1vZGFsIGV4dGVuZHMgU0NfTW9kYWwge1xyXG5cclxuICAgIHB1YmxpYyBwcm9taXNlOiBQcm9taXNlPGJvb2xlYW4+O1xyXG4gICAgcHJpdmF0ZSB1c2VyX2NvbmZpcm1lZF9vayA9IGZhbHNlO1xyXG4gICAgcHJpdmF0ZSByZXNvbHZlX3Byb21pc2U6ICh2YWx1ZTogKGJvb2xlYW4gfCBQcm9taXNlTGlrZTxib29sZWFuPikpID0+IHZvaWQ7XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBwcm9tcHRfZmllbGRzOiBQcm9tcHRGaWVsZFNldCxcclxuICAgICAgICAvKiogQ2FuIGJlIG51bGwsIGlmIHdhbnRlZCB0byBqdXN0IHByZXZpZXcgdGhlIFByb21wdCBtb2RhbCB3aXRob3V0IHJlYWxseSBleGVjdXRpbmcgYSBzaGVsbCBjb21tYW5kLiBJbnB1dHRlZCB2YWx1ZXMgd2lsbCBzdGlsbCBiZSBhc3NpZ25lZCB0byB0YXJnZXQgdmFyaWFibGVzLiAqL1xyXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kIHwgbnVsbCxcclxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IHBhcnNpbmdfcHJvY2VzczogU2hlbGxDb21tYW5kUGFyc2luZ1Byb2Nlc3MgfCBudWxsLFxyXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgcHJvbXB0OiBQcm9tcHQsXHJcbiAgICAgICAgcHJpdmF0ZSBzY19ldmVudDogU0NfRXZlbnQgfCBudWxsLFxyXG5cclxuICAgICAgICAvKiogQSBmdW5jdGlvbiB0aGF0IGlzIGNhbGxlZCB3aGVuIGEgdXNlciBjbGlja3MgdGhlIGV4ZWN1dGlvbiBidXR0b24uIFRoaXMgZnVuY3Rpb24gc2hvdWxkIGNoZWNrIHRoZSBmb3JtIGVsZW1lbnRzJyB2YWxpZGl0eSBhbmQgcmV0dXJuIGZhbHNlIGlmIHRoZXJlIGFyZSB1bmZpbGxlZCBmaWVsZHMuICovXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSB2YWxpZGF0b3I6ICgpID0+IFByb21pc2U8dm9pZD4sXHJcbiAgICApIHtcclxuICAgICAgICBzdXBlcihwbHVnaW4pO1xyXG4gICAgICAgIHRoaXMucHJvbWlzZSA9IG5ldyBQcm9taXNlPGJvb2xlYW4+KChyZXNvbHZlKSA9PiB7XHJcbiAgICAgICAgICAgIHRoaXMucmVzb2x2ZV9wcm9taXNlID0gcmVzb2x2ZTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgYXN5bmMgb25PcGVuKCkge1xyXG4gICAgICAgIHN1cGVyLm9uT3BlbigpO1xyXG5cclxuICAgICAgICAvLyBQYXJzZSBhbmQgZGlzcGxheSB0aXRsZVxyXG4gICAgICAgIGNvbnN0IHRpdGxlX3BhcnNpbmdfcmVzdWx0ID0gYXdhaXQgcGFyc2VWYXJpYWJsZXModGhpcy5wbHVnaW4sIHRoaXMucHJvbXB0LmdldFRpdGxlKCksIG51bGwsIHRoaXMudF9zaGVsbF9jb21tYW5kLCB0aGlzLnNjX2V2ZW50KTtcclxuICAgICAgICB0aGlzLnNldFRpdGxlKFxyXG4gICAgICAgICAgICB0aXRsZV9wYXJzaW5nX3Jlc3VsdC5zdWNjZWVkZWRcclxuICAgICAgICAgICAgPyB0aXRsZV9wYXJzaW5nX3Jlc3VsdC5wYXJzZWRfY29udGVudCBhcyBzdHJpbmdcclxuICAgICAgICAgICAgOiB0aXRsZV9wYXJzaW5nX3Jlc3VsdC5vcmlnaW5hbF9jb250ZW50XHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUGFyc2UgYW5kIGRpc3BsYXkgZGVzY3JpcHRpb25cclxuICAgICAgICBpZiAodGhpcy5wcm9tcHQuY29uZmlndXJhdGlvbi5kZXNjcmlwdGlvbikge1xyXG4gICAgICAgICAgICBjb25zdCBkZXNjcmlwdGlvbl9wYXJzaW5nX3Jlc3VsdDogUGFyc2luZ1Jlc3VsdCA9IGF3YWl0IHBhcnNlVmFyaWFibGVzKHRoaXMucGx1Z2luLCB0aGlzLnByb21wdC5jb25maWd1cmF0aW9uLmRlc2NyaXB0aW9uLCBudWxsLCB0aGlzLnRfc2hlbGxfY29tbWFuZCwgdGhpcy5zY19ldmVudCk7XHJcbiAgICAgICAgICAgIGNvbnN0IGRlc2NyaXB0aW9uOiBzdHJpbmcgPVxyXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb25fcGFyc2luZ19yZXN1bHQuc3VjY2VlZGVkXHJcbiAgICAgICAgICAgICAgICA/IGRlc2NyaXB0aW9uX3BhcnNpbmdfcmVzdWx0LnBhcnNlZF9jb250ZW50IGFzIHN0cmluZ1xyXG4gICAgICAgICAgICAgICAgOiBkZXNjcmlwdGlvbl9wYXJzaW5nX3Jlc3VsdC5vcmlnaW5hbF9jb250ZW50XHJcbiAgICAgICAgICAgIDtcclxuICAgICAgICAgICAgY29uc3QgZGVzY3JpcHRpb25fZWxlbWVudCA9IGNyZWF0ZU11bHRpbGluZVRleHRFbGVtZW50KFwicFwiLCBkZXNjcmlwdGlvbiwgdGhpcy5tb2RhbEVsKTtcclxuICAgICAgICAgICAgZGVzY3JpcHRpb25fZWxlbWVudC5hZGRDbGFzcyhcInNldHRpbmctaXRlbS1kZXNjcmlwdGlvblwiKTsgLy8gQSBDU1MgY2xhc3MgZGVmaW5lZCBieSBPYnNpZGlhbi5cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFByZXZpZXcgdGhlIHNoZWxsIGNvbW1hbmQgKGlmIHdhbnRlZClcclxuICAgICAgICAvLyBUT0RPOiBFeHRyYWN0IHRvIGEgc2VwYXJhdGUgbWV0aG9kLCBhcyB0aGlzIGlzIGEgYmlnIGJsb2NrIG9mIGNvZGUuXHJcbiAgICAgICAgbGV0IHVwZGF0ZV9zaGVsbF9jb21tYW5kX3ByZXZpZXc6ICgoKSA9PiB2b2lkKSB8IG51bGwgPSBudWxsOyAvLyBTdGF5cyBudWxsIGlmIC5wcmV2aWV3X3NoZWxsX2NvbW1hbmQgaXMgZmFsc2UuXHJcbiAgICAgICAgbGV0IGZvY3VzZWRfcHJvbXB0X2ZpZWxkOiBQcm9tcHRGaWVsZCB8IHVuZGVmaW5lZDtcclxuICAgICAgICBpZiAodGhpcy5wcm9tcHQuZ2V0Q29uZmlndXJhdGlvbigpLnByZXZpZXdfc2hlbGxfY29tbWFuZCkge1xyXG4gICAgICAgICAgICBsZXQgc2hlbGxfY29tbWFuZF9wcmV2aWV3X3RleHQ6IHN0cmluZztcclxuICAgICAgICAgICAgaWYgKHRoaXMudF9zaGVsbF9jb21tYW5kPy5nZXRBbGlhcygpKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLm1vZGFsRWwuY3JlYXRlRWwoXCJwXCIsIHt0ZXh0OiB0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRBbGlhcygpLCBhdHRyOiB7Y2xhc3M6IFwiU0Mtbm8tbWFyZ2luXCJ9fSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENyZWF0ZSBcIlNob3cgdmFyaWFibGUgdmFsdWVzXCIgdG9nZ2xlXHJcbiAgICAgICAgICAgIGxldCBwcmV2aWV3X3ZhcmlhYmxlX3ZhbHVlcyA9IHRydWU7XHJcbiAgICAgICAgICAgIGNvbnN0IHZhcmlhYmxlX25hbWVzX3Zpc2libGVfaWNvbiA9IFwiY29kZS1nbHlwaFwiO1xyXG4gICAgICAgICAgICBjb25zdCB2YXJpYWJsZV92YWx1ZXNfdmlzaWJsZV9nbHlwaCA9IFwicHJpY2UtdGFnLWdseXBoXCI7XHJcbiAgICAgICAgICAgIGNvbnN0IHByZXZpZXdfdmFyaWFibGVfdmFsdWVzX3NldHRpbmcgPSBuZXcgU2V0dGluZyh0aGlzLm1vZGFsRWwpXHJcbiAgICAgICAgICAgICAgICAuYWRkRXh0cmFCdXR0b24oYnV0dG9uID0+IGJ1dHRvblxyXG4gICAgICAgICAgICAgICAgICAgIC5zZXRJY29uKHZhcmlhYmxlX3ZhbHVlc192aXNpYmxlX2dseXBoKVxyXG4gICAgICAgICAgICAgICAgICAgIC5zZXRUb29sdGlwKFwiVG9nZ2xlIHNob3dpbmcgdmFyaWFibGUgbmFtZXMgb3IgdmFsdWVzLlwiKVxyXG4gICAgICAgICAgICAgICAgICAgIC5vbkNsaWNrKCgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgcHJldmlld192YXJpYWJsZV92YWx1ZXMgPSAhcHJldmlld192YXJpYWJsZV92YWx1ZXM7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbi5zZXRJY29uKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmlld192YXJpYWJsZV92YWx1ZXNcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gdmFyaWFibGVfdmFsdWVzX3Zpc2libGVfZ2x5cGhcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogdmFyaWFibGVfbmFtZXNfdmlzaWJsZV9pY29uXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChudWxsID09PSB1cGRhdGVfc2hlbGxfY29tbWFuZF9wcmV2aWV3KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUb2dnbGUgc2hvd2luZyB2YXJpYWJsZSBuYW1lcyBvciB2YWx1ZTogdXBkYXRlX3NoZWxsX2NvbW1hbmRfcHJldmlldyBmdW5jdGlvbiBpcyBub3QgZGVmaW5lZC5cIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlX3NoZWxsX2NvbW1hbmRfcHJldmlldygpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICA7XHJcblxyXG4gICAgICAgICAgICAvLyBEZWNpZGUgd2hhdCB0ZXh0IHRvIHVzZSBpbiB0aGUgcHJldmlld1xyXG4gICAgICAgICAgICBjb25zdCBzaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0OiBQYXJzaW5nUmVzdWx0IHwgdW5kZWZpbmVkID0gdGhpcy5wYXJzaW5nX3Byb2Nlc3M/LmdldFBhcnNpbmdSZXN1bHRzKCkuc2hlbGxfY29tbWFuZDtcclxuICAgICAgICAgICAgaWYgKHNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQ/LnN1Y2NlZWRlZCkge1xyXG4gICAgICAgICAgICAgICAgLy8gU2hvdyBhIHJlYWwgc2hlbGwgY29tbWFuZC4gVXNlIHByZXBhcnNlZCBjb250ZW50ICg9IGNvbnRlbnQgdGhhdCBtaWdodCBoYXZlIHNvbWUgdmFyaWFibGVzIGFscmVhZHkgcGFyc2VkKS5cclxuICAgICAgICAgICAgICAgIHNoZWxsX2NvbW1hbmRfcHJldmlld190ZXh0ID0gc2hlbGxDb21tYW5kUGFyc2luZ1Jlc3VsdC5wYXJzZWRfY29udGVudCBhcyBzdHJpbmc7IC8vIGFzIHN0cmluZyA9IGlmIHNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQ/LnN1Y2NlZWRlZCBpcyB0cnVlLCB0aGVuIC5wYXJzZWRfY29udGVudCBpcyBhbHdheXMgc3RyaW5nLlxyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMudF9zaGVsbF9jb21tYW5kKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBTaG93IGEgcmVhbCBzaGVsbCBjb21tYW5kLiBObyBwcmVwYXJzZWQgY29udGVudCBpcyBhdmFpbGFibGUuIFRoaXMgY29udGVudCBkb2VzIG5vdCBoYXZlIGFueSB2YXJpYWJsZXMgcGFyc2VkIHlldC5cclxuICAgICAgICAgICAgICAgIHNoZWxsX2NvbW1hbmRfcHJldmlld190ZXh0ID0gdGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0U2hlbGxDb21tYW5kKCk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBNYWtlIHVwIGEgZmFrZSBcInNoZWxsIGNvbW1hbmRcIiBmb3IgcHJldmlld2luZy5cclxuICAgICAgICAgICAgICAgIHNoZWxsX2NvbW1hbmRfcHJldmlld190ZXh0ID0gdGhpcy5wcm9tcHQuZ2V0RXhhbXBsZVNoZWxsQ29tbWFuZCgpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5tb2RhbEVsLmNyZWF0ZUVsKFwicFwiLCB7dGV4dDogXCIoVGhpcyBpcyBub3QgYSByZWFsIHNoZWxsIGNvbW1hbmQsIGl0J3MganVzdCBhbiBleGFtcGxlIGZvciB0aGlzIHByZXZpZXcgd2hlbiBubyByZWFsIHNoZWxsIGNvbW1hbmQgaXMgYXZhaWxhYmxlLilcIiwgYXR0cjoge2NsYXNzOiBcIlNDLW5vLW1hcmdpbiBTQy1zbWFsbC1mb250XCJ9fSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgdGhpcy5tb2RhbEVsLmNyZWF0ZUVsKFwiaHJcIik7XHJcblxyXG4gICAgICAgICAgICAvLyBBIGZ1bmN0aW9uIGZvciBoYW5kbGluZyBwcmV2aWV3IHRleHQgdXBkYXRlcy5cclxuICAgICAgICAgICAgdXBkYXRlX3NoZWxsX2NvbW1hbmRfcHJldmlldyA9IGFzeW5jICgpID0+IHtcclxuICAgICAgICAgICAgICAgIGxldCBzaGVsbF9jb21tYW5kX3ByZXZpZXdfdGV4dF9maW5hbCA9IHNoZWxsX2NvbW1hbmRfcHJldmlld190ZXh0O1xyXG4gICAgICAgICAgICAgICAgaWYgKHByZXZpZXdfdmFyaWFibGVfdmFsdWVzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIHByZXZpZXcgc2hvdWxkIHNob3cgdGhlIFZBTFVFUy5cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gRW5zdXJlIHRoZSBmb3JtIGZpZWxkcyBkbyBub3QgY29udGFpbiBhbnkgcGFyc2luZyBlcnJvcnMuIChJZiB0aGVyZSBhcmUgZXJyb3JzLCBhbiB1bnBhcnNlZCBwcmV2aWV3IHRleHQgd2lsbCBiZSBzaG93bikuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuZ2V0UHJvbXB0RmllbGRzUGFyc2luZ0Vycm9ycygpLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBBbGwgZmllbGRzIGFyZSBwYXJzZWQgb2sgKD0gaW5kaXZpZHVhbCBwYXJzaW5nKS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW5zZXJ0IHRoZSBmaWVsZCB2YWx1ZXMgaW50byB0aGUgc2hlbGwgY29tbWFuZCBwcmV2aWV3IGJ5IHBhcnNpbmcgdGhlIHByZXZpZXcgdGV4dC5cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdldCBjdXJyZW50IHZhbHVlcyBmcm9tIHRoZSBwcm9tcHQgZmllbGRzLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmcmVzaF92YWx1ZXMgPSB0aGlzLmdldFByb21wdEZpZWxkc1ZhbHVlcygpOyAvLyBUaGVzZSBQcm9tcHRGaWVsZCB2YWx1ZXMgYXJlIGZyZXNoLCBzbyBub3QgeWV0IHN0b3JlZCBpbiB0aGUgYWN0dWFsIHZhcmlhYmxlcy5cclxuXHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBQYXJzZSB2YXJpYWJsZXMgaW4gdGhlIHNoZWxsIGNvbW1hbmQgcHJldmlldyB0ZXh0LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwYXJzaW5nX3Jlc3VsdCA9IGF3YWl0IHBhcnNlVmFyaWFibGVzKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVsbF9jb21tYW5kX3ByZXZpZXdfdGV4dCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZ2V0U2hlbGwoKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zY19ldmVudCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuZGVmaW5lZCwgLy8gVXNlIGFsbCB2YXJpYWJsZXMuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAodmFyaWFibGU6IFZhcmlhYmxlLCByYXdfdmFsdWU6IFZhcmlhYmxlVmFsdWVSZXN1bHQpOiB2b2lkID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZnJlc2hfdmFsdWVzLmhhcyh2YXJpYWJsZS52YXJpYWJsZV9uYW1lKSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGFuZ2UgdGhlIHZhbHVlIHRvIHRoZSBvbmUgaW4gdGhlIHByb21wdCBmaWVsZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmF3X3ZhbHVlLmVycm9yX21lc3NhZ2VzID0gW107IC8vIFJlbW92ZSBhbnkgcG9zc2libGUgZXJyb3IgbWVzc2FnZXMuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhd192YWx1ZS5zdWNjZWVkZWQgPSB0cnVlOyAvLyBUaGlzIG5lZWRzIHRvIHJlZmxlY3QgdGhhdCB0aGVyZSBhcmUgbm8gZXJyb3IgbWVzc2FnZXMuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhd192YWx1ZS52YWx1ZSA9IGZyZXNoX3ZhbHVlcy5nZXQodmFyaWFibGUudmFyaWFibGVfbmFtZSkgYXMgc3RyaW5nOyAvLyBJdCdzIGFsd2F5cyBhIHN0cmluZyBiZWNhdXNlIGZyZXNoX3ZhbHVlcy5oYXMoKSBpcyB1c2VkIGFib3ZlLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBObyBtb2RpZmljYXRpb25zLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICh2YXJpYWJsZTogVmFyaWFibGUsIGVzY2FwZWRfdmFsdWU6IHN0cmluZyk6IHN0cmluZyA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRW1waGFzaXplIHRoZSB2YWx1ZSB0aGF0IGNhbWUgZnJvbSB0aGUgY3VycmVudGx5IGZvY3VzZWQgZmllbGQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGZvY3VzZWRfcHJvbXB0X2ZpZWxkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2YXJpYWJsZS52YXJpYWJsZV9uYW1lLnRvTG9jYWxlTG93ZXJDYXNlKCkgPT09IGZvY3VzZWRfcHJvbXB0X2ZpZWxkLmdldFRhcmdldFZhcmlhYmxlSW5zdGFuY2UoKS5nZXRQcmVmaXhlZE5hbWUoKS50b0xvY2FsZUxvd2VyQ2FzZSgpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNYWtlIHRoZSB2YWx1ZSBib2xkLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGA8c3Ryb25nPiR7ZXNjYXBlZF92YWx1ZX08L3N0cm9uZz5gO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5vIG1vZGlmaWNhdGlvbnMuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGVzY2FwZWRfdmFsdWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocGFyc2luZ19yZXN1bHQuc3VjY2VlZGVkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVsbF9jb21tYW5kX3ByZXZpZXdfdGV4dF9maW5hbCA9IHBhcnNpbmdfcmVzdWx0LnBhcnNlZF9jb250ZW50IGFzIHN0cmluZztcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIHByZXZpZXcgc2hvdWxkIHNob3cgdGhlIFZBUklBQkxFIE5BTUVTLlxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChmb2N1c2VkX3Byb21wdF9maWVsZCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwYXR0ZXJuID0gbmV3IFJlZ0V4cChmb2N1c2VkX3Byb21wdF9maWVsZC5nZXRUYXJnZXRWYXJpYWJsZSgpLmdldFBhdHRlcm4oKSwgXCJpZ3VcIik7IC8vIGk6IGNhc2UtaW5zZW5zaXRpdmU7IGc6IG1hdGNoIGFsbCBvY2N1cnJlbmNlcyBpbnN0ZWFkIG9mIGp1c3QgdGhlIGZpcnN0IG9uZS4gdTogc3VwcG9ydCA0LWJ5dGUgdW5pY29kZSBjaGFyYWN0ZXJzIHRvby5cclxuICAgICAgICAgICAgICAgICAgICAgICAgc2hlbGxfY29tbWFuZF9wcmV2aWV3X3RleHRfZmluYWwgPSBzaGVsbF9jb21tYW5kX3ByZXZpZXdfdGV4dF9maW5hbC5yZXBsYWNlKFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChyZXBsYWNlYWJsZV92YXJpYWJsZV9uYW1lKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFwiPHN0cm9uZz5cIiArIHJlcGxhY2VhYmxlX3ZhcmlhYmxlX25hbWUgKyBcIjwvc3Ryb25nPlwiO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBwcmV2aWV3X3ZhcmlhYmxlX3ZhbHVlc19zZXR0aW5nLmRlc2NFbC5pbm5lckhUTUwgPSBzaGVsbF9jb21tYW5kX3ByZXZpZXdfdGV4dF9maW5hbDtcclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIENyZWF0ZSBmaWVsZHNcclxuICAgICAgICBsZXQgaXNfZmlyc3RfZmllbGQgPSB0cnVlO1xyXG4gICAgICAgIGZvciAoY29uc3QgcHJvbXB0X2ZpZWxkIG9mIHRoaXMucHJvbXB0X2ZpZWxkcykge1xyXG4gICAgICAgICAgICBhd2FpdCBwcm9tcHRfZmllbGQuY3JlYXRlRmllbGQoXHJcbiAgICAgICAgICAgICAgICB0aGlzLm1vZGFsRWwuY3JlYXRlRGl2KHthdHRyOiB7Y2xhc3M6IFwiU0Mtc2V0dGluZy1ncm91cFwifX0pLFxyXG4gICAgICAgICAgICAgICAgdGhpcy50X3NoZWxsX2NvbW1hbmQsXHJcbiAgICAgICAgICAgICAgICB0aGlzLnNjX2V2ZW50XHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIGlmICh1cGRhdGVfc2hlbGxfY29tbWFuZF9wcmV2aWV3KSB7XHJcbiAgICAgICAgICAgICAgICBwcm9tcHRfZmllbGQub25DaGFuZ2UodXBkYXRlX3NoZWxsX2NvbW1hbmRfcHJldmlldyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgcHJvbXB0X2ZpZWxkLm9uRm9jdXMoKHByb21wdF9maWVsZDogUHJvbXB0RmllbGQpID0+IHtcclxuICAgICAgICAgICAgICAgIGZvY3VzZWRfcHJvbXB0X2ZpZWxkID0gcHJvbXB0X2ZpZWxkO1xyXG4gICAgICAgICAgICAgICAgaWYgKHVwZGF0ZV9zaGVsbF9jb21tYW5kX3ByZXZpZXcpIHtcclxuICAgICAgICAgICAgICAgICAgICB1cGRhdGVfc2hlbGxfY29tbWFuZF9wcmV2aWV3KCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICBpZiAoaXNfZmlyc3RfZmllbGQpIHtcclxuICAgICAgICAgICAgICAgIC8vIEZvY3VzIG9uIHRoZSBmaXJzdCBmaWVsZC5cclxuICAgICAgICAgICAgICAgIGlzX2ZpcnN0X2ZpZWxkID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICBwcm9tcHRfZmllbGQuc2V0Rm9jdXMoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodXBkYXRlX3NoZWxsX2NvbW1hbmRfcHJldmlldykge1xyXG4gICAgICAgICAgICAvLyBTZXQgYSBwcmV2aWV3IHRleHQuIE11c3QgYmUgZG9uZSBhZnRlciBmaWVsZHMgYXJlIGNyZWF0ZWQsIGJlY2F1c2UgdGhlaXIgdmFsdWVzIGFyZSBhY2Nlc3NlZC5cclxuICAgICAgICAgICAgdXBkYXRlX3NoZWxsX2NvbW1hbmRfcHJldmlldygpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gVGlwIGFib3V0IHZhcmlhYmxlc1xyXG4gICAgICAgIGxldCB0aXAgPSBcIlwiO1xyXG4gICAgICAgIGlmICh0aGlzLnByb21wdF9maWVsZHMuc2l6ZSA+IDApIHtcclxuICAgICAgICAgICAgLy8gVE9ETzogV2hlbiBpbXBsZW1lbnRpbmcgZGlmZmVyZW50IGZpZWxkIHR5cGVzLCBhZGQgYSBjaGVjayB0aGF0IHRoZSB0aXAgaXMgb25seSBzaG93biB3aGVuIHRoZXJlIGFyZSB0ZXh0L251bWVyaWMgZmllbGRzIHByZXNlbnQuXHJcbiAgICAgICAgICAgIC8vIE9ubHkgc2hvdyB0aGUgdGlwIGlmIHRoaXMgbW9kYWwgYWN0dWFsbHkgY29udGFpbnMgZmllbGRzLiBQcm9tcHRzIGNhbiBhbHNvIGJlIHVzZWQgYXMgY3VzdG9tICdjb25maXJtYXRpb24gcHJvbXB0cycgd2l0aG91dCBhbnkgZmllbGRzLlxyXG4gICAgICAgICAgICB0aXAgPSBcIlRpcCEgWW91IGNhbiB1c2Uge3t2YXJpYWJsZXN9fSBpbiB0ZXh0IGZpZWxkcy5cIjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEV4ZWN1dGUgYnV0dG9uXHJcbiAgICAgICAgY29uc3QgZXhlY3V0ZV9idXR0b25fdGV4dF9wYXJzaW5nX3Jlc3VsdCA9IGF3YWl0IHBhcnNlVmFyaWFibGVzKHRoaXMucGx1Z2luLCB0aGlzLnByb21wdC5jb25maWd1cmF0aW9uLmV4ZWN1dGVfYnV0dG9uX3RleHQsIG51bGwsIHRoaXMudF9zaGVsbF9jb21tYW5kLCB0aGlzLnNjX2V2ZW50KTtcclxuICAgICAgICBjb25zdCBleGVjdXRlX2J1dHRvbl90ZXh0ID1cclxuICAgICAgICAgICAgZXhlY3V0ZV9idXR0b25fdGV4dF9wYXJzaW5nX3Jlc3VsdC5zdWNjZWVkZWRcclxuICAgICAgICAgICAgPyBleGVjdXRlX2J1dHRvbl90ZXh0X3BhcnNpbmdfcmVzdWx0LnBhcnNlZF9jb250ZW50IGFzIHN0cmluZ1xyXG4gICAgICAgICAgICA6IGV4ZWN1dGVfYnV0dG9uX3RleHRfcGFyc2luZ19yZXN1bHQub3JpZ2luYWxfY29udGVudFxyXG4gICAgICAgIDtcclxuICAgICAgICBuZXcgU2V0dGluZyh0aGlzLm1vZGFsRWwpXHJcbiAgICAgICAgICAgIC5zZXREZXNjKHRpcClcclxuICAgICAgICAgICAgLmFkZEJ1dHRvbihidXR0b24gPT4gYnV0dG9uXHJcbiAgICAgICAgICAgICAgICAuc2V0QnV0dG9uVGV4dChleGVjdXRlX2J1dHRvbl90ZXh0KVxyXG4gICAgICAgICAgICAgICAgLm9uQ2xpY2soKCkgPT4gdGhpcy5hcHByb3ZlKCkpXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcblxyXG4gICAgICAgIGlmICghdGhpcy50X3NoZWxsX2NvbW1hbmQpIHtcclxuICAgICAgICAgICAgLy8gTm90aWNlIHRoYXQgdGhpcyBpcyBhIHByZXZpZXcgb25seSBQcm9tcHQuXHJcbiAgICAgICAgICAgIHRoaXMubW9kYWxFbC5jcmVhdGVFbChcInBcIiwge3RleHQ6IGBUaGlzIGlzIGEgcHJldmlldyBwcm9tcHQuIE5vIHNoZWxsIGNvbW1hbmQgd2lsbCBiZSBleGVjdXRlZCwgYnV0IGNsaWNraW5nIHRoZSAnJHt0aGlzLnByb21wdC5jb25maWd1cmF0aW9uLmV4ZWN1dGVfYnV0dG9uX3RleHR9JyBidXR0b24gd2lsbCBzdGlsbCBzdG9yZSB0aGUgaW5wdXR0ZWQgdmFsdWUocykgdG8gdmFyaWFibGUocykuYH0pLmFkZENsYXNzKFwiU0MtcHJvbXB0LWRyeS1ydW4tbm90aWNlXCIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQWRkIENTUyBjbGFzc2VzIHNvIHRoYXQgY3VzdG9tIHN0eWxpbmcgY2FuIGJlIGRvbmUgb24gYSBwZXItcHJvbXB0IG1vZGFsIGJhc2lzIChvciBmb3IgYWxsIHByb21wdCBtb2RhbHMgdmlhIGEgY29tbW9uIGNsYXNzKS5cclxuICAgICAgICB0aGlzLm1vZGFsRWwuYWRkQ2xhc3Nlcyh0aGlzLnByb21wdC5nZXRDU1NDbGFzc2VzKCkpO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBhcHByb3ZlKCk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMudmFsaWRhdG9yKCkudGhlbihhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICAgIC8vIFRoZSBmb3JtIGZpZWxkcyBhcmUgZmlsbGVkIG9rXHJcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuYXNzaWduVmFsdWVzVG9WYXJpYWJsZXMoKTtcclxuICAgICAgICAgICAgdGhpcy5yZXNvbHZlX3Byb21pc2UodHJ1ZSk7XHJcbiAgICAgICAgICAgIHRoaXMudXNlcl9jb25maXJtZWRfb2sgPSB0cnVlO1xyXG4gICAgICAgICAgICB0aGlzLmNsb3NlKCk7XHJcbiAgICAgICAgfSwgKGVycm9yX21lc3NhZ2VzOiBzdHJpbmdbXSB8IHVua25vd24pID0+IHtcclxuICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZXJyb3JfbWVzc2FnZXMpKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBUaGVyZSB3ZXJlIHNvbWUgcHJvYmxlbXMgd2l0aCB0aGUgZmllbGRzLlxyXG4gICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3RXJyb3JzKGVycm9yX21lc3NhZ2VzKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIFNvbWUgb3RoZXIgcnVudGltZSBlcnJvciBoYXMgb2NjdXJyZWQuXHJcbiAgICAgICAgICAgICAgICB0aHJvdyBlcnJvcl9tZXNzYWdlcztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbkNsb3NlKCk6IHZvaWQge1xyXG4gICAgICAgIHN1cGVyLm9uQ2xvc2UoKTtcclxuXHJcbiAgICAgICAgaWYgKCF0aGlzLnVzZXJfY29uZmlybWVkX29rKSB7IC8vIFRPRE86IEZpbmQgb3V0IGlmIHRoZXJlIGlzIGEgd2F5IHRvIG5vdCB1c2UgdGhpcyBraW5kIG9mIGZsYWcgcHJvcGVydHkuIENhbiB0aGUgc3RhdHVzIGJlIGNoZWNrZWQgZnJvbSB0aGUgcHJvbWlzZSBpdHNlbGY/XHJcbiAgICAgICAgICAgIHRoaXMucmVzb2x2ZV9wcm9taXNlKGZhbHNlKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBhc3luYyBhc3NpZ25WYWx1ZXNUb1ZhcmlhYmxlcygpIHtcclxuICAgICAgICBsZXQgcHJvbXB0RmllbGQ6IFByb21wdEZpZWxkO1xyXG4gICAgICAgIGZvciAocHJvbXB0RmllbGQgb2YgdGhpcy5wcm9tcHRfZmllbGRzKSB7XHJcbiAgICAgICAgICAgIGF3YWl0IHByb21wdEZpZWxkLmdldFRhcmdldFZhcmlhYmxlKCkuc2V0VmFsdWUocHJvbXB0RmllbGQuZ2V0UGFyc2VkT3JSYXdWYWx1ZSgpKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBHYXRoZXJzIGEgTWFwIG9mIHZhcmlhYmxlIHZhbHVlcyB0eXBlZCBpbiB0aGUgZm9ybSwgYnV0IGRvZXMgbm90IHN0b3JlIHRoZSB2YWx1ZXMgaW50byB0aGUgdmFyaWFibGVzLiBDYWxsZWQgd2hlblxyXG4gICAgICogZ2VuZXJhdGluZyBhIHByZXZpZXcgdGV4dCwgc28gdGhlIHJlc3VsdCBvZiB0aGlzIG1ldGhvZCB3aWxsIG5vdCBwZXJzaXN0IGluIGFueSB3YXkuXHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGdldFByb21wdEZpZWxkc1ZhbHVlcygpIHtcclxuICAgICAgICBjb25zdCB2YWx1ZXMgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xyXG4gICAgICAgIGZvciAoY29uc3QgcHJvbXB0X2ZpZWxkIG9mIHRoaXMucHJvbXB0X2ZpZWxkcykge1xyXG4gICAgICAgICAgICB2YWx1ZXMuc2V0KHByb21wdF9maWVsZC5nZXRUYXJnZXRWYXJpYWJsZSgpLnZhcmlhYmxlX25hbWUsIHByb21wdF9maWVsZC5nZXRQYXJzZWRWYWx1ZSgpID8/IFwiXCIpOyAvLyBUT0RPOiBTaG91bGQgZ2V0UGFyc2VkVmFsdWUoKSA/PyBcIlwiIGJlIGNoYW5nZWQgdG8gZ2V0UGFyc2VkT3JSYXdWYWx1ZSgpLCB0b28/XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YWx1ZXM7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBnZXRQcm9tcHRGaWVsZHNQYXJzaW5nRXJyb3JzKCkge1xyXG4gICAgICAgIGNvbnN0IHBhcnNpbmdfZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xyXG4gICAgICAgIGZvciAoY29uc3QgcHJvbXB0X2ZpZWxkIG9mIHRoaXMucHJvbXB0X2ZpZWxkcykge1xyXG4gICAgICAgICAgICBwYXJzaW5nX2Vycm9ycy5wdXNoKC4uLnByb21wdF9maWVsZC5nZXRQYXJzaW5nRXJyb3JzKCkpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gcGFyc2luZ19lcnJvcnM7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBnZXRTaGVsbCgpIHtcclxuICAgICAgICBpZiAodGhpcy50X3NoZWxsX2NvbW1hbmQpIHtcclxuICAgICAgICAgICAgLy8gVGhpcyBpcyBhIHJlYWwgdXNhZ2Ugb2YgdGhlIFByb21wdE1vZGFsLCBzbyBhIFRTaGVsbENvbW1hbmQgaXMgYXZhaWxhYmxlLiBMb29rIHVwIHRoZSBzaGVsbCBmcm9tIHRoYXQuXHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRTaGVsbCgpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIEp1c3QgdHJ5aW5nIHRoZSBQcm9tcHRNb2RhbC4gSnVzdCB1c2Ugc29tZSBzaGVsbCBmb3IgdmFyaWFibGUgZXNjYXBpbmcgaW4gYW4gZXhhbXBsZSBwcmV2aWV3LlxyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wbHVnaW4uZ2V0RGVmYXVsdFNoZWxsKCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1xyXG4gICAgZ2V0SURHZW5lcmF0b3IsXHJcbiAgICBNb2RlbCxcclxuICAgIFBhcmVudE1vZGVsT25lVG9NYW55SWRSZWxhdGlvbixcclxuICAgIFByZWFjdGlvbl9Qcm9tcHRfQ29uZmlndXJhdGlvbixcclxuICAgIFByb21wdCxcclxuICAgIFByb21wdENvbmZpZ3VyYXRpb24sXHJcbiAgICBQcm9tcHRTZXR0aW5nc01vZGFsLFxyXG59IGZyb20gXCIuLi8uLi9pbXBvcnRzXCI7XHJcbmltcG9ydCB7U2V0dGluZ30gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7U0NfTWFpblNldHRpbmdzfSBmcm9tIFwiLi4vLi4vc2V0dGluZ3MvU0NfTWFpblNldHRpbmdzXCI7XHJcbmltcG9ydCB7ZGVidWdMb2d9IGZyb20gXCIuLi8uLi9EZWJ1Z1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIFByb21wdE1vZGVsIGV4dGVuZHMgTW9kZWwge1xyXG5cclxuICAgIHByaXZhdGUgcHJvbXB0cyA9IG5ldyBQcm9tcHRNYXAoKTtcclxuXHJcbiAgICBwdWJsaWMgZ2V0U2luZ3VsYXJOYW1lKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIFwiUHJvbXB0XCI7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGRlZmluZVBhcmVudENvbmZpZ3VyYXRpb25SZWxhdGlvbihwcm9tcHQ6IFByb21wdCk6IFBhcmVudE1vZGVsT25lVG9NYW55SWRSZWxhdGlvbiB7XHJcbiAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgdHlwZTogXCJvbmUtdG8tbWFueS1pZFwiLFxyXG4gICAgICAgICAgICBrZXk6IFwicHJvbXB0c1wiLFxyXG4gICAgICAgICAgICBpZDogcHJvbXB0LmdldElEKCksXHJcbiAgICAgICAgfTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgbG9hZEluc3RhbmNlcyhwYXJlbnRfY29uZmlndXJhdGlvbjogU0NfTWFpblNldHRpbmdzKTogUHJvbXB0TWFwIHtcclxuICAgICAgICBkZWJ1Z0xvZyhcIkxvYWRpbmcgUHJvbXB0IGluc3RhbmNlcy5cIik7XHJcbiAgICAgICAgdGhpcy5wcm9tcHRzID0gbmV3IFByb21wdE1hcCgpO1xyXG4gICAgICAgIHBhcmVudF9jb25maWd1cmF0aW9uLnByb21wdHMuZm9yRWFjaCgocHJvbXB0X2NvbmZpZ3VyYXRpb246IFByb21wdENvbmZpZ3VyYXRpb24pID0+IHtcclxuICAgICAgICAgICAgY29uc3QgcHJvbXB0OiBQcm9tcHQgPSBuZXcgUHJvbXB0KHRoaXMsIHRoaXMucGx1Z2luLCBwcm9tcHRfY29uZmlndXJhdGlvbiwgcGFyZW50X2NvbmZpZ3VyYXRpb24pO1xyXG4gICAgICAgICAgICB0aGlzLnByb21wdHMuc2V0KHByb21wdF9jb25maWd1cmF0aW9uLmlkLCBwcm9tcHQpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybiB0aGlzLnByb21wdHM7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIG5ld0luc3RhbmNlKHBhcmVudF9jb25maWd1cmF0aW9uOiBTQ19NYWluU2V0dGluZ3MpOiBQcm9tcHQge1xyXG4gICAgICAgIGRlYnVnTG9nKFwiQ3JlYXRpbmcgYSBuZXcgUHJvbXB0IGluc3RhbmNlLlwiKTtcclxuICAgICAgICAvLyBUT0RPOiBNb3ZlIHRoaXMgbG9naWMgdG8gdGhlIGJhc2UgTW9kZWwgY2xhc3MuXHJcblxyXG4gICAgICAgIC8vIFNldHVwIGEgZGVmYXVsdCBjb25maWd1cmF0aW9uIGFuZCBnZW5lcmF0ZSBhbiBJRFxyXG4gICAgICAgIGNvbnN0IHByb21wdF9jb25maWd1cmF0aW9uID0gdGhpcy5nZXREZWZhdWx0Q29uZmlndXJhdGlvbigpO1xyXG5cclxuICAgICAgICAvLyBJbnN0YW50aWF0ZSBhIFByb21wdFxyXG4gICAgICAgIGNvbnN0IHByb21wdCA9IG5ldyBQcm9tcHQodGhpcywgdGhpcy5wbHVnaW4sIHByb21wdF9jb25maWd1cmF0aW9uLCB0aGlzLnBsdWdpbi5zZXR0aW5ncyk7XHJcbiAgICAgICAgdGhpcy5wcm9tcHRzLnNldChwcm9tcHQuZ2V0SUQoKSwgcHJvbXB0KTtcclxuXHJcbiAgICAgICAgLy8gU3RvcmUgdGhlIGNvbmZpZ3VyYXRpb24gaW50byBwbHVnaW4ncyBzZXR0aW5nc1xyXG4gICAgICAgIHRoaXMucGx1Z2luLnNldHRpbmdzLnByb21wdHMucHVzaChwcm9tcHRfY29uZmlndXJhdGlvbik7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiB0aGUgUHJvbXB0XHJcbiAgICAgICAgcmV0dXJuIHByb21wdDtcclxuXHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIF9jcmVhdGVTZXR0aW5nRmllbGRzKHByb21wdDogUHJvbXB0LCBjb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQpOiBTZXR0aW5nIHtcclxuICAgICAgICBkZWJ1Z0xvZyhcIkNyZWF0aW5nIHNldHRpbmcgZmllbGRzIGZvciBhIFByb21wdCBpbnN0YW5jZS5cIik7XHJcbiAgICAgICAgY29uc3QgcHJvbXB0X25hbWVfc2V0dGluZyA9IG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAvLyBDb25maWd1cmF0aW9uIGJ1dHRvblxyXG4gICAgICAgICAgICAuc2V0TmFtZShwcm9tcHQuZ2V0VGl0bGUoKSlcclxuICAgICAgICAgICAgLmFkZEV4dHJhQnV0dG9uKGJ1dHRvbiA9PiBidXR0b25cclxuICAgICAgICAgICAgICAgIC5zZXRUb29sdGlwKFwiRGVmaW5lIHByb21wdCBmaWVsZHNcIilcclxuICAgICAgICAgICAgICAgIC5zZXRJY29uKFwiZ2VhclwiKVxyXG4gICAgICAgICAgICAgICAgLm9uQ2xpY2soKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMub3BlblNldHRpbmdzTW9kYWwocHJvbXB0LCBwcm9tcHRfbmFtZV9zZXR0aW5nKTtcclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG4gICAgICAgIHJldHVybiBwcm9tcHRfbmFtZV9zZXR0aW5nO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyB2YWxpZGF0ZVZhbHVlKHByb21wdDogUHJvbXB0LCBmaWVsZDogc3RyaW5nLCB2YWx1ZTogdW5rbm93bik6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgICAgIC8vIFRoaXMgbWV0aG9kIGlzIG5vdCB1c2VkLCBzbyBpdCBjYW4ganVzdCByZXNvbHZlIGFsbCB0aGUgdGltZS5cclxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHVuZGVmaW5lZCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIG9wZW5TZXR0aW5nc01vZGFsKHByb21wdDogUHJvbXB0LCBwcm9tcHRfbmFtZV9zZXR0aW5nOiBTZXR0aW5nKSB7XHJcbiAgICAgICAgZGVidWdMb2coXCJPcGVuaW5nIHNldHRpbmdzIG1vZGFsIGZvciBhIFByb21wdCBpbnN0YW5jZS5cIik7XHJcbiAgICAgICAgY29uc3QgbW9kYWwgPSBuZXcgUHJvbXB0U2V0dGluZ3NNb2RhbCh0aGlzLnBsdWdpbiwgcHJvbXB0LCBwcm9tcHRfbmFtZV9zZXR0aW5nKTtcclxuICAgICAgICBtb2RhbC5vcGVuKCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGdldERlZmF1bHRDb25maWd1cmF0aW9uKCk6IFByb21wdENvbmZpZ3VyYXRpb24ge1xyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGlkOiBnZXRJREdlbmVyYXRvcigpLmdlbmVyYXRlSUQoKSxcclxuICAgICAgICAgICAgdGl0bGU6IFwiXCIsXHJcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlwiLFxyXG4gICAgICAgICAgICBwcmV2aWV3X3NoZWxsX2NvbW1hbmQ6IGZhbHNlLFxyXG4gICAgICAgICAgICBmaWVsZHM6IFtdLFxyXG4gICAgICAgICAgICBleGVjdXRlX2J1dHRvbl90ZXh0OiBcIkV4ZWN1dGVcIixcclxuICAgICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBfZGVsZXRlSW5zdGFuY2UocHJvbXB0OiBQcm9tcHQpOiB2b2lkIHtcclxuICAgICAgICBkZWJ1Z0xvZyhcIkRlbGV0aW5nIGEgUHJvbXB0IGluc3RhbmNlLlwiKTtcclxuXHJcbiAgICAgICAgLy8gUmVtb3ZlIHRoZSBQcm9tcHQgZnJvbSBhbGwgVFNoZWxsQ29tbWFuZHMgdGhhdCB1c2UgaXQuXHJcbiAgICAgICAgY29uc3Qgc2hlbGxfY29tbWFuZHMgPSB0aGlzLnBsdWdpbi5nZXRUU2hlbGxDb21tYW5kcygpO1xyXG4gICAgICAgIGZvciAoY29uc3Qgc2hlbGxfY29tbWFuZF9pZCBpbiBzaGVsbF9jb21tYW5kcykge1xyXG4gICAgICAgICAgICBjb25zdCB0X3NoZWxsX2NvbW1hbmQgPSBzaGVsbF9jb21tYW5kc1tzaGVsbF9jb21tYW5kX2lkXTtcclxuICAgICAgICAgICAgZm9yIChjb25zdCBwcmVhY3Rpb25fY29uZmlndXJhdGlvbiBvZiB0X3NoZWxsX2NvbW1hbmQuZ2V0Q29uZmlndXJhdGlvbigpLnByZWFjdGlvbnMpIHtcclxuICAgICAgICAgICAgICAgIGlmIChcInByb21wdFwiID09PSBwcmVhY3Rpb25fY29uZmlndXJhdGlvbi50eXBlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcHJlYWN0aW9uX3Byb21wdF9jb25maWd1cmF0aW9uID0gcHJlYWN0aW9uX2NvbmZpZ3VyYXRpb24gYXMgUHJlYWN0aW9uX1Byb21wdF9Db25maWd1cmF0aW9uO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChwcm9tcHQuZ2V0SUQoKSA9PT0gcHJlYWN0aW9uX3Byb21wdF9jb25maWd1cmF0aW9uLnByb21wdF9pZCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIFRTaGVsbENvbW1hbmQgdXNlcyB0aGlzIFByb21wdC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmVtb3ZlIHRoZSBQcm9tcHQgZnJvbSB1c2UuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZWFjdGlvbl9wcm9tcHRfY29uZmlndXJhdGlvbi5lbmFibGVkID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZWFjdGlvbl9wcm9tcHRfY29uZmlndXJhdGlvbi5wcm9tcHRfaWQgPSB1bmRlZmluZWQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRfc2hlbGxfY29tbWFuZC5yZXNldFByZWFjdGlvbnMoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2F2aW5nIGlzIGRvbmUgbGF0ZXIsIGFmdGVyIHRoZSBfZGVsZXRlSW5zdGFuY2UoKSBjYWxsLlxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5wcm9tcHRzLmRlbGV0ZShwcm9tcHQuZ2V0SUQoKSk7XHJcbiAgICB9XHJcbn1cclxuXHJcbmV4cG9ydCBjbGFzcyBQcm9tcHRNYXAgZXh0ZW5kcyBNYXA8c3RyaW5nLCBQcm9tcHQ+IHt9IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi9tYWluXCI7XHJcbmltcG9ydCB7U2V0dGluZ30gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7ZGVidWdMb2d9IGZyb20gXCIuLi9EZWJ1Z1wiO1xyXG5pbXBvcnQge1xyXG4gICAgZ2V0TW9kZWwsXHJcbiAgICBJbnN0YW5jZSxcclxuICAgIE1vZGVsLFxyXG59IGZyb20gXCIuLi9pbXBvcnRzXCI7XHJcblxyXG4vKipcclxuICogQHJldHVybiBQcm9taXNlPEluc3RhbmNlQ2xhc3M+IEEgcHJvbWlzZSB0aGF0IGdldHMgcmVzb2x2ZWQgaWYgYSB1c2VyIGNsaWNrcyB0aGUgYnV0dG9uLiBUaGUgcHJvbWlzZSBpcyBzdXBwbGllZCB3aXRoIHRoZSBuZXdseSBjcmVhdGVkIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU5ld01vZGVsSW5zdGFuY2VCdXR0b248XHJcbiAgICAgICAgTW9kZWxDbGFzcyBleHRlbmRzIE1vZGVsLFxyXG4gICAgICAgIEluc3RhbmNlQ2xhc3MgZXh0ZW5kcyBJbnN0YW5jZSxcclxuICAgID4oXHJcbiAgICAgICAgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgbW9kZWxfY2xhc3NfbmFtZTogc3RyaW5nLFxyXG4gICAgICAgIGJ1dHRvbl9jb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQsXHJcbiAgICAgICAgaW5zdGFuY2VfY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50LFxyXG4gICAgICAgIHBhcmVudF9pbnN0YW5jZV9vcl9jb25maWd1cmF0aW9uOiBJbnN0YW5jZUNsYXNzW1wicGFyZW50X2NvbmZpZ3VyYXRpb25cIl0gfCBJbnN0YW5jZUNsYXNzW1wicGFyZW50X2luc3RhbmNlXCJdXHJcbiAgICApOiBQcm9taXNlPHtpbnN0YW5jZTogSW5zdGFuY2VDbGFzcywgbWFpbl9zZXR0aW5nOiBTZXR0aW5nfT4ge1xyXG5cclxuICAgIGRlYnVnTG9nKFwiQ3JlYXRpbmcgYSBidXR0b24gZm9yIGNyZWF0aW5nIGEgbmV3IGluc3RhbmNlIGZvciBtb2RlbCBcIiArIG1vZGVsX2NsYXNzX25hbWUgKyBcIi5cIik7XHJcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmVfcHJvbWlzZSkgPT4ge1xyXG4gICAgICAgIGNvbnN0IG1vZGVsID0gZ2V0TW9kZWw8TW9kZWxDbGFzcz4obW9kZWxfY2xhc3NfbmFtZSk7XHJcbiAgICAgICAgbmV3IFNldHRpbmcoYnV0dG9uX2NvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuYWRkQnV0dG9uKGJ1dHRvbiA9PiBidXR0b25cclxuICAgICAgICAgICAgICAgIC5zZXRCdXR0b25UZXh0KFwiTmV3IFwiICsgbW9kZWwuZ2V0U2luZ3VsYXJOYW1lKCkudG9Mb2NhbGVMb3dlckNhc2UoKSlcclxuICAgICAgICAgICAgICAgIC5vbkNsaWNrKGFzeW5jICgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBpZiAobnVsbCA9PT0gcGFyZW50X2luc3RhbmNlX29yX2NvbmZpZ3VyYXRpb24pIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiY3JlYXRlTmV3TW9kZWxJbnN0YW5jZUJ1dHRvbigpOiBQYXJlbnQgaW5zdGFuY2Ugb3IgY29uZmlndXJhdGlvbiBpcyBudWxsLlwiKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5zdGFuY2UgPSBtb2RlbC5uZXdJbnN0YW5jZShwYXJlbnRfaW5zdGFuY2Vfb3JfY29uZmlndXJhdGlvbikgYXMgSW5zdGFuY2VDbGFzcztcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBtYWluX3NldHRpbmcgPSBtb2RlbC5jcmVhdGVTZXR0aW5nRmllbGRzKGluc3RhbmNlLCBpbnN0YW5jZV9jb250YWluZXJfZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZV9wcm9taXNlKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgXCJpbnN0YW5jZVwiOiBpbnN0YW5jZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgXCJtYWluX3NldHRpbmdcIjogbWFpbl9zZXR0aW5nLFxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG4gICAgfSk7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U0NfTW9kYWx9IGZyb20gXCIuLi8uLi9TQ19Nb2RhbFwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi8uLi9tYWluXCI7XHJcbmltcG9ydCB7XHJcbiAgICBTZXR0aW5nLFxyXG4gICAgVGV4dEFyZWFDb21wb25lbnQsXHJcbiAgICBUZXh0Q29tcG9uZW50LFxyXG59IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQge2NyZWF0ZU5ld01vZGVsSW5zdGFuY2VCdXR0b259IGZyb20gXCIuLi9jcmVhdGVOZXdNb2RlbEluc3RhbmNlQnV0dG9uXCI7XHJcbmltcG9ydCB7XHJcbiAgICBnZXRNb2RlbCxcclxuICAgIFByb21wdCxcclxuICAgIFByb21wdEZpZWxkLFxyXG4gICAgUHJvbXB0RmllbGRNb2RlbCxcclxufSBmcm9tIFwiLi4vLi4vaW1wb3J0c1wiO1xyXG5pbXBvcnQge2NyZWF0ZUF1dG9jb21wbGV0ZX0gZnJvbSBcIi4uLy4uL3NldHRpbmdzL3NldHRpbmdfZWxlbWVudHMvQXV0b2NvbXBsZXRlXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgUHJvbXB0U2V0dGluZ3NNb2RhbCBleHRlbmRzIFNDX01vZGFsIHtcclxuXHJcbiAgICBwcml2YXRlIGFwcHJvdmVkID0gZmFsc2U7XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcGx1Z2luOiBTQ19QbHVnaW4sXHJcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBwcm9tcHQ6IFByb21wdCxcclxuXHJcbiAgICAgICAgLyoqIENhbiBiZSB1bmRlZmluZWQgaWYgdGhlIG1vZGFsIGlzIGNyZWF0ZWQgZnJvbSBhIHBsYWNlIHdoZXJlIHRoZXJlIGlzIG5vIG5hbWUgZWxlbWVudC4gKi9cclxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IHByb21wdF9uYW1lX3NldHRpbmc/OiBTZXR0aW5nLFxyXG5cclxuICAgICAgICAvKiogSWYgZGVmaW5lZCwgYSBidXR0b24gd2lsbCBiZSBhZGRlZCBhbmQgb25fYWZ0ZXJfYXBwcm92YWwoKSAvIG9uX2FmdGVyX2NhbmNlbGxpbmcoKSB3aWxsIGJlIGNhbGxlZCBkZXBlbmRpbmcgb24gd2hldGhlciB0aGUgYnV0dG9uIHdhcyBjbGlja2VkIG9yIG5vdC4gKi9cclxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IG9rX2J1dHRvbl90ZXh0Pzogc3RyaW5nLFxyXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgb25fYWZ0ZXJfYXBwcm92YWw/OiAoKSA9PiB2b2lkLFxyXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgb25fYWZ0ZXJfY2FuY2VsbGluZz86ICgpID0+IHZvaWQsXHJcbiAgICApIHtcclxuICAgICAgICBzdXBlcihwbHVnaW4pO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBvbk9wZW4oKTogdm9pZCB7XHJcbiAgICAgICAgc3VwZXIub25PcGVuKCk7XHJcbiAgICAgICAgY29uc3QgY29udGFpbmVyX2VsZW1lbnQgPSB0aGlzLm1vZGFsRWw7XHJcbiAgICAgICAgY29uc3QgdGl0bGVfYW5kX2Rlc2NyaXB0aW9uX2dyb3VwX2VsZW1lbnQgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVEaXYoe2F0dHI6IHtjbGFzczogXCJTQy1zZXR0aW5nLWdyb3VwXCJ9fSk7XHJcblxyXG4gICAgICAgIC8vIFRpdGxlXHJcbiAgICAgICAgY29uc3QgdGl0bGVfc2V0dGluZyA9IG5ldyBTZXR0aW5nKHRpdGxlX2FuZF9kZXNjcmlwdGlvbl9ncm91cF9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0TmFtZShcIlByb21wdCB0aXRsZVwiKVxyXG4gICAgICAgICAgICAuYWRkRXh0cmFCdXR0b24oaWNvbiA9PiBpY29uXHJcbiAgICAgICAgICAgICAgICAuc2V0VG9vbHRpcChcIlRyeSB0aGUgcHJvbXB0IHdpdGhvdXQgZXhlY3V0aW5nIGFueSBzaGVsbCBjb21tYW5kLlwiKVxyXG4gICAgICAgICAgICAgICAgLnNldEljb24oXCJydW4tY29tbWFuZFwiKVxyXG4gICAgICAgICAgICAgICAgLm9uQ2xpY2soKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFwiRHJ5IHJ1blwiIHRoZSBQcm9tcHRcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnByb21wdC5vcGVuUHJvbXB0KG51bGwsIG51bGwsIG51bGwpLnRoZW4oKTtcclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICAgICAgLmFkZFRleHQodGV4dCA9PiB0ZXh0XHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wcm9tcHQuZ2V0VGl0bGUoKSlcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAobmV3X3RpdGxlOiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnByb21wdC5nZXRDb25maWd1cmF0aW9uKCkudGl0bGUgPSBuZXdfdGl0bGU7XHJcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vIFVwZGF0ZSB0aGUgdGl0bGUgaW4gYSBuYW1lIHNldHRpbmcuIChPbmx5IGlmIHRoZSBtb2RhbCB3YXMgY3JlYXRlZCBmcm9tIGEgcGxhY2Ugd2hlcmUgYSBQcm9tcHQgbmFtZSBlbGVtZW50IGV4aXN0cykuXHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wcm9tcHRfbmFtZV9zZXR0aW5nPy5zZXROYW1lKG5ld190aXRsZSk7XHJcbiAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgLnRoZW4oKHRpdGxlX3NldHRpbmdfY29tcG9uZW50OiBUZXh0Q29tcG9uZW50KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gQXV0b2NvbXBsZXRlIGZvciBUaXRsZS5cclxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5wbHVnaW4uc2V0dGluZ3Muc2hvd19hdXRvY29tcGxldGVfbWVudSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjcmVhdGVBdXRvY29tcGxldGUodGhpcy5wbHVnaW4sIHRpdGxlX3NldHRpbmdfY29tcG9uZW50LmlucHV0RWwsICgpID0+IHRpdGxlX3NldHRpbmdfY29tcG9uZW50Lm9uQ2hhbmdlZCgpKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgIDtcclxuICAgICAgICBjb25zdCB0aXRsZV9pbnB1dF9lbGVtZW50OiBIVE1MSW5wdXRFbGVtZW50ID0gdGl0bGVfc2V0dGluZy5jb250cm9sRWwuZmluZChcImlucHV0XCIpIGFzIEhUTUxJbnB1dEVsZW1lbnQ7XHJcbiAgICAgICAgXHJcbiAgICAgICAgLy8gRm9jdXMgb24gdGhlIHRpdGxlIGZpZWxkLlxyXG4gICAgICAgIHRpdGxlX2lucHV0X2VsZW1lbnQuZm9jdXMoKTtcclxuXHJcbiAgICAgICAgLy8gRGVzY3JpcHRpb25cclxuICAgICAgICBuZXcgU2V0dGluZyh0aXRsZV9hbmRfZGVzY3JpcHRpb25fZ3JvdXBfZWxlbWVudClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJEZXNjcmlwdGlvblwiKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIkRpc3BsYXllZCBiZXR3ZWVuIHRoZSBwcm9tcHQgdGl0bGUgYW5kIGZpZWxkcy4gQm90aCBEZXNjcmlwdGlvbiBhbmQgVGl0bGUgc3VwcG9ydCB7e3ZhcmlhYmxlc319LlwiKVxyXG4gICAgICAgICAgICAuYWRkVGV4dEFyZWEodGV4dGFyZWEgPT4gdGV4dGFyZWFcclxuICAgICAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnByb21wdC5jb25maWd1cmF0aW9uLmRlc2NyaXB0aW9uKVxyXG4gICAgICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jIChuZXdfZGVzY3JpcHRpb246IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucHJvbXB0LmdldENvbmZpZ3VyYXRpb24oKS5kZXNjcmlwdGlvbiA9IG5ld19kZXNjcmlwdGlvbjtcclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICAudGhlbigoZGVzY3JpcHRpb25fY29tcG9uZW50OiBUZXh0QXJlYUNvbXBvbmVudCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIEF1dG9jb21wbGV0ZSBmb3IgRGVzY3JpcHRpb24uXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMucGx1Z2luLnNldHRpbmdzLnNob3dfYXV0b2NvbXBsZXRlX21lbnUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlQXV0b2NvbXBsZXRlKHRoaXMucGx1Z2luLCBkZXNjcmlwdGlvbl9jb21wb25lbnQuaW5wdXRFbCwgKCkgPT4gZGVzY3JpcHRpb25fY29tcG9uZW50Lm9uQ2hhbmdlZCgpKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgIDtcclxuXHJcbiAgICAgICAgLy8gUHJldmlldyBzaGVsbCBjb21tYW5kXHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKFwiUHJldmlldyBzaGVsbCBjb21tYW5kIGluIHByb21wdFwiKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIklmIHRoaXMgaXMgb24sIHRoZSBwcm9tcHQgd2lsbCBkaXNwbGF5IHRoZSBleGVjdXRhYmxlIHNoZWxsIGNvbW1hbmQgd2l0aCB2YXJpYWJsZSBuYW1lcyBpbiBpdCwgYW5kIGhpZ2hsaWdodCB0aGUgdmFyaWFibGUocykgdGhhdCB3aWxsIGJlIGFmZmVjdGVkIGJ5IHRoZSB2YWx1ZXMgaW5wdXR0ZWQgaW4gdGhlIHByb21wdC5cIilcclxuICAgICAgICAgICAgLmFkZFRvZ2dsZSh0b2dnbGUgPT4gdG9nZ2xlXHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wcm9tcHQuZ2V0Q29uZmlndXJhdGlvbigpLnByZXZpZXdfc2hlbGxfY29tbWFuZClcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAobmV3X3ZhbHVlOiBib29sZWFuKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wcm9tcHQuZ2V0Q29uZmlndXJhdGlvbigpLnByZXZpZXdfc2hlbGxfY29tbWFuZCA9IG5ld192YWx1ZTtcclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG5cclxuICAgICAgICAvLyBGaWVsZHNcclxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJGaWVsZHNcIilcclxuICAgICAgICAgICAgLnNldERlc2MoXCJUaXAhIFlvdSBjYW4gdXNlIHt7dmFyaWFibGVzfX0gaW4gJ0ZpZWxkIGxhYmVsJywgJ0RlZmF1bHQgdmFsdWUnIGFuZCAnRGVzY3JpcHRpb24nLlwiKVxyXG4gICAgICAgIDtcclxuICAgICAgICBjb25zdCBwcm9tcHRfZmllbGRfbW9kZWwgPSBnZXRNb2RlbDxQcm9tcHRGaWVsZE1vZGVsPihQcm9tcHRGaWVsZE1vZGVsLm5hbWUpO1xyXG4gICAgICAgIGNvbnN0IGZpZWxkc19jb250YWluZXIgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVEaXYoKTtcclxuICAgICAgICB0aGlzLnByb21wdC5wcm9tcHRfZmllbGRzLmZvckVhY2goKHByb21wdF9maWVsZDogUHJvbXB0RmllbGQpID0+IHtcclxuICAgICAgICAgICAgcHJvbXB0X2ZpZWxkX21vZGVsLmNyZWF0ZVNldHRpbmdGaWVsZHMocHJvbXB0X2ZpZWxkLCBmaWVsZHNfY29udGFpbmVyKTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gTmV3IGZpZWxkIGJ1dHRvblxyXG4gICAgICAgIGNyZWF0ZU5ld01vZGVsSW5zdGFuY2VCdXR0b248UHJvbXB0RmllbGRNb2RlbCwgUHJvbXB0RmllbGQ+KHRoaXMucGx1Z2luLCBQcm9tcHRGaWVsZE1vZGVsLm5hbWUsIGNvbnRhaW5lcl9lbGVtZW50LCBmaWVsZHNfY29udGFpbmVyLCB0aGlzLnByb21wdCkudGhlbigpO1xyXG5cclxuICAgICAgICAvLyBFeGVjdXRlIGJ1dHRvbiB0ZXh0XHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQuY3JlYXRlRGl2KHthdHRyOiB7Y2xhc3M6IFwiU0Mtc2V0dGluZy1ncm91cFwifX0pKVxyXG4gICAgICAgICAgICAuc2V0TmFtZShcIkV4ZWN1dGUgYnV0dG9uIHRleHRcIilcclxuICAgICAgICAgICAgLmFkZFRleHQodGV4dCA9PiB0ZXh0XHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wcm9tcHQuY29uZmlndXJhdGlvbi5leGVjdXRlX2J1dHRvbl90ZXh0KVxyXG4gICAgICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jIChuZXdfZXhlY3V0ZV9idXR0b25fdGV4dCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucHJvbXB0LmNvbmZpZ3VyYXRpb24uZXhlY3V0ZV9idXR0b25fdGV4dCA9IG5ld19leGVjdXRlX2J1dHRvbl90ZXh0O1xyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgIC50aGVuKChleGVjdXRlX2J1dHRvbl90ZXh0X2NvbXBvbmVudDogVGV4dENvbXBvbmVudCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIEF1dG9jb21wbGV0ZSBmb3IgdGhlIEV4ZWN1dGUgYnV0dG9uIHRleHQuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMucGx1Z2luLnNldHRpbmdzLnNob3dfYXV0b2NvbXBsZXRlX21lbnUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY3JlYXRlQXV0b2NvbXBsZXRlKHRoaXMucGx1Z2luLCBleGVjdXRlX2J1dHRvbl90ZXh0X2NvbXBvbmVudC5pbnB1dEVsLCAoKSA9PiBleGVjdXRlX2J1dHRvbl90ZXh0X2NvbXBvbmVudC5vbkNoYW5nZWQoKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcblxyXG5cclxuICAgICAgICAvLyBPayBidXR0b25cclxuICAgICAgICBjb25zdCBva0J1dHRvblRleHQ6IHN0cmluZyB8IHVuZGVmaW5lZCA9IHRoaXMub2tfYnV0dG9uX3RleHQ7XHJcbiAgICAgICAgaWYgKG9rQnV0dG9uVGV4dCkge1xyXG4gICAgICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgICAgIC5hZGRCdXR0b24oYnV0dG9uID0+IGJ1dHRvblxyXG4gICAgICAgICAgICAgICAgICAgIC5zZXRCdXR0b25UZXh0KG9rQnV0dG9uVGV4dClcclxuICAgICAgICAgICAgICAgICAgICAub25DbGljaygoKSA9PiB0aGlzLmFwcHJvdmUoKSksXHJcbiAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgIDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEEgdGlwIGFib3V0IENTUyBzdHlsaW5nLlxyXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIlRpcCEgWW91IGNhbiBjdXN0b21pc2UgdGhlIHN0eWxlIG9mIHRoZSBwcm9tcHQgbW9kYWwgd2l0aCBDU1MgYnkgdXNpbmcgdGhlIGNsYXNzIC5cIiArIHRoaXMucHJvbXB0LmdldENTU0NsYXNzKCkgKyBcIiBvciAuXCIgKyBQcm9tcHQuZ2V0Q1NTQmFzZUNsYXNzKCkrXCIgKGZvciBhbGwgcHJvbXB0IG1vZGFscykuXCIpXHJcbiAgICAgICAgO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBhcHByb3ZlKCk6IHZvaWQge1xyXG4gICAgICAgIGlmICh0aGlzLm9uX2FmdGVyX2FwcHJvdmFsKSB7XHJcbiAgICAgICAgICAgIHRoaXMuYXBwcm92ZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICB0aGlzLm9uX2FmdGVyX2FwcHJvdmFsKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuY2xvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgb25DbG9zZSgpOiB2b2lkIHtcclxuICAgICAgICBzdXBlci5vbkNsb3NlKCk7XHJcblxyXG4gICAgICAgIC8vIENhbGwgYSBjYW5jZWxsaW5nIGhvb2sgaWYgb25lIGlzIGRlZmluZWQgKGFuZCBpZiB0aGUgY2xvc2luZyBoYXBwZW5zIGR1ZSB0byBjYW5jZWxsaW5nLCBpLmUuIHRoZSBvayBidXR0b24gaXMgTk9UIGNsaWNrZWQpLlxyXG4gICAgICAgIGlmICghdGhpcy5hcHByb3ZlZCAmJiB0aGlzLm9uX2FmdGVyX2NhbmNlbGxpbmcpIHtcclxuICAgICAgICAgICAgdGhpcy5vbl9hZnRlcl9jYW5jZWxsaW5nKCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1xyXG4gICAgU2V0dGluZyxcclxuICAgIFRleHRBcmVhQ29tcG9uZW50LFxyXG59IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi8uLi9tYWluXCI7XHJcbmltcG9ydCB7XHJcbiAgICBJUGxhdGZvcm1TcGVjaWZpY1N0cmluZyxcclxuICAgIFBsYXRmb3JtSWQsXHJcbiAgICBQbGF0Zm9ybU5hbWVzLFxyXG59IGZyb20gXCIuLi9TQ19NYWluU2V0dGluZ3NcIjtcclxuaW1wb3J0IHtcclxuICAgIGdldE9wZXJhdGluZ1N5c3RlbSxcclxuICAgIGdvdG9VUkwsXHJcbn0gZnJvbSBcIi4uLy4uL0NvbW1vblwiO1xyXG5pbXBvcnQge0NvbmZpcm1hdGlvbk1vZGFsfSBmcm9tIFwiLi4vLi4vQ29uZmlybWF0aW9uTW9kYWxcIjtcclxuaW1wb3J0IHtjcmVhdGVBdXRvY29tcGxldGV9IGZyb20gXCIuL0F1dG9jb21wbGV0ZVwiO1xyXG5pbXBvcnQge0RvY3VtZW50YXRpb25QQVRIQXVnbWVudGF0aW9uc0xpbmt9IGZyb20gXCIuLi8uLi9Eb2N1bWVudGF0aW9uXCI7XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUEFUSEF1Z21lbnRhdGlvbkZpZWxkcyhwbHVnaW46IFNDX1BsdWdpbiwgY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50LCBwYXRoX2F1Z21lbnRhdGlvbnM6IElQbGF0Zm9ybVNwZWNpZmljU3RyaW5nKSB7XHJcblxyXG4gICAgY29uc3QgcGF0aF92YXJpYWJsZV9uYW1lID0gZ2V0UEFUSEVudmlyb25tZW50VmFyaWFibGVOYW1lKCk7XHJcbiAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAuc2V0TmFtZShgQWRkIGRpcmVjdG9yaWVzIHRvIHRoZSAke3BhdGhfdmFyaWFibGVfbmFtZX0gZW52aXJvbm1lbnQgdmFyaWFibGVgKVxyXG4gICAgICAgIC5zZXRIZWFkaW5nKClcclxuICAgICAgICAuc2V0RGVzYyhgVGhpcyBpcyBzb21ldGltZXMgbmVlZGVkIGluIG9yZGVyIHRvIGJlIGFibGUgdG8gY2FsbCBzb21lIHVzZXIgaW5zdGFsbGVkIGFwcGxpY2F0aW9ucy4gVGhlIGRpcmVjdG9yaWVzIHdpbGwgYmUgYXBwZW5kZWQgQUZURVIgdGhlIGRlZmF1bHQgZGlyZWN0b3JpZXMgaW4gJHtwYXRoX3ZhcmlhYmxlX25hbWV9LCB1bmxlc3Mge3shZW52aXJvbm1lbnQ6JHtwYXRoX3ZhcmlhYmxlX25hbWV9fX0gaXMgaW5jbHVkZWQuIE90aGVyIHt7dmFyaWFibGVzfX0gY2FuIGJlIHVzZWQsIHRvbywgYnV0IHRoZXkgZG9uJ3QgYWZmZWN0IHRoZSBhcHBlbmRpbmcgb3JkZXIuYClcclxuXHJcbiAgICAgICAgLy8gQW4gaWNvbiBmb3Igc2hvd2luZyB0aGUgY3VycmVudCBQQVRIIGNvbnRlbnQuXHJcbiAgICAgICAgLmFkZEV4dHJhQnV0dG9uKGJ1dHRvbiA9PiBidXR0b25cclxuICAgICAgICAgICAgLnNldEljb24oXCJidWxsZXQtbGlzdFwiKVxyXG4gICAgICAgICAgICAuc2V0VG9vbHRpcChgU2hvdyB0aGUgY3VycmVudCAke3BhdGhfdmFyaWFibGVfbmFtZX0gY29udGVudCAod2l0aG91dCBhbnkgYWRkaXRpb25zKS5gKVxyXG4gICAgICAgICAgICAub25DbGljaygoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBpZiAodW5kZWZpbmVkID09PSBwcm9jZXNzLmVudi5QQVRIKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwicHJvY2Vzcy5lbnYuUEFUSCBpcyBub3QgYSBzdHJpbmcuXCIpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgY29uc3QgbW9kYWwgPSBuZXcgQ29uZmlybWF0aW9uTW9kYWwoXHJcbiAgICAgICAgICAgICAgICAgICAgcGx1Z2luLFxyXG4gICAgICAgICAgICAgICAgICAgIGBDdXJyZW50ICR7cGF0aF92YXJpYWJsZV9uYW1lfSBjb250ZW50YCxcclxuICAgICAgICAgICAgICAgICAgICBwcm9jZXNzLmVudi5QQVRILFxyXG4gICAgICAgICAgICAgICAgICAgIFwiQ2xvc2VcIixcclxuICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICBtb2RhbC5vcGVuKCk7XHJcbiAgICAgICAgICAgIH0pLFxyXG4gICAgICAgIClcclxuXHJcbiAgICAgICAgLy8gSGVscCBsaW5rXHJcbiAgICAgICAgLmFkZEV4dHJhQnV0dG9uKGJ1dHRvbiA9PiBidXR0b25cclxuICAgICAgICAgICAgLnNldEljb24oXCJoZWxwXCIpXHJcbiAgICAgICAgICAgIC5zZXRUb29sdGlwKGBEb2N1bWVudGF0aW9uOiBBZGRpdGlvbnMgdG8gdGhlICR7cGF0aF92YXJpYWJsZV9uYW1lfSBlbnZpcm9ubWVudCB2YXJpYWJsZWApXHJcbiAgICAgICAgICAgIC5vbkNsaWNrKCgpID0+IGdvdG9VUkwoRG9jdW1lbnRhdGlvblBBVEhBdWdtZW50YXRpb25zTGluaykpXHJcbiAgICAgICAgKVxyXG4gICAgO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIGZpZWxkIGZvciBlYWNoIG9wZXJhdGluZyBzeXN0ZW0uXHJcbiAgICBjb25zdCBzdWJfY29udGFpbmVyX2VsZW1lbnQgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVEaXYoKTtcclxuICAgIHN1Yl9jb250YWluZXJfZWxlbWVudC5hZGRDbGFzcyhcIlNDLXNldHRpbmctZ3JvdXBcIik7XHJcbiAgICBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhQbGF0Zm9ybU5hbWVzKS5mb3JFYWNoKChwbGF0Zm9ybV9pZDogUGxhdGZvcm1JZCkgPT4geyAvLyBVc2UgLmZvckVhY2goKSBhbmQgY2FsbGJhY2tzIGluc3RlYWQgb2YgYSBzaW1wbGUgZm9yIGxvb3AsIGJlY2F1c2UgJ3BsYXRmb3JtX2lkJyBuZWVkcyB0byByZXRhaW4gdGhlIHNhbWUgdmFsdWUgbGF0ZXIgaW4gdGhlIC5vbkNoYW5nZSgpIGNhbGxiYWNrLiBPdGhlcndpc2UsIGBwbGF0Zm9ybV9pZGAgd291bGQgc2hvdyB1cCBhcyBcIndpbjMyXCIgaW4gYWxsIC5vbkNoYW5nZSgpIGNhbGxzLlxyXG4gICAgICAgIGNvbnN0IHBsYXRmb3JtX25hbWUgPSBQbGF0Zm9ybU5hbWVzW3BsYXRmb3JtX2lkXTtcclxuXHJcbiAgICAgICAgbmV3IFNldHRpbmcoc3ViX2NvbnRhaW5lcl9lbGVtZW50KS5zZXROYW1lKHBsYXRmb3JtX25hbWUgKyBcIiBcIiArIGdldFBBVEhFbnZpcm9ubWVudFZhcmlhYmxlTmFtZShwbGF0Zm9ybV9pZCkgKyBcIiBhZGRpdGlvbnNcIilcclxuICAgICAgICAgICAgLnNldERlc2MoXCJEZWZpbmUgZWFjaCBkaXJlY3Rvcnkgb24gYSBzZXBhcmF0ZSBsaW5lLCBvciBtdWx0aXBsZSBkaXJlY3RvcmllcyBvbiBvbmUgbGluZSwgc2VwYXJhdGVkIGJ5IFwiICsgZ2V0UEFUSFNlcGFyYXRvcihwbGF0Zm9ybV9pZCwgdHJ1ZSkpXHJcbiAgICAgICAgICAgIC5hZGRUZXh0QXJlYSh0ZXh0YXJlYSA9PiB0ZXh0YXJlYVxyXG4gICAgICAgICAgICAgICAgLnNldFZhbHVlKHBhdGhfYXVnbWVudGF0aW9uc1twbGF0Zm9ybV9pZF0gPz8gXCJcIilcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAobmV3X3BhdGhfYXVnbWVudGF0aW9uOiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBQQVRIIGF1Z21lbnRhdGlvbiBoYXMgYmVlbiBjaGFuZ2VkLlxyXG4gICAgICAgICAgICAgICAgICAgIC8vIFVwZGF0ZSB0aGUgY29uZmlndXJhdGlvbi5cclxuICAgICAgICAgICAgICAgICAgICBpZiAobmV3X3BhdGhfYXVnbWVudGF0aW9uLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGF1Z21lbnRhdGlvbiBoYXMgY29udGVudC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgcGF0aF9hdWdtZW50YXRpb25zW3BsYXRmb3JtX2lkXSA9IG5ld19wYXRoX2F1Z21lbnRhdGlvbjtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgYXVnbWVudGF0aW9uIGhhcyBiZWVuIHJlbW92ZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSBwYXRoX2F1Z21lbnRhdGlvbnNbcGxhdGZvcm1faWRdO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCBwbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgLnRoZW4oKHRleHRhcmVhX2NvbXBvbmVudDogVGV4dEFyZWFDb21wb25lbnQpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBBZGQgYW4gYXV0b2NvbXBsZXRlIG1lbnUuXHJcbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlQXV0b2NvbXBsZXRlKHBsdWdpbiwgdGV4dGFyZWFfY29tcG9uZW50LmlucHV0RWwgYXMgdW5rbm93biBhcyBIVE1MSW5wdXRFbGVtZW50LCAoKSA9PiB0ZXh0YXJlYV9jb21wb25lbnQub25DaGFuZ2VkKCkpO1xyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBBVEhTZXBhcmF0b3IocGxhdGZvcm1faWQ6IFBsYXRmb3JtSWQsIHZlcmJvc2UgPSBmYWxzZSkge1xyXG4gICAgc3dpdGNoIChwbGF0Zm9ybV9pZCkge1xyXG4gICAgICAgIGNhc2UgXCJsaW51eFwiOlxyXG4gICAgICAgIGNhc2UgXCJkYXJ3aW5cIjogLy8gVGhpcyBpcyBtYWNPUy5cclxuICAgICAgICAgICAgcmV0dXJuIHZlcmJvc2UgPyBcImEgY29sb24gOlwiIDogXCI6XCI7XHJcbiAgICAgICAgY2FzZSBcIndpbjMyXCI6XHJcbiAgICAgICAgICAgIHJldHVybiB2ZXJib3NlID8gXCJhIHNlbWljb2xvbiA7XCIgOiBcIjtcIjtcclxuICAgIH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNvbnZlcnROZXdsaW5lc1RvUEFUSFNlcGFyYXRvcnMocGF0aDogc3RyaW5nLCBwbGF0Zm9ybV9pZDogUGxhdGZvcm1JZCkge1xyXG4gICAgY29uc3Qgc2VwYXJhdG9yID0gZ2V0UEFUSFNlcGFyYXRvcihwbGF0Zm9ybV9pZCk7XHJcbiAgICByZXR1cm4gcGF0aC5yZXBsYWNlKFxyXG4gICAgICAgIC8oXFxyXFxufFxccnxcXG4pKy9ndSwgLy8gKyBtZWFucyB0aGF0IG11bHRpcGxlIGFkamFjZW50IG5ld2xpbmVzIGNhbiBiZSBjb21iaW5lZCBpbnRvIGEgc2luZ2xlIHNlcGFyYXRvciBjaGFyYWN0ZXIuXHJcbiAgICAgICAgKCkgPT4gc2VwYXJhdG9yLCAvLyBUaGUgcmVwbGFjZW1lbnQgaXMgYSBjYWxsYmFjayBpbiBvcmRlciB0byBhdm9pZCBwcm9ibGVtcyB3aXRoICQgY2hhcmFjdGVycywgYWx0aG91Z2ggdGhhdCBwcm9ibGVtIHdvdWxkIG9ubHkgb2NjdXIgaWYgdGhlIHNlcGFyYXRvciB3b3VsZCBjb250YWluIGEgJCBjaGFyYWN0ZXIsIHdoaWNoIGlzIGRvZXMgbm90LCBidXQgZml4IGl0IGFueXdheS5cclxuICAgICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYSBQQVRIIGVudmlyb25tZW50IHZhcmlhYmxlIGF1Z21lbnRhdGlvbiBzdHJpbmcgKHNwZWNpZmljIHRvIHRoZSBjdXJyZW50IG9wZXJhdGluZyBzeXN0ZW0pIGZyb20gdGhlIHBsdWdpbidzXHJcbiAqIGNvbmZpZ3VyYXRpb24uIFJldHVybnMgaXQgV0lUSE9VVCBwYXJzaW5nIHBvc3NpYmxlIHZhcmlhYmxlcyBpbiB0aGUgc3RyaW5nLiBJZiB0aGUgY3VycmVudCBvcGVyYXRpbmcgc3lzdGVtIGRvZXMgbm90XHJcbiAqIGhhdmUgYSBkZWRpY2F0ZWQgUEFUSCBhdWdtZW50YXRpb24gc3RyaW5nIGluIHRoZSBjb25maWd1cmF0aW9uLCByZXR1cm5zIG51bGwuXHJcbiAqXHJcbiAqIEBwYXJhbSBwbHVnaW5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQQVRIQXVnbWVudGF0aW9uKHBsdWdpbjogU0NfUGx1Z2luKTogc3RyaW5nIHwgbnVsbCB7XHJcbiAgICByZXR1cm4gcGx1Z2luLnNldHRpbmdzLmVudmlyb25tZW50X3ZhcmlhYmxlX3BhdGhfYXVnbWVudGF0aW9uc1tnZXRPcGVyYXRpbmdTeXN0ZW0oKV0gPz8gbnVsbDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgT1Mgc3BlY2lmaWMgbmFtZSBmb3IgdGhlIFBBVEggZW52aXJvbm1lbnQgdmFyaWFibGUuIEZvciBXaW5kb3dzIGl0cyBQYXRoLCBidXQgZm9yIG1hY09TIGFuZCBMaW51eCBpdHMgUEFUSCwgc29cclxuICogdGhlIG9ubHkgZGlmZmVyZW5jZSBpcyBjYXNpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UEFUSEVudmlyb25tZW50VmFyaWFibGVOYW1lKHBsYXRmb3JtX2lkOiBQbGF0Zm9ybUlkID0gZ2V0T3BlcmF0aW5nU3lzdGVtKCkpIHtcclxuICAgIHN3aXRjaCAocGxhdGZvcm1faWQpIHtcclxuICAgICAgICBjYXNlIFwiZGFyd2luXCI6XHJcbiAgICAgICAgY2FzZSBcImxpbnV4XCI6XHJcbiAgICAgICAgICAgIHJldHVybiBcIlBBVEhcIjtcclxuICAgICAgICBjYXNlIFwid2luMzJcIjpcclxuICAgICAgICAgICAgcmV0dXJuIFwiUGF0aFwiO1xyXG4gICAgfVxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1xyXG4gICAgcGFyc2VWYXJpYWJsZXMsXHJcbiAgICBQYXJzaW5nUmVzdWx0LFxyXG59IGZyb20gXCIuL3BhcnNlVmFyaWFibGVzXCI7XHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uL21haW5cIjtcclxuaW1wb3J0IHtTQ19FdmVudH0gZnJvbSBcIi4uL2V2ZW50cy9TQ19FdmVudFwiO1xyXG5pbXBvcnQge1ZhcmlhYmxlU2V0fSBmcm9tIFwiLi9sb2FkVmFyaWFibGVzXCI7XHJcbmltcG9ydCB7XHJcbiAgICBjbG9uZU9iamVjdCxcclxuICAgIHVuaXF1ZUFycmF5LFxyXG59IGZyb20gXCIuLi9Db21tb25cIjtcclxuaW1wb3J0IHtUU2hlbGxDb21tYW5kfSBmcm9tIFwiLi4vVFNoZWxsQ29tbWFuZFwiO1xyXG5pbXBvcnQge2RlYnVnTG9nfSBmcm9tIFwiLi4vRGVidWdcIjtcclxuXHJcbi8qKlxyXG4gKiBQYXJzaW5nUHJvY2VzcyBpbnN0YW5jZXMgY2FuIGJlIHVzZWQgaW4gc2l0dWF0aW9ucyB3aGVyZSBpdCdzIHVuY2VydGFpbiBjYW4gYWxsIHZhcmlhYmxlcyBiZSBwYXJzZWQgYXQgdGhlIHRpbWUgYmVpbmcsXHJcbiAqIGkuZS4gd2hlbiBwYXJzaW5nIHNoZWxsIGNvbW1hbmRzIChhbmQgYWxpYXNlcyksIGFzIHRoZXkgY2FuIGhhdmUgcHJlYWN0aW9ucyB3aGljaCByZXF1aXJlIHBhcnNpbmcgdG8gYmUgZG9uZSBpbiB0d28gcGhhc2VzLlxyXG4gKlxyXG4gKiBBbHNvLCBzaGVsbCBjb21tYW5kcyBhcmUgb2Z0ZW4gcGFyc2VkIGluIGFkdmFuY2UgZm9yIGNvbW1hbmQgcGFsZXR0ZSBhbmQgY29udGV4dCBtZW51cy4gVGhlbiBpdCdzIGdvb2QgdG8gc3RvcmUgdGhlIHBhcnNpbmdcclxuICogcmVzdWx0IGJ5IHVzaW5nIGluc3RhbmNlcyBvZiB0aGlzIGNsYXNzLlxyXG4gKlxyXG4gKiBUaGVuIGFnYWluLCBpZiB0aGUgcGFyc2luZyB1c2UtY2FzZSBpcyBzaW1wbGVyLCBlLmcuIFByb21wdCBkZXNjcmlwdGlvbiBvciBwcm9tcHQgZmllbGQgdmFsdWVzLCBpdCdzIG1vcmUgc3RyYWlnaHRmb3J3YXJkXHJcbiAqIHRvIGp1c3QgY2FsbCBwYXJzZVZhcmlhYmxlcygpIHdpdGhvdXQgdXRpbGlzaW5nIHRoaXMgY2xhc3MuIEFmdGVyIGFsbCwgdGhpcyBjbGFzcyBpcyBhIHdyYXBwZXIgZm9yIHBhcnNlVmFyaWFibGVzKCkuXHJcbiAqXHJcbiAqIDxQYXJzaW5nTWFwPiBpcyBhIGdlbmVyYWxpemF0aW9uIGZvciBkZWZpbmluZyBrZXlzIGZvciBhbiBvYmplY3QgdGhhdCB3aWxsIGJlIHVzZWQgZm9yIHN1Ym1pdHRpbmcgdGhlIG9yaWdpbmFsIHBhcnNlYWJsZVxyXG4gKiBjb250ZW50LiBUaGUgc2FtZSBrZXlzIHdpbGwgdGhlbiBiZSB1c2VkIHRvIGZvcm0gYW5vdGhlciBvYmplY3QgY29udGFpbmluZyB0aGUgcGFyc2luZyByZXN1bHRzLlxyXG4gKi9cclxuZXhwb3J0IGNsYXNzIFBhcnNpbmdQcm9jZXNzPFBhcnNpbmdNYXAgZXh0ZW5kcyB7W2tleTogc3RyaW5nXTogc3RyaW5nfT4ge1xyXG5cclxuICAgIHByaXZhdGUgcmVhZG9ubHkgcGFyc2luZ19yZXN1bHRzOiBQYXJzaW5nUmVzdWx0Q29udGFpbmVyPFBhcnNpbmdNYXA+ID0ge307XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcHJpdmF0ZSBwbHVnaW46IFNDX1BsdWdpbixcclxuICAgICAgICBwcml2YXRlIG9yaWdpbmFsX2NvbnRlbnRzOiBQYXJzaW5nTWFwLFxyXG5cclxuICAgICAgICAvKiogVXNlZCB0byBnZXQgYSBzaGVsbCAoZ2V0U2hlbGwoKSkgYW5kIGRlZmF1bHQgdmFsdWVzIGZvciB2YXJpYWJsZXMuICovXHJcbiAgICAgICAgcHJpdmF0ZSB0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQsXHJcbiAgICAgICAgcHJpdmF0ZSBzY19ldmVudDogU0NfRXZlbnQgfCBudWxsLFxyXG5cclxuICAgICAgICAvKipcclxuICAgICAgICAgKiBXaGVuIC5wcm9jZXNzKCkgaXMgY2FsbGVkLCBpdCB3aWxsIHNoaWZ0IGFuZCBwcm9jZXNzIHRoZSBmaXJzdCBWYXJpYWJsZVNldCBwcmVzZW50IGluIHRoaXMgYXJyYXkuIFNvLCB0aGUgbmV4dCBjYWxsXHJcbiAgICAgICAgICogd2lsbCBzaGlmdCBhbmQgcHJvY2VzcyB0aGUgbmV4dCBzZXQuXHJcbiAgICAgICAgICovXHJcbiAgICAgICAgcHJpdmF0ZSB2YXJpYWJsZV9zZXRzOiBWYXJpYWJsZVNldFtdLFxyXG5cclxuICAgICAgICAvKipcclxuICAgICAgICAgKiBUaGlzIGNhbiBiZSB1c2VkIHRvIG1hcmsgY2VydGFpbiBjb250ZW50cyB0byBhbHdheXMgYXZvaWQgZXNjYXBpbmcgc3BlY2lhbCBjaGFyYWN0ZXJzIGluIHRoZWlyIHZhcmlhYmxlIHZhbHVlcy5cclxuICAgICAgICAgKiBUaGlzIHNob3VsZCBvbmx5IGJlIHVzZWQgZm9yIGNvbnRlbnQgdGhhdCBpcyBuZXZlciBzdWJtaXR0ZWQgdG8gYSBzaGVsbCwgaS5lLiBvdXRwdXQgd3JhcHBlcnMgYXQgdGhlIG1vbWVudC5cclxuICAgICAgICAgKlxyXG4gICAgICAgICAqIFRoaXMgaXMgYSBsaXN0IG9mICdjb250ZW50IGtleXMnLlxyXG4gICAgICAgICAqL1xyXG4gICAgICAgIHByaXZhdGUgYXZvaWRfZXNjYXBpbmc6IChrZXlvZiBQYXJzaW5nTWFwKVtdID0gW10sXHJcbiAgICApIHtcclxuICAgICAgICBkZWJ1Z0xvZyhcIlBhcnNpbmcgcHJvY2VzczogQ291bnQgdmFyaWFibGUgc2V0czogXCIgKyB0aGlzLnZhcmlhYmxlX3NldHMubGVuZ3RoKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGlzX2ZpcnN0X2NhbGwgPSB0cnVlO1xyXG4gICAgLyoqXHJcbiAgICAgKiBQZXJmb3JtcyB0aGUgbmV4dCBzdGVwIGluIHRoZSBwYXJzaW5nIHByb2Nlc3MuIFRoZSBzdGVwIGNhbiBiZSB0aGUgZmlyc3Qgb25lLCBvciBhIHN1YnNlcXVlbnQgc3RlcC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJuIFRydWUgaWYgcGFyc2luZyBzdWNjZWVkZWQsIGZhbHNlIG90aGVyd2lzZS4gUmVhZCB0aGUgcmVzdWx0cyBieSBjYWxsaW5nIC5nZXRQYXJzaW5nUmVzdWx0KCkuXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBhc3luYyBwcm9jZXNzKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xyXG4gICAgICAgIGlmICh0aGlzLnZhcmlhYmxlX3NldHMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIHZhcmlhYmxlIHNldHMgYXJlIGxlZnQgZm9yIHByb2Nlc3NpbmcuXCIpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zdCBjdXJyZW50X3ZhcmlhYmxlcyA9IHRoaXMudmFyaWFibGVfc2V0cy5zaGlmdCgpIGFzIFZhcmlhYmxlU2V0OyAvLyBhcyBWYXJpYWJsZVNldDogVGVsbCBUeXBlU2NyaXB0IHRoYXQgdGhlcmUgaXMgYWx3YXlzIGEgc2V0IG9mIHZhcmlhYmxlcy5cclxuICAgICAgICBsZXQgc3VjY2VzcyA9IHRydWU7XHJcblxyXG4gICAgICAgIGRlYnVnTG9nKFwiUGFyc2luZyBwcm9jZXNzOiBDb3VudCB2YXJpYWJsZXMgaW4gY3VycmVudCBzZXQ6IFwiICsgY3VycmVudF92YXJpYWJsZXMuc2l6ZSk7XHJcblxyXG4gICAgICAgIC8vIE11bHRpcGxlIGNvbnRlbnRzIGNhbiBiZSBwYXJzZWQgaW4gdGhlIHNhbWUgY2FsbC4gVFNoZWxsQ29tbWFuZCBpbnN0YW5jZXMgaGF2ZSAnc2hlbGxfY29tbWFuZCcgYW5kICdhbGlhcydcclxuICAgICAgICAvLyBjb250ZW50cyB3aGljaCBhcmUgcGFyc2VkIGF0IHRoZSBzYW1lIHRpbWUuIFRoaXMgbXVsdGktY29udGVudCBzdXBwb3J0IGNhbiBiZSB1c2VkIGZvciBldmVuIG1vcmUgc2l0dWF0aW9ucyBpZlxyXG4gICAgICAgIC8vIG5lZWRlZCBpbiB0aGUgZnV0dXJlLlxyXG4gICAgICAgIGZvciAoY29uc3QgY29udGVudF9rZXkgb2YgdGhpcy5nZXRDb250ZW50S2V5cygpKSB7XHJcblxyXG4gICAgICAgICAgICBsZXQgcGFyc2VfY29udGVudDogc3RyaW5nO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5pc19maXJzdF9jYWxsKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBVc2Ugb3JpZ2luYWwgY29udGVudC5cclxuICAgICAgICAgICAgICAgIHBhcnNlX2NvbnRlbnQgPSB0aGlzLm9yaWdpbmFsX2NvbnRlbnRzW2NvbnRlbnRfa2V5XTtcclxuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiU3RhcnRpbmcgdG8gcGFyc2UgJ1wiICsgY29udGVudF9rZXkgKyBcIic6IFwiICsgcGFyc2VfY29udGVudCk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBDb250aW51ZSBwYXJzaW5nIGNvbnRlbnQgZnJvbSBwcmV2aW91cyBwYXJzaW5nIHJlc3VsdC4gVGhpcyB0aW1lIHBhcnNlIHZhcmlhYmxlcyB0aGF0IHdlcmUgbm90IHBhcnNlIGJhY2sgdGhlbi5cclxuICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBQcm9ibGVtOiB2YXJpYWJsZSB2YWx1ZXMgdGhhdCBjYW1lIGZyb20gYW4gZWFybGllciBwaGFzZSBhcmUgZXhwb3NlZCB0byByZXBldGl0aXZlIHBhcnNpbmcuIEZpbmQgYSB3YXkgdG8gbGltaXQgdGhlIHBhcnNpbmcgdG8gb25seSBvcmlnaW5hbCBwYXJ0cyBvZiB0aGUgc2hlbGwgY29tbWFuZC5cclxuXHJcbiAgICAgICAgICAgICAgICBjb25zdCBwcmV2aW91c1BhcnNpbmdSZXN1bHQ6IFBhcnNpbmdSZXN1bHQgfCB1bmRlZmluZWQgPSB0aGlzLnBhcnNpbmdfcmVzdWx0c1tjb250ZW50X2tleV07XHJcbiAgICAgICAgICAgICAgICBpZiAodW5kZWZpbmVkID09PSBwcmV2aW91c1BhcnNpbmdSZXN1bHQpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIGp1c3QgYSB0eXBlIGd1YXJkLiB0aGlzLmdldENvbnRlbnRLZXlzKCkgc2hvdWxkIG9ubHkgcmV0dXJuIGtleXMgdGhhdCBleGlzdCwgc28gdGhlIGNoZWNrcyBzaG91bGQgbmV2ZXIgdGhyb3cgZXJyb3JzIGluIHByYWN0aXNlLlxyXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlBhcnNpbmcgcmVzdWx0cyBkbyBub3QgY29udGFpbiBrZXk6IFwiICsgY29udGVudF9rZXkpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIC8vIENoZWNrIHRoYXQgdGhlIHByZXZpb3VzIHBhcnNpbmcgZGlkIG5vdCBmYWlsLlxyXG4gICAgICAgICAgICAgICAgaWYgKG51bGwgPT09IHByZXZpb3VzUGFyc2luZ1Jlc3VsdC5wYXJzZWRfY29udGVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFByZXZpb3VzIHBhcnNpbmcgaGFkIHByb2JhYmx5IGZhaWxlZC5cclxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUcmllZCB0byBjb250aW51ZSBwYXJzaW5nLCBidXQgcHJldmlvdXMgcGFyc2luZyByZXN1bHQgaXMgbnVsbC4gUHJvYmFibHkgcHJldmlvdXMgcGFyc2luZyBoYXMgZmFpbGVkLlwiKTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAvLyBQcmV2aW91cyBwYXJzaW5nIHdhcyBvay5cclxuICAgICAgICAgICAgICAgIHBhcnNlX2NvbnRlbnQgPSBwcmV2aW91c1BhcnNpbmdSZXN1bHQucGFyc2VkX2NvbnRlbnQ7XHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkNvbnRpbnVpbmcgcGFyc2luZyAnXCIgKyBjb250ZW50X2tleSArIFwiJzogXCIgKyBwYXJzZV9jb250ZW50KTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gUGFyc2UgdGhlIHZhcmlhYmxlc1xyXG4gICAgICAgICAgICBjb25zdCBwYXJzaW5nX3Jlc3VsdCA9IGF3YWl0IHBhcnNlVmFyaWFibGVzKFxyXG4gICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4sXHJcbiAgICAgICAgICAgICAgICBwYXJzZV9jb250ZW50LFxyXG4gICAgICAgICAgICAgICAgdGhpcy5hdm9pZEVzY2FwaW5nKGNvbnRlbnRfa2V5KSA/IG51bGwgOiB0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRTaGVsbCgpLCAvLyBJZiBubyBlc2NhcGluZyBpcyBuZWVkZWQsIHBhc3MgbnVsbC5cclxuICAgICAgICAgICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLFxyXG4gICAgICAgICAgICAgICAgdGhpcy5zY19ldmVudCxcclxuICAgICAgICAgICAgICAgIGN1cnJlbnRfdmFyaWFibGVzLFxyXG4gICAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIHBhcnNpbmcgc3VjY2VlZGVkIG9yIGZhaWxlZC5cclxuICAgICAgICAgICAgc3VjY2VzcyA9IHN1Y2Nlc3MgJiYgcGFyc2luZ19yZXN1bHQuc3VjY2VlZGVkOyAvLyBGbGFnIGFzIGZhaWxlZCBhbHNvIGlmIGEgcHJldmlvdXMgcGhhc2UgaGFzIGZhaWxlZC5cclxuXHJcbiAgICAgICAgICAgIC8vIFN0b3JlIHRoZSBwYXJzaW5nIHJlc3VsdFxyXG4gICAgICAgICAgICB0aGlzLm1lcmdlVG9QYXJzaW5nUmVzdWx0cyhjb250ZW50X2tleSwgcGFyc2luZ19yZXN1bHQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRmluaXNoXHJcbiAgICAgICAgdGhpcy5pc19maXJzdF9jYWxsID0gZmFsc2U7XHJcbiAgICAgICAgcmV0dXJuIHN1Y2Nlc3M7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBBIHdyYXBwZXIgZm9yIC5wcm9jZXNzKCkgdGhhdCBwcm9jZXNzZXMgYWxsIHRoZSBWYXJpYWJsZVNldHMgdGhhdCBhcmUgc3RpbGwgbGVmdCB1bnByb2Nlc3NlZC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJuIFRydWUgaWYgcGFyc2luZyBhbGwgc2V0cyBzdWNjZWVkZWQsIGZhbHNlIG90aGVyd2lzZS5cclxuICAgICAqL1xyXG4gICAgcHVibGljIGFzeW5jIHByb2Nlc3NSZXN0KCk6IFByb21pc2U8Ym9vbGVhbj4ge1xyXG4gICAgICAgIC8vIDEuIENoZWNrIGEgcHJldmlvdXMgcGFyc2luZyByZXN1bHQgKGlmIGV4aXN0cykuXHJcbiAgICAgICAgZm9yIChjb25zdCBjb250ZW50X2tleSBvZiB0aGlzLmdldENvbnRlbnRLZXlzKCkpIHtcclxuICAgICAgICAgICAgY29uc3QgcGFyc2luZ1Jlc3VsdDogUGFyc2luZ1Jlc3VsdCB8IHVuZGVmaW5lZCA9IHRoaXMucGFyc2luZ19yZXN1bHRzW2NvbnRlbnRfa2V5XTtcclxuICAgICAgICAgICAgaWYgKHBhcnNpbmdSZXN1bHQpIHtcclxuICAgICAgICAgICAgICAgIC8vIEEgcHJldmlvdXMgcGFyc2luZyByZXN1bHQgZXhpc3RzLlxyXG4gICAgICAgICAgICAgICAgLy8gRW5zdXJlIGl0IGhhcyBub3QgZmFpbGVkLlxyXG4gICAgICAgICAgICAgICAgZGVidWdMb2coXCJQcmV2aW91cyBwYXJzaW5nIHN1Y2NlZWRlZD8gXCIgKyBwYXJzaW5nUmVzdWx0LnN1Y2NlZWRlZCk7XHJcbiAgICAgICAgICAgICAgICBpZiAoIXBhcnNpbmdSZXN1bHQuc3VjY2VlZGVkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIHByZXZpb3VzIHBhcnNpbmcgcmVzdWx0IGhhcyBmYWlsZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyAyLiBQcm9jZXNzIHRoZSByZXN0IG9mIHRoZSBWYXJpYWJsZVNldHMuXHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnZhcmlhYmxlX3NldHMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgICAgaWYgKCFhd2FpdCB0aGlzLnByb2Nlc3MoKSkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRQYXJzaW5nUmVzdWx0cygpIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5wYXJzaW5nX3Jlc3VsdHM7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDYWxscyBTQ19QbHVnaW4ubmV3RXJyb3JzKCkgdG8gY3JlYXRlIHZpc2libGUgZXJyb3IgYmFsbG9vbnMgZm9yIGFsbCB0aGUgaXNzdWVzIGVuY291bnRlcmVkIGR1cmluZyBwYXJzaW5nLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZGlzcGxheUVycm9yTWVzc2FnZXMoKTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy5wbHVnaW4ubmV3RXJyb3JzKHRoaXMuZ2V0RXJyb3JNZXNzYWdlcygpKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEBwcml2YXRlIENhbiBiZSBtYWRlIHB1YmxpYyBpZiBuZWVkZWQuXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgZ2V0RXJyb3JNZXNzYWdlcygpIHtcclxuICAgICAgICBsZXQgZXJyb3JfbWVzc2FnZXM6IHN0cmluZ1tdID0gW107XHJcbiAgICAgICAgZm9yIChjb25zdCBjb250ZW50X2tleSBvZiB0aGlzLmdldENvbnRlbnRLZXlzKCkpIHtcclxuICAgICAgICAgICAgY29uc3QgcGFyc2luZ1Jlc3VsdDogUGFyc2luZ1Jlc3VsdCB8IHVuZGVmaW5lZCA9IHRoaXMucGFyc2luZ19yZXN1bHRzW2NvbnRlbnRfa2V5XTtcclxuXHJcbiAgICAgICAgICAgIC8vIFR5cGUgZ3VhcmRcclxuICAgICAgICAgICAgaWYgKHVuZGVmaW5lZCA9PT0gcGFyc2luZ1Jlc3VsdCkge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhpcyBzaG91bGQgbmV2ZXIgaGFwcGVuLCBiZWNhdXNlIHRoaXMuZ2V0Q29udGVudEtleXMoKSBzaG91bGQgb25seSByZXR1cm4gZXhpc3Rpbmcga2V5cy5cclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlBhcnNpbmcgcmVzdWx0IGlzIHVuZGVmaW5lZC5cIik7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGVycm9yX21lc3NhZ2VzLnB1c2goXHJcbiAgICAgICAgICAgICAgICAuLi5wYXJzaW5nUmVzdWx0LmVycm9yX21lc3NhZ2VzLFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gUmVtb3ZlIGR1cGxpY2F0ZSBlcnJvciBtZXNzYWdlcy4gV2hlbiBwYXJzaW5nICdzaGVsbF9jb21tYW5kJyBhbmQgJ2FsaWFzJywgdGhleSBjYW4gY29udGFpbiBzYW1lIHZhcmlhYmxlcyBhbmRcclxuICAgICAgICAvLyB0aGVyZWZvcmUgZ2VuZXJhdGUgc2FtZSBlcnJvciBtZXNzYWdlcy5cclxuICAgICAgICBlcnJvcl9tZXNzYWdlcyA9IHVuaXF1ZUFycmF5KGVycm9yX21lc3NhZ2VzKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGVycm9yX21lc3NhZ2VzO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgZ2V0Q29udGVudEtleXMoKTogKGtleW9mIFBhcnNpbmdNYXApW10ge1xyXG4gICAgICAgIHJldHVybiBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyh0aGlzLm9yaWdpbmFsX2NvbnRlbnRzKSBhcyAoa2V5b2YgUGFyc2luZ01hcClbXTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIE1lcmdlcyBjb25zZWN1dGl2ZSBwYXJzaW5nIHJlc3VsdHMgdG9nZXRoZXIgc28gdGhhdCBpbmZvcm1hdGlvbiBmcm9tIGJvdGggdGhlIG9sZCBhbmQgbmV3IHBhcnNpbmcgcmVzdWx0cyBjYW4gYmUgcHJlc2VydmVkLlxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIG1lcmdlVG9QYXJzaW5nUmVzdWx0cyhjb250ZW50X2tleToga2V5b2YgUGFyc2luZ01hcCwgbmV3UGFyc2luZ1Jlc3VsdDogUGFyc2luZ1Jlc3VsdCkge1xyXG4gICAgICAgIGNvbnN0IG9yaWdpbmFsUGFyc2luZ1Jlc3VsdDogUGFyc2luZ1Jlc3VsdCB8IHVuZGVmaW5lZCA9IHRoaXMucGFyc2luZ19yZXN1bHRzW2NvbnRlbnRfa2V5XTtcclxuICAgICAgICBpZiAodW5kZWZpbmVkID09PSBvcmlnaW5hbFBhcnNpbmdSZXN1bHQpIHtcclxuICAgICAgICAgICAgLy8gTm8gbmVlZCB0byBtZXJnZS4gQnV0IGNsb25lIHRoZSBvYmplY3Qgc28gdGhhdCBwb3NzaWJsZSBmdXR1cmUgbWVyZ2VzIHdpbGwgbm90IG1lc3MgdXAgdGhlIG9yaWdpbmFsIG9iamVjdFxyXG4gICAgICAgICAgICAvLyBpbiBjYXNlIGl0J3MgdXNlZCBzb21ld2hlcmUgZWxzZS5cclxuICAgICAgICAgICAgdGhpcy5wYXJzaW5nX3Jlc3VsdHNbY29udGVudF9rZXldID0gY2xvbmVPYmplY3QobmV3UGFyc2luZ1Jlc3VsdCk7XHJcbiAgICAgICAgICAgIC8vIE5vdGUgdGhhdCBvcmlnaW5hbFBhcnNpbmdSZXN1bHQgaXMgc3RpbGwgdW5kZWZpbmVkLiBJZiB5b3UgY29udGludWUgd3JpdGluZyBjb2RlIGhlcmUgb3IgYWZ0ZXIgdGhlIGlmIGJsb2NrXHJcbiAgICAgICAgICAgIC8vIChuZWFyIHRoZSBlbmQgb2YgdGhlIGZ1bmN0aW9uKSwgZG8gc29tZXRoaW5nIGxpa2Ugb3JpZ2luYWxQYXJzaW5nUmVzdWx0ID0gdGhpcy5wYXJzaW5nX3Jlc3VsdHNbY29udGVudF9rZXldXHJcbiAgICAgICAgICAgIC8vIGJ1dCB0aGF0IHdvdWxkIHJlcXVpcmUgY2hhbmdpbmcgb3JpZ2luYWxQYXJzaW5nUmVzdWx0IGZyb20gY29uc3QgdG8gbGV0LlxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIE1lcmdlXHJcbiAgICAgICAgICAgIC8vIE5PVEU6IG9yaWdpbmFsUGFyc2luZ1Jlc3VsdC5vcmlnaW5hbF9jb250ZW50IElTIEtFUFQgVU5DSEFOR0VEISBUaGUgbmV3ZXIgXCJvcmlnaW5hbFwiIGNvbnRlbnQgaXMgbm90IGFjdHVhbGx5IG9yaWdpbmFsLCBiZWNhdXNlIGl0J3MgcGFydGx5IHBhcnNlZC4gVGhhdCdzIHdoeSB0aGUgb2xkIG9uZSBpcyBwcmVzZXJ2ZWQuXHJcbiAgICAgICAgICAgIG9yaWdpbmFsUGFyc2luZ1Jlc3VsdC5wYXJzZWRfY29udGVudCA9IG5ld1BhcnNpbmdSZXN1bHQucGFyc2VkX2NvbnRlbnQ7IC8vIE5ldyBwYXJzZWQgY29udGVudCBvdmVycmlkZXMgdGhlIG9sZCBvbmUuXHJcbiAgICAgICAgICAgIG9yaWdpbmFsUGFyc2luZ1Jlc3VsdC5zdWNjZWVkZWQgJiY9IG5ld1BhcnNpbmdSZXN1bHQuc3VjY2VlZGVkOyAvLyBCb3RoIHRoZSBvbGQgYW5kIG5ldyBwYXJzaW5nIG11c3QgaGF2ZSBzdWNjZWVkZWQgaW4gb3JkZXIgdG8gY29uc2lkZXIgdGhlIHdob2xlIHByb2Nlc3Mgc3VjY2VlZGVkLlxyXG4gICAgICAgICAgICBvcmlnaW5hbFBhcnNpbmdSZXN1bHQuZXJyb3JfbWVzc2FnZXMucHVzaCguLi5uZXdQYXJzaW5nUmVzdWx0LmVycm9yX21lc3NhZ2VzKTsgLy8gSW5jbHVkZSBib3RoIG9sZCBhbmQgbmV3IGVycm9yIG1lc3NhZ2VzLlxyXG4gICAgICAgICAgICBvcmlnaW5hbFBhcnNpbmdSZXN1bHQuY291bnRfcGFyc2VkX3ZhcmlhYmxlcyArPSBuZXdQYXJzaW5nUmVzdWx0LmNvdW50X3BhcnNlZF92YXJpYWJsZXM7IC8vIFN1bSB1cCB0aGUgdmFyaWFibGUgdXNhZ2UgY291bnRzLiBBdCB0aGUgdGltZSBvZiB3cml0aW5nLCB0aGUgc3VtIGlzIG9ubHkgdXNlZCBmb3IgZGV0ZXJtaW5pbmcgaWYgdGhlcmUgd2VyZSBhbnkgdmFyaWFibGVzIHBhcnNlZCBvciBub3QsIHNvIGFuIGFjY3VyYXRlIHN1bSBpcyBub3QgdXNlZCBhdG0uXHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVGVsbHMgd2hldGhlciB0aGUgZ2l2ZW4gY29udGVudF9rZXkgaGFzIGEgbWFyayB0aGF0IHNwZWNpYWwgY2hhcmFjdGVycyBpbiB0aGUgY29udGVudCdzIHZhcmlhYmxlIHZhbHVlcyBzaG91bGQgbm90IGJlIGVzY2FwZWQuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIGNvbnRlbnRfa2V5XHJcbiAgICAgKiBAcHJpdmF0ZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGF2b2lkRXNjYXBpbmcoY29udGVudF9rZXk6IGtleW9mIFBhcnNpbmdNYXApOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5hdm9pZF9lc2NhcGluZy5jb250YWlucyhjb250ZW50X2tleSk7XHJcbiAgICB9XHJcbn1cclxuXHJcbnR5cGUgUGFyc2luZ1Jlc3VsdENvbnRhaW5lcjxQYXJzaW5nTWFwPiA9IHtcclxuICAgIFtrZXkgaW4ga2V5b2YgUGFyc2luZ01hcF0/OiBQYXJzaW5nUmVzdWx0O1xyXG59OyIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtcclxuICAgIE91dHB1dENoYW5uZWxDb2RlcyxcclxuICAgIE91dHB1dENoYW5uZWxPcmRlcixcclxuICAgIE91dHB1dEhhbmRsaW5nTW9kZSxcclxufSBmcm9tIFwiLi4vb3V0cHV0X2NoYW5uZWxzL091dHB1dENoYW5uZWxDb2RlXCI7XHJcbmltcG9ydCB7XHJcbiAgICBJQ29tbWFuZFBhbGV0dGVPcHRpb25zLFxyXG4gICAgSVBsYXRmb3JtU3BlY2lmaWNTdHJpbmcsXHJcbiAgICBJUGxhdGZvcm1TcGVjaWZpY1N0cmluZ1dpdGhEZWZhdWx0LFxyXG59IGZyb20gXCIuL1NDX01haW5TZXR0aW5nc1wiO1xyXG5pbXBvcnQge1NDX0V2ZW50Q29uZmlndXJhdGlvbnN9IGZyb20gXCIuLi9ldmVudHMvU0NfRXZlbnRDb25maWd1cmF0aW9uXCI7XHJcbmltcG9ydCB7SW5oZXJpdGFibGVWYXJpYWJsZURlZmF1bHRWYWx1ZUNvbmZpZ3VyYXRpb259IGZyb20gXCIuLi92YXJpYWJsZXMvVmFyaWFibGVcIjtcclxuaW1wb3J0IHtcclxuICAgIFByZWFjdGlvbkNvbmZpZ3VyYXRpb25cclxufSBmcm9tIFwiLi4vaW1wb3J0c1wiO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBTaGVsbENvbW1hbmRDb25maWd1cmF0aW9uIHtcclxuICAgIGlkOiBzdHJpbmcsXHJcbiAgICAvKipcclxuICAgICAqIENvbnRhaW5zIG9wZXJhdGluZyBzeXN0ZW0gc3BlY2lmaWMgc2hlbGwgY29tbWFuZHMuXHJcbiAgICAgKiAgLSBrZXk6IHBsYXRmb3JtICg9IE9TKSBuYW1lXHJcbiAgICAgKiAgLSB2YWx1ZTogc2hlbGwgY29tbWFuZFxyXG4gICAgICovXHJcbiAgICBwbGF0Zm9ybV9zcGVjaWZpY19jb21tYW5kczogSVBsYXRmb3JtU3BlY2lmaWNTdHJpbmdXaXRoRGVmYXVsdDtcclxuICAgIHNoZWxsczogSVBsYXRmb3JtU3BlY2lmaWNTdHJpbmc7XHJcbiAgICBhbGlhczogc3RyaW5nO1xyXG4gICAgaWNvbjogc3RyaW5nIHwgbnVsbDtcclxuICAgIGNvbmZpcm1fZXhlY3V0aW9uOiBib29sZWFuO1xyXG4gICAgaWdub3JlX2Vycm9yX2NvZGVzOiBudW1iZXJbXTtcclxuICAgIGlucHV0X2NvbnRlbnRzOiB7XHJcbiAgICAgICAgc3RkaW46IHN0cmluZyB8IG51bGwsXHJcbiAgICB9LFxyXG4gICAgb3V0cHV0X2NoYW5uZWxzOiBPdXRwdXRDaGFubmVsQ29kZXMsXHJcbiAgICBvdXRwdXRfd3JhcHBlcnM6IHtcclxuICAgICAgICBzdGRvdXQ6IHN0cmluZyB8IG51bGwsXHJcbiAgICAgICAgc3RkZXJyOiBzdHJpbmcgfCBudWxsLFxyXG4gICAgfTtcclxuICAgIG91dHB1dF9jaGFubmVsX29yZGVyOiBPdXRwdXRDaGFubmVsT3JkZXI7XHJcbiAgICBvdXRwdXRfaGFuZGxpbmdfbW9kZTogT3V0cHV0SGFuZGxpbmdNb2RlO1xyXG4gICAgZXZlbnRzOiBTQ19FdmVudENvbmZpZ3VyYXRpb25zO1xyXG4gICAgY29tbWFuZF9wYWxldHRlX2F2YWlsYWJpbGl0eToga2V5b2YgSUNvbW1hbmRQYWxldHRlT3B0aW9ucztcclxuICAgIHByZWFjdGlvbnM6IFByZWFjdGlvbkNvbmZpZ3VyYXRpb25bXTtcclxuICAgIHZhcmlhYmxlX2RlZmF1bHRfdmFsdWVzOiB7XHJcbiAgICAgICAgW3ZhcmlhYmxlX2lkX29yX25hbWU6IHN0cmluZ106IEluaGVyaXRhYmxlVmFyaWFibGVEZWZhdWx0VmFsdWVDb25maWd1cmF0aW9uLFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBMRUdBQ1lcclxuICAgIC8qKiBAZGVwcmVjYXRlZCBDYW4gb25seSBiZSB1c2VkIGZvciBtaWdyYXRpb24uICovXHJcbiAgICBzaGVsbF9jb21tYW5kPzogc3RyaW5nO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gbmV3U2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbihzaGVsbF9jb21tYW5kX2lkOiBzdHJpbmcsIHNoZWxsX2NvbW1hbmQgPSBcIlwiKTogU2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbiB7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAgIGlkOiBzaGVsbF9jb21tYW5kX2lkLFxyXG4gICAgICAgIHBsYXRmb3JtX3NwZWNpZmljX2NvbW1hbmRzOiB7XHJcbiAgICAgICAgICAgIGRlZmF1bHQ6IHNoZWxsX2NvbW1hbmQsXHJcbiAgICAgICAgfSxcclxuICAgICAgICBzaGVsbHM6IHt9LFxyXG4gICAgICAgIGFsaWFzOiBcIlwiLFxyXG4gICAgICAgIGljb246IG51bGwsXHJcbiAgICAgICAgY29uZmlybV9leGVjdXRpb246IGZhbHNlLFxyXG4gICAgICAgIGlnbm9yZV9lcnJvcl9jb2RlczogW10sXHJcbiAgICAgICAgaW5wdXRfY29udGVudHM6IHtcclxuICAgICAgICAgICAgc3RkaW46IG51bGwsXHJcbiAgICAgICAgfSxcclxuICAgICAgICBvdXRwdXRfY2hhbm5lbHM6IHtcclxuICAgICAgICAgICAgc3Rkb3V0OiBcImlnbm9yZVwiLFxyXG4gICAgICAgICAgICBzdGRlcnI6IFwibm90aWZpY2F0aW9uXCIsXHJcbiAgICAgICAgfSxcclxuICAgICAgICBvdXRwdXRfd3JhcHBlcnM6IHtcclxuICAgICAgICAgICAgc3Rkb3V0OiBudWxsLFxyXG4gICAgICAgICAgICBzdGRlcnI6IG51bGwsXHJcbiAgICAgICAgfSxcclxuICAgICAgICBvdXRwdXRfY2hhbm5lbF9vcmRlcjogXCJzdGRvdXQtZmlyc3RcIixcclxuICAgICAgICBvdXRwdXRfaGFuZGxpbmdfbW9kZTogXCJidWZmZXJlZFwiLFxyXG4gICAgICAgIGV2ZW50czoge30sXHJcbiAgICAgICAgY29tbWFuZF9wYWxldHRlX2F2YWlsYWJpbGl0eTogXCJlbmFibGVkXCIsXHJcbiAgICAgICAgcHJlYWN0aW9uczogW10sXHJcbiAgICAgICAgdmFyaWFibGVfZGVmYXVsdF92YWx1ZXM6IHt9LFxyXG4gICAgfTtcclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IFNDX1BsdWdpbiBmcm9tIFwiLi9tYWluXCI7XHJcbmltcG9ydCB7bmV3U2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbiwgU2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbn0gZnJvbSBcIi4vc2V0dGluZ3MvU2hlbGxDb21tYW5kQ29uZmlndXJhdGlvblwiO1xyXG5pbXBvcnQge2RlYnVnTG9nfSBmcm9tIFwiLi9EZWJ1Z1wiO1xyXG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwiZnNcIjtcclxuaW1wb3J0IHtjb21iaW5lT2JqZWN0cywgZ2V0UGx1Z2luQWJzb2x1dGVQYXRofSBmcm9tIFwiLi9Db21tb25cIjtcclxuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwicGF0aFwiO1xyXG5pbXBvcnQge2dldERlZmF1bHRTZXR0aW5nc30gZnJvbSBcIi4vc2V0dGluZ3MvU0NfTWFpblNldHRpbmdzXCI7XHJcbmltcG9ydCB7XHJcbiAgICBDdXN0b21WYXJpYWJsZUNvbmZpZ3VyYXRpb24sXHJcbiAgICBDdXN0b21WYXJpYWJsZU1vZGVsLFxyXG59IGZyb20gXCIuL21vZGVscy9jdXN0b21fdmFyaWFibGUvQ3VzdG9tVmFyaWFibGVNb2RlbFwiO1xyXG5pbXBvcnQge2dldE1vZGVsfSBmcm9tIFwiLi9tb2RlbHMvTW9kZWxcIjtcclxuXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBSdW5NaWdyYXRpb25zKHBsdWdpbjogU0NfUGx1Z2luKSB7XHJcbiAgICBjb25zdCBzaG91bGRfc2F2ZSA9IFsgLy8gSWYgYXQgbGVhc3Qgb25lIG9mIHRoZSB2YWx1ZXMgaXMgdHJ1ZSwgc2F2aW5nIHdpbGwgYmUgdHJpZ2dlcmVkLlxyXG4gICAgICAgIEVuc3VyZU1haW5GaWVsZHNFeGlzdChwbHVnaW4pLCAvLyBEbyB0aGlzIGVhcmx5LlxyXG4gICAgICAgIE1pZ3JhdGVDb21tYW5kc1RvU2hlbGxDb21tYW5kcyhwbHVnaW4pLFxyXG4gICAgICAgIE1pZ3JhdGVTaGVsbENvbW1hbmRzT2JqZWN0VG9BcnJheShwbHVnaW4pLFxyXG4gICAgICAgIE1pZ3JhdGVTaGVsbENvbW1hbmRUb1BsYXRmb3JtcyhwbHVnaW4pLFxyXG4gICAgICAgIEVuc3VyZVNoZWxsQ29tbWFuZHNIYXZlQWxsRmllbGRzKHBsdWdpbiksXHJcbiAgICAgICAgRW5zdXJlQ3VzdG9tVmFyaWFibGVzSGF2ZUFsbEZpZWxkcyhwbHVnaW4pLFxyXG4gICAgICAgIERlbGV0ZUVtcHR5Q29tbWFuZHNGaWVsZChwbHVnaW4pLFxyXG4gICAgXTtcclxuICAgIGlmIChzaG91bGRfc2F2ZS5pbmNsdWRlcyh0cnVlKSkge1xyXG4gICAgICAgIC8vIE9ubHkgc2F2ZSBpZiB0aGVyZSB3ZXJlIGNoYW5nZXMgdG8gY29uZmlndXJhdGlvbi5cclxuICAgICAgICBkZWJ1Z0xvZyhcIlNhdmluZyBtaWdyYXRpb25zLi4uXCIpO1xyXG4gICAgICAgIGJhY2t1cFNldHRpbmdzRmlsZShwbHVnaW4pOyAvLyBNYWtlIGEgYmFja3VwIGNvcHkgb2YgdGhlIG9sZCBmaWxlIEJFRk9SRSB3cml0aW5nIHRoZSBuZXcsIG1pZ3JhdGVkIHNldHRpbmdzIGZpbGUuXHJcbiAgICAgICAgYXdhaXQgcGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgIGRlYnVnTG9nKFwiTWlncmF0aW9ucyBzYXZlZC4uLlwiKTtcclxuICAgIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENhbiBiZSByZW1vdmVkIGluIHRoZSBmdXR1cmUsIGJ1dCBJIGhhdmVuJ3QgeWV0IGRlY2lkZWQgd2lsbCBpdCBiZSBkb25lIGluIDEuMCBvciBsYXRlci5cclxuICovXHJcbmZ1bmN0aW9uIE1pZ3JhdGVTaGVsbENvbW1hbmRzT2JqZWN0VG9BcnJheShwbHVnaW46IFNDX1BsdWdpbikge1xyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHNoZWxsIGNvbW1hbmRzJyBjb250YWluZXIgaXMgYW4gb2JqZWN0LlxyXG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHBsdWdpbi5zZXR0aW5ncy5zaGVsbF9jb21tYW5kcykpIHtcclxuICAgICAgICAvLyBJdCBpcyBhbiBvYmplY3QuIEl0IG5lZWRzIHRvIGJlIGNoYW5nZWQgdG8gYW4gYXJyYXkgaW4gb3JkZXIgdG8gYWxsb3cgY3VzdG9tIG9yZGVyaW5nLlxyXG4gICAgICAgIGNvbnN0IHNoZWxsX2NvbW1hbmRzX2FycmF5OiBTaGVsbENvbW1hbmRDb25maWd1cmF0aW9uW10gPSBbXTtcclxuICAgICAgICBmb3IgKGNvbnN0IHNoZWxsX2NvbW1hbmRfaWQgb2YgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMocGx1Z2luLnNldHRpbmdzLnNoZWxsX2NvbW1hbmRzKSkgeyAvLyBSZW1lbWJlciB0aGF0IHBsdWdpbi5zZXR0aW5ncy5zaGVsbF9jb21tYW5kcyBpcyBhbiBvYmplY3QgaGVyZSEgTm90IGFuIGFycmF5ICh5ZXQpLlxyXG4gICAgICAgICAgICAvLyBAdHMtaWdub3JlIEkgZG9uJ3Qga25vdyB3aHkgVHlwZVNjcmlwdCB0aGlua3MgdGhlIGluZGV4IGlzIGluY29ycmVjdC5cclxuICAgICAgICAgICAgY29uc3Qgc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uOiBTaGVsbENvbW1hbmRDb25maWd1cmF0aW9uID0gcGx1Z2luLnNldHRpbmdzLnNoZWxsX2NvbW1hbmRzW3NoZWxsX2NvbW1hbmRfaWRdO1xyXG5cclxuICAgICAgICAgICAgLy8gQXNzaWduICdpZCcgdG8gU2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbiBiZWNhdXNlIGl0IGRpZCBub3QgY29udGFpbiBpdCBiZWZvcmUgdGhpcyBtaWdyYXRpb24uXHJcbiAgICAgICAgICAgIHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbi5pZCA9IHNoZWxsX2NvbW1hbmRfaWQ7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgdGhlIFNoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb24gdG8gdGhlIG5ldyBhcnJheSBjb250YWluZXIuXHJcbiAgICAgICAgICAgIHNoZWxsX2NvbW1hbmRzX2FycmF5LnB1c2goc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFJlcGxhY2UgdGhlIG9sZCBvYmplY3QgY29udGFpbmVyIHdpdGggdGhlIG5ldyBhcnJheSBjb250YWluZXIuXHJcbiAgICAgICAgcGx1Z2luLnNldHRpbmdzLnNoZWxsX2NvbW1hbmRzID0gc2hlbGxfY29tbWFuZHNfYXJyYXk7IC8vIE5vdyBwbHVnaW4uc2V0dGluZ3Muc2hlbGxfY29tbWFuZHMgY2hhbmdlcyB0byBiZSBhbiBhcnJheSBpbnN0ZWFkIG9mIGFuIG9iamVjdC5cclxuXHJcbiAgICAgICAgcmV0dXJuIHRydWU7IC8vIFNhdmUgdGhlIGNoYW5nZXMuXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFRoZSBjb250YWluZXIgaXMgYWxyZWFkeSBtaWdyYXRlZC5cclxuICAgICAgICByZXR1cm4gZmFsc2U7IC8vIE5vIG5lZWQgdG8gc2F2ZSBhbnl0aGluZy5cclxuICAgIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENhbiBiZSByZW1vdmVkIGluIDEuMC4wLlxyXG4gKlxyXG4gKiBAcGFyYW0gcGx1Z2luXHJcbiAqIEBjb25zdHJ1Y3RvclxyXG4gKi9cclxuZnVuY3Rpb24gTWlncmF0ZUNvbW1hbmRzVG9TaGVsbENvbW1hbmRzKHBsdWdpbjogU0NfUGx1Z2luKSB7XHJcbiAgICBpZiAodW5kZWZpbmVkID09PSBwbHVnaW4uc2V0dGluZ3MuY29tbWFuZHMpIHtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgICBjb25zdCBjb3VudF9zaGVsbF9jb21tYW5kcyA9IHBsdWdpbi5zZXR0aW5ncy5jb21tYW5kcy5sZW5ndGg7XHJcbiAgICBsZXQgc2F2ZSA9IGZhbHNlO1xyXG4gICAgaWYgKDAgPCBjb3VudF9zaGVsbF9jb21tYW5kcykge1xyXG4gICAgICAgIGxldCBjb3VudF9lbXB0eV9jb21tYW5kcyA9IDA7IC8vIEEgY291bnRlciBmb3IgZW1wdHkgb3IgbnVsbCBjb21tYW5kc1xyXG4gICAgICAgIGRlYnVnTG9nKFwic2V0dGluZ3MuY29tbWFuZHMgaXMgbm90IGVtcHR5LCB3aWxsIG1pZ3JhdGUgXCIgKyBjb3VudF9zaGVsbF9jb21tYW5kcyArIFwiIGNvbW1hbmRzIHRvIHNldHRpbmdzLnNoZWxsX2NvbW1hbmRzLlwiKTtcclxuICAgICAgICBmb3IgKGNvbnN0IHNoZWxsX2NvbW1hbmRfaWQgaW4gcGx1Z2luLnNldHRpbmdzLmNvbW1hbmRzKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHNoZWxsX2NvbW1hbmQgPSBwbHVnaW4uc2V0dGluZ3MuY29tbWFuZHNbc2hlbGxfY29tbWFuZF9pZF07XHJcbiAgICAgICAgICAgIC8vIEVuc3VyZSB0aGF0IHRoZSBjb21tYW5kIGlzIG5vdCBlbXB0eS4gSnVzdCBpbiBjYXNlLlxyXG4gICAgICAgICAgICBpZiAobnVsbCA9PT0gc2hlbGxfY29tbWFuZCB8fCAwID09PSBzaGVsbF9jb21tYW5kLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhlIGNvbW1hbmQgaXMgZW1wdHlcclxuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiTWlncmF0aW9uIGZhaWx1cmUgZm9yIHNoZWxsIGNvbW1hbmQgI1wiICsgc2hlbGxfY29tbWFuZF9pZCArIFwiOiBUaGUgb3JpZ2luYWwgc2hlbGwgY29tbWFuZCBzdHJpbmcgaXMgZW1wdHksIHNvIGl0IGNhbm5vdCBiZSBtaWdyYXRlZC5cIik7XHJcbiAgICAgICAgICAgICAgICBjb3VudF9lbXB0eV9jb21tYW5kcysrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGVsc2UgaWYgKHVuZGVmaW5lZCAhPT0gcGx1Z2luLmdldFNoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb25JbmRleChzaGVsbF9jb21tYW5kX2lkKSkge1xyXG4gICAgICAgICAgICAgICAgLy8gQSBjb21tYW5kIHdpdGggdGhlIHNhbWUgaWQgYWxyZWFkeSBleGlzdHNcclxuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiTWlncmF0aW9uIGZhaWx1cmUgZm9yIHNoZWxsIGNvbW1hbmQgI1wiICsgc2hlbGxfY29tbWFuZF9pZCArIFwiOiBBIHNoZWxsIGNvbW1hbmQgd2l0aCBzYW1lIElEIGFscmVhZHkgZXhpc3RzIGluIHNldHRpbmdzLnNoZWxsX2NvbW1hbmRzLlwiKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIEFsbCBPSywgbWlncmF0ZS5cclxuICAgICAgICAgICAgICAgIHBsdWdpbi5zZXR0aW5ncy5zaGVsbF9jb21tYW5kcy5wdXNoKG5ld1NoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb24oc2hlbGxfY29tbWFuZF9pZCwgc2hlbGxfY29tbWFuZCkpOyAvLyBDcmVhdGVzIGEgc2hlbGwgY29tbWFuZCB3aXRoIGRlZmF1bHQgdmFsdWVzIGFuZCBkZWZpbmVzIHRoZSBjb21tYW5kIGZvciBpdC5cclxuICAgICAgICAgICAgICAgIGRlbGV0ZSBwbHVnaW4uc2V0dGluZ3MuY29tbWFuZHNbc2hlbGxfY29tbWFuZF9pZF07IC8vIExlYXZlcyBhIG51bGwgaW4gcGxhY2UsIGJ1dCB3ZSBjYW4gZGVhbCB3aXRoIGl0IGJ5IGRlbGV0aW5nIHRoZSB3aG9sZSBhcnJheSBpZiBpdCBnZXRzIGVtcHR5LlxyXG4gICAgICAgICAgICAgICAgY291bnRfZW1wdHlfY29tbWFuZHMrKzsgLy8gQWNjb3VudCB0aGUgbnVsbCBnZW5lcmF0ZWQgb24gdGhlIHByZXZpb3VzIGxpbmUuXHJcbiAgICAgICAgICAgICAgICBzYXZlID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiTWlncmF0ZWQgc2hlbGwgY29tbWFuZCAjXCIgKyBzaGVsbF9jb21tYW5kX2lkICsgXCI6IFwiICsgc2hlbGxfY29tbWFuZCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKGNvdW50X2VtcHR5X2NvbW1hbmRzID09PSBjb3VudF9zaGVsbF9jb21tYW5kcykge1xyXG4gICAgICAgICAgICAvLyBUaGUgd2hvbGUgY29tbWFuZHMgYXJyYXkgbm93IGNvbnRhaW5zIG9ubHkgZW1wdHkvbnVsbCBjb21tYW5kcy5cclxuICAgICAgICAgICAgLy8gRGVsZXRlIGl0LlxyXG4gICAgICAgICAgICBkZWxldGUgcGx1Z2luLnNldHRpbmdzLmNvbW1hbmRzO1xyXG4gICAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgICAgZGVidWdMb2coXCJzZXR0aW5ncy5jb21tYW5kcyBpcyBlbXB0eSwgc28gbm8gbmVlZCB0byBtaWdyYXRlIGNvbW1hbmRzLiBHb29kIHRoaW5nISA6KVwiKTtcclxuICAgIH1cclxuICAgIHJldHVybiBzYXZlO1xyXG59XHJcblxyXG4vKipcclxuICogVGhpcyBpcyBhIGdlbmVyYWwgbWlncmF0b3IgdGhhdCBhZGRzIG5ldywgbWlzc2luZyBwcm9wZXJ0aWVzIHRvIFNoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb24gb2JqZWN0cy4gVGhpcyBpcyBub3QgdGllZCB0byBhbnkgc3BlY2lmaWMgdmVyc2lvbiB1cGRhdGUsIHVubGlrZSBNaWdyYXRlQ29tbWFuZHNUb1NoZWxsQ29tbWFuZHMoKS5cclxuICpcclxuICogQHBhcmFtIHBsdWdpblxyXG4gKiBAY29uc3RydWN0b3JcclxuICovXHJcbmZ1bmN0aW9uIEVuc3VyZVNoZWxsQ29tbWFuZHNIYXZlQWxsRmllbGRzKHBsdWdpbjogU0NfUGx1Z2luKSB7XHJcbiAgICBsZXQgc2F2ZSA9IGZhbHNlO1xyXG4gICAgY29uc3Qgc2hlbGxfY29tbWFuZF9kZWZhdWx0X2NvbmZpZ3VyYXRpb24gPSBuZXdTaGVsbENvbW1hbmRDb25maWd1cmF0aW9uKFwibm8taWRcIik7IC8vIFVzZSBhIGR1bW15IGlkIGhlcmUsIGJlY2F1c2Ugc29tZXRoaW5nIG5lZWRzIHRvIGJlIHVzZWQuIFRoaXMgaWQgc2hvdWxkIG5ldmVyIGVuZCB1cCBiZWluZyB1c2VkIGluIHByYWN0aWNlLlxyXG4gICAgY29uc3Qgc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9ucyA9IHBsdWdpbi5zZXR0aW5ncy5zaGVsbF9jb21tYW5kcztcclxuICAgIGZvciAoY29uc3Qgc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uIG9mIHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbnMpIHtcclxuICAgICAgICBmb3IgKGNvbnN0IHByb3BlcnR5X25hbWUgaW4gc2hlbGxfY29tbWFuZF9kZWZhdWx0X2NvbmZpZ3VyYXRpb24pIHtcclxuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZSBwcm9wZXJ0eV9kZWZhdWx0X3ZhbHVlIGNhbiBoYXZlIChhbG1vc3QpIHdoYXRldmVyIGRhdGF0eXBlXHJcbiAgICAgICAgICAgIGNvbnN0IHByb3BlcnR5X2RlZmF1bHRfdmFsdWUgPSBzaGVsbF9jb21tYW5kX2RlZmF1bHRfY29uZmlndXJhdGlvbltwcm9wZXJ0eV9uYW1lXTtcclxuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxyXG4gICAgICAgICAgICBpZiAodW5kZWZpbmVkID09PSBzaGVsbF9jb21tYW5kX2NvbmZpZ3VyYXRpb25bcHJvcGVydHlfbmFtZV0gJiYgcHJvcGVydHlfbmFtZSAhPT0gXCJpZFwiKSB7IC8vIFRoZSBcImlkXCIgY2hlY2sgaXMganVzdCBpbiBjYXNlIHRoYXQgTWlncmF0ZVNoZWxsQ29tbWFuZHNPYmplY3RUb0FycmF5KCkgd291bGQgbm90IGhhdmUgYWRkZWQgdGhlIFwiaWRcIiBwcm9wZXJ0eSwgaW4gd2hpY2ggY2FzZSB0aGUgZHVtbXkgXCJuby1pZFwiIGlkIHNob3VsZCBub3QgYmUgYWNjaWRlbnRhbGx5IGFzc2lnbmVkIHRvIHRoZSBzaGVsbCBjb21tYW5kLlxyXG4gICAgICAgICAgICAgICAgLy8gVGhpcyBzaGVsbCBjb21tYW5kIGRvZXMgbm90IGhhdmUgdGhpcyBwcm9wZXJ0eS5cclxuICAgICAgICAgICAgICAgIC8vIEFkZCB0aGUgcHJvcGVydHkgdG8gdGhlIHNoZWxsIGNvbW1hbmQgYW5kIHVzZSBhIGRlZmF1bHQgdmFsdWUuXHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkVuc3VyZVNoZWxsQ29tbWFuZHNIYXZlQWxsRmllbGRzKCk6IFNoZWxsIGNvbW1hbmQgI1wiICsgc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uLmlkICsgXCIgZG9lcyBub3QgaGF2ZSBhIHByb3BlcnR5ICdcIiArIHByb3BlcnR5X25hbWUgKyBcIicuIFdpbGwgY3JlYXRlIHRoZSBwcm9wZXJ0eSBhbmQgYXNzaWduIGEgZGVmYXVsdCB2YWx1ZSAnXCIgKyBwcm9wZXJ0eV9kZWZhdWx0X3ZhbHVlICsgXCInLlwiKTtcclxuICAgICAgICAgICAgICAgIC8vIEB0cy1pZ25vcmVcclxuICAgICAgICAgICAgICAgIHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbltwcm9wZXJ0eV9uYW1lXSA9IHByb3BlcnR5X2RlZmF1bHRfdmFsdWU7XHJcbiAgICAgICAgICAgICAgICBzYXZlID0gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBzYXZlO1xyXG59XHJcblxyXG5mdW5jdGlvbiBFbnN1cmVDdXN0b21WYXJpYWJsZXNIYXZlQWxsRmllbGRzKHBsdWdpbjogU0NfUGx1Z2luKSB7XHJcbiAgICBsZXQgc2F2ZSA9IGZhbHNlO1xyXG4gICAgY29uc3QgY3VzdG9tVmFyaWFibGVNb2RlbCA9IGdldE1vZGVsPEN1c3RvbVZhcmlhYmxlTW9kZWw+KEN1c3RvbVZhcmlhYmxlTW9kZWwubmFtZSk7XHJcbiAgICBjb25zdCBjdXN0b21WYXJpYWJsZURlZmF1bHRDb25maWd1cmF0aW9uOiBDdXN0b21WYXJpYWJsZUNvbmZpZ3VyYXRpb24gPSBjdXN0b21WYXJpYWJsZU1vZGVsLmdldERlZmF1bHRDb25maWd1cmF0aW9uKCk7XHJcbiAgICBsZXQgY3VzdG9tVmFyaWFibGVDb25maWd1cmF0aW9uOiBDdXN0b21WYXJpYWJsZUNvbmZpZ3VyYXRpb247XHJcbiAgICBmb3IgKGN1c3RvbVZhcmlhYmxlQ29uZmlndXJhdGlvbiBvZiBwbHVnaW4uc2V0dGluZ3MuY3VzdG9tX3ZhcmlhYmxlcykge1xyXG4gICAgICAgIGZvciAoY29uc3QgcHJvcGVydHlOYW1lIGluIGN1c3RvbVZhcmlhYmxlRGVmYXVsdENvbmZpZ3VyYXRpb24pIHtcclxuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZSBwcm9wZXJ0eURlZmF1bHRWYWx1ZSBjYW4gaGF2ZSAoYWxtb3N0KSB3aGF0ZXZlciBkYXRhdHlwZVxyXG4gICAgICAgICAgICBjb25zdCBwcm9wZXJ0eURlZmF1bHRWYWx1ZSA9IGN1c3RvbVZhcmlhYmxlRGVmYXVsdENvbmZpZ3VyYXRpb25bcHJvcGVydHlOYW1lXTtcclxuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxyXG4gICAgICAgICAgICBpZiAodW5kZWZpbmVkID09PSBjdXN0b21WYXJpYWJsZUNvbmZpZ3VyYXRpb25bcHJvcGVydHlOYW1lXSkge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhpcyBjdXN0b20gdmFyaWFibGUgZG9lcyBub3QgaGF2ZSB0aGlzIHByb3BlcnR5LlxyXG4gICAgICAgICAgICAgICAgLy8gQWRkIHRoZSBwcm9wZXJ0eSB0byBpdCBhbmQgdXNlIGEgZGVmYXVsdCB2YWx1ZS5cclxuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiRW5zdXJlQ3VzdG9tVmFyaWFibGVzSGF2ZUFsbEZpZWxkcygpOiBDdXN0b20gdmFyaWFibGUgI1wiICsgY3VzdG9tVmFyaWFibGVDb25maWd1cmF0aW9uLmlkICsgXCIgZG9lcyBub3QgaGF2ZSBhIHByb3BlcnR5ICdcIiArIHByb3BlcnR5TmFtZSArIFwiJy4gV2lsbCBjcmVhdGUgdGhlIHByb3BlcnR5IGFuZCBhc3NpZ24gYSBkZWZhdWx0IHZhbHVlICdcIiArIHByb3BlcnR5RGVmYXVsdFZhbHVlICsgXCInLlwiKTtcclxuICAgICAgICAgICAgICAgIC8vIEB0cy1pZ25vcmVcclxuICAgICAgICAgICAgICAgIGN1c3RvbVZhcmlhYmxlQ29uZmlndXJhdGlvbltwcm9wZXJ0eU5hbWVdID0gcHJvcGVydHlEZWZhdWx0VmFsdWU7XHJcbiAgICAgICAgICAgICAgICBzYXZlID0gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBzYXZlO1xyXG59XHJcblxyXG4vKipcclxuICogVGhpcyBpcyBhIGdlbmVyYWwgbWlncmF0b3IgdGhhdCBhZGRzIG5ldywgbWlzc2luZyBwcm9wZXJ0aWVzIHRvIHRoZSBtYWluIHNldHRpbmdzIG9iamVjdC4gVGhpcyBpcyBub3QgdGllZCB0byBhbnkgc3BlY2lmaWMgdmVyc2lvbiB1cGRhdGUsIHVubGlrZSBNaWdyYXRlQ29tbWFuZHNUb1NoZWxsQ29tbWFuZHMoKS5cclxuICpcclxuICogQHBhcmFtIHBsdWdpblxyXG4gKiBAY29uc3RydWN0b3JcclxuICovXHJcbmZ1bmN0aW9uIEVuc3VyZU1haW5GaWVsZHNFeGlzdChwbHVnaW46IFNDX1BsdWdpbikge1xyXG4gICAgbGV0IGhhc19taXNzaW5nX2ZpZWxkcyA9IGZhbHNlO1xyXG4gICAgY29uc3Qgc2V0dGluZ3MgPSBwbHVnaW4uc2V0dGluZ3M7XHJcbiAgICBjb25zdCBkZWZhdWx0X3NldHRpbmdzID0gZ2V0RGVmYXVsdFNldHRpbmdzKGZhbHNlKTtcclxuICAgIGZvciAoY29uc3QgcHJvcGVydHlfbmFtZSBpbiBkZWZhdWx0X3NldHRpbmdzKSB7XHJcbiAgICAgICAgLy8gQHRzLWlnbm9yZVxyXG4gICAgICAgIGlmICh1bmRlZmluZWQgPT09IHNldHRpbmdzW3Byb3BlcnR5X25hbWVdKSB7XHJcbiAgICAgICAgICAgIC8vIFRoZSBzZXR0aW5ncyBvYmplY3QgZG9lcyBub3QgaGF2ZSB0aGlzIHByb3BlcnR5LlxyXG4gICAgICAgICAgICAvLyBAdHMtaWdub3JlIHByb3BlcnR5X2RlZmF1bHRfdmFsdWUgY2FuIGhhdmUgKGFsbW9zdCkgd2hhdGV2ZXIgZGF0YXR5cGVcclxuICAgICAgICAgICAgY29uc3QgcHJvcGVydHlfZGVmYXVsdF92YWx1ZSA9IGRlZmF1bHRfc2V0dGluZ3NbcHJvcGVydHlfbmFtZV07XHJcbiAgICAgICAgICAgIGRlYnVnTG9nKFwiRW5zdXJlTWFpbkZpZWxkc0V4aXN0KCk6IE1haW4gc2V0dGluZ3MgZG9lcyBub3QgaGF2ZSBwcm9wZXJ0eSAnXCIgKyBwcm9wZXJ0eV9uYW1lICsgXCInLiBXaWxsIGxhdGVyIGNyZWF0ZSB0aGUgcHJvcGVydHkgYW5kIGFzc2lnbiBhIGRlZmF1bHQgdmFsdWUgJ1wiICsgcHJvcGVydHlfZGVmYXVsdF92YWx1ZSArIFwiJy5cIik7XHJcbiAgICAgICAgICAgIGhhc19taXNzaW5nX2ZpZWxkcyA9IHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChoYXNfbWlzc2luZ19maWVsZHMpIHtcclxuICAgICAgICBkZWJ1Z0xvZyhcIkVuc3VyZU1haW5GaWVsZHNFeGlzdCgpOiBEb2luZyB0aGUgYWJvdmUtbWVudGlvbmVkIG5ldyBmaWVsZCBjcmVhdGlvbnMuLi5cIik7XHJcbiAgICAgICAgcGx1Z2luLnNldHRpbmdzID0gY29tYmluZU9iamVjdHMoZGVmYXVsdF9zZXR0aW5ncywgcGx1Z2luLnNldHRpbmdzKTtcclxuICAgICAgICBkZWJ1Z0xvZyhcIkVuc3VyZU1haW5GaWVsZHNFeGlzdCgpOiBEb25lLlwiKTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTsgLy8gU2F2ZSB0aGUgY2hhbmdlc1xyXG4gICAgfVxyXG5cclxuICAgIGRlYnVnTG9nKFwiRW5zdXJlTWFpbkZpZWxkc0V4aXN0KCk6IE5vIG5ldyBmaWVsZHMgdG8gY3JlYXRlLCBhbGwgb2suXCIpO1xyXG4gICAgcmV0dXJuIGZhbHNlOyAvLyBOb3RoaW5nIHRvIHNhdmUuXHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDYW4gYmUgcmVtb3ZlZCBpbiAxLjAuMC5cclxuICpcclxuICogQHBhcmFtIHBsdWdpblxyXG4gKiBAY29uc3RydWN0b3JcclxuICovXHJcbmZ1bmN0aW9uIE1pZ3JhdGVTaGVsbENvbW1hbmRUb1BsYXRmb3JtcyhwbHVnaW46IFNDX1BsdWdpbikge1xyXG4gICAgbGV0IHNhdmUgPSBmYWxzZTtcclxuICAgIGZvciAoY29uc3Qgc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uIG9mIHBsdWdpbi5zZXR0aW5ncy5zaGVsbF9jb21tYW5kcykge1xyXG4gICAgICAgIGlmICh1bmRlZmluZWQgIT09IHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbi5zaGVsbF9jb21tYW5kKSB7XHJcbiAgICAgICAgICAgIC8vIFRoZSBzaGVsbCBjb21tYW5kIHNob3VsZCBiZSBtaWdyYXRlZC5cclxuICAgICAgICAgICAgaWYgKHVuZGVmaW5lZCA9PT0gc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uLnBsYXRmb3JtX3NwZWNpZmljX2NvbW1hbmRzIHx8IHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbi5wbGF0Zm9ybV9zcGVjaWZpY19jb21tYW5kcy5kZWZhdWx0ID09PSBcIlwiKSB7XHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIk1pZ3JhdGluZyBzaGVsbCBjb21tYW5kICNcIiArIHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbi5pZCArIFwiOiBzaGVsbF9jb21tYW5kIHN0cmluZyB3aWxsIGJlIG1vdmVkIHRvIHBsYXRmb3Jtcy5kZWZhdWx0OiBcIiArIHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbi5zaGVsbF9jb21tYW5kKTtcclxuICAgICAgICAgICAgICAgIHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbi5wbGF0Zm9ybV9zcGVjaWZpY19jb21tYW5kcyA9IHtcclxuICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OiBzaGVsbF9jb21tYW5kX2NvbmZpZ3VyYXRpb24uc2hlbGxfY29tbWFuZCxcclxuICAgICAgICAgICAgICAgIH07XHJcbiAgICAgICAgICAgICAgICBkZWxldGUgc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uLnNoZWxsX2NvbW1hbmQ7XHJcbiAgICAgICAgICAgICAgICBzYXZlID0gdHJ1ZTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiTWlncmF0aW9uIGZhaWx1cmUgZm9yIHNoZWxsIGNvbW1hbmQgI1wiICsgc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uLmlkICsgXCI6IHBsYXRmb3JtcyBleGlzdHMgYWxyZWFkeS5cIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gc2F2ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENhbiBiZSByZW1vdmVkIGluIDEuMC4wLlxyXG4gKlxyXG4gKiBAcGFyYW0gcGx1Z2luXHJcbiAqIEBjb25zdHJ1Y3RvclxyXG4gKi9cclxuZnVuY3Rpb24gRGVsZXRlRW1wdHlDb21tYW5kc0ZpZWxkKHBsdWdpbjogU0NfUGx1Z2luKSB7XHJcbiAgICBsZXQgc2F2ZSA9IGZhbHNlO1xyXG4gICAgaWYgKHVuZGVmaW5lZCAhPT0gcGx1Z2luLnNldHRpbmdzLmNvbW1hbmRzKSB7XHJcbiAgICAgICAgaWYgKHBsdWdpbi5zZXR0aW5ncy5jb21tYW5kcy5sZW5ndGggPT09IDApIHtcclxuICAgICAgICAgICAgZGVsZXRlIHBsdWdpbi5zZXR0aW5ncy5jb21tYW5kcztcclxuICAgICAgICAgICAgc2F2ZSA9IHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIHNhdmU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQZXJtYW5lbnQsIGRvIG5vdCByZW1vdmUuXHJcbiAqXHJcbiAqIEBwYXJhbSBwbHVnaW5cclxuICovXHJcbmZ1bmN0aW9uIGJhY2t1cFNldHRpbmdzRmlsZShwbHVnaW46IFNDX1BsdWdpbikge1xyXG4gICAgLy8gcGx1Z2luLmFwcC5maWxlTWFuYWdlci5cclxuICAgIC8vIEB0cy1pZ25vcmVcclxuICAgIGNvbnN0IGN1cnJlbnRfc2V0dGluZ3NfdmVyc2lvbiA9IChwbHVnaW4uc2V0dGluZ3Muc2V0dGluZ3NfdmVyc2lvbiA9PT0gXCJwcmlvci10by0wLjcuMFwiKSA/IFwiMC54XCIgOiBwbHVnaW4uc2V0dGluZ3Muc2V0dGluZ3NfdmVyc2lvbjtcclxuICAgIGNvbnN0IHBsdWdpbl9wYXRoID0gZ2V0UGx1Z2luQWJzb2x1dGVQYXRoKHBsdWdpbik7XHJcbiAgICBjb25zdCBzZXR0aW5nc19maWxlX3BhdGggPSBwYXRoLmpvaW4ocGx1Z2luX3BhdGgsIFwiZGF0YS5qc29uXCIpO1xyXG4gICAgY29uc3QgYmFja3VwX2ZpbGVfcGF0aF93aXRob3V0X2V4dGVuc2lvbiA9IHBhdGguam9pbihwbHVnaW5fcGF0aCwgXCJkYXRhLWJhY2t1cC12ZXJzaW9uLVwiICsgY3VycmVudF9zZXR0aW5nc192ZXJzaW9uICsgXCItYmVmb3JlLXVwZ3JhZGluZy10by1cIiArIFNDX1BsdWdpbi5TZXR0aW5nc1ZlcnNpb24pO1xyXG5cclxuICAgIC8vIENoZWNrIHRoYXQgdGhlIGN1cnJlbnQgc2V0dGluZ3MgZmlsZSBjYW4gYmUgZm91bmQuXHJcbiAgICBpZiAoIWZzLmV4aXN0c1N5bmMoc2V0dGluZ3NfZmlsZV9wYXRoKSkge1xyXG4gICAgICAgIC8vIE5vdCBmb3VuZC4gUHJvYmFibHkgdGhlIHZhdWx0IHVzZXMgYSBkaWZmZXJlbnQgY29uZmlnIGZvbGRlciB0aGFuIC5vYnNpZGlhbi5cclxuICAgICAgICBkZWJ1Z0xvZyhcImJhY2t1cFNldHRpbmdzRmlsZSgpOiBDYW5ub3QgZmluZCBkYXRhLmpzb25cIik7XHJcbiAgICAgICAgcGx1Z2luLm5ld0Vycm9yKFwiU2hlbGwgY29tbWFuZHM6IENhbm5vdCBjcmVhdGUgYSBiYWNrdXAgb2YgY3VycmVudCBzZXR0aW5ncyBmaWxlLCBiZWNhdXNlIGRhdGEuanNvbiBpcyBub3QgZm91bmQuXCIpO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgYmFja3VwX2ZpbGVfcGF0aCA9IGJhY2t1cF9maWxlX3BhdGhfd2l0aG91dF9leHRlbnNpb24gKyBcIi5qc29uXCI7XHJcbiAgICBsZXQgcnVubmluZ19udW1iZXIgPSAxO1xyXG4gICAgd2hpbGUgKGZzLmV4aXN0c1N5bmMoYmFja3VwX2ZpbGVfcGF0aCkpIHtcclxuICAgICAgICBydW5uaW5nX251bWJlcisrOyAvLyBUaGUgZmlyc3QgbnVtYmVyIHdpbGwgYmUgMi5cclxuICAgICAgICBiYWNrdXBfZmlsZV9wYXRoID0gYmFja3VwX2ZpbGVfcGF0aF93aXRob3V0X2V4dGVuc2lvbiArIFwiLVwiICsgcnVubmluZ19udW1iZXIgKyBcIi5qc29uXCI7XHJcbiAgICAgICAgaWYgKHJ1bm5pbmdfbnVtYmVyID49IDEwMDApIHtcclxuICAgICAgICAgICAgLy8gVGhlcmUgaXMgc29tZSBwcm9ibGVtIHdpdGggZGV0ZWN0aW5nIGV4aXN0aW5nL2luZXhpc3RpbmcgZmlsZXMuXHJcbiAgICAgICAgICAgIC8vIFByZXZlbnQgaGFuZ2luZyB0aGUgcHJvZ3JhbSBpbiBhbiBldGVybmFsIGxvb3AuXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImJhY2t1cFNldHRpbmdzRmlsZSgpOiBFdGVybmFsIGxvb3AgZGV0ZWN0ZWQuXCIpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIGZzLmNvcHlGaWxlU3luYyhzZXR0aW5nc19maWxlX3BhdGgsIGJhY2t1cF9maWxlX3BhdGgpO1xyXG59XHJcblxyXG4vLyBUT0RPOiBBZGQgbWlncmF0aW9uOiBzaGVsbCBjb21tYW5kIHZhcmlhYmxlX2RlZmF1bHRfdmFsdWVzOiBpZiB0eXBlIGlzIFwic2hvdy1lcnJvcnNcIiwgY2hhbmdlIGl0IHRvIFwiaW5oZXJpdFwiLCBidXQgb25seSBpZiBvbGQgc2V0dGluZ3MgdmVyc2lvbiB3YXMgYmVsb3cgMTguIiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0lQbGF0Zm9ybVNwZWNpZmljU3RyaW5nLCBQbGF0Zm9ybUlkLCBQbGF0Zm9ybU5hbWVzfSBmcm9tIFwiLi4vU0NfTWFpblNldHRpbmdzXCI7XHJcbmltcG9ydCB7ZXh0cmFjdEZpbGVOYW1lLCBnZXRPcGVyYXRpbmdTeXN0ZW19IGZyb20gXCIuLi8uLi9Db21tb25cIjtcclxuaW1wb3J0IHtnZXRVc2Vyc0RlZmF1bHRTaGVsbCwgUGxhdGZvcm1TaGVsbHN9IGZyb20gXCIuLi8uLi9TaGVsbFwiO1xyXG5pbXBvcnQge1NldHRpbmd9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi8uLi9tYWluXCI7XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlU2hlbGxTZWxlY3Rpb25GaWVsZChwbHVnaW46IFNDX1BsdWdpbiwgY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50LCBzaGVsbHM6IElQbGF0Zm9ybVNwZWNpZmljU3RyaW5nLCBpc19nbG9iYWxfc2V0dGluZ3M6IGJvb2xlYW4pIHtcclxuICAgIGxldCBwbGF0Zm9ybV9pZDogUGxhdGZvcm1JZDtcclxuICAgIGZvciAocGxhdGZvcm1faWQgaW4gUGxhdGZvcm1OYW1lcykge1xyXG4gICAgICAgIGNvbnN0IHBsYXRmb3JtX25hbWUgPSBQbGF0Zm9ybU5hbWVzW3BsYXRmb3JtX2lkXTtcclxuICAgICAgICBsZXQgb3B0aW9uczogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcclxuICAgICAgICBpZiAoaXNfZ2xvYmFsX3NldHRpbmdzKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRfc3lzdGVtX2RlZmF1bHQgPSAoZ2V0T3BlcmF0aW5nU3lzdGVtKCkgPT09IHBsYXRmb3JtX2lkKSA/IFwiIChcIiArIGV4dHJhY3RGaWxlTmFtZShnZXRVc2Vyc0RlZmF1bHRTaGVsbCgpKSArIFwiKVwiIDogXCJcIjtcclxuICAgICAgICAgICAgb3B0aW9ucyA9IHtcImRlZmF1bHRcIjogXCJVc2Ugc3lzdGVtIGRlZmF1bHRcIiArIGN1cnJlbnRfc3lzdGVtX2RlZmF1bHR9O1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIG9wdGlvbnMgPSB7XCJkZWZhdWx0XCI6IFwiVXNlIGRlZmF1bHRcIn07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGZvciAoY29uc3Qgc2hlbGxfcGF0aCBpbiBQbGF0Zm9ybVNoZWxsc1twbGF0Zm9ybV9pZF0pIHtcclxuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZSAvLyBUT0RPOiBHZXQgcmlkIG9mIHRoZXNlIHR3byB0cy1pZ25vcmVzLlxyXG4gICAgICAgICAgICBjb25zdCBzaGVsbF9uYW1lID0gUGxhdGZvcm1TaGVsbHNbcGxhdGZvcm1faWRdW3NoZWxsX3BhdGhdO1xyXG4gICAgICAgICAgICAvLyBAdHMtaWdub3JlXHJcbiAgICAgICAgICAgIG9wdGlvbnNbc2hlbGxfcGF0aF0gPSBzaGVsbF9uYW1lO1xyXG4gICAgICAgIH1cclxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgLnNldE5hbWUocGxhdGZvcm1fbmFtZSArIChpc19nbG9iYWxfc2V0dGluZ3MgPyBcIiBkZWZhdWx0IHNoZWxsXCIgOiBcIiBzaGVsbFwiKSlcclxuICAgICAgICAgICAgLnNldERlc2MoKGlzX2dsb2JhbF9zZXR0aW5ncyA/IFwiQ2FuIGJlIG92ZXJyaWRkZW4gYnkgZWFjaCBzaGVsbCBjb21tYW5kLiBcIiA6IFwiXCIpICsgKFwid2luMzJcIiA9PT0gcGxhdGZvcm1faWQgPyBcIlBvd2Vyc2hlbGwgaXMgcmVjb21tZW5kZWQgb3ZlciBjbWQuZXhlLCBiZWNhdXNlIHRoaXMgcGx1Z2luIGRvZXMgbm90IHN1cHBvcnQgZXNjYXBpbmcgdmFyaWFibGVzIGluIENNRC5cIiA6IFwiXCIpKVxyXG4gICAgICAgICAgICAuYWRkRHJvcGRvd24oZHJvcGRvd24gPT4gZHJvcGRvd25cclxuICAgICAgICAgICAgICAgIC5hZGRPcHRpb25zKG9wdGlvbnMpXHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUoc2hlbGxzW3BsYXRmb3JtX2lkXSA/PyBcImRlZmF1bHRcIilcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZSgoKF9wbGF0Zm9ybV9pZDogUGxhdGZvcm1JZCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBhc3luYyAodmFsdWU6IHN0cmluZykgPT4geyAvLyBOZWVkIHRvIHVzZSBhIG5lc3RlZCBmdW5jdGlvbiBzbyB0aGF0IHBsYXRmb3JtX2lkIGNhbiBiZSBzdG9yZWQgc3RhdGljYWxseSwgb3RoZXJ3aXNlIGl0IHdvdWxkIGFsd2F5cyBiZSBcIndpbjMyXCIgKHRoZSBsYXN0IHZhbHVlIG9mIFBsYXRmb3JtTmFtZXMpLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoXCJkZWZhdWx0XCIgPT09IHZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBXaGVuIHVzaW5nIGRlZmF1bHQgc2hlbGwsIHRoZSB2YWx1ZSBzaG91bGQgYmUgdW5zZXQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgc2hlbGxzW19wbGF0Zm9ybV9pZF07XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOb3JtYWwgY2FzZTogYXNzaWduIHRoZSBzaGVsbCB2YWx1ZS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWxsc1tfcGxhdGZvcm1faWRdID0gdmFsdWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgcGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgICAgIH07XHJcbiAgICAgICAgICAgICAgICB9KShwbGF0Zm9ybV9pZCkpXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uLy4uL21haW5cIjtcclxuaW1wb3J0IHtUZXh0QXJlYUNvbXBvbmVudH0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcblxyXG4vKipcclxuICogTWFrZXMgYSB0ZXh0YXJlYSBncm93IGFuZCBzaHJpbmsgYmFzZWQgb24gdGhlIGNvbnRlbnQgaGVpZ2h0LCBhbmQgYXBwbGllcyBDU1Mgc3R5bGVzIG9uIGl0IHRvIG1ha2UgaXQgbG9vayBtb3JlIGxpa2UgYW4gPGlucHV0PiBlbGVtZW50IChub3Qgc28gbXVjaCBwYWRkaW5nKS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBkZWNvcmF0ZU11bHRpbGluZUZpZWxkKHBsdWdpbjogU0NfUGx1Z2luLCB0ZXh0YXJlYUNvbXBvbmVudDogVGV4dEFyZWFDb21wb25lbnQsIGV4dHJhT25DaGFuZ2U/OiAoY29udGVudDogc3RyaW5nKSA9PiB2b2lkKSB7XHJcblxyXG4gICAgY29uc3QgdGV4dGFyZWFFbGVtZW50ID0gdGV4dGFyZWFDb21wb25lbnQuaW5wdXRFbDtcclxuXHJcbiAgICB0ZXh0YXJlYUVsZW1lbnQuYWRkQ2xhc3MoXCJTQy1tdWx0aWxpbmVcIik7XHJcblxyXG4gICAgY29uc3QgdXBkYXRlVGV4dGFyZWFIZWlnaHQgPSAoKSA9PiB7XHJcbiAgICAgICAgLy8gUmVzaXplIHRoZSBzaGVsbCBjb21tYW5kIHRleHRhcmVhIHRvIG1hdGNoIHRoZSBhbW91bnQgb2YgbGluZXMgaW4gaXQuXHJcbiAgICAgICAgY29uc3QgY29udGVudCA9IHRleHRhcmVhRWxlbWVudC52YWx1ZTtcclxuICAgICAgICBjb25zdCBwbGFjZWhvbGRlciA9IHRleHRhcmVhRWxlbWVudC5wbGFjZWhvbGRlcjtcclxuICAgICAgICBjb25zdCBuZXdsaW5lc19wYXR0ZXJuID0gL1xcclxcbnxcXHJ8XFxuLztcclxuICAgICAgICBjb25zdCBjb3VudF9saW5lc19pbl9zaGVsbF9jb21tYW5kID0gY29udGVudC5zcGxpdChuZXdsaW5lc19wYXR0ZXJuKS5sZW5ndGg7XHJcbiAgICAgICAgY29uc3QgY291bnRfbGluZXNfaW5fc2hlbGxfY29tbWFuZF9wbGFjZWhvbGRlciA9IHBsYWNlaG9sZGVyLnNwbGl0KG5ld2xpbmVzX3BhdHRlcm4pLmxlbmd0aDtcclxuICAgICAgICBsZXQgY291bnRfbGluZXNfZmluYWwgPSBNYXRoLm1heChcclxuICAgICAgICAgICAgY291bnRfbGluZXNfaW5fc2hlbGxfY29tbWFuZCxcclxuICAgICAgICAgICAgY291bnRfbGluZXNfaW5fc2hlbGxfY29tbWFuZF9wbGFjZWhvbGRlcixcclxuICAgICAgICApO1xyXG4gICAgICAgIGlmIChwbHVnaW4uc2V0dGluZ3MubWF4X3Zpc2libGVfbGluZXNfaW5fc2hlbGxfY29tbWFuZF9maWVsZHMpIHtcclxuICAgICAgICAgICAgLy8gTGltaXQgdGhlIGhlaWdodCBzbyB0aGF0IHRoZSBmaWVsZCB3aWxsIG5vdCB0YWtlIHVwIHRvbyBtdWNoIHNwYWNlLlxyXG4gICAgICAgICAgICBjb3VudF9saW5lc19maW5hbCA9IE1hdGgubWluKFxyXG4gICAgICAgICAgICAgICAgcGx1Z2luLnNldHRpbmdzLm1heF92aXNpYmxlX2xpbmVzX2luX3NoZWxsX2NvbW1hbmRfZmllbGRzLFxyXG4gICAgICAgICAgICAgICAgY291bnRfbGluZXNfZmluYWwsXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRleHRhcmVhRWxlbWVudC5yb3dzID0gY291bnRfbGluZXNfZmluYWw7XHJcbiAgICB9O1xyXG5cclxuICAgIHVwZGF0ZVRleHRhcmVhSGVpZ2h0KCk7IC8vIFNldCBhIGNvcnJlY3QgaW5pdGlhbCBoZWlnaHQuXHJcbiAgICB0ZXh0YXJlYUNvbXBvbmVudC5vbkNoYW5nZSgoKSA9PiB7XHJcbiAgICAgICAgdXBkYXRlVGV4dGFyZWFIZWlnaHQoKTsgLy8gVXBkYXRlIHRoZSBoZWlnaHQgZXZlcnkgdGltZSB0aGUgZmllbGQncyB2YWx1ZSBjaGFuZ2VzLlxyXG4gICAgICAgIGlmIChleHRyYU9uQ2hhbmdlKSB7XHJcbiAgICAgICAgICAgIGV4dHJhT25DaGFuZ2UodGV4dGFyZWFFbGVtZW50LnZhbHVlKTtcclxuICAgICAgICB9XHJcbiAgICB9KTtcclxufVxyXG5cclxuIiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi8uLi9tYWluXCI7XHJcbmltcG9ydCB7U2V0dGluZ0ZpZWxkR3JvdXB9IGZyb20gXCIuLi9TQ19NYWluU2V0dGluZ3NUYWJcIjtcclxuaW1wb3J0IHtTZXR0aW5nfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHtwYXJzZVZhcmlhYmxlc30gZnJvbSBcIi4uLy4uL3ZhcmlhYmxlcy9wYXJzZVZhcmlhYmxlc1wiO1xyXG5pbXBvcnQge2NyZWF0ZUF1dG9jb21wbGV0ZX0gZnJvbSBcIi4vQXV0b2NvbXBsZXRlXCI7XHJcbmltcG9ydCB7U0NfRXZlbnR9IGZyb20gXCIuLi8uLi9ldmVudHMvU0NfRXZlbnRcIjtcclxuaW1wb3J0IHtUU2hlbGxDb21tYW5kfSBmcm9tIFwiLi4vLi4vVFNoZWxsQ29tbWFuZFwiO1xyXG5pbXBvcnQge2NyZWF0ZU11bHRpbGluZVRleHRFbGVtZW50fSBmcm9tIFwiLi4vLi4vQ29tbW9uXCI7XHJcbmltcG9ydCB7RU9MfSBmcm9tIFwib3NcIjtcclxuaW1wb3J0IHtkZWNvcmF0ZU11bHRpbGluZUZpZWxkfSBmcm9tIFwiLi9tdWx0aWxpbmVGaWVsZFwiO1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIENyZWF0ZVNoZWxsQ29tbWFuZEZpZWxkQ29yZShcclxuICAgIHBsdWdpbjogU0NfUGx1Z2luLFxyXG4gICAgY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50LFxyXG4gICAgc2V0dGluZ19pY29uX2FuZF9uYW1lOiBzdHJpbmcsXHJcbiAgICBzaGVsbF9jb21tYW5kOiBzdHJpbmcsXHJcbiAgICBzaGVsbDogc3RyaW5nLFxyXG4gICAgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kLFxyXG4gICAgc2hvd19hdXRvY29tcGxldGVfbWVudTogYm9vbGVhbixcclxuICAgIGV4dHJhX29uX2NoYW5nZTogKHNoZWxsX2NvbW1hbmQ6IHN0cmluZykgPT4gdm9pZCxcclxuICAgIHNoZWxsX2NvbW1hbmRfcGxhY2Vob2xkZXIgPSBcIkVudGVyIHlvdXIgY29tbWFuZFwiXHJcbiAgICApIHtcclxuXHJcbiAgICBhc3luYyBmdW5jdGlvbiBvbl9jaGFuZ2Uoc2hlbGxfY29tbWFuZDogc3RyaW5nKSB7XHJcbiAgICAgICAgLy8gVXBkYXRlIHByZXZpZXdcclxuICAgICAgICBzZXR0aW5nX2dyb3VwLnByZXZpZXdfc2V0dGluZy5kZXNjRWwuaW5uZXJIVE1MID0gXCJcIjsgLy8gUmVtb3ZlIHByZXZpb3VzIGNvbnRlbnQuXHJcbiAgICAgICAgY3JlYXRlTXVsdGlsaW5lVGV4dEVsZW1lbnQoXHJcbiAgICAgICAgICAgIFwic3BhblwiLCAvLyBUT0RPOiBNYXliZSBjbGVhbmVyIHdvdWxkIGJlIG5vdCB0byBjcmVhdGUgYSA8c3Bhbj4sIGJ1dCB0byBpbnNlcnQgdGhlIGNvbnRlbnQgZGlyZWN0bHkgaW50byBkZXNjRWwuXHJcbiAgICAgICAgICAgIGF3YWl0IGdldFNoZWxsQ29tbWFuZFByZXZpZXcocGx1Z2luLCBzaGVsbF9jb21tYW5kLCBzaGVsbCwgdF9zaGVsbF9jb21tYW5kLCBudWxsIC8qIE5vIGV2ZW50IGlzIGF2YWlsYWJsZSBkdXJpbmcgcHJldmlldy4gKi8pLFxyXG4gICAgICAgICAgICBzZXR0aW5nX2dyb3VwLnByZXZpZXdfc2V0dGluZy5kZXNjRWwsXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gTGV0IHRoZSBjYWxsZXIgZXh0ZW5kIHRoaXMgb25DaGFuZ2UsIHRvIHByZWZvcm0gc2F2aW5nIHRoZSBzZXR0aW5nczpcclxuICAgICAgICBleHRyYV9vbl9jaGFuZ2Uoc2hlbGxfY29tbWFuZCk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3Qgc2V0dGluZ19ncm91cDogU2V0dGluZ0ZpZWxkR3JvdXAgPSB7XHJcbiAgICAgICAgbmFtZV9zZXR0aW5nOlxyXG4gICAgICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgICAgIC5zZXRDbGFzcyhcIlNDLW5hbWUtc2V0dGluZ1wiKVxyXG4gICAgICAgICAgICAgICAgLnRoZW4oKG5hbWVfc2V0dGluZykgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIG5hbWVfc2V0dGluZy5uYW1lRWwuaW5uZXJIVE1MID0gc2V0dGluZ19pY29uX2FuZF9uYW1lO1xyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAsXHJcbiAgICAgICAgc2hlbGxfY29tbWFuZF9zZXR0aW5nOlxyXG4gICAgICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgICAgIC5hZGRUZXh0QXJlYSh0ZXh0YXJlYUNvbXBvbmVudCA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRleHRhcmVhQ29tcG9uZW50XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuc2V0UGxhY2Vob2xkZXIoc2hlbGxfY29tbWFuZF9wbGFjZWhvbGRlcilcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5zZXRWYWx1ZShzaGVsbF9jb21tYW5kKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICA7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlY29yYXRlTXVsdGlsaW5lRmllbGQocGx1Z2luLCB0ZXh0YXJlYUNvbXBvbmVudCwgb25fY2hhbmdlKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgICAuc2V0Q2xhc3MoXCJTQy1zaGVsbC1jb21tYW5kLXNldHRpbmdcIilcclxuICAgICAgICAsXHJcbiAgICAgICAgcHJldmlld19zZXR0aW5nOlxyXG4gICAgICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgICAgIC5zZXRDbGFzcyhcIlNDLXByZXZpZXctc2V0dGluZ1wiKVxyXG4gICAgICAgICAgICAgICAgLnRoZW4oYXN5bmMgKHNldHRpbmc6IFNldHRpbmcpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBzZXR0aW5nLmRlc2NFbC5pbm5lckhUTUwgPSBcIlwiOyAvLyBSZW1vdmUgcHJldmlvdXMgY29udGVudC4gTm90IGFjdHVhbGx5IG5lZWRlZCBoZXJlIGJlY2F1c2UgaXQncyBlbXB0eSBhbHJlYWR5LCBidXQgZG8gaXQganVzdCBpbiBjYXNlLlxyXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZU11bHRpbGluZVRleHRFbGVtZW50KFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBcInNwYW5cIiwgLy8gVE9ETzogTWF5YmUgY2xlYW5lciB3b3VsZCBiZSBub3QgdG8gY3JlYXRlIGEgPHNwYW4+LCBidXQgdG8gaW5zZXJ0IHRoZSBjb250ZW50IGRpcmVjdGx5IGludG8gZGVzY0VsLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBnZXRTaGVsbENvbW1hbmRQcmV2aWV3KHBsdWdpbiwgc2hlbGxfY29tbWFuZCwgc2hlbGwsIHRfc2hlbGxfY29tbWFuZCwgbnVsbCAvKiBObyBldmVudCBpcyBhdmFpbGFibGUgZHVyaW5nIHByZXZpZXcuICovKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgc2V0dGluZy5kZXNjRWwsXHJcbiAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgLFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBBdXRvY29tcGxldGUgbWVudVxyXG4gICAgaWYgKHNob3dfYXV0b2NvbXBsZXRlX21lbnUpIHtcclxuICAgICAgICBjcmVhdGVBdXRvY29tcGxldGUocGx1Z2luLCBzZXR0aW5nX2dyb3VwLnNoZWxsX2NvbW1hbmRfc2V0dGluZy5zZXR0aW5nRWwuZmluZChcInRleHRhcmVhXCIpIGFzIEhUTUxUZXh0QXJlYUVsZW1lbnQsIG9uX2NoYW5nZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHNldHRpbmdfZ3JvdXA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKlxyXG4gKiBAcGFyYW0gcGx1Z2luXHJcbiAqIEBwYXJhbSBzaGVsbF9jb21tYW5kXHJcbiAqIEBwYXJhbSBzaGVsbFxyXG4gKiBAcGFyYW0gdF9zaGVsbF9jb21tYW5kXHJcbiAqIEBwYXJhbSBzY19ldmVudFxyXG4gKiBAcHVibGljIEV4cG9ydGVkIGJlY2F1c2UgY3JlYXRlU2hlbGxDb21tYW5kRmllbGQgdXNlcyB0aGlzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldFNoZWxsQ29tbWFuZFByZXZpZXcocGx1Z2luOiBTQ19QbHVnaW4sIHNoZWxsX2NvbW1hbmQ6IHN0cmluZywgc2hlbGw6IHN0cmluZywgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kLCBzY19ldmVudDogU0NfRXZlbnQgfCBudWxsKTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgIGNvbnN0IHBhcnNpbmdfcmVzdWx0ID0gYXdhaXQgcGFyc2VWYXJpYWJsZXMocGx1Z2luLCBzaGVsbF9jb21tYW5kLCBzaGVsbCwgdF9zaGVsbF9jb21tYW5kLCBzY19ldmVudCk7XHJcbiAgICBpZiAoIXBhcnNpbmdfcmVzdWx0LnN1Y2NlZWRlZCkge1xyXG4gICAgICAgIC8vIFZhcmlhYmxlIHBhcnNpbmcgZmFpbGVkLlxyXG4gICAgICAgIGlmIChwYXJzaW5nX3Jlc3VsdC5lcnJvcl9tZXNzYWdlcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgIC8vIFJldHVybiBhbGwgZXJyb3IgbWVzc2FnZXMsIGVhY2ggaW4gaXRzIG93biBsaW5lLiAoVXN1YWxseSB0aGVyZSdzIGp1c3Qgb25lIG1lc3NhZ2UpLlxyXG4gICAgICAgICAgICByZXR1cm4gcGFyc2luZ19yZXN1bHQuZXJyb3JfbWVzc2FnZXMuam9pbihFT0wpOyAvLyBOZXdsaW5lcyBhcmUgY29udmVydGVkIHRvIDxicj4ncyBieSB0aGUgY29uc3VtZXJzIG9mIHRoaXMgZnVuY3Rpb24uXHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gSWYgdGhlcmUgYXJlIG5vIGVycm9yIG1lc3NhZ2VzLCB0aGVuIGVycm9ycyBhcmUgc2lsZW50bHkgaWdub3JlZCBieSB1c2VyJ3MgdmFyaWFibGUgY29uZmlndXJhdGlvbi5cclxuICAgICAgICAgICAgLy8gVGhlIHByZXZpZXcgY2FuIHRoZW4gc2hvdyB0aGUgb3JpZ2luYWwsIHVucGFyc2VkIHNoZWxsIGNvbW1hbmQuXHJcbiAgICAgICAgICAgIHJldHVybiBzaGVsbF9jb21tYW5kO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIC8vIFZhcmlhYmxlIHBhcnNpbmcgc3VjY2VlZGVkXHJcbiAgICByZXR1cm4gcGFyc2luZ19yZXN1bHQucGFyc2VkX2NvbnRlbnQgYXMgc3RyaW5nO1xyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge0NyZWF0ZVNoZWxsQ29tbWFuZEZpZWxkQ29yZX0gZnJvbSBcIi4vQ3JlYXRlU2hlbGxDb21tYW5kRmllbGRDb3JlXCI7XHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uLy4uL21haW5cIjtcclxuaW1wb3J0IHtUU2hlbGxDb21tYW5kfSBmcm9tIFwiLi4vLi4vVFNoZWxsQ29tbWFuZFwiO1xyXG5pbXBvcnQge1BsYXRmb3JtSWQsIFBsYXRmb3JtTmFtZXN9IGZyb20gXCIuLi9TQ19NYWluU2V0dGluZ3NcIjtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQbGF0Zm9ybVNwZWNpZmljU2hlbGxDb21tYW5kRmllbGQocGx1Z2luOiBTQ19QbHVnaW4sIGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCwgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kLCBwbGF0Zm9ybV9pZDogUGxhdGZvcm1JZCwgc2hvd19hdXRvY29tcGxldGVfbWVudTogYm9vbGVhbikge1xyXG4gICAgY29uc3QgcGxhdGZvcm1fbmFtZSA9IFBsYXRmb3JtTmFtZXNbcGxhdGZvcm1faWRdO1xyXG4gICAgY29uc3Qgc2V0dGluZ19ncm91cCA9IENyZWF0ZVNoZWxsQ29tbWFuZEZpZWxkQ29yZShcclxuICAgICAgICBwbHVnaW4sXHJcbiAgICAgICAgY29udGFpbmVyX2VsZW1lbnQsXHJcbiAgICAgICAgXCJTaGVsbCBjb21tYW5kIG9uIFwiICsgcGxhdGZvcm1fbmFtZSxcclxuICAgICAgICB0X3NoZWxsX2NvbW1hbmQuZ2V0UGxhdGZvcm1TcGVjaWZpY1NoZWxsQ29tbWFuZHMoKVtwbGF0Zm9ybV9pZF0gPz8gXCJcIixcclxuICAgICAgICB0X3NoZWxsX2NvbW1hbmQuZ2V0U2hlbGwoKSxcclxuICAgICAgICB0X3NoZWxsX2NvbW1hbmQsXHJcbiAgICAgICAgc2hvd19hdXRvY29tcGxldGVfbWVudSxcclxuICAgICAgICBhc3luYyAoc2hlbGxfY29tbWFuZDogc3RyaW5nKSA9PiB7XHJcbiAgICAgICAgICAgIGlmIChzaGVsbF9jb21tYW5kLmxlbmd0aCkge1xyXG4gICAgICAgICAgICAgICAgLy8gc2hlbGxfY29tbWFuZCBpcyBub3QgZW1wdHksIHNvIGl0J3MgYSBub3JtYWwgY29tbWFuZC5cclxuICAgICAgICAgICAgICAgIHRfc2hlbGxfY29tbWFuZC5nZXRQbGF0Zm9ybVNwZWNpZmljU2hlbGxDb21tYW5kcygpW3BsYXRmb3JtX2lkXSA9IHNoZWxsX2NvbW1hbmQ7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBzaGVsbF9jb21tYW5kIGlzIGVtcHR5LCBzbyB0aGUgZGVmYXVsdCBjb21tYW5kIHNob3VsZCBiZSB1c2VkLlxyXG4gICAgICAgICAgICAgICAgZGVsZXRlIHRfc2hlbGxfY29tbWFuZC5nZXRQbGF0Zm9ybVNwZWNpZmljU2hlbGxDb21tYW5kcygpW3BsYXRmb3JtX2lkXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBhd2FpdCBwbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICB0X3NoZWxsX2NvbW1hbmQuZ2V0RGVmYXVsdFNoZWxsQ29tbWFuZCgpLFxyXG4gICAgKTtcclxuICAgIHNldHRpbmdfZ3JvdXAubmFtZV9zZXR0aW5nLnNldERlc2MoXCJJZiBlbXB0eSwgdGhlIGRlZmF1bHQgc2hlbGwgY29tbWFuZCB3aWxsIGJlIHVzZWQgb24gXCIgKyBwbGF0Zm9ybV9uYW1lICsgXCIuXCIpO1xyXG4gICAgcmV0dXJuIHNldHRpbmdfZ3JvdXA7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7c2V0SWNvbn0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFRhYiB7XHJcbiAgICB0aXRsZTogc3RyaW5nO1xyXG4gICAgaWNvbjogc3RyaW5nO1xyXG4gICAgY29udGVudF9nZW5lcmF0b3I6IChjb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQpID0+IHZvaWQ7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgVGFiU3RydWN0dXJlIHtcclxuICAgIGhlYWRlcjogSFRNTEVsZW1lbnQsXHJcbiAgICBhY3RpdmVfdGFiX2lkOiBzdHJpbmcsXHJcbiAgICBidXR0b25zOiB7XHJcbiAgICAgICAgW2tleTogc3RyaW5nXTogSFRNTEVsZW1lbnQsXHJcbiAgICB9XHJcbiAgICBjb250ZW50Q29udGFpbmVyczoge1xyXG4gICAgICAgIFtrZXk6IHN0cmluZ106IEhUTUxFbGVtZW50LFxyXG4gICAgfSxcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBUYWJzIHtcclxuICAgIFtrZXk6IHN0cmluZ106IFRhYjtcclxufVxyXG5cclxuaW50ZXJmYWNlIFRhYkNvbnRlbnRDb250YWluZXJzIHtcclxuICAgIFtrZXk6IHN0cmluZ106IEhUTUxFbGVtZW50LFxyXG59XHJcblxyXG5pbnRlcmZhY2UgVGFiQnV0dG9ucyB7XHJcbiAgICBba2V5OiBzdHJpbmddOiBIVE1MRWxlbWVudCxcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVRhYnMoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50LCB0YWJzOiBUYWJzKTogVGFiU3RydWN0dXJlIHtcclxuICAgIGNvbnN0IHRhYl9oZWFkZXIgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVFbChcImRpdlwiLCB7YXR0cjoge2NsYXNzOiBcIlNDLXRhYi1oZWFkZXJcIn19KTtcclxuICAgIGNvbnN0IHRhYl9jb250ZW50X2NvbnRhaW5lcnM6IFRhYkNvbnRlbnRDb250YWluZXJzID0ge307XHJcbiAgICBjb25zdCB0YWJfYnV0dG9uczogVGFiQnV0dG9ucyA9IHt9O1xyXG4gICAgY29uc3QgdGFiX3N0cnVjdHVyZSA9IHtcclxuICAgICAgICBoZWFkZXI6IHRhYl9oZWFkZXIsXHJcbiAgICAgICAgYWN0aXZlX3RhYl9pZDogT2JqZWN0LmtleXModGFicylbMF0gYXMgc3RyaW5nLCAvLyBJbmRpY2F0ZSB0aGF0IHRoZSBmaXJzdCB0YWIgaXMgYWN0aXZlLiBUaGlzIGRvZXMgbm90IGFmZmVjdCB3aGF0IHRhYiBpcyBhY3RpdmUgaW4gcHJhY3Rpc2UsIGl0IGp1c3QgcmVwb3J0cyB0aGUgYWN0aXZlIHRhYi5cclxuICAgICAgICBidXR0b25zOiB0YWJfYnV0dG9ucyxcclxuICAgICAgICBjb250ZW50Q29udGFpbmVyczogdGFiX2NvbnRlbnRfY29udGFpbmVycyxcclxuICAgIH07XHJcbiAgICBsZXQgZmlyc3RfYnV0dG9uOiBIVE1MRWxlbWVudCB8IHVuZGVmaW5lZDtcclxuICAgIGZvciAoY29uc3QgdGFiX2lkIGluIHRhYnMpIHtcclxuICAgICAgICBjb25zdCB0YWIgPSB0YWJzW3RhYl9pZF07XHJcblxyXG4gICAgICAgIC8vIENyZWF0ZSBidXR0b25cclxuICAgICAgICBjb25zdCBidXR0b24gPSB0YWJfaGVhZGVyLmNyZWF0ZUVsKFwiYnV0dG9uXCIsIHtcclxuICAgICAgICAgICAgYXR0cjoge1xyXG4gICAgICAgICAgICAgICAgY2xhc3M6IFwiU0MtdGFiLWhlYWRlci1idXR0b25cIixcclxuICAgICAgICAgICAgICAgIGFjdGl2YXRlVGFiOiBcIlNDLXRhYi1cIiArIHRhYl9pZCxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICB9KTtcclxuICAgICAgICBidXR0b24ub25jbGljayA9IGZ1bmN0aW9uIChldmVudDogTW91c2VFdmVudCkge1xyXG4gICAgICAgICAgICBjb25zdCB0YWJfYnV0dG9uID0gdGhpcyBhcyBIVE1MRWxlbWVudDsgLy8gVXNlICd0aGlzJyBpbnN0ZWFkIG9mIGV2ZW50LnRhcmdldCBiZWNhdXNlIHRoaXMgd2F5IHdlJ2xsIGFsd2F5cyBnZXQgYSBidXR0b24gZWxlbWVudCwgbm90IGFuIGVsZW1lbnQgaW5zaWRlIHRoZSAgYnV0dG9uIChpLmUuIGFuIGljb24pLlxyXG5cclxuICAgICAgICAgICAgLy8gSGlkZSBhbGwgdGFiIGNvbnRlbnRzIGFuZCBnZXQgdGhlIG1heCBkaW1lbnNpb25zXHJcbiAgICAgICAgICAgIGxldCBtYXhfd2lkdGggPSAwO1xyXG4gICAgICAgICAgICBsZXQgbWF4X2hlaWdodCA9IDA7XHJcbiAgICAgICAgICAgIGNvbnN0IHRhYl9oZWFkZXIgPSB0YWJfYnV0dG9uLnBhcmVudEVsZW1lbnQ7XHJcbiAgICAgICAgICAgIGlmIChudWxsID09PSB0YWJfaGVhZGVyKSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUYWIgaGVhZGVyIGlzIG1pc3NpbmcuIERpZCBub3QgZ2V0IGEgcGFyZW50IGZyb20gdGFiIGJ1dHRvbi5cIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgY29uc3QgY29udGFpbmVyX2VsZW1lbnQgPSB0YWJfaGVhZGVyLnBhcmVudEVsZW1lbnQ7XHJcbiAgICAgICAgICAgIGlmIChudWxsID09PSBjb250YWluZXJfZWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29udGFpbmVyIGVsZW1lbnQgaXMgbWlzc2luZy4gRGlkIG5vdCBnZXQgYSBwYXJlbnQgZnJvbSB0YWIgaGVhZGVyLlwiKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBjb25zdCB0YWJfY29udGVudHMgPSBjb250YWluZXJfZWxlbWVudC5maW5kQWxsKFwiZGl2LlNDLXRhYi1jb250ZW50XCIpOyAvLyBEbyBub3QgZ2V0IGFsbCB0YWIgY29udGVudHMgdGhhdCBleGlzdCwgYmVjYXVzZSB0aGVyZSBtaWdodCBiZSBtdWx0aXBsZSB0YWIgc3lzdGVtcyBvcGVuIGF0IHRoZSBzYW1lIHRpbWUuXHJcbiAgICAgICAgICAgIGNvbnN0IGlzX21haW5fc2V0dGluZ3NfbW9kYWwgPSBjb250YWluZXJfZWxlbWVudC5oYXNDbGFzcyhcInZlcnRpY2FsLXRhYi1jb250ZW50XCIpO1xyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGluZGV4IGluIHRhYl9jb250ZW50cykge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgdGFiX2NvbnRlbnQgPSB0YWJfY29udGVudHNbaW5kZXhdO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIEdldCB0aGUgbWF4aW11bSB0YWIgZGltZW5zaW9ucyBzbyB0aGF0IGFsbCB0YWJzIGNhbiBoYXZlIHRoZSBzYW1lIGRpbWVuc2lvbnMuXHJcbiAgICAgICAgICAgICAgICAvLyBCdXQgZG9uJ3QgZG8gaXQgaWYgdGhpcyBpcyB0aGUgbWFpbiBzZXR0aW5ncyBtb2RhbFxyXG4gICAgICAgICAgICAgICAgaWYgKCFpc19tYWluX3NldHRpbmdzX21vZGFsKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGFiX2NvbnRlbnQuYWRkQ2xhc3MoXCJTQy10YWItYWN0aXZlXCIpOyAvLyBOZWVkIHRvIG1ha2UgdGhlIHRhYiB2aXNpYmxlIHRlbXBvcmFyaWx5IGluIG9yZGVyIHRvIGdldCB0aGUgZGltZW5zaW9ucy5cclxuICAgICAgICAgICAgICAgICAgICBpZiAodGFiX2NvbnRlbnQub2Zmc2V0SGVpZ2h0ID4gbWF4X2hlaWdodCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBtYXhfaGVpZ2h0ID0gdGFiX2NvbnRlbnQub2Zmc2V0SGVpZ2h0O1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAodGFiX2NvbnRlbnQub2Zmc2V0V2lkdGggPiBtYXhfd2lkdGgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgbWF4X3dpZHRoID0gdGFiX2NvbnRlbnQub2Zmc2V0V2lkdGg7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIC8vIEZpbmFsbHkgaGlkZSB0aGUgdGFiXHJcbiAgICAgICAgICAgICAgICB0YWJfY29udGVudC5yZW1vdmVDbGFzcyhcIlNDLXRhYi1hY3RpdmVcIik7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIFJlbW92ZSBhY3RpdmUgc3RhdHVzIGZyb20gYWxsIGJ1dHRvbnNcclxuICAgICAgICAgICAgY29uc3QgYWRqYWNlbnRfdGFiX2J1dHRvbnMgPSB0YWJfaGVhZGVyLmZpbmRBbGwoXCIuU0MtdGFiLWhlYWRlci1idXR0b25cIik7IC8vIERvIG5vdCBnZXQgYWxsIHRhYiBidXR0b25zIHRoYXQgZXhpc3QsIGJlY2F1c2UgdGhlcmUgbWlnaHQgYmUgbXVsdGlwbGUgdGFiIHN5c3RlbXMgb3BlbiBhdCB0aGUgc2FtZSB0aW1lLlxyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGluZGV4IGluIGFkamFjZW50X3RhYl9idXR0b25zKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCB0YWJfYnV0dG9uID0gYWRqYWNlbnRfdGFiX2J1dHRvbnNbaW5kZXhdO1xyXG4gICAgICAgICAgICAgICAgdGFiX2J1dHRvbi5yZW1vdmVDbGFzcyhcIlNDLXRhYi1hY3RpdmVcIik7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIEFjdGl2YXRlIHRoZSBjbGlja2VkIHRhYlxyXG4gICAgICAgICAgICB0YWJfYnV0dG9uLmFkZENsYXNzKFwiU0MtdGFiLWFjdGl2ZVwiKTtcclxuICAgICAgICAgICAgY29uc3QgYWN0aXZhdGVUYWJBdHRyaWJ1dGU6IEF0dHIgfCBudWxsID0gdGFiX2J1dHRvbi5hdHRyaWJ1dGVzLmdldE5hbWVkSXRlbShcImFjdGl2YXRlVGFiXCIpO1xyXG4gICAgICAgICAgICBpZiAobnVsbCA9PT0gYWN0aXZhdGVUYWJBdHRyaWJ1dGUpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlRhYiBidXR0b24gaGFzIG5vICdhY3RpdmF0ZVRhYicgSFRNTCBhdHRyaWJ1dGUhIE11cnIhXCIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGNvbnN0IGFjdGl2YXRlX3RhYl9pZCA9IGFjdGl2YXRlVGFiQXR0cmlidXRlLnZhbHVlO1xyXG4gICAgICAgICAgICBjb25zdCB0YWJfY29udGVudDogSFRNTEVsZW1lbnQgfCBudWxsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoYWN0aXZhdGVfdGFiX2lkKTtcclxuICAgICAgICAgICAgaWYgKG51bGwgPT09IHRhYl9jb250ZW50KSB7XHJcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyB0YWIgY29udGVudCB3YXMgZm91bmQgd2l0aCBhY3RpdmF0ZV90YWJfaWQgJ1wiK2FjdGl2YXRlX3RhYl9pZCtcIichIEhtcGghXCIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHRhYl9jb250ZW50LmFkZENsYXNzKFwiU0MtdGFiLWFjdGl2ZVwiKTtcclxuXHJcbiAgICAgICAgICAgIC8vIE1hcmsgdGhlIGNsaWNrZWQgdGFiIGFzIGFjdGl2ZSBpbiBUYWJTdHJ1Y3R1cmUgKGp1c3QgdG8gcmVwb3J0IHdoaWNoIHRhYiBpcyBjdXJyZW50bHkgYWN0aXZlKVxyXG4gICAgICAgICAgICB0YWJfc3RydWN0dXJlLmFjdGl2ZV90YWJfaWQgPSBhY3RpdmF0ZV90YWJfaWQucmVwbGFjZSgvXlNDLXRhYi0vLCBcIlwiKTsgLy8gUmVtb3ZlIFwiU0MtdGFiXCIgcHJlZml4LlxyXG5cclxuICAgICAgICAgICAgLy8gRm9jdXMgYW4gZWxlbWVudCAoaWYgYSBmb2N1c2FibGUgZWxlbWVudCBpcyBwcmVzZW50KVxyXG4gICAgICAgICAgICB0YWJfY29udGVudC5maW5kKFwiLlNDLWZvY3VzLWVsZW1lbnQtb24tdGFiLW9wZW5pbmdcIik/LmZvY3VzKCk7IC8vID8gPSBJZiBub3QgZm91bmQsIGRvIG5vdGhpbmcuXHJcblxyXG4gICAgICAgICAgICAvLyBBcHBseSB0aGUgbWF4IGRpbWVuc2lvbnMgdG8gdGhpcyB0YWJcclxuICAgICAgICAgICAgLy8gQnV0IGRvbid0IGRvIGl0IGlmIHRoaXMgaXMgdGhlIG1haW4gc2V0dGluZ3MgbW9kYWxcclxuICAgICAgICAgICAgaWYgKCFpc19tYWluX3NldHRpbmdzX21vZGFsKSB7XHJcbiAgICAgICAgICAgICAgICB0YWJfY29udGVudC5zdHlsZS53aWR0aCA9IG1heF93aWR0aCArIFwicHhcIjtcclxuICAgICAgICAgICAgICAgIHRhYl9jb250ZW50LnN0eWxlLmhlaWdodCA9IG1heF9oZWlnaHQgKyBcInB4XCI7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIERvIG5vdGhpbmcgZWxzZSAoSSBkb24ndCBrbm93IGlmIHRoaXMgaXMgbmVlZGVkIG9yIG5vdClcclxuICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICB9O1xyXG4gICAgICAgIHNldEljb24oYnV0dG9uLCB0YWIuaWNvbik7XHJcbiAgICAgICAgYnV0dG9uLmluc2VydEFkamFjZW50VGV4dChcImJlZm9yZWVuZFwiLCBcIiBcIiArIHRhYi50aXRsZSk7XHJcbiAgICAgICAgdGFiX2J1dHRvbnNbdGFiX2lkXSA9IGJ1dHRvbjtcclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGNvbnRlbnQgY29udGFpbmVyXHJcbiAgICAgICAgdGFiX2NvbnRlbnRfY29udGFpbmVyc1t0YWJfaWRdID0gY29udGFpbmVyX2VsZW1lbnQuY3JlYXRlRWwoXCJkaXZcIiwge2F0dHI6IHtjbGFzczogXCJTQy10YWItY29udGVudFwiLCBpZDogXCJTQy10YWItXCIgKyB0YWJfaWR9fSk7XHJcblxyXG4gICAgICAgIC8vIEdlbmVyYXRlIGNvbnRlbnRcclxuICAgICAgICB0YWIuY29udGVudF9nZW5lcmF0b3IodGFiX2NvbnRlbnRfY29udGFpbmVyc1t0YWJfaWRdKTtcclxuXHJcbiAgICAgICAgLy8gTWVtb3JpemUgdGhlIGZpcnN0IHRhYidzIGJ1dHRvblxyXG4gICAgICAgIGlmICh1bmRlZmluZWQgPT09IGZpcnN0X2J1dHRvbikge1xyXG4gICAgICAgICAgICBmaXJzdF9idXR0b24gPSBidXR0b247XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEFjdGl2YXRlIHRoZSBmaXJzdCB0YWJcclxuICAgIGlmICh1bmRlZmluZWQgIT09IGZpcnN0X2J1dHRvbikge1xyXG4gICAgICAgIGZpcnN0X2J1dHRvbi5jbGljaygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybiB0aGUgVGFiU3RydWN0dXJlXHJcbiAgICByZXR1cm4gdGFiX3N0cnVjdHVyZTtcclxufVxyXG5cclxuIiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG4vLyBAdHMtaWdub3JlXHJcbmltcG9ydCB7U2V0dGluZ30gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uL21haW5cIjtcclxuaW1wb3J0IHtTQ19NYWluU2V0dGluZ3NUYWJ9IGZyb20gXCIuL1NDX01haW5TZXR0aW5nc1RhYlwiO1xyXG5pbXBvcnQge2dldE91dHB1dENoYW5uZWxzT3B0aW9uTGlzdH0gZnJvbSBcIi4uL291dHB1dF9jaGFubmVscy9PdXRwdXRDaGFubmVsRnVuY3Rpb25zXCI7XHJcbmltcG9ydCB7XHJcbiAgICBPdXRwdXRDaGFubmVsQ29kZSxcclxuICAgIE91dHB1dENoYW5uZWxPcmRlcixcclxuICAgIE91dHB1dEhhbmRsaW5nTW9kZSxcclxuICAgIE91dHB1dFN0cmVhbSxcclxufSBmcm9tIFwiLi4vb3V0cHV0X2NoYW5uZWxzL091dHB1dENoYW5uZWxDb2RlXCI7XHJcbmltcG9ydCB7VFNoZWxsQ29tbWFuZH0gZnJvbSBcIi4uL1RTaGVsbENvbW1hbmRcIjtcclxuaW1wb3J0IHtDb21tYW5kUGFsZXR0ZU9wdGlvbnMsIElDb21tYW5kUGFsZXR0ZU9wdGlvbnMsIFBsYXRmb3JtSWQsIFBsYXRmb3JtTmFtZXN9IGZyb20gXCIuL1NDX01haW5TZXR0aW5nc1wiO1xyXG5pbXBvcnQge2NyZWF0ZVNoZWxsU2VsZWN0aW9uRmllbGR9IGZyb20gXCIuL3NldHRpbmdfZWxlbWVudHMvQ3JlYXRlU2hlbGxTZWxlY3Rpb25GaWVsZFwiO1xyXG5pbXBvcnQge1xyXG4gICAgZ2VuZXJhdGVJZ25vcmVkRXJyb3JDb2Rlc0ljb25UaXRsZSxcclxuICAgIGdlbmVyYXRlU2hlbGxDb21tYW5kRmllbGRJY29uQW5kTmFtZVxyXG59IGZyb20gXCIuL3NldHRpbmdfZWxlbWVudHMvQ3JlYXRlU2hlbGxDb21tYW5kRmllbGRcIjtcclxuaW1wb3J0IHtjcmVhdGVQbGF0Zm9ybVNwZWNpZmljU2hlbGxDb21tYW5kRmllbGR9IGZyb20gXCIuL3NldHRpbmdfZWxlbWVudHMvQ3JlYXRlUGxhdGZvcm1TcGVjaWZpY1NoZWxsQ29tbWFuZEZpZWxkXCI7XHJcbmltcG9ydCB7Y3JlYXRlVGFicywgVGFiU3RydWN0dXJlfSBmcm9tIFwiLi9zZXR0aW5nX2VsZW1lbnRzL1RhYnNcIjtcclxuaW1wb3J0IHtjcmVhdGVBdXRvY29tcGxldGV9IGZyb20gXCIuL3NldHRpbmdfZWxlbWVudHMvQXV0b2NvbXBsZXRlXCI7XHJcbmltcG9ydCB7Z2V0U0NfRXZlbnRzfSBmcm9tIFwiLi4vZXZlbnRzL1NDX0V2ZW50TGlzdFwiO1xyXG5pbXBvcnQge1NDX0V2ZW50fSBmcm9tIFwiLi4vZXZlbnRzL1NDX0V2ZW50XCI7XHJcbmltcG9ydCB7XHJcbiAgICBjb3B5VG9DbGlwYm9hcmQsXHJcbiAgICBnb3RvVVJMLFxyXG59IGZyb20gXCIuLi9Db21tb25cIjtcclxuaW1wb3J0IHtTQ19Nb2RhbH0gZnJvbSBcIi4uL1NDX01vZGFsXCI7XHJcbmltcG9ydCB7XHJcbiAgICBnZXREZWZhdWx0UHJlYWN0aW9uX1Byb21wdF9Db25maWd1cmF0aW9uLFxyXG4gICAgZ2V0TW9kZWwsXHJcbiAgICBQcmVhY3Rpb25fUHJvbXB0X0NvbmZpZ3VyYXRpb24sXHJcbiAgICBQcm9tcHQsXHJcbiAgICBQcm9tcHRNb2RlbCxcclxuICAgIFByb21wdFNldHRpbmdzTW9kYWwsXHJcbn0gZnJvbSBcIi4uL2ltcG9ydHNcIjtcclxuaW1wb3J0IHtDbWRPckN0cmx9IGZyb20gXCIuLi9Ib3RrZXlzXCI7XHJcbmltcG9ydCB7XHJcbiAgICBnZXRJY29uSFRNTCxcclxuICAgIElDT05fTElTVF9TT1JURURfVU5JUVVFLFxyXG59IGZyb20gXCIuLi9JY29uc1wiO1xyXG5pbXBvcnQge091dHB1dFdyYXBwZXJ9IGZyb20gXCIuLi9tb2RlbHMvb3V0cHV0X3dyYXBwZXIvT3V0cHV0V3JhcHBlclwiO1xyXG5pbXBvcnQge091dHB1dFdyYXBwZXJNb2RlbH0gZnJvbSBcIi4uL21vZGVscy9vdXRwdXRfd3JhcHBlci9PdXRwdXRXcmFwcGVyTW9kZWxcIjtcclxuaW1wb3J0IHtPdXRwdXRXcmFwcGVyU2V0dGluZ3NNb2RhbH0gZnJvbSBcIi4uL21vZGVscy9vdXRwdXRfd3JhcHBlci9PdXRwdXRXcmFwcGVyU2V0dGluZ3NNb2RhbFwiO1xyXG5pbXBvcnQge1xyXG4gICAgRG9jdW1lbnRhdGlvbk91dHB1dEhhbmRsaW5nTW9kZUxpbmssXHJcbiAgICBEb2N1bWVudGF0aW9uU3RkaW5Db250ZW50TGluayxcclxufSBmcm9tIFwiLi4vRG9jdW1lbnRhdGlvblwiO1xyXG5pbXBvcnQge2RlY29yYXRlTXVsdGlsaW5lRmllbGR9IGZyb20gXCIuL3NldHRpbmdfZWxlbWVudHMvbXVsdGlsaW5lRmllbGRcIjtcclxuaW1wb3J0IHtjcmVhdGVWYXJpYWJsZURlZmF1bHRWYWx1ZUZpZWxkc30gZnJvbSBcIi4vc2V0dGluZ19lbGVtZW50cy9jcmVhdGVWYXJpYWJsZURlZmF1bHRWYWx1ZUZpZWxkc1wiO1xyXG5cclxuLyoqXHJcbiAqIFRPRE86IFJlbmFtZSB0byBTaGVsbENvbW1hbmRTZXR0aW5nc01vZGFsXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgRXh0cmFPcHRpb25zTW9kYWwgZXh0ZW5kcyBTQ19Nb2RhbCB7XHJcbiAgICBwdWJsaWMgc3RhdGljIEdFTkVSQUxfT1BUSU9OU19TVU1NQVJZID0gXCJBbGlhcywgSWNvbiwgQ29uZmlybWF0aW9uLCBTdGRpblwiO1xyXG4gICAgcHVibGljIHN0YXRpYyBQUkVBQ1RJT05TX09QVElPTlNfU1VNTUFSWSA9IFwiUHJlYWN0aW9uczogUHJvbXB0IGZvciBhc2tpbmcgdmFsdWVzIGZyb20gdXNlclwiO1xyXG4gICAgcHVibGljIHN0YXRpYyBPVVRQVVRfT1BUSU9OU19TVU1NQVJZID0gXCJTdGRvdXQvc3RkZXJyIGhhbmRsaW5nLCBJZ25vcmUgZXJyb3JzXCI7XHJcbiAgICBwdWJsaWMgc3RhdGljIEVOVklST05NRU5UU19PUFRJT05TX1NVTU1BUlkgPSBcIlNoZWxsIHNlbGVjdGlvbiwgT3BlcmF0aW5nIHN5c3RlbSBzcGVjaWZpYyBzaGVsbCBjb21tYW5kc1wiO1xyXG4gICAgcHVibGljIHN0YXRpYyBFVkVOVFNfU1VNTUFSWSA9IFwiRXZlbnRzXCI7XHJcbiAgICBwdWJsaWMgc3RhdGljIFZBUklBQkxFU19TVU1NQVJZID0gXCJEZWZhdWx0IHZhbHVlcyBmb3IgdmFyaWFibGVzXCI7XHJcblxyXG4gICAgcHJpdmF0ZSByZWFkb25seSBzaGVsbF9jb21tYW5kX2lkOiBzdHJpbmc7XHJcbiAgICBwcml2YXRlIHJlYWRvbmx5IHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZDtcclxuICAgIHByaXZhdGUgbmFtZV9zZXR0aW5nOiBTZXR0aW5nO1xyXG4gICAgcHJpdmF0ZSBzZXR0aW5nX3RhYjogU0NfTWFpblNldHRpbmdzVGFiO1xyXG4gICAgcHJpdmF0ZSB0YWJfc3RydWN0dXJlOiBUYWJTdHJ1Y3R1cmU7XHJcblxyXG4gICAgY29uc3RydWN0b3IocGx1Z2luOiBTQ19QbHVnaW4sIHNoZWxsX2NvbW1hbmRfaWQ6IHN0cmluZywgc2V0dGluZ190YWI6IFNDX01haW5TZXR0aW5nc1RhYikge1xyXG4gICAgICAgIHN1cGVyKHBsdWdpbik7XHJcbiAgICAgICAgdGhpcy5zaGVsbF9jb21tYW5kX2lkID0gc2hlbGxfY29tbWFuZF9pZDtcclxuICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZCA9IHBsdWdpbi5nZXRUU2hlbGxDb21tYW5kcygpW3NoZWxsX2NvbW1hbmRfaWRdO1xyXG4gICAgICAgIHRoaXMubmFtZV9zZXR0aW5nID0gc2V0dGluZ190YWIuc2V0dGluZ19ncm91cHNbc2hlbGxfY29tbWFuZF9pZF0ubmFtZV9zZXR0aW5nO1xyXG4gICAgICAgIHRoaXMuc2V0dGluZ190YWIgPSBzZXR0aW5nX3RhYjtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgb25PcGVuKCkge1xyXG4gICAgICAgIHN1cGVyLm9uT3BlbigpO1xyXG5cclxuICAgICAgICB0aGlzLm1vZGFsRWwuY3JlYXRlRWwoXCJoMlwiLCB7dGV4dDogdGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0RGVmYXVsdFNoZWxsQ29tbWFuZCgpfSk7ICAvLyBUT0RPOiBVc2UgdGhpcy5zZXRUaXRsZSgpIGluc3RlYWQuXHJcblxyXG4gICAgICAgIC8vIFRhYnNcclxuICAgICAgICB0aGlzLnRhYl9zdHJ1Y3R1cmUgPSBjcmVhdGVUYWJzKHRoaXMubW9kYWxFbCwge1xyXG4gICAgICAgICAgICBcImV4dHJhLW9wdGlvbnMtZ2VuZXJhbFwiOiB7XHJcbiAgICAgICAgICAgICAgICB0aXRsZTogXCJHZW5lcmFsXCIsXHJcbiAgICAgICAgICAgICAgICBpY29uOiBcImdlYXJcIixcclxuICAgICAgICAgICAgICAgIGNvbnRlbnRfZ2VuZXJhdG9yOiAoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50YWJHZW5lcmFsKGNvbnRhaW5lcl9lbGVtZW50KTtcclxuICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIFwiZXh0cmEtb3B0aW9ucy1wcmVhY3Rpb25zXCI6IHtcclxuICAgICAgICAgICAgICAgIHRpdGxlOiBcIlByZWFjdGlvbnNcIixcclxuICAgICAgICAgICAgICAgIGljb246IFwibm90ZS1nbHlwaFwiLFxyXG4gICAgICAgICAgICAgICAgY29udGVudF9nZW5lcmF0b3I6IChjb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnRhYlByZWFjdGlvbnMoY29udGFpbmVyX2VsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgXCJleHRyYS1vcHRpb25zLW91dHB1dFwiOiB7XHJcbiAgICAgICAgICAgICAgICB0aXRsZTogXCJPdXRwdXRcIixcclxuICAgICAgICAgICAgICAgIGljb246IFwibGluZXMtb2YtdGV4dFwiLFxyXG4gICAgICAgICAgICAgICAgY29udGVudF9nZW5lcmF0b3I6IChjb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnRhYk91dHB1dChjb250YWluZXJfZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBcImV4dHJhLW9wdGlvbnMtZW52aXJvbm1lbnRzXCI6IHtcclxuICAgICAgICAgICAgICAgIHRpdGxlOiBcIkVudmlyb25tZW50c1wiLFxyXG4gICAgICAgICAgICAgICAgaWNvbjogXCJzdGFja2VkLWxldmVsc1wiLFxyXG4gICAgICAgICAgICAgICAgY29udGVudF9nZW5lcmF0b3I6IChjb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnRhYkVudmlyb25tZW50cyhjb250YWluZXJfZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBcImV4dHJhLW9wdGlvbnMtZXZlbnRzXCI6IHtcclxuICAgICAgICAgICAgICAgIHRpdGxlOiBcIkV2ZW50c1wiLFxyXG4gICAgICAgICAgICAgICAgaWNvbjogXCJkaWNlXCIsXHJcbiAgICAgICAgICAgICAgICBjb250ZW50X2dlbmVyYXRvcjogKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMudGFiRXZlbnRzKGNvbnRhaW5lcl9lbGVtZW50KTtcclxuICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIFwiZXh0cmEtb3B0aW9ucy12YXJpYWJsZXNcIjoge1xyXG4gICAgICAgICAgICAgICAgdGl0bGU6IFwiVmFyaWFibGVzXCIsXHJcbiAgICAgICAgICAgICAgICBpY29uOiBcImNvZGUtZ2x5cGhcIixcclxuICAgICAgICAgICAgICAgIGNvbnRlbnRfZ2VuZXJhdG9yOiAoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50YWJWYXJpYWJsZXMoY29udGFpbmVyX2VsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gSG90a2V5cyBmb3IgbW92aW5nIHRvIG5leHQvcHJldmlvdXMgc2hlbGwgY29tbWFuZFxyXG4gICAgICAgIGNvbnN0IHN3aXRjaF90b190X3NoZWxsX2NvbW1hbmQgPSAodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IG5ld19tb2RhbCA9IG5ldyBFeHRyYU9wdGlvbnNNb2RhbCh0aGlzLnBsdWdpbiwgdF9zaGVsbF9jb21tYW5kLmdldElkKCksIHRoaXMuc2V0dGluZ190YWIpO1xyXG4gICAgICAgICAgICB0aGlzLmNsb3NlKCk7IC8vIE5lZWRzIHRvIGJlIGNsb3NlZCBiZWZvcmUgdGhlIG5ldyBvbmUgaXMgb3BlbmVkLCBvdGhlcndpc2UgdGhlIG5ldyBvbmUncyB0YWIgY29udGVudCB3b24ndCBiZSBzaG93bi5cclxuICAgICAgICAgICAgbmV3X21vZGFsLm9wZW4oKTtcclxuICAgICAgICAgICAgbmV3X21vZGFsLmFjdGl2YXRlVGFiKHRoaXMudGFiX3N0cnVjdHVyZS5hY3RpdmVfdGFiX2lkKTtcclxuICAgICAgICB9O1xyXG4gICAgICAgIHRoaXMuc2NvcGUucmVnaXN0ZXIoW1wiTW9kXCJdLCBcIkFycm93VXBcIiwgKCkgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCBwcmV2aW91c1RTaGVsbENvbW1hbmQgPSB0aGlzLnRfc2hlbGxfY29tbWFuZC5wcmV2aW91c1RTaGVsbENvbW1hbmQoKTtcclxuICAgICAgICAgICAgaWYgKHByZXZpb3VzVFNoZWxsQ29tbWFuZCkge1xyXG4gICAgICAgICAgICAgICAgc3dpdGNoX3RvX3Rfc2hlbGxfY29tbWFuZChwcmV2aW91c1RTaGVsbENvbW1hbmQpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgdGhpcy5zY29wZS5yZWdpc3RlcihbXCJNb2RcIl0sIFwiQXJyb3dEb3duXCIsICgpID0+IHtcclxuICAgICAgICAgICAgY29uc3QgbmV4dFRTaGVsbENvbW1hbmQgPSB0aGlzLnRfc2hlbGxfY29tbWFuZC5uZXh0VFNoZWxsQ29tbWFuZCgpO1xyXG4gICAgICAgICAgICBpZiAobmV4dFRTaGVsbENvbW1hbmQpIHtcclxuICAgICAgICAgICAgICAgIHN3aXRjaF90b190X3NoZWxsX2NvbW1hbmQobmV4dFRTaGVsbENvbW1hbmQpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgbmV3IFNldHRpbmcodGhpcy5tb2RhbEVsKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIlRpcCEgSGl0IFwiICsgQ21kT3JDdHJsKCkgKyBcIiArIHVwL2Rvd24gdG8gc3dpdGNoIHRvIHByZXZpb3VzL25leHQgc2hlbGwgY29tbWFuZC5cIilcclxuICAgICAgICA7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB0YWJHZW5lcmFsKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCkge1xyXG4gICAgICAgIC8vIEFsaWFzIGZpZWxkXHJcbiAgICAgICAgY29uc3QgYWxpYXNfY29udGFpbmVyID0gY29udGFpbmVyX2VsZW1lbnQuY3JlYXRlRGl2KHthdHRyOiB7Y2xhc3M6IFwiU0Mtc2V0dGluZy1ncm91cFwifX0pO1xyXG4gICAgICAgIG5ldyBTZXR0aW5nKGFsaWFzX2NvbnRhaW5lcilcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJBbGlhc1wiKVxyXG4gICAgICAgIDtcclxuICAgICAgICBjb25zdCBvbl9hbGlhc19jaGFuZ2UgPSBhc3luYyAodmFsdWU6IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICAvLyBDaGFuZ2UgdGhlIGFjdHVhbCBhbGlhcyB2YWx1ZVxyXG4gICAgICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRDb25maWd1cmF0aW9uKCkuYWxpYXMgPSB2YWx1ZTtcclxuXHJcbiAgICAgICAgICAgIC8vIFVwZGF0ZSBPYnNpZGlhbiBjb21tYW5kIHBhbGV0dGVcclxuICAgICAgICAgICAgdGhpcy50X3NoZWxsX2NvbW1hbmQucmVuYW1lT2JzaWRpYW5Db21tYW5kKHRoaXMudF9zaGVsbF9jb21tYW5kLmdldFNoZWxsQ29tbWFuZCgpLCB0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRBbGlhcygpKTtcclxuXHJcbiAgICAgICAgICAgIC8vIFVwZGF0ZVNoZWxsIGNvbW1hbmRzIHNldHRpbmdzIHBhbmVsXHJcbiAgICAgICAgICAgIHRoaXMubmFtZV9zZXR0aW5nLm5hbWVFbC5pbm5lckhUTUwgPSBnZW5lcmF0ZVNoZWxsQ29tbWFuZEZpZWxkSWNvbkFuZE5hbWUodGhpcy50X3NoZWxsX2NvbW1hbmQpO1xyXG5cclxuICAgICAgICAgICAgLy8gU2F2ZVxyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICB9O1xyXG4gICAgICAgIGNvbnN0IGFsaWFzX3NldHRpbmcgPSBuZXcgU2V0dGluZyhhbGlhc19jb250YWluZXIpXHJcbiAgICAgICAgICAgIC5hZGRUZXh0KHRleHQgPT4gdGV4dFxyXG4gICAgICAgICAgICAgICAgLnNldFZhbHVlKHRoaXMudF9zaGVsbF9jb21tYW5kLmdldEFsaWFzKCkpXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2Uob25fYWxpYXNfY2hhbmdlKVxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgICAgIC5zZXRDbGFzcyhcIlNDLW5vLWRlc2NyaXB0aW9uXCIpXHJcbiAgICAgICAgO1xyXG4gICAgICAgIGNvbnN0IGFsaWFzX2lucHV0X2VsZW1lbnQ6IEhUTUxJbnB1dEVsZW1lbnQgPSBhbGlhc19zZXR0aW5nLmNvbnRyb2xFbC5maW5kKFwiaW5wdXRcIikgYXMgSFRNTElucHV0RWxlbWVudDtcclxuICAgICAgICBhbGlhc19pbnB1dF9lbGVtZW50LmFkZENsYXNzKFwiU0MtZm9jdXMtZWxlbWVudC1vbi10YWItb3BlbmluZ1wiKTsgLy8gRm9jdXMgd2l0aG91dCBhIG5lZWQgdG8gY2xpY2sgdGhlIGZpZWxkLlxyXG4gICAgICAgIGlmICh0aGlzLnBsdWdpbi5zZXR0aW5ncy5zaG93X2F1dG9jb21wbGV0ZV9tZW51KSB7XHJcbiAgICAgICAgICAgIC8vIFNob3cgYXV0b2NvbXBsZXRlIG1lbnUgKD0gYSBsaXN0IG9mIGF2YWlsYWJsZSB2YXJpYWJsZXMpLlxyXG4gICAgICAgICAgICBjcmVhdGVBdXRvY29tcGxldGUodGhpcy5wbHVnaW4sIGFsaWFzX2lucHV0X2VsZW1lbnQsIG9uX2FsaWFzX2NoYW5nZSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBhbGlhc19jb250YWluZXIuY3JlYXRlRWwoXCJwXCIsIHt0ZXh0OiBcIklmIG5vdCBlbXB0eSwgdGhlIGFsaWFzIHdpbGwgYmUgZGlzcGxheWVkIGluIHRoZSBjb21tYW5kIHBhbGV0dGUgaW5zdGVhZCBvZiB0aGUgYWN0dWFsIGNvbW1hbmQuIEFuIGFsaWFzIGlzIG5ldmVyIGV4ZWN1dGVkIGFzIGEgY29tbWFuZC5cIn0pO1xyXG4gICAgICAgIGFsaWFzX2NvbnRhaW5lci5jcmVhdGVFbChcInBcIiwge3RleHQ6IFwiWW91IGNhbiBhbHNvIHVzZSB0aGUgc2FtZSB7e319IHN0eWxlIHZhcmlhYmxlcyBpbiBhbGlhc2VzIHRoYXQgYXJlIHVzZWQgaW4gc2hlbGwgY29tbWFuZHMuIFdoZW4gdmFyaWFibGVzIGFyZSB1c2VkIGluIGFsaWFzZXMsIHRoZXkgZG8gbm90IGFmZmVjdCB0aGUgY29tbWFuZCBleGVjdXRpb24gaW4gYW55IHdheSwgYnV0IGl0J3MgYSBuaWNlIHdheSB0byByZXZlYWwgd2hhdCB2YWx1ZXMgeW91ciBjb21tYW5kIHdpbGwgdXNlLCBldmVuIHdoZW4gYW4gYWxpYXMgaGlkZXMgbW9zdCBvZiB0aGUgb3RoZXIgdGVjaG5pY2FsIGRldGFpbHMuIFN0YXJ0aW5nIGEgdmFyaWFibGUgd2l0aCB7eyEgd2lsbCBwcmV2ZW50IGVzY2FwaW5nIHNwZWNpYWwgY2hhcmFjdGVycyBpbiBjb21tYW5kIHBhbGV0dGUuXCJ9KTtcclxuXHJcbiAgICAgICAgLy8gSWNvbiBmaWVsZFxyXG4gICAgICAgIGNvbnN0IGN1cnJlbnRfaWNvbiA9IHRoaXMudF9zaGVsbF9jb21tYW5kLmdldENvbmZpZ3VyYXRpb24oKS5pY29uO1xyXG4gICAgICAgIGNvbnN0IGljb25fc2V0dGluZyA9IG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIklmIGRlZmluZWQsIHRoZSBpY29uIHdpbGwgYmUgc2hvd24gaW4gZmlsZSBtZW51LCBmb2xkZXIgbWVudSwgYW5kIGVkaXRvciBtZW51IGluIGZyb250IG9mIHRoZSBhbGlhcyB0ZXh0LiBJdCdzIGFsc28gc2hvd24gaW4gdGhlIHNldHRpbmdzLiBJdCBtYWtlcyBpdCBlYXNpZXIgdG8gZGlzdGluZ3Vpc2ggZGlmZmVyZW50IHNoZWxsIGNvbW1hbmRzIHZpc3VhbGx5IGZyb20gZWFjaCBvdGhlci5cIilcclxuICAgICAgICAgICAgLmFkZERyb3Bkb3duKGRyb3Bkb3duID0+IGRyb3Bkb3duXHJcbiAgICAgICAgICAgICAgICAuYWRkT3B0aW9uKFwibm8taWNvblwiLCBcIk5vIGljb25cIikgLy8gTmVlZCB0byB1c2UgYSBub24tZW1wdHkgc3RyaW5nIGxpa2UgXCJuby1pY29uXCIsIGJlY2F1c2UgaWYgJ3ZhbHVlJyB3b3VsZCBiZSBcIlwiIHRoZW4gaXQgYmVjb21lcyB0aGUgc2FtZSBhcyAnZGlzcGxheScgZnJvbSBzb21lIHJlYXNvbiwgaS5lLiBcIk5vIGljb25cIi5cclxuICAgICAgICAgICAgICAgIC50aGVuKChkcm9wZG93bikgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIEl0ZXJhdGUgYWxsIGF2YWlsYWJsZSBpY29ucy5cclxuICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGljb25faWQgb2YgSUNPTl9MSVNUX1NPUlRFRF9VTklRVUUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ3JlYXRlIGFuIG9wdGlvbiBmb3IgdGhlIGljb24uXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRyb3Bkb3duLmFkZE9wdGlvbihpY29uX2lkLCBpY29uX2lkKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgZHJvcGRvd24uc2V0VmFsdWUoY3VycmVudF9pY29uID8/IFwiXCIpOyAvLyBcIlwiID09IHRoZSAnTm8gaWNvbicgb3B0aW9uLlxyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAobmV3X2ljb24pID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoXCJuby1pY29uXCIgPT09IG5ld19pY29uKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIERpc2FibGUgaWNvblxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRDb25maWd1cmF0aW9uKCkuaWNvbiA9IG51bGw7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBSZW1vdmUgdGhlIGljb24gZnJvbSB0aGUgbW9kYWxcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWNvbl9zZXR0aW5nLm5hbWVFbC5pbm5lckhUTUwgPSBcIkljb25cIjtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBTZXQgb3IgY2hhbmdlIHRoZSBpY29uXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLmdldENvbmZpZ3VyYXRpb24oKS5pY29uID0gbmV3X2ljb247XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVcGRhdGUgdGhlIGljb24gaW4gdGhlIG1vZGFsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGljb25fc2V0dGluZy5uYW1lRWwuaW5uZXJIVE1MID0gXCJJY29uIFwiICsgZ2V0SWNvbkhUTUwobmV3X2ljb24pO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gVXBkYXRlIChvciByZW1vdmUpIHRoZSBpY29uIGluIHRoZSBtYWluIHNldHRpbmdzIHBhbmVsXHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5uYW1lX3NldHRpbmcubmFtZUVsLmlubmVySFRNTCA9IGdlbmVyYXRlU2hlbGxDb21tYW5kRmllbGRJY29uQW5kTmFtZSh0aGlzLnRfc2hlbGxfY29tbWFuZCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vIFNhdmUgc2V0dGluZ3NcclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG4gICAgICAgIGljb25fc2V0dGluZy5uYW1lRWwuaW5uZXJIVE1MID0gXCJJY29uIFwiICsgKGN1cnJlbnRfaWNvbiA/IGdldEljb25IVE1MKGN1cnJlbnRfaWNvbikgOiBcIlwiKTtcclxuXHJcbiAgICAgICAgLy8gQ29uZmlybSBleGVjdXRpb24gZmllbGRcclxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJBc2sgY29uZmlybWF0aW9uIGJlZm9yZSBleGVjdXRpb25cIilcclxuICAgICAgICAgICAgLmFkZFRvZ2dsZSh0b2dnbGUgPT4gdG9nZ2xlXHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUodGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0Q29uZmlybUV4ZWN1dGlvbigpKVxyXG4gICAgICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jICh2YWx1ZSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLmdldENvbmZpZ3VyYXRpb24oKS5jb25maXJtX2V4ZWN1dGlvbiA9IHZhbHVlO1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGljb25fY29udGFpbmVyID0gdGhpcy5uYW1lX3NldHRpbmcubmFtZUVsLmZpbmQoXCJzcGFuLnNoZWxsLWNvbW1hbmRzLWNvbmZpcm0tZXhlY3V0aW9uLWljb24tY29udGFpbmVyXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRDb25maXJtRXhlY3V0aW9uKCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2hvdyBpY29uXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGljb25fY29udGFpbmVyLnJlbW92ZUNsYXNzKFwiU0MtaGlkZVwiKTtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBIaWRlIGljb25cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWNvbl9jb250YWluZXIuYWRkQ2xhc3MoXCJTQy1oaWRlXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcblxyXG4gICAgICAgIC8vIFN0ZGluIGZpZWxkXHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKFwiUGFzcyB2YXJpYWJsZXMgdG8gc3RhbmRhcmQgaW5wdXQgKHN0ZGluKSAoZXhwZXJpbWVudGFsKVwiKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIlVzZWQgdG8gcGFzcyBsb25nIHRleHRzIGFzIGlucHV0IHRvIHRoZSBzaGVsbCBjb21tYW5kLiBUaGVyZSBpcyBhIGxpbWl0IHRvIGNvbW1hbmQgbGluZSBsZW5ndGgsIGFuZCBlLmcuIHt7bm90ZV9jb250ZW50fX0gbWlnaHQgcHJvdmlkZSBhIHZhbHVlIHRvbyBsb25nIHRvIGJlIHVzZWQgYXMgYW4gYXJndW1lbnQsIHNvIGl0IHdvcmtzIGJldHRlciB3aGVuIHBhc3NlZCB0byBzdGRpbi4gQWxzbywgcHJvZ3JhbXMgdGhhdCBhc2sgbXVsdGlwbGUgdmFsdWVzIGludGVyYWN0aXZlbHksIGNhbiBiZSBmZWQgd2l0aCB2YWx1ZXMgdXNpbmcgc3RkaW4uIElmIHRoZXJlIGFyZSBtdWx0aXBsZSB2YWx1ZXMgdGhhdCBuZWVkIHRvIGJlIGlucHV0dGVkLCBwdXQgdGhlbSBvbiBzZXBhcmF0ZSBsaW5lcy4gTWFueSBzaGVsbCBwcm9ncmFtcyBpbnRlcnByZXQgbmV3bGluZXMgYXMgc2VwYXJhdG9ycyBiZXR3ZWVuIGRpZmZlcmVudCB2YWx1ZXMuXCIpXHJcbiAgICAgICAgICAgIC5hZGRFeHRyYUJ1dHRvbihleHRyYUJ1dHRvbkNvbXBvbmVudCA9PiBleHRyYUJ1dHRvbkNvbXBvbmVudFxyXG4gICAgICAgICAgICAgICAgLnNldEljb24oXCJoZWxwXCIpXHJcbiAgICAgICAgICAgICAgICAuc2V0VG9vbHRpcChcIkRvY3VtZW50YXRpb246IFBhc3MgdmFyaWFibGVzIHRvIHN0ZGluXCIpXHJcbiAgICAgICAgICAgICAgICAub25DbGljaygoKSA9PiBnb3RvVVJMKERvY3VtZW50YXRpb25TdGRpbkNvbnRlbnRMaW5rKSlcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgIDtcclxuICAgICAgICBjb25zdCBzdGRpblNldHRpbmdDb250YWluZXIgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVEaXYoe2F0dHI6IHtjbGFzczogXCJTQy1zZXR0aW5nLWdyb3VwXCJ9fSk7XHJcbiAgICAgICAgY29uc3Qgb25TdGRpbkNoYW5nZSA9IGFzeW5jIChuZXdTdGRpbkNvbnRlbnQ6IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICBpZiAoXCJcIiA9PT0gbmV3U3RkaW5Db250ZW50KSB7XHJcbiAgICAgICAgICAgICAgICAvLyBTZXQgdG8gbnVsbFxyXG4gICAgICAgICAgICAgICAgdGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0Q29uZmlndXJhdGlvbigpLmlucHV0X2NvbnRlbnRzLnN0ZGluID0gbnVsbDtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIFNldCB2YWx1ZVxyXG4gICAgICAgICAgICAgICAgdGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0Q29uZmlndXJhdGlvbigpLmlucHV0X2NvbnRlbnRzLnN0ZGluID0gbmV3U3RkaW5Db250ZW50O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgIH07XHJcbiAgICAgICAgbmV3IFNldHRpbmcoc3RkaW5TZXR0aW5nQ29udGFpbmVyKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIkNhbiBjb250YWluIHt7dmFyaWFibGVzfX0gYW5kL29yIHN0YXRpYyB0ZXh0LlwiKVxyXG4gICAgICAgICAgICAuYWRkVGV4dEFyZWEodGV4dGFyZWFDb21wb25lbnQgPT4ge1xyXG4gICAgICAgICAgICAgICAgdGV4dGFyZWFDb21wb25lbnRcclxuICAgICAgICAgICAgICAgICAgICAuc2V0VmFsdWUodGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0SW5wdXRDaGFubmVscygpLnN0ZGluID8/IFwiXCIpXHJcbiAgICAgICAgICAgICAgICA7XHJcbiAgICAgICAgICAgICAgICBkZWNvcmF0ZU11bHRpbGluZUZpZWxkKHRoaXMucGx1Z2luLCB0ZXh0YXJlYUNvbXBvbmVudCwgb25TdGRpbkNoYW5nZSk7XHJcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5wbHVnaW4uc2V0dGluZ3Muc2hvd19hdXRvY29tcGxldGVfbWVudSkge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFNob3cgYXV0b2NvbXBsZXRlIG1lbnUgKD0gYSBsaXN0IG9mIGF2YWlsYWJsZSB2YXJpYWJsZXMpLlxyXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZUF1dG9jb21wbGV0ZSh0aGlzLnBsdWdpbiwgdGV4dGFyZWFDb21wb25lbnQuaW5wdXRFbCwgb25TdGRpbkNoYW5nZSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgO1xyXG5cclxuICAgICAgICAvLyBTaGVsbCBjb21tYW5kIGlkXHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXREZXNjKGBTaGVsbCBjb21tYW5kIGlkOiAke3RoaXMuc2hlbGxfY29tbWFuZF9pZH1gKVxyXG4gICAgICAgICAgICAuYWRkRXh0cmFCdXR0b24oYnV0dG9uID0+IGJ1dHRvblxyXG4gICAgICAgICAgICAgICAgLnNldEljb24oXCJkb2N1bWVudHNcIilcclxuICAgICAgICAgICAgICAgIC5zZXRUb29sdGlwKGBDb3B5ICR7dGhpcy5zaGVsbF9jb21tYW5kX2lkfSB0byB0aGUgY2xpcGJvYXJkLmApXHJcbiAgICAgICAgICAgICAgICAub25DbGljaygoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29weVRvQ2xpcGJvYXJkKHRoaXMuc2hlbGxfY29tbWFuZF9pZCk7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4ubmV3Tm90aWZpY2F0aW9uKGAke3RoaXMuc2hlbGxfY29tbWFuZF9pZH0gd2FzIGNvcGllZCB0byB0aGUgY2xpcGJvYXJkLmApO1xyXG4gICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcbiAgICAgICAgaWYgKHRoaXMudF9zaGVsbF9jb21tYW5kLmNhbkFkZFRvQ29tbWFuZFBhbGV0dGUoKSkge1xyXG4gICAgICAgICAgICAvLyBPbmx5IHNob3cgT2JzaWRpYW4gY29tbWFuZCBwYWxldHRlIGlkIGlmIHRoZSBzaGVsbCBjb21tYW5kIGlzIGF2YWlsYWJsZSBpbiB0aGUgY29tbWFuZCBwYWxldHRlLlxyXG4gICAgICAgICAgICBjb25zdCBvYnNpZGlhbl9jb21tYW5kX2lkID0gdGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0T2JzaWRpYW5Db21tYW5kKCkuaWQ7XHJcbiAgICAgICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAgICAgLnNldERlc2MoYE9ic2lkaWFuIGNvbW1hbmQgcGFsZXR0ZSBpZDogJHtvYnNpZGlhbl9jb21tYW5kX2lkfWApXHJcbiAgICAgICAgICAgICAgICAuYWRkRXh0cmFCdXR0b24oYnV0dG9uID0+IGJ1dHRvblxyXG4gICAgICAgICAgICAgICAgICAgIC5zZXRJY29uKFwiZG9jdW1lbnRzXCIpXHJcbiAgICAgICAgICAgICAgICAgICAgLnNldFRvb2x0aXAoYENvcHkgJHtvYnNpZGlhbl9jb21tYW5kX2lkfSB0byB0aGUgY2xpcGJvYXJkLmApXHJcbiAgICAgICAgICAgICAgICAgICAgLm9uQ2xpY2soKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb3B5VG9DbGlwYm9hcmQob2JzaWRpYW5fY29tbWFuZF9pZCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLm5ld05vdGlmaWNhdGlvbihgJHtvYnNpZGlhbl9jb21tYW5kX2lkfSB3YXMgY29waWVkIHRvIHRoZSBjbGlwYm9hcmQuYCk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgICAuc2V0dGluZ0VsLmFkZENsYXNzKFwiU0Mtbm8tdG9wLWJvcmRlclwiKSAvLyBObyBob3Jpem9udGFsIHJ1bGVyIGJldHdlZW4gdGhlIHR3byBpZCBlbGVtZW50cy5cclxuICAgICAgICAgICAgO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHRhYlByZWFjdGlvbnMoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XHJcbiAgICAgICAgY29udGFpbmVyX2VsZW1lbnQuY3JlYXRlRWwoXCJwXCIsIHt0ZXh0OiBcIlByZWFjdGlvbnMgYXJlIHBlcmZvcm1lZCBiZWZvcmUgdGhlIGFjdHVhbCBzaGVsbCBjb21tYW5kIGdldHMgZXhlY3V0ZWQsIHRvIGRvIGNlcnRhaW4gcHJlcGFyYXRpb25zIGZvciB0aGUgc2hlbGwgY29tbWFuZC5cIn0pO1xyXG4gICAgICAgIGNvbnN0IHByZWFjdGlvbnNfY29uZmlndXJhdGlvbiA9IHRoaXMudF9zaGVsbF9jb21tYW5kLmdldENvbmZpZ3VyYXRpb24oKS5wcmVhY3Rpb25zO1xyXG5cclxuICAgICAgICAvLyBMb2FkIGNvbmZpZyB2YWx1ZXNcclxuICAgICAgICBsZXQgcHJlYWN0aW9uX3Byb21wdF9jb25maWd1cmF0aW9uOiBQcmVhY3Rpb25fUHJvbXB0X0NvbmZpZ3VyYXRpb24gfCBudWxsID0gbnVsbDtcclxuICAgICAgICBmb3IgKGNvbnN0IHByZWFjdGlvbl9jb25maWd1cmF0aW9uIG9mIHByZWFjdGlvbnNfY29uZmlndXJhdGlvbikge1xyXG4gICAgICAgICAgICBzd2l0Y2ggKHByZWFjdGlvbl9jb25maWd1cmF0aW9uLnR5cGUpIHtcclxuICAgICAgICAgICAgICAgIGNhc2UgXCJwcm9tcHRcIjpcclxuICAgICAgICAgICAgICAgICAgICBwcmVhY3Rpb25fcHJvbXB0X2NvbmZpZ3VyYXRpb24gPSBwcmVhY3Rpb25fY29uZmlndXJhdGlvbiBhcyBQcmVhY3Rpb25fUHJvbXB0X0NvbmZpZ3VyYXRpb247XHJcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVucmVjb2duaXNlZCBwcmVhY3Rpb24gdHlwZTogXCIgKyBwcmVhY3Rpb25fY29uZmlndXJhdGlvbi50eXBlKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gUHJlYWN0aW9uOiBQcm9tcHRcclxuICAgICAgICBjb25zdCBwcm9tcHRfb3B0aW9uczoge1trZXk6IHN0cmluZ106IHN0cmluZ30gPSB7fTtcclxuICAgICAgICB0aGlzLnBsdWdpbi5nZXRQcm9tcHRzKCkuZm9yRWFjaCgocHJvbXB0OiBQcm9tcHQpID0+IHtcclxuICAgICAgICAgICAgcHJvbXB0X29wdGlvbnNbcHJvbXB0LmdldElEKCldID0gcHJvbXB0LmdldFRpdGxlKCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgbGV0IG9sZF9zZWxlY3RlZF9wcm9tcHRfb3B0aW9uOiBzdHJpbmcgPSAocHJlYWN0aW9uX3Byb21wdF9jb25maWd1cmF0aW9uPy5lbmFibGVkKSA/IHByZWFjdGlvbl9wcm9tcHRfY29uZmlndXJhdGlvbi5wcm9tcHRfaWQgYXMgc3RyaW5nIDogXCJuby1wcm9tcHRcIjtcclxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJQcm9tcHRcIilcclxuICAgICAgICAgICAgLnNldERlc2MoXCJQcm9tcHRzIGFyZSB1c2VkIHRvIGFzayB2YWx1ZXMgZnJvbSB0aGUgdXNlciByaWdodCBiZWZvcmUgc2hlbGwgY29tbWFuZCBleGVjdXRpb24uIFRoZSB2YWx1ZXMgY2FuIGJlIGFjY2Vzc2VkIGluIHRoZSBzaGVsbCBjb21tYW5kIHZpYSBjdXN0b20gdmFyaWFibGVzLiBZb3UgY2FuIG1hbmFnZSBhbGwgcHJvbXB0cyBpbiB0aGUgcGx1Z2luJ3MgbWFpbiBzZXR0aW5ncyB2aWV3LCB1bmRlciB0aGUgJ1ByZWFjdGlvbnMnIHRhYi5cIilcclxuICAgICAgICAgICAgLmFkZERyb3Bkb3duKGRyb3Bkb3duID0+IGRyb3Bkb3duXHJcbiAgICAgICAgICAgICAgICAuYWRkT3B0aW9uKFwibm8tcHJvbXB0XCIsIFwiTm8gcHJvbXB0XCIpXHJcbiAgICAgICAgICAgICAgICAuYWRkT3B0aW9ucyhwcm9tcHRfb3B0aW9ucylcclxuICAgICAgICAgICAgICAgIC5hZGRPcHRpb24oXCJuZXdcIiwgXCJDcmVhdGUgYSBuZXcgcHJvbXB0XCIpXHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUob2xkX3NlbGVjdGVkX3Byb21wdF9vcHRpb24pXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKG5ld19wcm9tcHRfaWQ6IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIENyZWF0ZSBhIFByZWFjdGlvblByb21wdENvbmZpZ3VyYXRpb24gaWYgaXQgZG9lcyBub3QgZXhpc3QuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFwcmVhY3Rpb25fcHJvbXB0X2NvbmZpZ3VyYXRpb24pIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgcHJlYWN0aW9uX3Byb21wdF9jb25maWd1cmF0aW9uID0gZ2V0RGVmYXVsdFByZWFjdGlvbl9Qcm9tcHRfQ29uZmlndXJhdGlvbigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBwcmVhY3Rpb25zX2NvbmZpZ3VyYXRpb24ucHVzaChwcmVhY3Rpb25fcHJvbXB0X2NvbmZpZ3VyYXRpb24pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZC5yZXNldFByZWFjdGlvbnMoKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vIEludGVycHJldCB0aGUgc2VsZWN0aW9uXHJcbiAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChuZXdfcHJvbXB0X2lkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJuZXdcIjoge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ3JlYXRlIGEgbmV3IFByb21wdC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG1vZGVsID0gZ2V0TW9kZWw8UHJvbXB0TW9kZWw+KFByb21wdE1vZGVsLm5hbWUpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbmV3X3Byb21wdCA9IG1vZGVsLm5ld0luc3RhbmNlKHRoaXMucGx1Z2luLnNldHRpbmdzKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpLnRoZW4oKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG1vZGFsID0gbmV3IFByb21wdFNldHRpbmdzTW9kYWwoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdfcHJvbXB0LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmRlZmluZWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiQ3JlYXRlIHByb21wdFwiLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQcm9tcHQgaXMgY3JlYXRlZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRyb3Bkb3duLmFkZE9wdGlvbihuZXdfcHJvbXB0LmdldElEKCksIG5ld19wcm9tcHQuZ2V0VGl0bGUoKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcm9wZG93bi5zZXRWYWx1ZShuZXdfcHJvbXB0LmdldElEKCkpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHByZWFjdGlvbl9wcm9tcHRfY29uZmlndXJhdGlvbiBhcyBQcmVhY3Rpb25fUHJvbXB0X0NvbmZpZ3VyYXRpb24pLmVuYWJsZWQgPSB0cnVlOyAvLyAnYXMgUHJlYWN0aW9uX1Byb21wdF9Db25maWd1cmF0aW9uJyB0ZWxscyBUeXBlU2NyaXB0IHRoYXQgdGhlIHZhcmlhYmxlIGlzIG5vdCBudWxsLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHByZWFjdGlvbl9wcm9tcHRfY29uZmlndXJhdGlvbiBhcyBQcmVhY3Rpb25fUHJvbXB0X0NvbmZpZ3VyYXRpb24pLnByb21wdF9pZCA9IG5ld19wcm9tcHQuZ2V0SUQoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkX3NlbGVjdGVkX3Byb21wdF9vcHRpb24gPSBkcm9wZG93bi5nZXRWYWx1ZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQcm9tcHQgY3JlYXRpb24gd2FzIGNhbmNlbGxlZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRyb3Bkb3duLnNldFZhbHVlKG9sZF9zZWxlY3RlZF9wcm9tcHRfb3B0aW9uKTsgLy8gUmVzZXQgdGhlIGRyb3Bkb3duIHNlbGVjdGlvbi5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLmRlbGV0ZUluc3RhbmNlKG5ld19wcm9tcHQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RhbC5vcGVuKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9IGNhc2UgXCJuby1wcm9tcHRcIjoge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGlzYWJsZSB0aGUgcHJvbXB0LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlYWN0aW9uX3Byb21wdF9jb25maWd1cmF0aW9uLmVuYWJsZWQgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLnJlc2V0UHJlYWN0aW9ucygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRfc2VsZWN0ZWRfcHJvbXB0X29wdGlvbiA9IGRyb3Bkb3duLmdldFZhbHVlKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSBkZWZhdWx0OiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgYW4gZXhpc3RpbmcgcHJvbXB0LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlYWN0aW9uX3Byb21wdF9jb25maWd1cmF0aW9uLmVuYWJsZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlYWN0aW9uX3Byb21wdF9jb25maWd1cmF0aW9uLnByb21wdF9pZCA9IG5ld19wcm9tcHRfaWQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZF9zZWxlY3RlZF9wcm9tcHRfb3B0aW9uID0gZHJvcGRvd24uZ2V0VmFsdWUoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB0YWJPdXRwdXQoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XHJcbiAgICAgICAgLy8gT3V0cHV0IGNoYW5uZWxpbmdcclxuICAgICAgICBjb25zdCBzdGRvdXRfY2hhbm5lbF9zZXR0aW5nID0gdGhpcy5uZXdPdXRwdXRDaGFubmVsU2V0dGluZyhjb250YWluZXJfZWxlbWVudCwgXCJPdXRwdXQgY2hhbm5lbCBmb3Igc3Rkb3V0XCIsIFwic3Rkb3V0XCIpO1xyXG4gICAgICAgIHRoaXMubmV3T3V0cHV0Q2hhbm5lbFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQsIFwiT3V0cHV0IGNoYW5uZWwgZm9yIHN0ZGVyclwiLCBcInN0ZGVyclwiLCBcIklmIGJvdGggc3Rkb3V0IGFuZCBzdGRlcnIgdXNlIHRoZSBzYW1lIGNoYW5uZWwsIHN0ZGVyciB3aWxsIGJlIGNvbWJpbmVkIHRvIHNhbWUgbWVzc2FnZSB3aXRoIHN0ZG91dC5cIik7XHJcblxyXG4gICAgICAgIC8vIE91dHB1dCB3cmFwcGVyc1xyXG4gICAgICAgIHRoaXMubmV3T3V0cHV0V3JhcHBlclNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQsIFwiT3V0cHV0IHdyYXBwZXIgZm9yIHN0ZG91dFwiLCBcInN0ZG91dFwiLCBcIk91dHB1dCB3cmFwcGVycyBjYW4gYmUgdXNlZCB0byBzdXJyb3VuZCBvdXRwdXQgd2l0aCBwcmVkZWZpbmVkIHRleHQsIGUuZy4gdG8gcHV0IG91dHB1dCBpbnRvIGEgY29kZSBibG9jay4gTm90ZTogSWYgJ091dHB1dCBtb2RlJyBpcyAnUmVhbHRpbWUnLCB3cmFwcGVycyB3aWxsIHByb2JhYmx5IGFwcGVhciBtdWx0aXBsZSB0aW1lcyBpbiBvdXRwdXQhXCIpO1xyXG4gICAgICAgIHRoaXMubmV3T3V0cHV0V3JhcHBlclNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQsIFwiT3V0cHV0IHdyYXBwZXIgZm9yIHN0ZGVyclwiLCBcInN0ZGVyclwiKTtcclxuXHJcbiAgICAgICAgLy8gT3V0cHV0IGhhbmRsaW5nIG1vZGVcclxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJPdXRwdXQgaGFuZGxpbmcgbW9kZVwiKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIlNldCB0byAnUmVhbHRpbWUnIGlmIHlvdXIgc2hlbGwgY29tbWFuZCBydW5zIGZvciBhIGxvbmcgdGltZSBBTkQgeW91IHdhbnQgb3V0cHV0IGhhbmRsaW5nIHRvIHN0YXJ0IGFzIHNvb24gYXMgYW55IG91dHB1dHRlZCBjb250ZW50IGlzIGF2YWlsYWJsZS4gT3V0cHV0IGNoYW5uZWxzIG1pZ2h0IGJlIHVzZWQgbXVsdGlwbGUgdGltZXMgZHVyaW5nIGEgc2luZ2xlIHByb2Nlc3MuICdXYWl0IHVudGlsIGZpbmlzaGVkJyBwb3N0cG9uZXMgb3V0cHV0IGhhbmRsaW5nIHVudGlsIGFsbCBvdXRwdXQgaXMgcmVjZWl2ZWQsIGFuZCBoYW5kbGVzIGl0IGFzIGEgc2luZ2xlIGJ1bmNoLiBJZiB1bmNlcnRhaW4sIHVzZSB0aGUgdHJhZGl0aW9uYWwgJ1dhaXQgdW50aWwgZmluaXNoZWQnLlwiKVxyXG4gICAgICAgICAgICAuYWRkRHJvcGRvd24oZHJvcGRvd24gPT4gZHJvcGRvd25cclxuICAgICAgICAgICAgICAgIC5hZGRPcHRpb25zKHtcclxuICAgICAgICAgICAgICAgICAgICBcImJ1ZmZlcmVkXCI6IFwiV2FpdCB1bnRpbCBmaW5pc2hlZFwiLFxyXG4gICAgICAgICAgICAgICAgICAgIFwicmVhbHRpbWVcIjogXCJSZWFsdGltZSAoZXhwZXJpbWVudGFsKVwiLFxyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRDb25maWd1cmF0aW9uKCkub3V0cHV0X2hhbmRsaW5nX21vZGUpXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKG5ld01vZGU6IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLmdldENvbmZpZ3VyYXRpb24oKS5vdXRwdXRfaGFuZGxpbmdfbW9kZSA9IG5ld01vZGUgYXMgT3V0cHV0SGFuZGxpbmdNb2RlO1xyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIClcclxuXHJcbiAgICAgICAgICAgIC8vIERvY3VtZW50YXRpb24gbGlua1xyXG4gICAgICAgICAgICAuYWRkRXh0cmFCdXR0b24oaWNvbiA9PiBpY29uXHJcbiAgICAgICAgICAgICAgICAuc2V0SWNvbihcImhlbHBcIilcclxuICAgICAgICAgICAgICAgIC5vbkNsaWNrKCgpID0+IGdvdG9VUkwoRG9jdW1lbnRhdGlvbk91dHB1dEhhbmRsaW5nTW9kZUxpbmspKVxyXG4gICAgICAgICAgICAgICAgLnNldFRvb2x0aXAoXCJEb2N1bWVudGF0aW9uOiBPdXRwdXQgaGFuZGxpbmcgbW9kZVwiKSxcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgIDtcclxuXHJcbiAgICAgICAgLy8gT3JkZXIgb2Ygb3V0cHV0IGNoYW5uZWxzXHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKFwiT3JkZXIgb2Ygc3Rkb3V0L3N0ZGVyciBvdXRwdXRcIilcclxuICAgICAgICAgICAgLnNldERlc2MoXCJXaGVuIG91dHB1dCBjb250YWlucyBib3RoIGVycm9ycyBhbmQgbm9ybWFsIG91dHB1dCwgd2hpY2ggb25lIHNob3VsZCBiZSBwcmVzZW50ZWQgZmlyc3Q/IChPbmx5IG1hdHRlcnMgaWYgJ091dHB1dCBoYW5kbGluZycgaXMgJ1dhaXQgdW50aWwgZmluaXNoZWQnKS5cIilcclxuICAgICAgICAgICAgLmFkZERyb3Bkb3duKGRyb3Bkb3duID0+IGRyb3Bkb3duXHJcbiAgICAgICAgICAgICAgICAuYWRkT3B0aW9ucyh7XHJcbiAgICAgICAgICAgICAgICAgICAgXCJzdGRvdXQtZmlyc3RcIjogXCJTdGRvdXQgZmlyc3QsIHRoZW4gc3RkZXJyLlwiLFxyXG4gICAgICAgICAgICAgICAgICAgIFwic3RkZXJyLWZpcnN0XCI6IFwiU3RkZXJyIGZpcnN0LCB0aGVuIHN0ZG91dC5cIixcclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUodGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0T3V0cHV0Q2hhbm5lbE9yZGVyKCkpXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBPdXRwdXRDaGFubmVsT3JkZXIpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRDb25maWd1cmF0aW9uKCkub3V0cHV0X2NoYW5uZWxfb3JkZXIgPSB2YWx1ZTtcclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcblxyXG4gICAgICAgIC8vIEZvY3VzIG9uIHRoZSBzdGRvdXQgY2hhbm5lbCBkcm9wZG93biBmaWVsZFxyXG4gICAgICAgIHN0ZG91dF9jaGFubmVsX3NldHRpbmcuY29udHJvbEVsLmZpbmQoXCJzZWxlY3RcIikuYWRkQ2xhc3MoXCJTQy1mb2N1cy1lbGVtZW50LW9uLXRhYi1vcGVuaW5nXCIpO1xyXG5cclxuICAgICAgICAvLyBJZ25vcmUgZXJyb3JzIGZpZWxkXHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKFwiSWdub3JlIGVycm9yIGNvZGVzXCIpXHJcbiAgICAgICAgICAgIC5zZXREZXNjKFwiQSBjb21tYSBzZXBhcmF0ZWQgbGlzdCBvZiBudW1iZXJzLiBJZiBleGVjdXRpbmcgYSBzaGVsbCBjb21tYW5kIGZhaWxzIHdpdGggb25lIG9mIHRoZXNlIGV4aXQgY29kZXMsIG5vIGVycm9yIG1lc3NhZ2Ugd2lsbCBiZSBkaXNwbGF5ZWQsIGFuZCB0aGUgYWJvdmUgc3RkZXJyIGNoYW5uZWwgd2lsbCBiZSBpZ25vcmVkLiBTdGRvdXQgY2hhbm5lbCB3aWxsIHN0aWxsIGJlIHVzZWQgZm9yIHN0ZG91dC4gRXJyb3IgY29kZXMgbXVzdCBiZSBpbnRlZ2VycyBhbmQgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIDAuIEFueXRoaW5nIGVsc2Ugd2lsbCBiZSByZW1vdmVkLiBOb3RlOiBJZiAnT3V0cHV0IGhhbmRsaW5nJyBpcyAnUmVhbHRpbWUnLCBubyBleGl0IGNvZGUgYmFzZWQgaWdub3JpbmcgY2FuIGJlIGRvbmUsIGFzIGFuIGVycm9yIGNvZGUgaXMgb25seSByZWNlaXZlZCB3aGVuIGEgc2hlbGwgY29tbWFuZCBwcm9jZXNzIGZpbmlzaGVzLlwiKVxyXG4gICAgICAgICAgICAuYWRkVGV4dCh0ZXh0ID0+IHRleHRcclxuICAgICAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRJZ25vcmVFcnJvckNvZGVzKCkuam9pbihcIixcIikpXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKHZhbHVlKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gUGFyc2UgdGhlIHN0cmluZyBvZiBjb21tYSBzZXBhcmF0ZWQgbnVtYmVyc1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGlnbm9yZV9lcnJvcl9jb2RlczogbnVtYmVyW10gPSBbXTtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCByYXdfZXJyb3JfY29kZXMgPSB2YWx1ZS5zcGxpdChcIixcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBpIGluIHJhd19lcnJvcl9jb2Rlcykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByYXdfZXJyb3JfY29kZSA9IHJhd19lcnJvcl9jb2Rlc1tpXTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3JfY29kZV9jYW5kaWRhdGUgPSBwYXJzZUludChyYXdfZXJyb3JfY29kZS50cmltKCkpOyAvLyBFLmcuIGFuIGVtcHR5IHN0cmluZyBjb252ZXJ0cyB0byBOYU4gKD0gTm90IGEgTnVtYmVyKS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRW5zdXJlIHRoYXQgdGhlIGVycm9yIGNvZGUgaXMgbm90IE5hTiwgMCBvciBhIG5lZ2F0aXZlIG51bWJlci5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpc05hTihlcnJvcl9jb2RlX2NhbmRpZGF0ZSkgJiYgZXJyb3JfY29kZV9jYW5kaWRhdGUgPj0gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGNhbmRpZGF0ZSBpcyBsZWdpdC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZV9lcnJvcl9jb2Rlcy5wdXNoKGVycm9yX2NvZGVfY2FuZGlkYXRlKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gU2F2ZSB0aGUgdmFsaWRhdGVkIGVycm9yIG51bWJlcnNcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRDb25maWd1cmF0aW9uKCkuaWdub3JlX2Vycm9yX2NvZGVzID0gaWdub3JlX2Vycm9yX2NvZGVzO1xyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyBVcGRhdGUgaWNvblxyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGljb25fY29udGFpbmVyID0gdGhpcy5uYW1lX3NldHRpbmcubmFtZUVsLmZpbmQoXCJzcGFuLnNoZWxsLWNvbW1hbmRzLWlnbm9yZWQtZXJyb3ItY29kZXMtaWNvbi1jb250YWluZXJcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMudF9zaGVsbF9jb21tYW5kLmdldElnbm9yZUVycm9yQ29kZXMoKS5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2hvdyBpY29uXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGljb25fY29udGFpbmVyLnNldEF0dHIoXCJhcmlhLWxhYmVsXCIsIGdlbmVyYXRlSWdub3JlZEVycm9yQ29kZXNJY29uVGl0bGUodGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0SWdub3JlRXJyb3JDb2RlcygpKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGljb25fY29udGFpbmVyLnJlbW92ZUNsYXNzKFwiU0MtaGlkZVwiKTtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBIaWRlIGljb25cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWNvbl9jb250YWluZXIuYWRkQ2xhc3MoXCJTQy1oaWRlXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB0YWJFbnZpcm9ubWVudHMoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XHJcbiAgICAgICAgLy8gUGxhdGZvcm0gc3BlY2lmaWMgc2hlbGwgY29tbWFuZHNcclxuICAgICAgICBsZXQgcGxhdGZvcm1faWQ6IFBsYXRmb3JtSWQ7XHJcbiAgICAgICAgbGV0IGlzX2ZpcnN0ID0gdHJ1ZTtcclxuICAgICAgICBmb3IgKHBsYXRmb3JtX2lkIGluIFBsYXRmb3JtTmFtZXMpIHtcclxuICAgICAgICAgICAgY29uc3Qgc2V0dGluZ19ncm91cCA9IGNyZWF0ZVBsYXRmb3JtU3BlY2lmaWNTaGVsbENvbW1hbmRGaWVsZCh0aGlzLnBsdWdpbiwgY29udGFpbmVyX2VsZW1lbnQsIHRoaXMudF9zaGVsbF9jb21tYW5kLCBwbGF0Zm9ybV9pZCwgdGhpcy5wbHVnaW4uc2V0dGluZ3Muc2hvd19hdXRvY29tcGxldGVfbWVudSk7XHJcbiAgICAgICAgICAgIGlmIChpc19maXJzdCkge1xyXG4gICAgICAgICAgICAgICAgLy8gRm9jdXMgb24gdGhlIGZpcnN0IE9TIHNwZWNpZmljIHNoZWxsIGNvbW1hbmQgZmllbGRcclxuICAgICAgICAgICAgICAgIHNldHRpbmdfZ3JvdXAuc2hlbGxfY29tbWFuZF9zZXR0aW5nLmNvbnRyb2xFbC5maW5kKFwidGV4dGFyZWFcIikuYWRkQ2xhc3MoXCJTQy1mb2N1cy1lbGVtZW50LW9uLXRhYi1vcGVuaW5nXCIpO1xyXG4gICAgICAgICAgICAgICAgaXNfZmlyc3QgPSBmYWxzZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gUGxhdGZvcm0gc3BlY2lmaWMgc2hlbGwgc2VsZWN0aW9uXHJcbiAgICAgICAgY3JlYXRlU2hlbGxTZWxlY3Rpb25GaWVsZCh0aGlzLnBsdWdpbiwgY29udGFpbmVyX2VsZW1lbnQsIHRoaXMudF9zaGVsbF9jb21tYW5kLmdldFNoZWxscygpLCBmYWxzZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB0YWJFdmVudHMoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XHJcbiAgICAgICAgLy8gQ29tbWFuZCBwYWxldHRlXHJcbiAgICAgICAgY29uc3QgY29tbWFuZF9wYWxldHRlX2F2YWlsYWJpbGl0eV9zZXR0aW5nID0gbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKFwiQXZhaWxhYmlsaXR5IGluIE9ic2lkaWFuJ3MgY29tbWFuZCBwYWxldHRlXCIpXHJcbiAgICAgICAgICAgIC5hZGREcm9wZG93bihkcm9wZG93biA9PiBkcm9wZG93blxyXG4gICAgICAgICAgICAgICAgLmFkZE9wdGlvbnMoQ29tbWFuZFBhbGV0dGVPcHRpb25zKVxyXG4gICAgICAgICAgICAgICAgLnNldFZhbHVlKHRoaXMudF9zaGVsbF9jb21tYW5kLmdldENvbmZpZ3VyYXRpb24oKS5jb21tYW5kX3BhbGV0dGVfYXZhaWxhYmlsaXR5KVxyXG4gICAgICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jICh2YWx1ZToga2V5b2YgSUNvbW1hbmRQYWxldHRlT3B0aW9ucykgPT4ge1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyBTdG9yZSB2YWx1ZVxyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLmdldENvbmZpZ3VyYXRpb24oKS5jb21tYW5kX3BhbGV0dGVfYXZhaWxhYmlsaXR5ID0gdmFsdWU7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vIFVwZGF0ZSBjb21tYW5kIHBhbGV0dGVcclxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy50X3NoZWxsX2NvbW1hbmQuY2FuQWRkVG9Db21tYW5kUGFsZXR0ZSgpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlZ2lzdGVyIHRvIGNvbW1hbmQgcGFsZXR0ZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZC5yZWdpc3RlclRvQ29tbWFuZFBhbGV0dGUoKTtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVbnJlZ2lzdGVyIGZyb20gY29tbWFuZCBwYWxldHRlXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLnVucmVnaXN0ZXJGcm9tQ29tbWFuZFBhbGV0dGUoKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vIFNhdmVcclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG5cclxuICAgICAgICAvLyBGb2N1cyBvbiB0aGUgY29tbWFuZCBwYWxldHRlIGF2YWlsYWJpbGl0eSBmaWVsZFxyXG4gICAgICAgIGNvbW1hbmRfcGFsZXR0ZV9hdmFpbGFiaWxpdHlfc2V0dGluZy5jb250cm9sRWwuZmluZChcInNlbGVjdFwiKS5hZGRDbGFzcyhcIlNDLWZvY3VzLWVsZW1lbnQtb24tdGFiLW9wZW5pbmdcIik7XHJcblxyXG4gICAgICAgIC8vIEV2ZW50c1xyXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0TmFtZShcIkV4ZWN1dGUgdGhpcyBzaGVsbCBjb21tYW5kIGF1dG9tYXRpY2FsbHkgd2hlbjpcIilcclxuICAgICAgICAgICAgLnNldEhlYWRpbmcoKSAvLyBNYWtlIHRoZSBuYW1lIGJvbGRcclxuICAgICAgICA7XHJcbiAgICAgICAgZ2V0U0NfRXZlbnRzKHRoaXMucGx1Z2luKS5mb3JFYWNoKChzY19ldmVudDogU0NfRXZlbnQpID0+IHtcclxuICAgICAgICAgICAgY29uc3QgaXNfZXZlbnRfZW5hYmxlZDogYm9vbGVhbiA9IHRoaXMudF9zaGVsbF9jb21tYW5kLmlzU0NfRXZlbnRFbmFibGVkKHNjX2V2ZW50LnN0YXRpYygpLmdldENvZGUoKSk7XHJcbiAgICAgICAgICAgIGNvbnN0IHNldHRpbmcgPSBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgICAgIC5zZXROYW1lKHNjX2V2ZW50LnN0YXRpYygpLmdldFRpdGxlKCkpXHJcbiAgICAgICAgICAgICAgICAuYWRkVG9nZ2xlKHRvZ2dsZSA9PiB0b2dnbGVcclxuICAgICAgICAgICAgICAgICAgICAuc2V0VmFsdWUoaXNfZXZlbnRfZW5hYmxlZClcclxuICAgICAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKGVuYWJsZTogYm9vbGVhbikgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZW5hYmxlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBFbmFibGUgdGhlIGV2ZW50XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZC5lbmFibGVTQ19FdmVudChzY19ldmVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHRyYV9zZXR0aW5nc19jb250YWluZXIuc3R5bGUuZGlzcGxheSA9IFwiYmxvY2tcIjsgLy8gU2hvdyBleHRyYSBzZXR0aW5nc1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGlzYWJsZSB0aGUgZXZlbnRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLmRpc2FibGVTQ19FdmVudChzY19ldmVudCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHRyYV9zZXR0aW5nc19jb250YWluZXIuc3R5bGUuZGlzcGxheSA9IFwibm9uZVwiOyAvLyBIaWRlIGV4dHJhIHNldHRpbmdzXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2F2ZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgICAgIClcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBEb2N1bWVudGF0aW9uIGljb25cclxuICAgICAgICAgICAgICAgIC5hZGRFeHRyYUJ1dHRvbihpY29uID0+IGljb25cclxuICAgICAgICAgICAgICAgICAgICAuc2V0SWNvbihcImhlbHBcIilcclxuICAgICAgICAgICAgICAgICAgICAub25DbGljaygoKSA9PiBnb3RvVVJMKHNjX2V2ZW50LnN0YXRpYygpLmdldERvY3VtZW50YXRpb25MaW5rKCkpKVxyXG4gICAgICAgICAgICAgICAgICAgIC5zZXRUb29sdGlwKFwiRG9jdW1lbnRhdGlvbjogXCIgKyBzY19ldmVudC5zdGF0aWMoKS5nZXRUaXRsZSgpICsgXCIgZXZlbnRcIiksXHJcbiAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgIDtcclxuXHJcbiAgICAgICAgICAgIC8vIE1lbnRpb24gYWRkaXRpb25hbCB2YXJpYWJsZXMgKGlmIGFueSlcclxuICAgICAgICAgICAgaWYgKHNjX2V2ZW50LmNyZWF0ZVN1bW1hcnlPZkV2ZW50VmFyaWFibGVzKHNldHRpbmcuZGVzY0VsKSkge1xyXG4gICAgICAgICAgICAgICAgc2V0dGluZy5kZXNjRWwuaW5zZXJ0QWRqYWNlbnRUZXh0KFwiYWZ0ZXJiZWdpblwiLCBcIkFkZGl0aW9uYWwgdmFyaWFibGVzOiBcIik7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIEV4dHJhIHNldHRpbmdzXHJcbiAgICAgICAgICAgIGNvbnN0IGV4dHJhX3NldHRpbmdzX2NvbnRhaW5lciA9IGNvbnRhaW5lcl9lbGVtZW50LmNyZWF0ZURpdigpO1xyXG4gICAgICAgICAgICBleHRyYV9zZXR0aW5nc19jb250YWluZXIuc3R5bGUuZGlzcGxheSA9IGlzX2V2ZW50X2VuYWJsZWQgPyBcImJsb2NrXCIgOiBcIm5vbmVcIjtcclxuICAgICAgICAgICAgc2NfZXZlbnQuY3JlYXRlRXh0cmFTZXR0aW5nc0ZpZWxkcyhleHRyYV9zZXR0aW5nc19jb250YWluZXIsIHRoaXMudF9zaGVsbF9jb21tYW5kKTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHRhYlZhcmlhYmxlcyhjb250YWluZXJFbGVtZW50OiBIVE1MRWxlbWVudCkge1xyXG5cclxuICAgICAgICAvLyBEZWZhdWx0IHZhbHVlcyBmb3IgdmFyaWFibGVzXHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyRWxlbWVudClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJEZWZhdWx0IHZhbHVlcyBmb3IgdmFyaWFibGVzXCIpXHJcbiAgICAgICAgICAgIC5zZXREZXNjKFwiQ2VydGFpbiB2YXJpYWJsZXMgY2FuIGJlIGluYWNjZXNzaWJsZSBkdXJpbmcgY2VydGFpbiBzaXR1YXRpb25zLCBlLmcuIHt7ZmlsZV9uYW1lfX0gaXMgbm90IGF2YWlsYWJsZSB3aGVuIG5vIGZpbGUgcGFuZSBpcyBmb2N1c2VkLiBZb3UgY2FuIGRlZmluZSBkZWZhdWx0IHZhbHVlcyB0aGF0IHdpbGwgYmUgdXNlZCB3aGVuIGEgdmFyaWFibGUgaXMgb3RoZXJ3aXNlIHVuYXZhaWxhYmxlLlwiKVxyXG4gICAgICAgICAgICAuc2V0SGVhZGluZygpXHJcbiAgICAgICAgO1xyXG5cclxuICAgICAgICBjcmVhdGVWYXJpYWJsZURlZmF1bHRWYWx1ZUZpZWxkcyhcclxuICAgICAgICAgICAgdGhpcy5wbHVnaW4sXHJcbiAgICAgICAgICAgIGNvbnRhaW5lckVsZW1lbnQsXHJcbiAgICAgICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLFxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGFjdGl2YXRlVGFiKHRhYl9pZDogc3RyaW5nKSB7XHJcbiAgICAgICAgaWYgKHVuZGVmaW5lZCA9PT0gdGhpcy50YWJfc3RydWN0dXJlLmJ1dHRvbnNbdGFiX2lkXSkge1xyXG4gICAgICAgICAgICB0aHJvdyBFcnJvcihcIkludmFsaWQgdGFiIGlkOiBcIiArIHRhYl9pZCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMudGFiX3N0cnVjdHVyZS5idXR0b25zW3RhYl9pZF0uY2xpY2soKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIG5ld091dHB1dENoYW5uZWxTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCwgdGl0bGU6IHN0cmluZywgb3V0cHV0X3N0cmVhbV9uYW1lOiBPdXRwdXRTdHJlYW0sIGRlc2NyaXB0aW9uID0gXCJcIikge1xyXG4gICAgICAgIGNvbnN0IG91dHB1dF9jaGFubmVsX29wdGlvbnMgPSBnZXRPdXRwdXRDaGFubmVsc09wdGlvbkxpc3Qob3V0cHV0X3N0cmVhbV9uYW1lKTtcclxuICAgICAgICByZXR1cm4gbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKHRpdGxlKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhkZXNjcmlwdGlvbilcclxuICAgICAgICAgICAgLmFkZERyb3Bkb3duKGRyb3Bkb3duID0+IGRyb3Bkb3duXHJcbiAgICAgICAgICAgICAgICAuYWRkT3B0aW9ucyhvdXRwdXRfY2hhbm5lbF9vcHRpb25zKVxyXG4gICAgICAgICAgICAgICAgLnNldFZhbHVlKHRoaXMudF9zaGVsbF9jb21tYW5kLmdldE91dHB1dENoYW5uZWxzKClbb3V0cHV0X3N0cmVhbV9uYW1lXSlcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAodmFsdWU6IE91dHB1dENoYW5uZWxDb2RlKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0Q29uZmlndXJhdGlvbigpLm91dHB1dF9jaGFubmVsc1tvdXRwdXRfc3RyZWFtX25hbWVdID0gdmFsdWU7XHJcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgbmV3T3V0cHV0V3JhcHBlclNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50LCB0aXRsZTogc3RyaW5nLCBvdXRwdXRfc3RyZWFtX25hbWU6IE91dHB1dFN0cmVhbSwgZGVzY3JpcHRpb24gPSBcIlwiKSB7XHJcbiAgICAgICAgY29uc3Qgb3V0cHV0X3dyYXBwZXJfb3B0aW9uczoge1trZXk6IHN0cmluZ106IHN0cmluZ30gPSB7fTtcclxuICAgICAgICB0aGlzLnBsdWdpbi5nZXRPdXRwdXRXcmFwcGVycygpLmZvckVhY2goKG91dHB1dF93cmFwcGVyOiBPdXRwdXRXcmFwcGVyKSA9PiB7XHJcbiAgICAgICAgICAgIG91dHB1dF93cmFwcGVyX29wdGlvbnNbb3V0cHV0X3dyYXBwZXIuZ2V0SUQoKV0gPSBvdXRwdXRfd3JhcHBlci5nZXRUaXRsZSgpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIGNvbnN0IG91dHB1dF93cmFwcGVycyA9IHRoaXMudF9zaGVsbF9jb21tYW5kLmdldENvbmZpZ3VyYXRpb24oKS5vdXRwdXRfd3JhcHBlcnM7XHJcbiAgICAgICAgbGV0IG9sZF9zZWxlY3RlZF9vdXRwdXRfd3JhcHBlcl9vcHRpb246IHN0cmluZyA9IG91dHB1dF93cmFwcGVyc1tvdXRwdXRfc3RyZWFtX25hbWVdID8/IFwibm8tb3V0cHV0LXdyYXBwZXJcIjtcclxuICAgICAgICByZXR1cm4gbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKHRpdGxlKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhkZXNjcmlwdGlvbilcclxuICAgICAgICAgICAgLmFkZERyb3Bkb3duKGRyb3Bkb3duX2NvbXBvbmVudCA9PiBkcm9wZG93bl9jb21wb25lbnRcclxuICAgICAgICAgICAgICAgIC5hZGRPcHRpb24oXCJuby1vdXRwdXQtd3JhcHBlclwiLCBcIk5vIFwiK291dHB1dF9zdHJlYW1fbmFtZStcIiB3cmFwcGVyXCIpXHJcbiAgICAgICAgICAgICAgICAuYWRkT3B0aW9ucyhvdXRwdXRfd3JhcHBlcl9vcHRpb25zKVxyXG4gICAgICAgICAgICAgICAgLmFkZE9wdGlvbihcIm5ld1wiLCBcIkNyZWF0ZSBhIG5ldyBvdXRwdXQgd3JhcHBlclwiKVxyXG4gICAgICAgICAgICAgICAgLnNldFZhbHVlKG9sZF9zZWxlY3RlZF9vdXRwdXRfd3JhcHBlcl9vcHRpb24pXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKG91dHB1dF93cmFwcGVyX2lkOiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKG91dHB1dF93cmFwcGVyX2lkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgXCJuZXdcIjoge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ3JlYXRlIGEgbmV3IE91dHB1dFdyYXBwZXIuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBvdXRwdXRfd3JhcHBlcl9tb2RlbCA9IGdldE1vZGVsPE91dHB1dFdyYXBwZXJNb2RlbD4oT3V0cHV0V3JhcHBlck1vZGVsLm5hbWUpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbmV3X291dHB1dF93cmFwcGVyID0gb3V0cHV0X3dyYXBwZXJfbW9kZWwubmV3SW5zdGFuY2UodGhpcy5wbHVnaW4uc2V0dGluZ3MpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCkudGhlbigoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbW9kYWwgPSBuZXcgT3V0cHV0V3JhcHBlclNldHRpbmdzTW9kYWwoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdfb3V0cHV0X3dyYXBwZXIsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJDcmVhdGUgb3V0cHV0IHdyYXBwZXJcIixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3V0cHV0IHdyYXBwZXIgaXMgY3JlYXRlZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRyb3Bkb3duX2NvbXBvbmVudC5hZGRPcHRpb24obmV3X291dHB1dF93cmFwcGVyLmdldElEKCksIG5ld19vdXRwdXRfd3JhcHBlci5nZXRUaXRsZSgpKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRyb3Bkb3duX2NvbXBvbmVudC5zZXRWYWx1ZShuZXdfb3V0cHV0X3dyYXBwZXIuZ2V0SUQoKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRwdXRfd3JhcHBlcnNbb3V0cHV0X3N0cmVhbV9uYW1lXSA9IG5ld19vdXRwdXRfd3JhcHBlci5nZXRJRCgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRfc2VsZWN0ZWRfb3V0cHV0X3dyYXBwZXJfb3B0aW9uID0gZHJvcGRvd25fY29tcG9uZW50LmdldFZhbHVlKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzeW5jICgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFByb21wdCBjcmVhdGlvbiB3YXMgY2FuY2VsbGVkLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJvcGRvd25fY29tcG9uZW50LnNldFZhbHVlKG9sZF9zZWxlY3RlZF9vdXRwdXRfd3JhcHBlcl9vcHRpb24pOyAvLyBSZXNldCB0aGUgZHJvcGRvd24gc2VsZWN0aW9uLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0X3dyYXBwZXJfbW9kZWwuZGVsZXRlSW5zdGFuY2UobmV3X291dHB1dF93cmFwcGVyKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kYWwub3BlbigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlIFwibm8tb3V0cHV0LXdyYXBwZXJcIjoge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGlzYWJsZSBvdXRwdXQgd3JhcHBlci5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dF93cmFwcGVyc1tvdXRwdXRfc3RyZWFtX25hbWVdID0gbnVsbDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDoge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVXNlIGFuIGV4aXN0aW5nIG91dHB1dCB3cmFwcGVyLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0X3dyYXBwZXJzW291dHB1dF9zdHJlYW1fbmFtZV0gPSBvdXRwdXRfd3JhcHBlcl9pZDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG4gICAgfVxyXG5cclxuICAgIHByb3RlY3RlZCBhcHByb3ZlKCk6IHZvaWQge1xyXG4gICAgICAgIC8vIE5vIG5lZWQgdG8gcGVyZm9ybSBhbnkgYWN0aW9uLCBqdXN0IGNsb3NlIHRoZSBtb2RhbC5cclxuICAgICAgICB0aGlzLmNsb3NlKCk7XHJcbiAgICB9XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7U0NfTW9kYWx9IGZyb20gXCIuLi9TQ19Nb2RhbFwiO1xyXG5pbXBvcnQgU0NfUGx1Z2luIGZyb20gXCIuLi9tYWluXCI7XHJcbmltcG9ydCB7U2V0dGluZ0ZpZWxkR3JvdXB9IGZyb20gXCIuL1NDX01haW5TZXR0aW5nc1RhYlwiO1xyXG5pbXBvcnQge1RTaGVsbENvbW1hbmR9IGZyb20gXCIuLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7ZGVidWdMb2d9IGZyb20gXCIuLi9EZWJ1Z1wiO1xyXG5cclxuLyoqXHJcbiAqIFRPRE86IFJlbmFtZSB0byBEZWxldGVTaGVsbENvbW1hbmRNb2RhbFxyXG4gKi9cclxuZXhwb3J0IGNsYXNzIERlbGV0ZU1vZGFsIGV4dGVuZHMgU0NfTW9kYWwge1xyXG5cclxuICAgIHByaXZhdGUgcmVhZG9ubHkgc2hlbGxfY29tbWFuZF9pZDogc3RyaW5nO1xyXG4gICAgcHJpdmF0ZSByZWFkb25seSB0X3NoZWxsX2NvbW1hbmQ6IFRTaGVsbENvbW1hbmQ7XHJcbiAgICBwcml2YXRlIHNldHRpbmdfZ3JvdXA6IFNldHRpbmdGaWVsZEdyb3VwO1xyXG4gICAgcHJpdmF0ZSBzaGVsbF9jb21tYW5kX2VsZW1lbnQ6IEhUTUxFbGVtZW50O1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKHBsdWdpbjogU0NfUGx1Z2luLCBzaGVsbF9jb21tYW5kX2lkOiBzdHJpbmcsIHNldHRpbmdfZ3JvdXA6IFNldHRpbmdGaWVsZEdyb3VwLCBzaGVsbF9jb21tYW5kX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XHJcbiAgICAgICAgc3VwZXIocGx1Z2luKTtcclxuICAgICAgICB0aGlzLnNoZWxsX2NvbW1hbmRfaWQgPSBzaGVsbF9jb21tYW5kX2lkO1xyXG4gICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kID0gcGx1Z2luLmdldFRTaGVsbENvbW1hbmRzKClbc2hlbGxfY29tbWFuZF9pZF07XHJcbiAgICAgICAgdGhpcy5zZXR0aW5nX2dyb3VwID0gc2V0dGluZ19ncm91cDtcclxuICAgICAgICB0aGlzLnNoZWxsX2NvbW1hbmRfZWxlbWVudCA9IHNoZWxsX2NvbW1hbmRfZWxlbWVudDtcclxuICAgIH1cclxuXHJcbiAgICBwdWJsaWMgb25PcGVuKCkge1xyXG4gICAgICAgIHN1cGVyLm9uT3BlbigpO1xyXG5cclxuICAgICAgICB0aGlzLm1vZGFsRWwuY3JlYXRlRWwoXCJoMlwiLCB7dGV4dDogXCJEZWxldGU6IFwiICsgdGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0U2hlbGxDb21tYW5kKCl9KTsgLy8gVE9ETzogVXNlIHRoaXMuc2V0VGl0bGUoKSBpbnN0ZWFkLlxyXG4gICAgICAgIGlmICh0aGlzLnRfc2hlbGxfY29tbWFuZC5nZXRBbGlhcygpKSB7XHJcbiAgICAgICAgICAgIHRoaXMubW9kYWxFbC5jcmVhdGVFbChcInBcIiwge3RleHQ6IFwiQWxpYXM6IFwiICsgdGhpcy50X3NoZWxsX2NvbW1hbmQuZ2V0QWxpYXMoKX0pO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLm1vZGFsRWwuY3JlYXRlRWwoXCJwXCIsIHt0ZXh0OiBcIkFyZSB5b3Ugc3VyZSB5b3Ugd2FudCB0byBkZWxldGUgdGhpcyBzaGVsbCBjb21tYW5kP1wifSk7XHJcbiAgICAgICAgY29uc3QgZGVsZXRlX2J1dHRvbiA9IHRoaXMubW9kYWxFbC5jcmVhdGVFbChcImJ1dHRvblwiLCB7dGV4dDogXCJZZXMsIGRlbGV0ZVwifSk7XHJcbiAgICAgICAgZGVsZXRlX2J1dHRvbi5vbmNsaWNrID0gYXN5bmMgKCkgPT4gdGhpcy5hcHByb3ZlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvdGVjdGVkIGFzeW5jIGFwcHJvdmUoKSB7XHJcbiAgICAgICAgLy8gVW5yZWdpc3RlciBwb3NzaWJsZSBldmVudHMgaW4gb3JkZXIgdG8gcHJldmVudCB0aGVtIGJlY29taW5nIGdob3N0cyB0aGF0IGp1c3Qga2VlcCBleGVjdXRpbmcgZXZlbiBhZnRlciByZW1vdmluZyB0aGUgY29uZmlndXJhdGlvbi5cclxuICAgICAgICB0aGlzLnRfc2hlbGxfY29tbWFuZC51bnJlZ2lzdGVyU0NfRXZlbnRzKCk7XHJcblxyXG4gICAgICAgIC8vIFJlbW92ZSB0aGUgY29tbWFuZFxyXG4gICAgICAgIGRlYnVnTG9nKFwiQ29tbWFuZCBcIiArIHRoaXMuc2hlbGxfY29tbWFuZF9pZCArIFwiIGdvbm5hIGJlIHJlbW92ZWQuXCIpO1xyXG4gICAgICAgIHRoaXMudF9zaGVsbF9jb21tYW5kLnVucmVnaXN0ZXJGcm9tQ29tbWFuZFBhbGV0dGUoKTsgLy8gUmVtb3ZlIGZyb20gdGhlIGNvbW1hbmQgcGFsZXR0ZS5cclxuICAgICAgICBkZWxldGUgdGhpcy5wbHVnaW4uZ2V0VFNoZWxsQ29tbWFuZHMoKVt0aGlzLnNoZWxsX2NvbW1hbmRfaWRdOyAvLyBSZW1vdmUgdGhlIFRTaGVsbENvbW1hbmQgb2JqZWN0LlxyXG5cclxuICAgICAgICAvLyBSZW1vdmUgZnJvbSB0aGUgcGx1Z2luJ3Mgc2V0dGluZ3MuXHJcbiAgICAgICAgY29uc3Qgc2hlbGxDb21tYW5kSW5kZXg6IG51bWJlciB8IHVuZGVmaW5lZCA9IHRoaXMucGx1Z2luLmdldFNoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb25JbmRleCh0aGlzLnNoZWxsX2NvbW1hbmRfaWQpO1xyXG4gICAgICAgIC8vIEluZGV4IHByb2JhYmx5IGFsd2F5cyBleGlzdHMsIGJ1dCBjaGVjayBqdXN0IGluIGNhc2UuIFdpbGwgbWFrZSBUeXBlU2NyaXB0IGNvbXBpbGVyIGhhcHB5LiA6KVxyXG4gICAgICAgIGlmICh1bmRlZmluZWQgPT0gc2hlbGxDb21tYW5kSW5kZXgpIHtcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU2hlbGwgY29tbWFuZCBkZWxldGlvbiBmYWlsZWQuIERpZCBub3QgZ2V0IHNoZWxsIGNvbW1hbmQgaW5kZXggaW4gc2V0dGluZ3MgY29udGFpbmVyLlwiKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3Muc2hlbGxfY29tbWFuZHMuc3BsaWNlKHNoZWxsQ29tbWFuZEluZGV4LDEpO1xyXG5cclxuICAgICAgICAvLyBSZW1vdmUgdGhlIHNldHRpbmcgZmllbGRzXHJcbiAgICAgICAgdGhpcy5zaGVsbF9jb21tYW5kX2VsZW1lbnQucmVtb3ZlKCk7XHJcblxyXG4gICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgIGRlYnVnTG9nKFwiQ29tbWFuZCByZW1vdmVkLlwiKTtcclxuICAgICAgICB0aGlzLmNsb3NlKCk7XHJcbiAgICB9XHJcblxyXG59IiwiLypcclxuICogJ1NoZWxsIGNvbW1hbmRzJyBwbHVnaW4gZm9yIE9ic2lkaWFuLlxyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YVxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxyXG4gKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxyXG4gKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCB2ZXJzaW9uIDMuMCBvZiB0aGUgTGljZW5zZS5cclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXHJcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXHJcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gU2VlIHRoZVxyXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxyXG4gKlxyXG4gKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxyXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gSWYgbm90LCBzZWUgPGh0dHBzOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cclxuICpcclxuICogQ29udGFjdCB0aGUgYXV0aG9yIChKYXJra28gTGlubmFudmlydGEpOiBodHRwczovL2dpdGh1Yi5jb20vVGFpdGF2YS9cclxuICovXHJcblxyXG5pbXBvcnQge1RTaGVsbENvbW1hbmR9IGZyb20gXCIuLi8uLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7SG90a2V5LCBzZXRJY29ufSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHtFeHRyYU9wdGlvbnNNb2RhbH0gZnJvbSBcIi4uL0V4dHJhT3B0aW9uc01vZGFsXCI7XHJcbmltcG9ydCB7RGVsZXRlTW9kYWx9IGZyb20gXCIuLi9EZWxldGVNb2RhbFwiO1xyXG5pbXBvcnQge0NtZE9yQ3RybCwgZ2V0SG90a2V5c0ZvclNoZWxsQ29tbWFuZCwgSG90a2V5VG9TdHJpbmd9IGZyb20gXCIuLi8uLi9Ib3RrZXlzXCI7XHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uLy4uL21haW5cIjtcclxuaW1wb3J0IHtDcmVhdGVTaGVsbENvbW1hbmRGaWVsZENvcmV9IGZyb20gXCIuL0NyZWF0ZVNoZWxsQ29tbWFuZEZpZWxkQ29yZVwiO1xyXG5pbXBvcnQge2RlYnVnTG9nfSBmcm9tIFwiLi4vLi4vRGVidWdcIjtcclxuaW1wb3J0IHtFT0x9IGZyb20gXCJvc1wiO1xyXG5pbXBvcnQge1xyXG4gICAgZXNjYXBlTWFya2Rvd25MaW5rQ2hhcmFjdGVycyxcclxuICAgIGNvcHlUb0NsaXBib2FyZCxcclxufSBmcm9tIFwiLi4vLi4vQ29tbW9uXCI7XHJcbmltcG9ydCB7XHJcbiAgICBTaGVsbENvbW1hbmRFeGVjdXRvclxyXG59IGZyb20gXCIuLi8uLi9pbXBvcnRzXCI7XHJcbmltcG9ydCB7U0NfTWFpblNldHRpbmdzVGFifSBmcm9tIFwiLi4vU0NfTWFpblNldHRpbmdzVGFiXCI7XHJcblxyXG4vKipcclxuICpcclxuICogQHBhcmFtIHBsdWdpblxyXG4gKiBAcGFyYW0gY29udGFpbmVyX2VsZW1lbnRcclxuICogQHBhcmFtIHNldHRpbmdfdGFiXHJcbiAqIEBwYXJhbSBzaGVsbF9jb21tYW5kX2lkIEVpdGhlciBhIHN0cmluZyBmb3JtYXR0ZWQgaW50ZWdlciAoXCIwXCIsIFwiMVwiIGV0Yykgb3IgXCJuZXdcIiBpZiBpdCdzIGEgZmllbGQgZm9yIGEgY29tbWFuZCB0aGF0IGRvZXMgbm90IGV4aXN0IHlldC5cclxuICogQHBhcmFtIHNob3dfYXV0b2NvbXBsZXRlX21lbnVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTaGVsbENvbW1hbmRGaWVsZChwbHVnaW46IFNDX1BsdWdpbiwgY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50LCBzZXR0aW5nX3RhYjogU0NfTWFpblNldHRpbmdzVGFiLCBzaGVsbF9jb21tYW5kX2lkOiBzdHJpbmcsIHNob3dfYXV0b2NvbXBsZXRlX21lbnU6IGJvb2xlYW4pIHtcclxuICAgIGNvbnN0IGlzX25ldyA9IFwibmV3XCIgPT09IHNoZWxsX2NvbW1hbmRfaWQ7XHJcbiAgICBsZXQgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kO1xyXG4gICAgaWYgKGlzX25ldykge1xyXG4gICAgICAgIC8vIENyZWF0ZSBhbiBlbXB0eSBjb21tYW5kXHJcbiAgICAgICAgdF9zaGVsbF9jb21tYW5kID0gcGx1Z2luLm5ld1RTaGVsbENvbW1hbmQoKTtcclxuICAgICAgICBzaGVsbF9jb21tYW5kX2lkID0gdF9zaGVsbF9jb21tYW5kLmdldElkKCk7IC8vIFJlcGxhY2UgXCJuZXdcIiB3aXRoIGEgcmVhbCBpZC5cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gVXNlIGFuIG9sZCBzaGVsbCBjb21tYW5kXHJcbiAgICAgICAgdF9zaGVsbF9jb21tYW5kID0gcGx1Z2luLmdldFRTaGVsbENvbW1hbmRzKClbc2hlbGxfY29tbWFuZF9pZF07XHJcbiAgICB9XHJcbiAgICBkZWJ1Z0xvZyhcIkNyZWF0ZSBjb21tYW5kIGZpZWxkIGZvciBjb21tYW5kICNcIiArIHNoZWxsX2NvbW1hbmRfaWQgKyAoaXNfbmV3ID8gXCIgKE5FVylcIiA6IFwiXCIpKTtcclxuICAgIGxldCBzaGVsbF9jb21tYW5kOiBzdHJpbmc7XHJcbiAgICBpZiAoaXNfbmV3KSB7XHJcbiAgICAgICAgc2hlbGxfY29tbWFuZCA9IFwiXCI7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAgIHNoZWxsX2NvbW1hbmQgPSB0X3NoZWxsX2NvbW1hbmQuZ2V0RGVmYXVsdFNoZWxsQ29tbWFuZCgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFdyYXAgYWxsIHNoZWxsIGNvbW1hbmQgc2V0dGluZyBlbGVtZW50cyBpbiBhIHNpbmdsZSBkaXYuXHJcbiAgICBjb25zdCBzaGVsbF9jb21tYW5kX2VsZW1lbnQgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVEaXYoKTtcclxuICAgIHNoZWxsX2NvbW1hbmRfZWxlbWVudC5hZGRDbGFzcyhcIlNDLWlkLVwiICsgc2hlbGxfY29tbWFuZF9pZCk7XHJcblxyXG4gICAgY29uc3Qgc2V0dGluZ19ncm91cCA9IENyZWF0ZVNoZWxsQ29tbWFuZEZpZWxkQ29yZShcclxuICAgICAgICBwbHVnaW4sXHJcbiAgICAgICAgc2hlbGxfY29tbWFuZF9lbGVtZW50LFxyXG4gICAgICAgIGdlbmVyYXRlU2hlbGxDb21tYW5kRmllbGRJY29uQW5kTmFtZSh0X3NoZWxsX2NvbW1hbmQpLFxyXG4gICAgICAgIHNoZWxsX2NvbW1hbmQsXHJcbiAgICAgICAgdF9zaGVsbF9jb21tYW5kLmdldFNoZWxsKCksXHJcbiAgICAgICAgdF9zaGVsbF9jb21tYW5kLFxyXG4gICAgICAgIHNob3dfYXV0b2NvbXBsZXRlX21lbnUsXHJcbiAgICAgICAgYXN5bmMgKHNoZWxsX2NvbW1hbmQ6IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICBpZiAoaXNfbmV3KSB7XHJcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkNyZWF0aW5nIG5ldyBjb21tYW5kIFwiICsgc2hlbGxfY29tbWFuZF9pZCArIFwiOiBcIiArIHNoZWxsX2NvbW1hbmQpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgZGVidWdMb2coXCJDb21tYW5kIFwiICsgc2hlbGxfY29tbWFuZF9pZCArIFwiIGdvbm5hIGNoYW5nZSB0bzogXCIgKyBzaGVsbF9jb21tYW5kKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gRG8gdGhpcyBpbiBib3RoIGNhc2VzLCB3aGVuIGNyZWF0aW5nIGEgbmV3IGNvbW1hbmQgYW5kIHdoZW4gY2hhbmdpbmcgYW4gb2xkIG9uZTpcclxuICAgICAgICAgICAgdF9zaGVsbF9jb21tYW5kLmdldENvbmZpZ3VyYXRpb24oKS5wbGF0Zm9ybV9zcGVjaWZpY19jb21tYW5kcy5kZWZhdWx0ID0gc2hlbGxfY29tbWFuZDtcclxuXHJcbiAgICAgICAgICAgIGlmIChpc19uZXcpIHtcclxuICAgICAgICAgICAgICAgIC8vIENyZWF0ZSBhIG5ldyBjb21tYW5kXHJcbiAgICAgICAgICAgICAgICAvLyBwbHVnaW4ucmVnaXN0ZXJTaGVsbENvbW1hbmQodF9zaGVsbF9jb21tYW5kKTsgLy8gSSBkb24ndCB0aGluayB0aGlzIGlzIG5lZWRlZCB0byBiZSBkb25lIGFueW1vcmVcclxuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiQ29tbWFuZCBjcmVhdGVkLlwiKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIENoYW5nZSBhbiBvbGQgY29tbWFuZFxyXG4gICAgICAgICAgICAgICAgdF9zaGVsbF9jb21tYW5kLnJlbmFtZU9ic2lkaWFuQ29tbWFuZCh0X3NoZWxsX2NvbW1hbmQuZ2V0U2hlbGxDb21tYW5kKCksIHRfc2hlbGxfY29tbWFuZC5nZXRBbGlhcygpKTsgLy8gQ2hhbmdlIHRoZSBjb21tYW5kJ3MgbmFtZSBpbiBPYnNpZGlhbidzIGNvbW1hbmQgcGFsZXR0ZSBhbmQgaW4gaG90a2V5IHNldHRpbmdzLlxyXG4gICAgICAgICAgICAgICAgZGVidWdMb2coXCJDb21tYW5kIGNoYW5nZWQuXCIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGF3YWl0IHBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICB9LFxyXG4gICAgKTtcclxuICAgIHNldHRpbmdfdGFiLnNldHRpbmdfZ3JvdXBzW3NoZWxsX2NvbW1hbmRfaWRdID0gc2V0dGluZ19ncm91cDtcclxuXHJcbiAgICAvLyBQcmltYXJ5IGljb24gYnV0dG9uc1xyXG4gICAgc2V0dGluZ19ncm91cC5uYW1lX3NldHRpbmdcclxuICAgICAgICAuYWRkRXh0cmFCdXR0b24oYnV0dG9uID0+IGJ1dHRvblxyXG4gICAgICAgICAgICAuc2V0VG9vbHRpcChcIk5vcm1hbCBjbGljazogRXhlY3V0ZSBub3cuIFwiICsgQ21kT3JDdHJsKCkgKyBcIiArIGNsaWNrOiBFeGVjdXRlIGFuZCBhc2sgd2hhdCB0byBkbyB3aXRoIG91dHB1dC5cIilcclxuICAgICAgICAgICAgLnNldEljb24oXCJydW4tY29tbWFuZFwiKVxyXG4gICAgICAgICAgICAuZXh0cmFTZXR0aW5nc0VsLmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCBhc3luYyAoZXZlbnQ6IE1vdXNlRXZlbnQpID0+IHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IGN0cmxfY2xpY2tlZCA9IGV2ZW50LmN0cmxLZXk7XHJcbiAgICAgICAgICAgICAgICAvLyBFeGVjdXRlIHRoZSBzaGVsbCBjb21tYW5kIG5vdyAoZm9yIHRyeWluZyBpdCBvdXQgaW4gdGhlIHNldHRpbmdzKVxyXG4gICAgICAgICAgICAgICAgY29uc3QgcGFyc2luZ19wcm9jZXNzID0gdF9zaGVsbF9jb21tYW5kLmNyZWF0ZVBhcnNpbmdQcm9jZXNzKG51bGwpOyAvLyBObyBTQ19FdmVudCBpcyBhdmFpbGFibGUgd2hlbiBleGVjdXRpbmcgc2hlbGwgY29tbWFuZHMgbWFudWFsbHkuXHJcbiAgICAgICAgICAgICAgICBpZiAoYXdhaXQgcGFyc2luZ19wcm9jZXNzLnByb2Nlc3MoKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGV4ZWN1dG9yID0gbmV3IFNoZWxsQ29tbWFuZEV4ZWN1dG9yKHBsdWdpbiwgdF9zaGVsbF9jb21tYW5kLCBudWxsKTsgLy8gTm8gU0NfRXZlbnQgaXMgYXZhaWxhYmxlIHdoZW4gbWFudWFsbHkgZXhlY3V0aW5nIHRoZSBzaGVsbCBjb21tYW5kLlxyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGV4ZWN1dG9yLmRvUHJlYWN0aW9uc0FuZEV4ZWN1dGVTaGVsbENvbW1hbmQoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcnNpbmdfcHJvY2VzcyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgY3RybF9jbGlja2VkID8gXCJtb2RhbFwiIDogdW5kZWZpbmVkIC8vIElmIGN0cmwvY21kIGlzIHByZXNzZWQsIG92ZXJyaWRlIG91dHB1dCBjaGFubmVscyB3aXRoICdBc2sgYWZ0ZXIgZXhlY3V0aW9uJyBtb2RhbC4gT3RoZXJ3aXNlLCB1c2UgdW5kZWZpbmVkIHRvIGluZGljYXRlIHRoYXQgdGhlIHNoZWxsIGNvbW1hbmQncyBub3JtYWwgb3V0cHV0IGNoYW5uZWxzIHNob3VsZCBiZSB1c2VkLlxyXG4gICAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgIHBhcnNpbmdfcHJvY2Vzcy5kaXNwbGF5RXJyb3JNZXNzYWdlcygpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgIClcclxuICAgICAgICAuYWRkRXh0cmFCdXR0b24oYnV0dG9uID0+IGJ1dHRvblxyXG4gICAgICAgICAgICAuc2V0VG9vbHRpcChFeHRyYU9wdGlvbnNNb2RhbC5HRU5FUkFMX09QVElPTlNfU1VNTUFSWSlcclxuICAgICAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gT3BlbiBhbiBleHRyYSBvcHRpb25zIG1vZGFsOiBHZW5lcmFsIHRhYlxyXG4gICAgICAgICAgICAgICAgY29uc3QgbW9kYWwgPSBuZXcgRXh0cmFPcHRpb25zTW9kYWwocGx1Z2luLCBzaGVsbF9jb21tYW5kX2lkLCBzZXR0aW5nX3RhYik7XHJcbiAgICAgICAgICAgICAgICBtb2RhbC5vcGVuKCk7XHJcbiAgICAgICAgICAgICAgICBtb2RhbC5hY3RpdmF0ZVRhYihcImV4dHJhLW9wdGlvbnMtZ2VuZXJhbFwiKTtcclxuICAgICAgICAgICAgfSlcclxuICAgICAgICApXHJcbiAgICAgICAgLmFkZEV4dHJhQnV0dG9uKGJ1dHRvbiA9PiBidXR0b25cclxuICAgICAgICAgICAgLnNldFRvb2x0aXAoRXh0cmFPcHRpb25zTW9kYWwuUFJFQUNUSU9OU19PUFRJT05TX1NVTU1BUlkpXHJcbiAgICAgICAgICAgIC5zZXRJY29uKFwibm90ZS1nbHlwaFwiKVxyXG4gICAgICAgICAgICAub25DbGljayhhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAvLyBPcGVuIGFuIGV4dHJhIG9wdGlvbnMgbW9kYWw6IFByZWFjdGlvbnMgdGFiXHJcbiAgICAgICAgICAgICAgICBjb25zdCBtb2RhbCA9IG5ldyBFeHRyYU9wdGlvbnNNb2RhbChwbHVnaW4sIHNoZWxsX2NvbW1hbmRfaWQsIHNldHRpbmdfdGFiKTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLm9wZW4oKTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLmFjdGl2YXRlVGFiKFwiZXh0cmEtb3B0aW9ucy1wcmVhY3Rpb25zXCIpO1xyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgIClcclxuICAgICAgICAuYWRkRXh0cmFCdXR0b24oYnV0dG9uID0+IGJ1dHRvblxyXG4gICAgICAgICAgICAuc2V0VG9vbHRpcChFeHRyYU9wdGlvbnNNb2RhbC5PVVRQVVRfT1BUSU9OU19TVU1NQVJZKVxyXG4gICAgICAgICAgICAuc2V0SWNvbihcImxpbmVzLW9mLXRleHRcIilcclxuICAgICAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gT3BlbiBhbiBleHRyYSBvcHRpb25zIG1vZGFsOiBPdXRwdXQgdGFiXHJcbiAgICAgICAgICAgICAgICBjb25zdCBtb2RhbCA9IG5ldyBFeHRyYU9wdGlvbnNNb2RhbChwbHVnaW4sIHNoZWxsX2NvbW1hbmRfaWQsIHNldHRpbmdfdGFiKTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLm9wZW4oKTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLmFjdGl2YXRlVGFiKFwiZXh0cmEtb3B0aW9ucy1vdXRwdXRcIik7XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgKVxyXG4gICAgICAgIC5hZGRFeHRyYUJ1dHRvbihidXR0b24gPT4gYnV0dG9uXHJcbiAgICAgICAgICAgIC5zZXRUb29sdGlwKEV4dHJhT3B0aW9uc01vZGFsLkVOVklST05NRU5UU19PUFRJT05TX1NVTU1BUlkpXHJcbiAgICAgICAgICAgIC5zZXRJY29uKFwic3RhY2tlZC1sZXZlbHNcIilcclxuICAgICAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gT3BlbiBhbiBleHRyYSBvcHRpb25zIG1vZGFsOiBFbnZpcm9ubWVudHMgdGFiXHJcbiAgICAgICAgICAgICAgICBjb25zdCBtb2RhbCA9IG5ldyBFeHRyYU9wdGlvbnNNb2RhbChwbHVnaW4sIHNoZWxsX2NvbW1hbmRfaWQsIHNldHRpbmdfdGFiKTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLm9wZW4oKTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLmFjdGl2YXRlVGFiKFwiZXh0cmEtb3B0aW9ucy1lbnZpcm9ubWVudHNcIik7XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgKVxyXG4gICAgICAgIC5hZGRFeHRyYUJ1dHRvbihidXR0b24gPT4gYnV0dG9uXHJcbiAgICAgICAgICAgIC5zZXRUb29sdGlwKEV4dHJhT3B0aW9uc01vZGFsLkVWRU5UU19TVU1NQVJZKVxyXG4gICAgICAgICAgICAuc2V0SWNvbihcImRpY2VcIilcclxuICAgICAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gT3BlbiBhbiBleHRyYSBvcHRpb25zIG1vZGFsOiBFdmVudHMgdGFiXHJcbiAgICAgICAgICAgICAgICBjb25zdCBtb2RhbCA9IG5ldyBFeHRyYU9wdGlvbnNNb2RhbChwbHVnaW4sIHNoZWxsX2NvbW1hbmRfaWQsIHNldHRpbmdfdGFiKTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLm9wZW4oKTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLmFjdGl2YXRlVGFiKFwiZXh0cmEtb3B0aW9ucy1ldmVudHNcIik7XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgKVxyXG4gICAgICAgIC5hZGRFeHRyYUJ1dHRvbihidXR0b24gPT4gYnV0dG9uXHJcbiAgICAgICAgICAgIC5zZXRUb29sdGlwKEV4dHJhT3B0aW9uc01vZGFsLlZBUklBQkxFU19TVU1NQVJZKVxyXG4gICAgICAgICAgICAuc2V0SWNvbihcImNvZGUtZ2x5cGhcIilcclxuICAgICAgICAgICAgLm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gT3BlbiBhbiBleHRyYSBvcHRpb25zIG1vZGFsOiBWYXJpYWJsZXMgdGFiXHJcbiAgICAgICAgICAgICAgICBjb25zdCBtb2RhbCA9IG5ldyBFeHRyYU9wdGlvbnNNb2RhbChwbHVnaW4sIHNoZWxsX2NvbW1hbmRfaWQsIHNldHRpbmdfdGFiKTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLm9wZW4oKTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLmFjdGl2YXRlVGFiKFwiZXh0cmEtb3B0aW9ucy12YXJpYWJsZXNcIik7XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgKVxyXG4gICAgICAgIC5hZGRFeHRyYUJ1dHRvbihidXR0b24gPT4gYnV0dG9uXHJcbiAgICAgICAgICAgIC5zZXRUb29sdGlwKFwiRGVsZXRlIHRoaXMgc2hlbGwgY29tbWFuZFwiKVxyXG4gICAgICAgICAgICAuc2V0SWNvbihcInRyYXNoXCIpXHJcbiAgICAgICAgICAgIC5vbkNsaWNrKGFzeW5jICgpID0+IHtcclxuICAgICAgICAgICAgICAgIC8vIE9wZW4gYSBkZWxldGUgbW9kYWxcclxuICAgICAgICAgICAgICAgIGNvbnN0IG1vZGFsID0gbmV3IERlbGV0ZU1vZGFsKHBsdWdpbiwgc2hlbGxfY29tbWFuZF9pZCwgc2V0dGluZ19ncm91cCwgc2hlbGxfY29tbWFuZF9lbGVtZW50KTtcclxuICAgICAgICAgICAgICAgIG1vZGFsLm9wZW4oKTtcclxuICAgICAgICAgICAgfSlcclxuICAgICAgICApXHJcbiAgICA7XHJcblxyXG4gICAgLy8gSW5mb3JtYXRpb25hbCBpY29ucyAoPSBub24tY2xpY2thYmxlKVxyXG4gICAgY29uc3QgaWNvbl9jb250YWluZXIgPSBzZXR0aW5nX2dyb3VwLm5hbWVfc2V0dGluZy5uYW1lRWwuY3JlYXRlRWwoXCJzcGFuXCIsIHthdHRyOiB7Y2xhc3M6IFwiU0MtbWFpbi1pY29uLWNvbnRhaW5lclwifX0pO1xyXG5cclxuICAgIC8vIFwiQXNrIGNvbmZpcm1hdGlvblwiIGljb24uXHJcbiAgICBjb25zdCBjb25maXJtX2V4ZWN1dGlvbl9pY29uX2NvbnRhaW5lciA9IGljb25fY29udGFpbmVyLmNyZWF0ZUVsKFwic3BhblwiLCB7YXR0cjoge1wiYXJpYS1sYWJlbFwiOiBcIkFza3MgY29uZmlybWF0aW9uIGJlZm9yZSBleGVjdXRpb24uXCIsIGNsYXNzOiBcInNoZWxsLWNvbW1hbmRzLWNvbmZpcm0tZXhlY3V0aW9uLWljb24tY29udGFpbmVyXCJ9fSk7XHJcbiAgICBzZXRJY29uKGNvbmZpcm1fZXhlY3V0aW9uX2ljb25fY29udGFpbmVyLCBcImxhbmd1YWdlc1wiKTtcclxuICAgIGlmICghdF9zaGVsbF9jb21tYW5kLmdldENvbmZpcm1FeGVjdXRpb24oKSkge1xyXG4gICAgICAgIC8vIERvIG5vdCBkaXNwbGF5IHRoZSBpY29uIGZvciBjb21tYW5kcyB0aGF0IGRvIG5vdCB1c2UgY29uZmlybWF0aW9uLlxyXG4gICAgICAgIGNvbmZpcm1fZXhlY3V0aW9uX2ljb25fY29udGFpbmVyLmFkZENsYXNzKFwiU0MtaGlkZVwiKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBcIklnbm9yZWQgZXJyb3IgY29kZXNcIiBpY29uXHJcbiAgICBjb25zdCBpZ25vcmVkX2Vycm9yX2NvZGVzX2ljb25fY29udGFpbmVyID0gaWNvbl9jb250YWluZXIuY3JlYXRlRWwoXCJzcGFuXCIsIHthdHRyOiB7XCJhcmlhLWxhYmVsXCI6IGdlbmVyYXRlSWdub3JlZEVycm9yQ29kZXNJY29uVGl0bGUodF9zaGVsbF9jb21tYW5kLmdldElnbm9yZUVycm9yQ29kZXMoKSksIGNsYXNzOiBcInNoZWxsLWNvbW1hbmRzLWlnbm9yZWQtZXJyb3ItY29kZXMtaWNvbi1jb250YWluZXJcIn19KTtcclxuICAgIHNldEljb24oaWdub3JlZF9lcnJvcl9jb2Rlc19pY29uX2NvbnRhaW5lciwgXCJzdHJpa2V0aHJvdWdoLWdseXBoXCIpO1xyXG4gICAgaWYgKCF0X3NoZWxsX2NvbW1hbmQuZ2V0SWdub3JlRXJyb3JDb2RlcygpLmxlbmd0aCkge1xyXG4gICAgICAgIC8vIERvIG5vdCBkaXNwbGF5IHRoZSBpY29uIGZvciBjb21tYW5kcyB0aGF0IGRvIG5vdCBpZ25vcmUgYW55IGVycm9ycy5cclxuICAgICAgICBpZ25vcmVkX2Vycm9yX2NvZGVzX2ljb25fY29udGFpbmVyLmFkZENsYXNzKFwiU0MtaGlkZVwiKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZWNvbmRhcnkgaWNvbiBidXR0b25zXHJcbiAgICBzZXR0aW5nX2dyb3VwLnByZXZpZXdfc2V0dGluZy5hZGRFeHRyYUJ1dHRvbihidXR0b24gPT4gYnV0dG9uXHJcbiAgICAgICAgLnNldEljb24oXCJsaW5rXCIpXHJcbiAgICAgICAgLnNldFRvb2x0aXAoXCJDb3B5IHRoaXMgc2hlbGwgY29tbWFuZCdzIE9ic2lkaWFuIFVSSSB0byB0aGUgY2xpcGJvYXJkLiBWaXNpdGluZyB0aGUgVVJJIGV4ZWN1dGVzIHRoZSBzaGVsbCBjb21tYW5kLiBcIiArIENtZE9yQ3RybCgpICsgXCIgKyBjbGljazogQ29weSBhIG1hcmtkb3duIGxpbmsuXCIpXHJcblxyXG4gICAgICAgIC8vIG9uQ2xpY2soKSBoYW5kbGVyIC0gdXNlIGEgY3VzdG9tIG9uZSBpbnN0ZWFkIG9mIEV4dHJhQnV0dG9uQ29tcG9uZW50Lm9uQ2xpY2soKSwgYmVjYXVzZSBPYnNpZGlhbiBBUEkgKGF0IGxlYXN0IHYuIDAuMTQuOCkgZG9lcyBub3Qgc3VwcG9ydCBkZXRlY3RpbmcgQ1RSTCBwcmVzcy4gaHR0cHM6Ly9mb3J1bS5vYnNpZGlhbi5tZC90L2ZyLXNldHRpbmdzLXBhc3MtbW91c2VldmVudC10by1leHRyYWJ1dHRvbmNvbXBvbmVudC1vbmNsaWNrLzM3MTc3XHJcbiAgICAgICAgLmV4dHJhU2V0dGluZ3NFbC5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgKGV2ZW50OiBNb3VzZUV2ZW50KSA9PiB7XHJcbiAgICAgICAgICAgIGNvbnN0IGN0cmxfY2xpY2tlZCA9IGV2ZW50LmN0cmxLZXk7XHJcbiAgICAgICAgICAgIGNvbnN0IGV4ZWN1dGlvbl91cmkgPSB0X3NoZWxsX2NvbW1hbmQuZ2V0RXhlY3V0aW9uVVJJKCk7XHJcbiAgICAgICAgICAgIGxldCByZXN1bHQ6IHN0cmluZztcclxuICAgICAgICAgICAgaWYgKGN0cmxfY2xpY2tlZCkge1xyXG4gICAgICAgICAgICAgICAgLy8gQSBmdWxsIGxpbmsgaXMgd2FudGVkLlxyXG4gICAgICAgICAgICAgICAgcmVzdWx0ID0gYFske2VzY2FwZU1hcmtkb3duTGlua0NoYXJhY3RlcnModF9zaGVsbF9jb21tYW5kLmdldEFsaWFzKCkpfV0oJHtlc2NhcGVNYXJrZG93bkxpbmtDaGFyYWN0ZXJzKGV4ZWN1dGlvbl91cmkpfSlgO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgLy8gT25seSB0aGUgVVJJIGlzIHdhbnRlZC5cclxuICAgICAgICAgICAgICAgIHJlc3VsdCA9IGV4ZWN1dGlvbl91cmk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGNvcHlUb0NsaXBib2FyZChyZXN1bHQpO1xyXG4gICAgICAgICAgICBwbHVnaW4ubmV3Tm90aWZpY2F0aW9uKFwiQ29waWVkIHRvIGNsaXBib2FyZDogXCIgKyBFT0wgKyByZXN1bHQpO1xyXG4gICAgICAgIH0pLFxyXG4gICAgKTtcclxuXHJcbiAgICBpZiAodF9zaGVsbF9jb21tYW5kLmNhbkhhdmVIb3RrZXlzKCkpIHtcclxuICAgICAgICBzZXR0aW5nX2dyb3VwLnByZXZpZXdfc2V0dGluZy5hZGRFeHRyYUJ1dHRvbihidXR0b24gPT4gYnV0dG9uXHJcbiAgICAgICAgICAgIC5zZXRJY29uKFwiYW55LWtleVwiKVxyXG4gICAgICAgICAgICAuc2V0VG9vbHRpcChcIkdvIHRvIGhvdGtleSBzZXR0aW5ncy5cIilcclxuICAgICAgICAgICAgLm9uQ2xpY2soKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gVGhlIG1vc3QgaW1wb3J0YW50IHBhcnRzIG9mIHRoaXMgY2xvc3VyZSBmdW5jdGlvbiBhcmUgY29waWVkIDIwMjItMDQtMjcgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vcGplYnkvaG90a2V5LWhlbHBlci9ibG9iL2M4YTAzMmU0YzUyYmQ5Y2UwOGNiOTA5Y2VjMTVkMWVkOWQwYTM0Mzkvc3JjL3BsdWdpbi5qcyNMNDM2LUw0NDIgKGFsc28gZnJvbSBvdGhlciBsaW5lcyBvZiB0aGUgc2FtZSBmaWxlKS5cclxuXHJcbiAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlIFRoaXMgaXMgcHJpdmF0ZSBBUEkgYWNjZXNzLiBOb3QgZ29vZCwgYnV0IHRoZW4gYWdhaW4gdGhlIGZlYXR1cmUgaXMgbm90IGNydWNpYWwgLSBpZiBpdCBicmVha3MsIGl0IHdvbid0IGludGVycnVwdCBhbnl0aGluZyBpbXBvcnRhbnQuXHJcbiAgICAgICAgICAgICAgICBwbHVnaW4uYXBwLnNldHRpbmc/Lm9wZW5UYWJCeUlkKFwiaG90a2V5c1wiKTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXHJcbiAgICAgICAgICAgICAgICBjb25zdCBob3RrZXlzX3NldHRpbmdzX3RhYiA9IHBsdWdpbi5hcHAuc2V0dGluZy5zZXR0aW5nVGFicy5maWx0ZXIodGFiID0+IHRhYi5pZCA9PT0gXCJob3RrZXlzXCIpLnNoaWZ0KCk7XHJcbiAgICAgICAgICAgICAgICBpZiAoaG90a2V5c19zZXR0aW5nc190YWIgJiYgaG90a2V5c19zZXR0aW5nc190YWIuc2VhcmNoSW5wdXRFbCAmJiBob3RrZXlzX3NldHRpbmdzX3RhYi51cGRhdGVIb3RrZXlWaXNpYmlsaXR5KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgZGVidWdMb2coXCJIb3RrZXlzOiBGaWx0ZXJpbmcgYnkgc2hlbGwgY29tbWFuZCBcIiArIHRfc2hlbGxfY29tbWFuZC5nZXRPYnNpZGlhbkNvbW1hbmQoKS5uYW1lKTtcclxuICAgICAgICAgICAgICAgICAgICBob3RrZXlzX3NldHRpbmdzX3RhYi5zZWFyY2hJbnB1dEVsLnZhbHVlID0gdF9zaGVsbF9jb21tYW5kLmdldE9ic2lkaWFuQ29tbWFuZCgpLm5hbWU7XHJcbiAgICAgICAgICAgICAgICAgICAgaG90a2V5c19zZXR0aW5nc190YWIudXBkYXRlSG90a2V5VmlzaWJpbGl0eSgpO1xyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkhvdGtleXM6IENhbm5vdCBkbyBmaWx0ZXJpbmcgZHVlIHRvIEFQSSBjaGFuZ2VzLlwiKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSksXHJcbiAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBZGQgaG90a2V5IGluZm9ybWF0aW9uXHJcbiAgICBpZiAoIWlzX25ldyAmJiB0X3NoZWxsX2NvbW1hbmQuY2FuSGF2ZUhvdGtleXMoKSkge1xyXG4gICAgICAgIGNvbnN0IGhvdGtleXMgPSBnZXRIb3RrZXlzRm9yU2hlbGxDb21tYW5kKHBsdWdpbiwgc2hlbGxfY29tbWFuZF9pZCk7XHJcbiAgICAgICAgaWYgKGhvdGtleXMpIHtcclxuICAgICAgICAgICAgbGV0IGhvdGtleXNfam9pbmVkID0gXCJcIjtcclxuICAgICAgICAgICAgaG90a2V5cy5mb3JFYWNoKChob3RrZXk6IEhvdGtleSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgaWYgKGhvdGtleXNfam9pbmVkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgaG90a2V5c19qb2luZWQgKz0gXCI8YnI+XCI7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBob3RrZXlzX2pvaW5lZCArPSBIb3RrZXlUb1N0cmluZyhob3RrZXkpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgY29uc3QgaG90a2V5X2RpdiA9IHNldHRpbmdfZ3JvdXAucHJldmlld19zZXR0aW5nLmNvbnRyb2xFbC5jcmVhdGVFbChcImRpdlwiLCB7YXR0cjoge2NsYXNzOiBcInNldHRpbmctaXRlbS1kZXNjcmlwdGlvbiBTQy1ob3RrZXktaW5mb1wifX0pO1xyXG4gICAgICAgICAgICAvLyBDb21tZW50IG91dCB0aGUgaWNvbiBiZWNhdXNlIGl0IHdvdWxkIGxvb2sgbGlrZSBhIGNsaWNrYWJsZSBidXR0b24gKGFzIHRoZXJlIGFyZSBvdGhlciBjbGlja2FibGUgaWNvbnMgaW4gdGhlIHNldHRpbmdzKS5cclxuICAgICAgICAgICAgLy8gc2V0SWNvbihob3RrZXlfZGl2LCBcImFueS1rZXlcIiwgMjIpOyAvLyBIb3RrZXkgaWNvblxyXG4gICAgICAgICAgICBob3RrZXlfZGl2Lmluc2VydEFkamFjZW50SFRNTChcImJlZm9yZWVuZFwiLCBcIiBcIiArIGhvdGtleXNfam9pbmVkKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBkZWJ1Z0xvZyhcIkNyZWF0ZWQuXCIpO1xyXG59XHJcblxyXG4vKipcclxuICogQHBhcmFtIHRfc2hlbGxfY29tbWFuZFxyXG4gKiBAcHVibGljIEV4cG9ydGVkIGJlY2F1c2UgU2hlbGxDb21tYW5kRXh0cmFPcHRpb25zTW9kYWwgdXNlcyB0aGlzIHRvby5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZVNoZWxsQ29tbWFuZEZpZWxkSWNvbkFuZE5hbWUodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKSB7XHJcbiAgICBjb25zdCBpY29uX2h0bWwgPSB0X3NoZWxsX2NvbW1hbmQuZ2V0SWNvbkhUTUwoKSArIFwiIFwiO1xyXG4gICAgaWYgKHRfc2hlbGxfY29tbWFuZC5nZXRBbGlhcygpKSB7XHJcbiAgICAgICAgcmV0dXJuIGljb25faHRtbCArIHRfc2hlbGxfY29tbWFuZC5nZXRBbGlhcygpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGljb25faHRtbCArIFwiU2hlbGwgY29tbWFuZCB3aXRob3V0IGFsaWFzXCI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBAcGFyYW0gaWdub3JlZF9lcnJvcl9jb2Rlc1xyXG4gKiBAcHVibGljIEV4cG9ydGVkIGJlY2F1c2UgU2hlbGxDb21tYW5kRXh0cmFPcHRpb25zTW9kYWwgdXNlcyB0aGlzIHRvby5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZUlnbm9yZWRFcnJvckNvZGVzSWNvblRpdGxlKGlnbm9yZWRfZXJyb3JfY29kZXM6IG51bWJlcltdKSB7XHJcbiAgICBjb25zdCBwbHVyYWwgPSBpZ25vcmVkX2Vycm9yX2NvZGVzLmxlbmd0aCAhPT0gMSA/IFwic1wiIDogXCJcIjtcclxuICAgIHJldHVybiBcIklnbm9yZWQgZXJyb3JcIitwbHVyYWwrXCI6IFwiICsgaWdub3JlZF9lcnJvcl9jb2Rlcy5qb2luKFwiLFwiKTtcclxufSIsIi8qXHJcbiAqICdTaGVsbCBjb21tYW5kcycgcGx1Z2luIGZvciBPYnNpZGlhbi5cclxuICogQ29weXJpZ2h0IChDKSAyMDIxIC0gMjAyMyBKYXJra28gTGlubmFudmlydGFcclxuICpcclxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcclxuICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcclxuICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgdmVyc2lvbiAzLjAgb2YgdGhlIExpY2Vuc2UuXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxyXG4gKiBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxyXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuIFNlZSB0aGVcclxuICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cclxuICpcclxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcclxuICogYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXHJcbiAqXHJcbiAqIENvbnRhY3QgdGhlIGF1dGhvciAoSmFya2tvIExpbm5hbnZpcnRhKTogaHR0cHM6Ly9naXRodWIuY29tL1RhaXRhdmEvXHJcbiAqL1xyXG5cclxuaW1wb3J0IHtBcHAsIFBsdWdpblNldHRpbmdUYWIsIFNlYXJjaENvbXBvbmVudCwgU2V0dGluZ30gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCBTQ19QbHVnaW4gZnJvbSBcIi4uL21haW5cIjtcclxuaW1wb3J0IHtnZXRWYXVsdEFic29sdXRlUGF0aCwgZ290b1VSTH0gZnJvbSBcIi4uL0NvbW1vblwiO1xyXG5pbXBvcnQge2NyZWF0ZVNoZWxsU2VsZWN0aW9uRmllbGR9IGZyb20gXCIuL3NldHRpbmdfZWxlbWVudHMvQ3JlYXRlU2hlbGxTZWxlY3Rpb25GaWVsZFwiO1xyXG5pbXBvcnQge2NyZWF0ZVNoZWxsQ29tbWFuZEZpZWxkfSBmcm9tIFwiLi9zZXR0aW5nX2VsZW1lbnRzL0NyZWF0ZVNoZWxsQ29tbWFuZEZpZWxkXCI7XHJcbmltcG9ydCB7Y3JlYXRlVGFicywgVGFiU3RydWN0dXJlfSBmcm9tIFwiLi9zZXR0aW5nX2VsZW1lbnRzL1RhYnNcIjtcclxuaW1wb3J0IHtkZWJ1Z0xvZ30gZnJvbSBcIi4uL0RlYnVnXCI7XHJcbmltcG9ydCB7XHJcbiAgICBEb2N1bWVudGF0aW9uQXV0b2NvbXBsZXRlTGluayxcclxuICAgIERvY3VtZW50YXRpb25NYWluTGluayxcclxuICAgIERvY3VtZW50YXRpb25CdWlsdEluVmFyaWFibGVzSW5kZXhMaW5rLFxyXG4gICAgR2l0SHViTGluayxcclxuICAgIENoYW5nZWxvZ0xpbmssXHJcbiAgICBEb2N1bWVudGF0aW9uQ3VzdG9tVmFyaWFibGVzTGluayxcclxuICAgIExpY2Vuc2VMaW5rLFxyXG4gICAgRG9jdW1lbnRhdGlvbk91dHB1dFdyYXBwZXJzTGluayxcclxufSBmcm9tIFwiLi4vRG9jdW1lbnRhdGlvblwiO1xyXG5pbXBvcnQge2dldFNDX0V2ZW50c30gZnJvbSBcIi4uL2V2ZW50cy9TQ19FdmVudExpc3RcIjtcclxuaW1wb3J0IHtTQ19FdmVudH0gZnJvbSBcIi4uL2V2ZW50cy9TQ19FdmVudFwiO1xyXG5pbXBvcnQge1RTaGVsbENvbW1hbmR9IGZyb20gXCIuLi9UU2hlbGxDb21tYW5kXCI7XHJcbmltcG9ydCB7XHJcbiAgICBDdXN0b21WYXJpYWJsZSxcclxuICAgIEN1c3RvbVZhcmlhYmxlSW5zdGFuY2UsXHJcbiAgICBDdXN0b21WYXJpYWJsZU1vZGVsLFxyXG4gICAgZ2V0TW9kZWwsXHJcbiAgICBjcmVhdGVQQVRIQXVnbWVudGF0aW9uRmllbGRzLFxyXG4gICAgUHJvbXB0LFxyXG4gICAgUHJvbXB0TW9kZWxcclxufSBmcm9tIFwiLi4vaW1wb3J0c1wiO1xyXG5pbXBvcnQge2NyZWF0ZU5ld01vZGVsSW5zdGFuY2VCdXR0b259IGZyb20gXCIuLi9tb2RlbHMvY3JlYXRlTmV3TW9kZWxJbnN0YW5jZUJ1dHRvblwiO1xyXG5pbXBvcnQge0V4ZWN1dGlvbk5vdGlmaWNhdGlvbk1vZGV9IGZyb20gXCIuL1NDX01haW5TZXR0aW5nc1wiO1xyXG5pbXBvcnQge091dHB1dFdyYXBwZXJNb2RlbH0gZnJvbSBcIi4uL21vZGVscy9vdXRwdXRfd3JhcHBlci9PdXRwdXRXcmFwcGVyTW9kZWxcIjtcclxuaW1wb3J0IHtPdXRwdXRXcmFwcGVyfSBmcm9tIFwiLi4vbW9kZWxzL291dHB1dF93cmFwcGVyL091dHB1dFdyYXBwZXJcIjtcclxuaW1wb3J0IHtjcmVhdGVWYXJpYWJsZURlZmF1bHRWYWx1ZUZpZWxkfSBmcm9tIFwiLi9zZXR0aW5nX2VsZW1lbnRzL2NyZWF0ZVZhcmlhYmxlRGVmYXVsdFZhbHVlRmllbGRzXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgU0NfTWFpblNldHRpbmdzVGFiIGV4dGVuZHMgUGx1Z2luU2V0dGluZ1RhYiB7XHJcbiAgICBwcml2YXRlIHJlYWRvbmx5IHBsdWdpbjogU0NfUGx1Z2luO1xyXG5cclxuICAgIHByaXZhdGUgdGFiX3N0cnVjdHVyZTogVGFiU3RydWN0dXJlO1xyXG5cclxuICAgIHB1YmxpYyBzZXR0aW5nX2dyb3VwczogU2V0dGluZ0ZpZWxkR3JvdXBDb250YWluZXIgPSB7fTtcclxuXHJcbiAgICBjb25zdHJ1Y3RvcihhcHA6IEFwcCwgcGx1Z2luOiBTQ19QbHVnaW4pIHtcclxuICAgICAgICBzdXBlcihhcHAsIHBsdWdpbik7XHJcbiAgICAgICAgdGhpcy5wbHVnaW4gPSBwbHVnaW47XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIGRpc3BsYXkoKTogdm9pZCB7XHJcbiAgICAgICAgY29uc3Qge2NvbnRhaW5lckVsfSA9IHRoaXM7XHJcblxyXG4gICAgICAgIGNvbnRhaW5lckVsLmVtcHR5KCk7XHJcblxyXG4gICAgICAgIHRoaXMudGFiX3N0cnVjdHVyZSA9IGNyZWF0ZVRhYnMoY29udGFpbmVyRWwsIHtcclxuICAgICAgICAgICAgXCJtYWluLXNoZWxsLWNvbW1hbmRzXCI6IHtcclxuICAgICAgICAgICAgICAgIHRpdGxlOiBcIlNoZWxsIGNvbW1hbmRzXCIsXHJcbiAgICAgICAgICAgICAgICBpY29uOiBcInJ1bi1jb21tYW5kXCIsXHJcbiAgICAgICAgICAgICAgICBjb250ZW50X2dlbmVyYXRvcjogKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMudGFiU2hlbGxDb21tYW5kcyhjb250YWluZXJfZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBcIm1haW4tZW52aXJvbm1lbnRzXCI6IHtcclxuICAgICAgICAgICAgICAgIHRpdGxlOiBcIkVudmlyb25tZW50c1wiLFxyXG4gICAgICAgICAgICAgICAgaWNvbjogXCJzdGFja2VkLWxldmVsc1wiLFxyXG4gICAgICAgICAgICAgICAgY29udGVudF9nZW5lcmF0b3I6IChjb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnRhYkVudmlyb25tZW50cyhjb250YWluZXJfZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBcIm1haW4tcHJlYWN0aW9uc1wiOiB7XHJcbiAgICAgICAgICAgICAgICB0aXRsZTogXCJQcmVhY3Rpb25zXCIsXHJcbiAgICAgICAgICAgICAgICBpY29uOiBcIm5vdGUtZ2x5cGhcIixcclxuICAgICAgICAgICAgICAgIGNvbnRlbnRfZ2VuZXJhdG9yOiAoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50YWJQcmVhY3Rpb25zKGNvbnRhaW5lcl9lbGVtZW50KTtcclxuICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIFwibWFpbi1vdXRwdXRcIjoge1xyXG4gICAgICAgICAgICAgICAgdGl0bGU6IFwiT3V0cHV0XCIsXHJcbiAgICAgICAgICAgICAgICBpY29uOiBcImxpbmVzLW9mLXRleHRcIixcclxuICAgICAgICAgICAgICAgIGNvbnRlbnRfZ2VuZXJhdG9yOiAoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50YWJPdXRwdXQoY29udGFpbmVyX2VsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgXCJtYWluLWV2ZW50c1wiOiB7XHJcbiAgICAgICAgICAgICAgICB0aXRsZTogXCJFdmVudHNcIixcclxuICAgICAgICAgICAgICAgIGljb246IFwiZGljZVwiLFxyXG4gICAgICAgICAgICAgICAgY29udGVudF9nZW5lcmF0b3I6IChjb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnRhYkV2ZW50cyhjb250YWluZXJfZWxlbWVudCk7XHJcbiAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBcIm1haW4tdmFyaWFibGVzXCI6IHtcclxuICAgICAgICAgICAgICAgIHRpdGxlOiBcIlZhcmlhYmxlc1wiLFxyXG4gICAgICAgICAgICAgICAgaWNvbjogXCJjb2RlLWdseXBoXCIsXHJcbiAgICAgICAgICAgICAgICBjb250ZW50X2dlbmVyYXRvcjogKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMudGFiVmFyaWFibGVzKGNvbnRhaW5lcl9lbGVtZW50KTtcclxuICAgICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIERvY3VtZW50YXRpb24gbGluayAmIEdpdEh1YiBsaW5rc1xyXG4gICAgICAgIGNvbnRhaW5lckVsLmNyZWF0ZUVsKFwicFwiKS5pbnNlcnRBZGphY2VudEhUTUwoXCJiZWZvcmVlbmRcIixcclxuICAgICAgICAgICAgXCI8YSBocmVmPVxcXCJcIiArIERvY3VtZW50YXRpb25NYWluTGluayArIFwiXFxcIj5Eb2N1bWVudGF0aW9uPC9hPiAtIFwiICtcclxuICAgICAgICAgICAgXCI8YSBocmVmPVxcXCJcIiArIEdpdEh1YkxpbmsgKyBcIlxcXCI+U0Mgb24gR2l0SHViPC9hPiAtIFwiICtcclxuICAgICAgICAgICAgXCI8YSBocmVmPVxcXCJcIiArIENoYW5nZWxvZ0xpbmsgKyBcIlxcXCI+U0MgdmVyc2lvbjogXCIgKyB0aGlzLnBsdWdpbi5nZXRQbHVnaW5WZXJzaW9uKCkgKyBcIjwvYT5cIixcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBDb3B5cmlnaHQgbm90aWNlXHJcbiAgICAgICAgY29uc3QgY29weXJpZ2h0X3BhcmFncmFwaCA9IGNvbnRhaW5lckVsLmNyZWF0ZUVsKFwicFwiKTtcclxuICAgICAgICBjb3B5cmlnaHRfcGFyYWdyYXBoLmFkZENsYXNzKFwiU0Mtc21hbGwtZm9udFwiKTtcclxuICAgICAgICBjb3B5cmlnaHRfcGFyYWdyYXBoLmluc2VydEFkamFjZW50SFRNTChcImJlZm9yZWVuZFwiLCBgXHJcbiAgICAgICAgICAgIDxlbT5TaGVsbCBjb21tYW5kczwvZW0+IHBsdWdpbiBDb3B5cmlnaHQgJmNvcHk7IDIwMjEgLSAyMDIzIEphcmtrbyBMaW5uYW52aXJ0YS4gVGhpcyBwcm9ncmFtIGNvbWVzIHdpdGggQUJTT0xVVEVMWSBOTyBXQVJSQU5UWS4gVGhpcyBpcyBmcmVlIHNvZnR3YXJlLCBhbmQgeW91IGFyZSB3ZWxjb21lIHRvIHJlZGlzdHJpYnV0ZSBpdCB1bmRlciBjZXJ0YWluIGNvbmRpdGlvbnMuIFNlZSBtb3JlIGluZm9ybWF0aW9uIGluIHRoZSBsaWNlbnNlOiA8YSBocmVmPVwiJHtMaWNlbnNlTGlua31cIj5HTlUgR1BMLTMuMDwvYT4uXHJcbiAgICAgICAgYCk7XHJcblxyXG4gICAgICAgIC8vIEtFRVAgVEhJUyBBRlRFUiBDUkVBVElORyBBTEwgRUxFTUVOVFM6XHJcbiAgICAgICAgdGhpcy5yZW1lbWJlckxhc3RQb3NpdGlvbihjb250YWluZXJFbCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB0YWJTaGVsbENvbW1hbmRzKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCkge1xyXG4gICAgICAgIC8vIFNob3cgYSBzZWFyY2ggZmllbGRcclxuICAgICAgICB0aGlzLmNyZWF0ZVNlYXJjaEZpZWxkKGNvbnRhaW5lcl9lbGVtZW50KTtcclxuXHJcbiAgICAgICAgLy8gQSA8ZGl2PiBlbGVtZW50IGZvciBhbGwgY29tbWFuZCBpbnB1dCBmaWVsZHMuIE5ldyBjb21tYW5kIGZpZWxkcyBjYW4gYmUgY3JlYXRlZCBhdCB0aGUgYm90dG9tIG9mIHRoaXMgZWxlbWVudC5cclxuICAgICAgICBjb25zdCBjb21tYW5kX2ZpZWxkc19jb250YWluZXIgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVFbChcImRpdlwiKTtcclxuXHJcbiAgICAgICAgLy8gRmllbGRzIGZvciBtb2RpZnlpbmcgZXhpc3RpbmcgY29tbWFuZHNcclxuICAgICAgICBsZXQgc2hlbGxfY29tbWFuZHNfZXhpc3QgPSBmYWxzZTtcclxuICAgICAgICBmb3IgKGNvbnN0IGNvbW1hbmRfaWQgaW4gdGhpcy5wbHVnaW4uZ2V0VFNoZWxsQ29tbWFuZHMoKSkge1xyXG4gICAgICAgICAgICBjcmVhdGVTaGVsbENvbW1hbmRGaWVsZCh0aGlzLnBsdWdpbiwgY29tbWFuZF9maWVsZHNfY29udGFpbmVyLCB0aGlzLCBjb21tYW5kX2lkLCB0aGlzLnBsdWdpbi5zZXR0aW5ncy5zaG93X2F1dG9jb21wbGV0ZV9tZW51KTtcclxuICAgICAgICAgICAgc2hlbGxfY29tbWFuZHNfZXhpc3QgPSB0cnVlO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gJ05vIHNoZWxsIGNvbW1hbmRzIHlldCcgcGFyYWdyYXBoLlxyXG4gICAgICAgIGNvbnN0IG5vX3NoZWxsX2NvbW1hbmRzX3BhcmFncmFwaCA9IGNvbnRhaW5lcl9lbGVtZW50LmNyZWF0ZUVsKFwicFwiLCB7dGV4dDogXCJObyBzaGVsbCBjb21tYW5kcyB5ZXQsIGNsaWNrIHRoZSAnTmV3IHNoZWxsIGNvbW1hbmQnIGJ1dHRvbiBiZWxvdy5cIn0pO1xyXG4gICAgICAgIGlmIChzaGVsbF9jb21tYW5kc19leGlzdCkge1xyXG4gICAgICAgICAgICAvLyBTaGVsbCBjb21tYW5kcyBleGlzdCwgc28gZG8gbm90IHNob3cgdGhlIFwiTm8gc2hlbGwgY29tbWFuZHMgeWV0XCIgdGV4dC5cclxuICAgICAgICAgICAgbm9fc2hlbGxfY29tbWFuZHNfcGFyYWdyYXBoLmhpZGUoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFwiTmV3IGNvbW1hbmRcIiBidXR0b25cclxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgLmFkZEJ1dHRvbihidXR0b24gPT4gYnV0dG9uXHJcbiAgICAgICAgICAgICAgICAuc2V0QnV0dG9uVGV4dChcIk5ldyBzaGVsbCBjb21tYW5kXCIpXHJcbiAgICAgICAgICAgICAgICAub25DbGljayhhc3luYyAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgY3JlYXRlU2hlbGxDb21tYW5kRmllbGQodGhpcy5wbHVnaW4sIGNvbW1hbmRfZmllbGRzX2NvbnRhaW5lciwgdGhpcywgXCJuZXdcIiwgdGhpcy5wbHVnaW4uc2V0dGluZ3Muc2hvd19hdXRvY29tcGxldGVfbWVudSk7XHJcbiAgICAgICAgICAgICAgICAgICAgbm9fc2hlbGxfY29tbWFuZHNfcGFyYWdyYXBoLmhpZGUoKTtcclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIk5ldyBlbXB0eSBjb21tYW5kIGNyZWF0ZWQuXCIpO1xyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgIDtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGNyZWF0ZVNlYXJjaEZpZWxkKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCkge1xyXG4gICAgICAgIGNvbnN0IHNlYXJjaF9jb250YWluZXIgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVEaXYoKTtcclxuICAgICAgICBjb25zdCBzZWFyY2hfdGl0bGUgPSBcIlNlYXJjaCBzaGVsbCBjb21tYW5kc1wiO1xyXG4gICAgICAgIGNvbnN0IHNlYXJjaF9zZXR0aW5nID0gbmV3IFNldHRpbmcoc2VhcmNoX2NvbnRhaW5lcilcclxuICAgICAgICAgICAgLnNldE5hbWUoc2VhcmNoX3RpdGxlKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIkxvb2tzIHVwIHNoZWxsIGNvbW1hbmRzJyBhbGlhc2VzLCBjb21tYW5kcywgaWRzIGFuZCBpY29ucy5cIilcclxuICAgICAgICAgICAgLmFkZFNlYXJjaChzZWFyY2hfY29tcG9uZW50ID0+IHNlYXJjaF9jb21wb25lbnRcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZSgoc2VhcmNoX3Rlcm06IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIGxldCBjb3VudF9tYXRjaGVzID0gMDtcclxuICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IHNoZWxsX2NvbW1hbmRfaWQgaW4gdGhpcy5wbHVnaW4uZ2V0VFNoZWxsQ29tbWFuZHMoKSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgbWF0Y2hlZCA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBpZiBhIHNlYXJjaCB0ZXJtIHdhcyBkZWZpbmVkLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoXCJcIiA9PSBzZWFyY2hfdGVybSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2hvdyBhbGwgc2hlbGwgY29tbWFuZHMuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEEgc2VhcmNoIHRlcm0gaXMgZGVmaW5lZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERlZmluZSBmaWVsZHMgd2hlcmUgdG8gbG9vayBmb3IgdGhlIHNlYXJjaCB0ZXJtXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB0X3NoZWxsX2NvbW1hbmQgPSB0aGlzLnBsdWdpbi5nZXRUU2hlbGxDb21tYW5kcygpW3NoZWxsX2NvbW1hbmRfaWRdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2VhcmNoX3RhcmdldHM6IHN0cmluZ1tdID0gW1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRfc2hlbGxfY29tbWFuZC5nZXRJZCgpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRfc2hlbGxfY29tbWFuZC5nZXRDb25maWd1cmF0aW9uKCkuYWxpYXMsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VhcmNoX3RhcmdldHMucHVzaCguLi5PYmplY3QudmFsdWVzKHRfc2hlbGxfY29tbWFuZC5nZXRQbGF0Zm9ybVNwZWNpZmljU2hlbGxDb21tYW5kcygpKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPbmx5IGluY2x1ZGUgaWNvbiBpbiB0aGUgc2VhcmNoIGlmIGl0J3MgZGVmaW5lZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGljb246IHN0cmluZyB8IG51bGwgPSB0X3NoZWxsX2NvbW1hbmQuZ2V0Q29uZmlndXJhdGlvbigpLmljb247XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoaWNvbikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlYXJjaF90YXJnZXRzLnB1c2goaWNvbik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgaXQncyBhIG1hdGNoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWFyY2hfdGFyZ2V0cy5mb3JFYWNoKChzZWFyY2hfdGFyZ2V0OiBzdHJpbmcpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoc2VhcmNoX3RhcmdldC50b0xvY2FsZUxvd2VyQ2FzZSgpLmNvbnRhaW5zKHNlYXJjaF90ZXJtLnRvTG9jYWxlTG93ZXJDYXNlKCkpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIlNlYXJjaCBcIiArIHNlYXJjaF90ZXJtICsgXCIgTUFUQ0hFRCBcIiArIHNlYXJjaF90YXJnZXQpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG93IG9yIGhpZGUgdGhlIHNoZWxsIGNvbW1hbmQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHNoZWxsX2NvbW1hbmRfZWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXCJkaXYuU0MtaWQtXCIgKyBzaGVsbF9jb21tYW5kX2lkKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFzaGVsbF9jb21tYW5kX2VsZW1lbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlNoZWxsIGNvbW1hbmQgc2V0dGluZyBlbGVtZW50IGRvZXMgbm90IGV4aXN0IHdpdGggc2VsZWN0b3IgZGl2LlNDLWlkLVwiICsgc2hlbGxfY29tbWFuZF9pZCk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWxsX2NvbW1hbmRfZWxlbWVudC5yZW1vdmVDbGFzcyhcIlNDLWhpZGVcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudF9tYXRjaGVzKys7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVsbF9jb21tYW5kX2VsZW1lbnQuYWRkQ2xhc3MoXCJTQy1oaWRlXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyBEaXNwbGF5IG1hdGNoIGNvdW50XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKFwiXCIgPT0gc2VhcmNoX3Rlcm0pIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRG9uJ3Qgc2hvdyBtYXRjaCBjb3VudC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgc2VhcmNoX3NldHRpbmcuc2V0TmFtZShzZWFyY2hfdGl0bGUpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNob3cgbWF0Y2ggY291bnQuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaCAoY291bnRfbWF0Y2hlcykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAwOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VhcmNoX3NldHRpbmcuc2V0TmFtZShcIk5vIG1hdGNoZXNcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlIDE6IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWFyY2hfc2V0dGluZy5zZXROYW1lKFwiMSBtYXRjaFwiKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWFyY2hfc2V0dGluZy5zZXROYW1lKGNvdW50X21hdGNoZXMgKyBcIiBtYXRjaGVzXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSkudGhlbigoc2VhcmNoX2NvbXBvbmVudDogU2VhcmNoQ29tcG9uZW50KSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gRm9jdXMgb24gdGhlIHNlYXJjaCBmaWVsZC5cclxuICAgICAgICAgICAgICAgICAgICBzZWFyY2hfY29tcG9uZW50LmlucHV0RWwuYWRkQ2xhc3MoXCJTQy1mb2N1cy1lbGVtZW50LW9uLXRhYi1vcGVuaW5nXCIpO1xyXG4gICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB0YWJFdmVudHMoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XHJcblxyXG4gICAgICAgIC8vIEEgZ2VuZXJhbCBkZXNjcmlwdGlvbiBhYm91dCBldmVudHNcclxuICAgICAgICBjb250YWluZXJfZWxlbWVudC5jcmVhdGVFbChcInBcIiwge3RleHQ6IFwiRXZlbnRzIGludHJvZHVjZSBhIHdheSB0byBleGVjdXRlIHNoZWxsIGNvbW1hbmRzIGF1dG9tYXRpY2FsbHkgaW4gY2VydGFpbiBzaXR1YXRpb25zLCBlLmcuIHdoZW4gT2JzaWRpYW4gc3RhcnRzLiBUaGV5IGFyZSBzZXQgdXAgZm9yIGVhY2ggc2hlbGwgY29tbWFuZCBzZXBhcmF0ZWx5LCBidXQgdGhpcyB0YWIgY29udGFpbnMgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGVtLlwifSk7XHJcblxyXG4gICAgICAgIC8vIEVuYWJsZS9kaXNhYmxlIGFsbCBldmVudHNcclxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJFbmFibGUgZXZlbnRzXCIpXHJcbiAgICAgICAgICAgIC5zZXREZXNjKFwiVGhpcyBpcyBhIHF1aWNrIHdheSB0byBpbW1lZGlhdGVseSB0dXJuIG9mZiBhbGwgZXZlbnRzLCBpZiB5b3Ugd2FudC5cIilcclxuICAgICAgICAgICAgLmFkZFRvZ2dsZSh0b2dnbGUgPT4gdG9nZ2xlXHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wbHVnaW4uc2V0dGluZ3MuZW5hYmxlX2V2ZW50cylcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAoZW5hYmxlX2V2ZW50czogYm9vbGVhbikgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFRoZSB0b2dnbGUgd2FzIGNsaWNrZWQuXHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MuZW5hYmxlX2V2ZW50cyA9IGVuYWJsZV9ldmVudHM7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKGVuYWJsZV9ldmVudHMpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmVnaXN0ZXIgZXZlbnRzLlxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5yZWdpc3RlclNDX0V2ZW50cyh0cnVlKTtcclxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVbnJlZ2lzdGVyIGV2ZW50cy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4udW5yZWdpc3RlclNDX0V2ZW50cygpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG5cclxuICAgICAgICAvLyBBIGxpc3Qgb2YgY3VycmVudCBlbmFibGUgZXZlbnRzXHJcbiAgICAgICAgY29udGFpbmVyX2VsZW1lbnQuY3JlYXRlRWwoXCJwXCIsIHt0ZXh0OiBcIlRoZSBmb2xsb3dpbmcgZ2l2ZXMganVzdCBhIHF1aWNrIGdsYW5jZSBvdmVyIHdoaWNoIGV2ZW50cyBhcmUgZW5hYmxlZCBvbiB3aGljaCBzaGVsbCBjb21tYW5kcy4gVG8gZW5hYmxlL2Rpc2FibGUgZXZlbnRzIGZvciBhIHNoZWxsIGNvbW1hbmQsIGdvIHRvIHRoZSBwYXJ0aWN1bGFyIHNoZWxsIGNvbW1hbmQncyBzZXR0aW5ncyB2aWEgdGhlICdTaGVsbCBjb21tYW5kcycgdGFiLiBUaGUgbGlzdCBpcyBvbmx5IHVwZGF0ZWQgd2hlbiB5b3UgcmVvcGVuIHRoZSB3aG9sZSBzZXR0aW5ncyBwYW5lbC5cIn0pO1xyXG4gICAgICAgIGxldCBmb3VuZF9lbmFibGVkX2V2ZW50ID0gZmFsc2U7XHJcbiAgICAgICAgZ2V0U0NfRXZlbnRzKHRoaXMucGx1Z2luKS5mb3JFYWNoKChzY19ldmVudDogU0NfRXZlbnQpID0+IHtcclxuICAgICAgICAgICAgY29uc3QgZXZlbnRfZW5hYmxlZF90X3NoZWxsX2NvbW1hbmRzID0gc2NfZXZlbnQuZ2V0VFNoZWxsQ29tbWFuZHMoKTtcclxuICAgICAgICAgICAgLy8gSGFzIHRoZSBldmVudCBiZWVuIGVuYWJsZWQgZm9yIGFueSBzaGVsbCBjb21tYW5kcz9cclxuICAgICAgICAgICAgaWYgKGV2ZW50X2VuYWJsZWRfdF9zaGVsbF9jb21tYW5kcy5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICAgIC8vIFllcywgaXQncyBlbmFibGVkLlxyXG4gICAgICAgICAgICAgICAgLy8gU2hvdyBhIGxpc3Qgb2Ygc2hlbGwgY29tbWFuZHNcclxuICAgICAgICAgICAgICAgIGNvbnN0IHBhcmFncmFwaF9lbGVtZW50ID0gY29udGFpbmVyX2VsZW1lbnQuY3JlYXRlRWwoXCJwXCIsIHt0ZXh0OiBzY19ldmVudC5zdGF0aWMoKS5nZXRUaXRsZSgpfSk7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBsaXN0X2VsZW1lbnQgPSBwYXJhZ3JhcGhfZWxlbWVudC5jcmVhdGVFbChcInVsXCIpO1xyXG4gICAgICAgICAgICAgICAgZXZlbnRfZW5hYmxlZF90X3NoZWxsX2NvbW1hbmRzLmZvckVhY2goKHRfc2hlbGxfY29tbWFuZDogVFNoZWxsQ29tbWFuZCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIGxpc3RfZWxlbWVudC5jcmVhdGVFbChcImxpXCIsIHt0ZXh0OiB0X3NoZWxsX2NvbW1hbmQuZ2V0QWxpYXNPclNoZWxsQ29tbWFuZCgpfSk7XHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgIGZvdW5kX2VuYWJsZWRfZXZlbnQgPSB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgaWYgKCFmb3VuZF9lbmFibGVkX2V2ZW50KSB7XHJcbiAgICAgICAgICAgIGNvbnRhaW5lcl9lbGVtZW50LmNyZWF0ZUVsKFwicFwiLCB7dGV4dDogXCJObyBldmVudHMgYXJlIGVuYWJsZWQgZm9yIGFueSBzaGVsbCBjb21tYW5kcy5cIn0pO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIHRhYlZhcmlhYmxlcyhjb250YWluZXJfZWxlbWVudDogSFRNTEVsZW1lbnQpXHJcbiAgICB7XHJcbiAgICAgICAgLy8gXCJQcmV2aWV3IHZhcmlhYmxlcyBpbiBjb21tYW5kIHBhbGV0dGVcIiBmaWVsZFxyXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0TmFtZShcIlByZXZpZXcgdmFyaWFibGVzIGluIGNvbW1hbmQgcGFsZXR0ZSBhbmQgbWVudXNcIilcclxuICAgICAgICAgICAgLnNldERlc2MoXCJJZiBvbiwgdmFyaWFibGUgbmFtZXMgYXJlIHN1YnN0aXR1dGVkIHdpdGggdGhlaXIgcmVhbHRpbWUgdmFsdWVzIHdoZW4geW91IHZpZXcgeW91ciBjb21tYW5kcyBpbiB0aGUgY29tbWFuZCBwYWxldHRlIGFuZCByaWdodCBjbGljayBjb250ZXh0IG1lbnVzIChpZiB1c2VkKS4gQSBuaWNlIHdheSB0byBlbnN1cmUgeW91ciBjb21tYW5kcyB3aWxsIHVzZSBjb3JyZWN0IHZhbHVlcy5cIilcclxuICAgICAgICAgICAgLmFkZFRvZ2dsZShjaGVja2JveCA9PiBjaGVja2JveFxyXG4gICAgICAgICAgICAgICAgLnNldFZhbHVlKHRoaXMucGx1Z2luLnNldHRpbmdzLnByZXZpZXdfdmFyaWFibGVzX2luX2NvbW1hbmRfcGFsZXR0ZSlcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAodmFsdWU6IGJvb2xlYW4pID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkNoYW5naW5nIHByZXZpZXdfdmFyaWFibGVzX2luX2NvbW1hbmRfcGFsZXR0ZSB0byBcIiArIHZhbHVlKTtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5wcmV2aWV3X3ZhcmlhYmxlc19pbl9jb21tYW5kX3BhbGV0dGUgPSB2YWx1ZTtcclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcblxyXG4gICAgICAgIC8vIFwiU2hvdyBhdXRvY29tcGxldGUgbWVudVwiIGZpZWxkXHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKFwiU2hvdyBhdXRvY29tcGxldGUgbWVudVwiKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIklmIG9uLCBhIGRyb3Bkb3duIG1lbnUgc2hvd3MgdXAgd2hlbiB5b3UgYmVnaW4gd3JpdGluZyB7e3ZhcmlhYmxlfX0gbmFtZXMsIHNob3dpbmcgbWF0Y2hpbmcgdmFyaWFibGVzIGFuZCB0aGVpciBpbnN0cnVjdGlvbnMuIEFsc28gYWxsb3dzIGRlZmluaW5nIGN1c3RvbSBzdWdnZXN0aW9ucyBpbiBhdXRvY29tcGxldGUueWFtbCBmaWxlIC0gc2VlIHRoZSBkb2N1bWVudGF0aW9uLlwiKVxyXG4gICAgICAgICAgICAuYWRkVG9nZ2xlKGNoZWNrYm94ID0+IGNoZWNrYm94XHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wbHVnaW4uc2V0dGluZ3Muc2hvd19hdXRvY29tcGxldGVfbWVudSlcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAodmFsdWU6IGJvb2xlYW4pID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkNoYW5naW5nIHNob3dfYXV0b2NvbXBsZXRlX21lbnUgdG8gXCIgKyB2YWx1ZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3Muc2hvd19hdXRvY29tcGxldGVfbWVudSA9IHZhbHVlO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZGlzcGxheSgpOyAvLyBSZS1yZW5kZXIgdGhlIHdob2xlIHNldHRpbmdzIHZpZXcgdG8gYXBwbHkgdGhlIGNoYW5nZS5cclxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgICAgIC5hZGRFeHRyYUJ1dHRvbihleHRyYV9idXR0b24gPT4gZXh0cmFfYnV0dG9uXHJcbiAgICAgICAgICAgICAgICAuc2V0SWNvbihcImhlbHBcIilcclxuICAgICAgICAgICAgICAgIC5zZXRUb29sdGlwKFwiRG9jdW1lbnRhdGlvbjogQXV0b2NvbXBsZXRlXCIpXHJcbiAgICAgICAgICAgICAgICAub25DbGljaygoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZ290b1VSTChEb2N1bWVudGF0aW9uQXV0b2NvbXBsZXRlTGluayk7XHJcbiAgICAgICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgIDtcclxuXHJcbiAgICAgICAgLy8gQ3VzdG9tIHZhcmlhYmxlc1xyXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0TmFtZShcIkN1c3RvbSB2YXJpYWJsZXNcIilcclxuICAgICAgICAgICAgLnNldEhlYWRpbmcoKSAvLyBNYWtlIHRoZSBcIlZhcmlhYmxlc1wiIHRleHQgYm9sZC5cclxuICAgICAgICAgICAgLmFkZEV4dHJhQnV0dG9uKGV4dHJhX2J1dHRvbiA9PiBleHRyYV9idXR0b25cclxuICAgICAgICAgICAgICAgIC5zZXRJY29uKFwicGFuZS1sYXlvdXRcIilcclxuICAgICAgICAgICAgICAgIC5zZXRUb29sdGlwKFwiT3BlbiBhIHBhbmUgdGhhdCBkaXNwbGF5cyBhbGwgY3VzdG9tIHZhcmlhYmxlcyBhbmQgdGhlaXIgdmFsdWVzLlwiKVxyXG4gICAgICAgICAgICAgICAgLm9uQ2xpY2soKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLmNyZWF0ZUN1c3RvbVZhcmlhYmxlVmlldygpO1xyXG4gICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICAgICAgLmFkZEV4dHJhQnV0dG9uKGV4dHJhX2J1dHRvbiA9PiBleHRyYV9idXR0b25cclxuICAgICAgICAgICAgICAgIC5zZXRJY29uKFwiaGVscFwiKVxyXG4gICAgICAgICAgICAgICAgLnNldFRvb2x0aXAoXCJEb2N1bWVudGF0aW9uOiBDdXN0b20gdmFyaWFibGVzXCIpXHJcbiAgICAgICAgICAgICAgICAub25DbGljaygoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZ290b1VSTChEb2N1bWVudGF0aW9uQ3VzdG9tVmFyaWFibGVzTGluayk7XHJcbiAgICAgICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgIDtcclxuXHJcbiAgICAgICAgLy8gU2V0dGluZ3MgZm9yIGVhY2ggQ3VzdG9tVmFyaWFibGVcclxuICAgICAgICBjb25zdCBjdXN0b21fdmFyaWFibGVfbW9kZWwgPSBnZXRNb2RlbDxDdXN0b21WYXJpYWJsZU1vZGVsPihDdXN0b21WYXJpYWJsZU1vZGVsLm5hbWUpO1xyXG4gICAgICAgIGNvbnN0IGN1c3RvbV92YXJpYWJsZV9jb250YWluZXIgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVEaXYoKTtcclxuICAgICAgICB0aGlzLnBsdWdpbi5nZXRDdXN0b21WYXJpYWJsZUluc3RhbmNlcygpLmZvckVhY2goKGN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZTogQ3VzdG9tVmFyaWFibGVJbnN0YW5jZSkgPT4ge1xyXG4gICAgICAgICAgICBjdXN0b21fdmFyaWFibGVfbW9kZWwuY3JlYXRlU2V0dGluZ0ZpZWxkcyhjdXN0b21fdmFyaWFibGVfaW5zdGFuY2UsIGN1c3RvbV92YXJpYWJsZV9jb250YWluZXIpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIGNyZWF0ZU5ld01vZGVsSW5zdGFuY2VCdXR0b248Q3VzdG9tVmFyaWFibGVNb2RlbCwgQ3VzdG9tVmFyaWFibGVJbnN0YW5jZT4odGhpcy5wbHVnaW4sIEN1c3RvbVZhcmlhYmxlTW9kZWwubmFtZSwgY29udGFpbmVyX2VsZW1lbnQsIGN1c3RvbV92YXJpYWJsZV9jb250YWluZXIsIHRoaXMucGx1Z2luLnNldHRpbmdzKS50aGVuKCk7XHJcblxyXG5cclxuICAgICAgICAvLyBCdWlsdC1pbiB2YXJpYWJsZSBpbnN0cnVjdGlvbnNcclxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJfZWxlbWVudClcclxuICAgICAgICAgICAgLnNldE5hbWUoXCJCdWlsdC1pbiB2YXJpYWJsZXNcIilcclxuICAgICAgICAgICAgLnNldEhlYWRpbmcoKSAvLyBNYWtlIHRoZSBcIlZhcmlhYmxlc1wiIHRleHQgYm9sZC5cclxuICAgICAgICAgICAgLmFkZEV4dHJhQnV0dG9uKGV4dHJhX2J1dHRvbiA9PiBleHRyYV9idXR0b25cclxuICAgICAgICAgICAgICAgIC5zZXRJY29uKFwiaGVscFwiKVxyXG4gICAgICAgICAgICAgICAgLnNldFRvb2x0aXAoXCJEb2N1bWVudGF0aW9uOiBCdWlsdC1pbiB2YXJpYWJsZXNcIilcclxuICAgICAgICAgICAgICAgIC5vbkNsaWNrKCgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBnb3RvVVJMKERvY3VtZW50YXRpb25CdWlsdEluVmFyaWFibGVzSW5kZXhMaW5rKTtcclxuICAgICAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG5cclxuICAgICAgICBmb3IgKGNvbnN0IHZhcmlhYmxlIG9mIHRoaXMucGx1Z2luLmdldFZhcmlhYmxlcygpKSB7XHJcbiAgICAgICAgICAgIGlmICghKHZhcmlhYmxlIGluc3RhbmNlb2YgQ3VzdG9tVmFyaWFibGUpKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCB2YXJpYWJsZVNldHRpbmdHcm91cEVsZW1lbnQgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVEaXYoKTtcclxuICAgICAgICAgICAgICAgIHZhcmlhYmxlU2V0dGluZ0dyb3VwRWxlbWVudC5hZGRDbGFzcyhcIlNDLXNldHRpbmctZ3JvdXBcIik7XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gVmFyaWFibGUgbmFtZSBhbmQgZG9jdW1lbnRhdGlvbiBsaW5rXHJcbiAgICAgICAgICAgICAgICBjb25zdCB2YXJpYWJsZUhlYWRpbmdTZXR0aW5nID0gbmV3IFNldHRpbmcodmFyaWFibGVTZXR0aW5nR3JvdXBFbGVtZW50KSAvLyBVc2UgY29udGFpbmVyX2VsZW1lbnQgaW5zdGVhZCBvZiB2YXJpYWJsZVNldHRpbmdHcm91cC5cclxuICAgICAgICAgICAgICAgICAgICAuc2V0SGVhZGluZygpXHJcbiAgICAgICAgICAgICAgICAgICAgLmFkZEV4dHJhQnV0dG9uKGV4dHJhQnV0dG9uID0+IGV4dHJhQnV0dG9uXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC5zZXRJY29uKFwiaGVscFwiKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAuc2V0VG9vbHRpcChcIkRvY3VtZW50YXRpb246IFwiICsgdmFyaWFibGUuZ2V0RnVsbE5hbWUoKSArIFwiIHZhcmlhYmxlXCIpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC5vbkNsaWNrKCgpID0+IGdvdG9VUkwodmFyaWFibGUuZ2V0RG9jdW1lbnRhdGlvbkxpbmsoKSkpXHJcbiAgICAgICAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgICAgO1xyXG4gICAgICAgICAgICAgICAgdmFyaWFibGVIZWFkaW5nU2V0dGluZy5uYW1lRWwuaW5zZXJ0QWRqYWNlbnRIVE1MKFwiYWZ0ZXJiZWdpblwiLCB2YXJpYWJsZS5nZXRIZWxwTmFtZSgpKTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBWYXJpYWJsZSBkZXNjcmlwdGlvblxyXG4gICAgICAgICAgICAgICAgY29uc3QgdmFyaWFibGVEZXNjcmlwdGlvblNldHRpbmcgPSBuZXcgU2V0dGluZyh2YXJpYWJsZVNldHRpbmdHcm91cEVsZW1lbnQpXHJcbiAgICAgICAgICAgICAgICAgICAgLnNldENsYXNzKFwiU0MtZnVsbC1kZXNjcmlwdGlvblwiKSAvLyBXaXRob3V0IHRoaXMsIGRlc2NyaXB0aW9uIHdvdWxkIGJlIHNocnVuayB0byA1MCUgb2Ygc3BhY2UuIFRoaXMgc2V0dGluZyBkb2VzIG5vdCBoYXZlIGNvbnRyb2wgZWxlbWVudHMsIHNvIDEwMCUgd2lkdGggaXMgb2suXHJcbiAgICAgICAgICAgICAgICA7XHJcbiAgICAgICAgICAgICAgICB2YXJpYWJsZURlc2NyaXB0aW9uU2V0dGluZy5kZXNjRWwuaW5zZXJ0QWRqYWNlbnRIVE1MKFwiYWZ0ZXJiZWdpblwiLCB2YXJpYWJsZS5oZWxwX3RleHQpO1xyXG4gICAgICAgICAgICAgICAgY29uc3QgYXZhaWxhYmlsaXR5X3RleHQ6IHN0cmluZyA9IHZhcmlhYmxlLmdldEF2YWlsYWJpbGl0eVRleHQoKTtcclxuICAgICAgICAgICAgICAgIGlmIChhdmFpbGFiaWxpdHlfdGV4dCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlRGVzY3JpcHRpb25TZXR0aW5nLmRlc2NFbC5pbnNlcnRBZGphY2VudEhUTUwoXCJiZWZvcmVlbmRcIiwgXCI8YnI+XCIgKyBhdmFpbGFiaWxpdHlfdGV4dCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gVmFyaWFibGUgZGVmYXVsdCB2YWx1ZVxyXG4gICAgICAgICAgICAgICAgY29uc3QgZGVmYXVsdFZhbHVlU2V0dGluZ1RpdGxlID0gXCJEZWZhdWx0IHZhbHVlIGZvciBcIit2YXJpYWJsZS5nZXRGdWxsTmFtZSgpO1xyXG4gICAgICAgICAgICAgICAgaWYgKHZhcmlhYmxlLmlzQWx3YXlzQXZhaWxhYmxlKCkpIHtcclxuICAgICAgICAgICAgICAgICAgICBuZXcgU2V0dGluZyh2YXJpYWJsZVNldHRpbmdHcm91cEVsZW1lbnQpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC5zZXROYW1lKGRlZmF1bHRWYWx1ZVNldHRpbmdUaXRsZSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgLnNldERlc2ModmFyaWFibGUuZ2V0RnVsbE5hbWUoKSArIFwiIGlzIGFsd2F5cyBhdmFpbGFibGUsIHNvIGl0IGNhbm5vdCBoYXZlIGEgZGVmYXVsdCB2YWx1ZS5cIilcclxuICAgICAgICAgICAgICAgICAgICA7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZVZhcmlhYmxlRGVmYXVsdFZhbHVlRmllbGQoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZVNldHRpbmdHcm91cEVsZW1lbnQsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHRWYWx1ZVNldHRpbmdUaXRsZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUsXHJcbiAgICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29udGFpbmVyX2VsZW1lbnQuY3JlYXRlRWwoXCJwXCIsIHt0ZXh0OiBcIldoZW4geW91IHR5cGUgdmFyaWFibGVzIGludG8gY29tbWFuZHMsIGEgcHJldmlldyB0ZXh0IGFwcGVhcnMgdW5kZXIgdGhlIGNvbW1hbmQgZmllbGQgdG8gc2hvdyBob3cgdGhlIGNvbW1hbmQgd2lsbCBsb29rIGxpa2Ugd2hlbiBpdCBnZXRzIGV4ZWN1dGVkIHdpdGggdmFyaWFibGVzIHN1YnN0aXR1dGVkIHdpdGggdGhlaXIgcmVhbCB2YWx1ZXMuXCJ9KTtcclxuICAgICAgICBjb250YWluZXJfZWxlbWVudC5jcmVhdGVFbChcInBcIiwge3RleHQ6IFwiU3BlY2lhbCBjaGFyYWN0ZXJzIGluIHZhcmlhYmxlIHZhbHVlcyBhcmUgdHJpZWQgdG8gYmUgZXNjYXBlZCAoZXhjZXB0IGlmIHlvdSB1c2UgQ01EIGFzIHRoZSBzaGVsbCBpbiBXaW5kb3dzKS4gVGhpcyBpcyB0byBpbXByb3ZlIHNlY3VyaXR5IHNvIHRoYXQgYSB2YXJpYWJsZSB3b24ndCBhY2NpZGVudGFsbHkgY2F1c2UgYmFkIHRoaW5ncyB0byBoYXBwZW4uIElmIHlvdSB3YW50IHRvIHVzZSBhIHJhdywgdW5lc2NhcGVkIHZhbHVlLCBhZGQgYW4gZXhjbGFtYXRpb24gbWFyayBiZWZvcmUgdGhlIHZhcmlhYmxlJ3MgbmFtZSwgZS5nLiB7eyF0aXRsZX19LCBidXQgYmUgY2FyZWZ1bCwgaXQncyBkYW5nZXJvdXMhXCJ9KTtcclxuICAgICAgICBjb250YWluZXJfZWxlbWVudC5jcmVhdGVFbChcInBcIiwge3RleHQ6IFwiVGhlcmUgaXMgbm8gd2F5IHRvIHByZXZlbnQgdmFyaWFibGUgcGFyc2luZy4gSWYgeW91IG5lZWQge3sgfX0gY2hhcmFjdGVycyBpbiB5b3VyIGNvbW1hbmQsIHRoZXkgd29uJ3QgYmUgcGFyc2VkIGFzIHZhcmlhYmxlcyBhcyBsb25nIGFzIHRoZXkgZG8gbm90IGNvbnRhaW4gYW55IG9mIHRoZSB2YXJpYWJsZSBuYW1lcyBsaXN0ZWQgYWJvdmUuIElmIHlvdSBuZWVkIHRvIHBhc3MgZS5nLiB7e3RpdGxlfX0gbGl0ZXJhbGx5IHRvIHlvdXIgY29tbWFuZCwgdGhlcmUgaXMgbm8gd2F5IHRvIGRvIGl0IGF0bSwgcGxlYXNlIGNyZWF0ZSBhIGRpc2N1c3Npb24gaW4gR2l0SHViLlwifSk7XHJcbiAgICAgICAgY29udGFpbmVyX2VsZW1lbnQuY3JlYXRlRWwoXCJwXCIsIHt0ZXh0OiBcIkFsbCB2YXJpYWJsZXMgdGhhdCBhY2Nlc3MgdGhlIGN1cnJlbnQgZmlsZSwgbWF5IGNhdXNlIHRoZSBjb21tYW5kIHByZXZpZXcgdG8gZmFpbCBpZiB5b3UgaGFkIG5vIGZpbGUgcGFuZWwgYWN0aXZlIHdoZW4geW91IG9wZW5lZCB0aGUgc2V0dGluZ3Mgd2luZG93IC0gZS5nLiB5b3UgaGFkIGZvY3VzIG9uIGdyYXBoIHZpZXcgaW5zdGVhZCBvZiBhIG5vdGUgPSBubyBmaWxlIGlzIGN1cnJlbnRseSBhY3RpdmUuIEJ1dCB0aGlzIGRvZXMgbm90IGJyZWFrIGFueXRoaW5nIGVsc2UgdGhhbiB0aGUgcHJldmlldy5cIn0pO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgdGFiRW52aXJvbm1lbnRzKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCkge1xyXG4gICAgICAgIC8vIFwiV29ya2luZyBkaXJlY3RvcnlcIiBmaWVsZFxyXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0TmFtZShcIldvcmtpbmcgZGlyZWN0b3J5XCIpXHJcbiAgICAgICAgICAgIC5zZXREZXNjKFwiQSBkaXJlY3Rvcnkgd2hlcmUgeW91ciBjb21tYW5kcyB3aWxsIGJlIHJ1bi4gSWYgZW1wdHksIGRlZmF1bHRzIHRvIHlvdXIgdmF1bHQncyBsb2NhdGlvbi4gQ2FuIGJlIHJlbGF0aXZlICg9IGEgZm9sZGVyIGluIHRoZSB2YXVsdCkgb3IgYWJzb2x1dGUgKD0gY29tcGxldGUgZnJvbSBmaWxlc3lzdGVtIHJvb3QpLlwiKVxyXG4gICAgICAgICAgICAuYWRkVGV4dCh0ZXh0ID0+IHRleHRcclxuICAgICAgICAgICAgICAgIC5zZXRQbGFjZWhvbGRlcihnZXRWYXVsdEFic29sdXRlUGF0aCh0aGlzLmFwcCkpXHJcbiAgICAgICAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wbHVnaW4uc2V0dGluZ3Mud29ya2luZ19kaXJlY3RvcnkpXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKHZhbHVlKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZGVidWdMb2coXCJDaGFuZ2luZyB3b3JraW5nX2RpcmVjdG9yeSB0byBcIiArIHZhbHVlKTtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy53b3JraW5nX2RpcmVjdG9yeSA9IHZhbHVlO1xyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgIDtcclxuXHJcbiAgICAgICAgLy8gUGxhdGZvcm1zJyBkZWZhdWx0IHNoZWxsc1xyXG4gICAgICAgIGNyZWF0ZVNoZWxsU2VsZWN0aW9uRmllbGQodGhpcy5wbHVnaW4sIGNvbnRhaW5lcl9lbGVtZW50LCB0aGlzLnBsdWdpbi5zZXR0aW5ncy5kZWZhdWx0X3NoZWxscywgdHJ1ZSk7XHJcblxyXG4gICAgICAgIC8vIFBBVEggZW52aXJvbm1lbnQgdmFyaWFibGUgZmllbGRzXHJcbiAgICAgICAgY3JlYXRlUEFUSEF1Z21lbnRhdGlvbkZpZWxkcyh0aGlzLnBsdWdpbiwgY29udGFpbmVyX2VsZW1lbnQsIHRoaXMucGx1Z2luLnNldHRpbmdzLmVudmlyb25tZW50X3ZhcmlhYmxlX3BhdGhfYXVnbWVudGF0aW9ucyk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB0YWJQcmVhY3Rpb25zKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCkge1xyXG5cclxuICAgICAgICAvLyBQcm9tcHRzXHJcbiAgICAgICAgY29uc3QgcHJvbXB0X21vZGVsID0gZ2V0TW9kZWw8UHJvbXB0TW9kZWw+KFByb21wdE1vZGVsLm5hbWUpO1xyXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0TmFtZShcIlByb21wdHNcIilcclxuICAgICAgICAgICAgLnNldEhlYWRpbmcoKSAvLyBNYWtlIHRoZSBcIlByb21wdHNcIiB0ZXh0IHRvIGFwcGVhciBhcyBhIGhlYWRpbmcuXHJcbiAgICAgICAgO1xyXG4gICAgICAgIGNvbnN0IHByb21wdHNfY29udGFpbmVyX2VsZW1lbnQgPSBjb250YWluZXJfZWxlbWVudC5jcmVhdGVEaXYoKTtcclxuICAgICAgICB0aGlzLnBsdWdpbi5nZXRQcm9tcHRzKCkuZm9yRWFjaCgocHJvbXB0OiBQcm9tcHQpID0+IHtcclxuICAgICAgICAgICAgcHJvbXB0X21vZGVsLmNyZWF0ZVNldHRpbmdGaWVsZHMocHJvbXB0LCBwcm9tcHRzX2NvbnRhaW5lcl9lbGVtZW50KTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gJ05ldyBwcm9tcHQnIGJ1dHRvblxyXG4gICAgICAgIGNvbnN0IG5ld19wcm9tcHRfYnV0dG9uX3Byb21pc2UgPSBjcmVhdGVOZXdNb2RlbEluc3RhbmNlQnV0dG9uPFByb21wdE1vZGVsLCBQcm9tcHQ+KHRoaXMucGx1Z2luLCBQcm9tcHRNb2RlbC5uYW1lLCBjb250YWluZXJfZWxlbWVudCwgcHJvbXB0c19jb250YWluZXJfZWxlbWVudCwgdGhpcy5wbHVnaW4uc2V0dGluZ3MpO1xyXG4gICAgICAgIG5ld19wcm9tcHRfYnV0dG9uX3Byb21pc2UudGhlbigocmVzdWx0OiB7aW5zdGFuY2U6IFByb21wdCwgbWFpbl9zZXR0aW5nOiBTZXR0aW5nfSkgPT4ge1xyXG4gICAgICAgICAgICBwcm9tcHRfbW9kZWwub3BlblNldHRpbmdzTW9kYWwocmVzdWx0Lmluc3RhbmNlLCByZXN1bHQubWFpbl9zZXR0aW5nKTsgLy8gT3BlbiB0aGUgcHJvbXB0IHNldHRpbmdzIG1vZGFsLCBhcyB0aGUgdXNlciB3aWxsIHByb2JhYmx5IHdhbnQgdG8gY29uZmlndXJlIGl0IG5vdyBhbnl3YXkuXHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSB0YWJPdXRwdXQoY29udGFpbmVyX2VsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XHJcblxyXG4gICAgICAgIC8vIE91dHB1dCB3cmFwcGVyc1xyXG4gICAgICAgIGNvbnN0IG91dHB1dF93cmFwcGVyX21vZGVsID0gZ2V0TW9kZWw8T3V0cHV0V3JhcHBlck1vZGVsPihPdXRwdXRXcmFwcGVyTW9kZWwubmFtZSk7XHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKFwiT3V0cHV0IHdyYXBwZXJzXCIpXHJcbiAgICAgICAgICAgIC5zZXRIZWFkaW5nKCkgLy8gTWFrZSB0aGUgXCJPdXRwdXQgd3JhcHBlcnNcIiB0ZXh0IHRvIGFwcGVhciBhcyBhIGhlYWRpbmcuXHJcbiAgICAgICAgICAgIC5hZGRFeHRyYUJ1dHRvbihleHRyYV9idXR0b24gPT4gZXh0cmFfYnV0dG9uXHJcbiAgICAgICAgICAgICAgICAuc2V0SWNvbihcImhlbHBcIilcclxuICAgICAgICAgICAgICAgIC5zZXRUb29sdGlwKFwiRG9jdW1lbnRhdGlvbjogT3V0cHV0IHdyYXBwZXJzXCIpXHJcbiAgICAgICAgICAgICAgICAub25DbGljaygoKSA9PiBnb3RvVVJMKERvY3VtZW50YXRpb25PdXRwdXRXcmFwcGVyc0xpbmspKVxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgO1xyXG4gICAgICAgIGNvbnN0IG91dHB1dF93cmFwcGVyc19jb250YWluZXJfZWxlbWVudCA9IGNvbnRhaW5lcl9lbGVtZW50LmNyZWF0ZURpdigpO1xyXG4gICAgICAgIHRoaXMucGx1Z2luLmdldE91dHB1dFdyYXBwZXJzKCkuZm9yRWFjaCgob3V0cHV0X3dyYXBwZXI6IE91dHB1dFdyYXBwZXIpID0+IHtcclxuICAgICAgICAgICAgb3V0cHV0X3dyYXBwZXJfbW9kZWwuY3JlYXRlU2V0dGluZ0ZpZWxkcyhvdXRwdXRfd3JhcHBlciwgb3V0cHV0X3dyYXBwZXJzX2NvbnRhaW5lcl9lbGVtZW50KTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gJ05ldyBvdXRwdXQgd3JhcHBlcicgYnV0dG9uXHJcbiAgICAgICAgY29uc3QgbmV3X291dHB1dF93cmFwcGVyX2J1dHRvbl9wcm9taXNlID0gY3JlYXRlTmV3TW9kZWxJbnN0YW5jZUJ1dHRvbjxPdXRwdXRXcmFwcGVyTW9kZWwsIE91dHB1dFdyYXBwZXI+KHRoaXMucGx1Z2luLCBPdXRwdXRXcmFwcGVyTW9kZWwubmFtZSwgY29udGFpbmVyX2VsZW1lbnQsIG91dHB1dF93cmFwcGVyc19jb250YWluZXJfZWxlbWVudCwgdGhpcy5wbHVnaW4uc2V0dGluZ3MpO1xyXG4gICAgICAgIG5ld19vdXRwdXRfd3JhcHBlcl9idXR0b25fcHJvbWlzZS50aGVuKChyZXN1bHQ6IHtpbnN0YW5jZTogT3V0cHV0V3JhcHBlciwgbWFpbl9zZXR0aW5nOiBTZXR0aW5nfSkgPT4ge1xyXG4gICAgICAgICAgICBvdXRwdXRfd3JhcHBlcl9tb2RlbC5vcGVuU2V0dGluZ3NNb2RhbChyZXN1bHQuaW5zdGFuY2UsIHJlc3VsdC5tYWluX3NldHRpbmcpOyAvLyBPcGVuIHRoZSBvdXRwdXQgd3JhcHBlciBzZXR0aW5ncyBtb2RhbCwgYXMgdGhlIHVzZXIgd2lsbCBwcm9iYWJseSB3YW50IHRvIGNvbmZpZ3VyZSBpdCBub3cgYW55d2F5LlxyXG4gICAgICAgIH0pO1xyXG5cclxuXHJcbiAgICAgICAgLy8gXCJFcnJvciBtZXNzYWdlIGR1cmF0aW9uXCIgZmllbGRcclxuICAgICAgICB0aGlzLmNyZWF0ZU5vdGlmaWNhdGlvbkR1cmF0aW9uRmllbGQoY29udGFpbmVyX2VsZW1lbnQsIFwiRXJyb3IgbWVzc2FnZSBkdXJhdGlvblwiLCBcIkNvbmNlcm5zIG1lc3NhZ2VzIGFib3V0IGZhaWxlZCBzaGVsbCBjb21tYW5kcy5cIiwgXCJlcnJvcl9tZXNzYWdlX2R1cmF0aW9uXCIpO1xyXG5cclxuICAgICAgICAvLyBcIk5vdGlmaWNhdGlvbiBtZXNzYWdlIGR1cmF0aW9uXCIgZmllbGRcclxuICAgICAgICB0aGlzLmNyZWF0ZU5vdGlmaWNhdGlvbkR1cmF0aW9uRmllbGQoY29udGFpbmVyX2VsZW1lbnQsIFwiTm90aWZpY2F0aW9uIG1lc3NhZ2UgZHVyYXRpb25cIiwgXCJDb25jZXJucyBpbmZvcm1hdGlvbmFsLCBub24tZmF0YWwgbWVzc2FnZXMsIGUuZy4gb3V0cHV0IGRpcmVjdGVkIHRvICdOb3RpZmljYXRpb24gYmFsbG9vbicuXCIsIFwibm90aWZpY2F0aW9uX21lc3NhZ2VfZHVyYXRpb25cIik7XHJcblxyXG4gICAgICAgIC8vIFwiU2hvdyBhIG5vdGlmaWNhdGlvbiB3aGVuIGV4ZWN1dGluZyBzaGVsbCBjb21tYW5kc1wiIGZpZWxkXHJcbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyX2VsZW1lbnQpXHJcbiAgICAgICAgICAgIC5zZXROYW1lKFwiU2hvdyBhIG5vdGlmaWNhdGlvbiB3aGVuIGV4ZWN1dGluZyBzaGVsbCBjb21tYW5kc1wiKVxyXG4gICAgICAgICAgICAuYWRkRHJvcGRvd24oZHJvcGRvd25fY29tcG9uZW50ID0+IGRyb3Bkb3duX2NvbXBvbmVudFxyXG4gICAgICAgICAgICAgICAgLmFkZE9wdGlvbnMoe1xyXG4gICAgICAgICAgICAgICAgICAgIFwiZGlzYWJsZWRcIjogXCJEbyBub3Qgc2hvd1wiLFxyXG4gICAgICAgICAgICAgICAgICAgIFwicXVpY2tcIjogXCJTaG93IGZvciBcIiArIHRoaXMucGx1Z2luLnNldHRpbmdzLm5vdGlmaWNhdGlvbl9tZXNzYWdlX2R1cmF0aW9uICsgXCIgc2Vjb25kc1wiLFxyXG4gICAgICAgICAgICAgICAgICAgIFwicGVybWFuZW50XCI6IFwiU2hvdyB1bnRpbCB0aGUgcHJvY2VzcyBpcyBmaW5pc2hlZFwiLFxyXG4gICAgICAgICAgICAgICAgICAgIFwiaWYtbG9uZ1wiOiBcIlNob3cgb25seSBpZiBleGVjdXRpbmcgdGFrZXMgbG9uZ1wiLFxyXG4gICAgICAgICAgICAgICAgfSlcclxuICAgICAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnBsdWdpbi5zZXR0aW5ncy5leGVjdXRpb25fbm90aWZpY2F0aW9uX21vZGUpXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKG5ld19leGVjdXRpb25fbm90aWZpY2F0aW9uX21vZGU6IHN0cmluZykgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIFNhdmUgdGhlIGNoYW5nZS5cclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5leGVjdXRpb25fbm90aWZpY2F0aW9uX21vZGUgPSBuZXdfZXhlY3V0aW9uX25vdGlmaWNhdGlvbl9tb2RlIGFzIEV4ZWN1dGlvbk5vdGlmaWNhdGlvbk1vZGU7XHJcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgIDtcclxuXHJcbiAgICAgICAgLy8gXCJPdXRwdXQgY2hhbm5lbCAnQ2xpcGJvYXJkJyBkaXNwbGF5cyBhIG5vdGlmaWNhdGlvbiBtZXNzYWdlLCB0b29cIiBmaWVsZFxyXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0TmFtZShcIk91dHB1dCBjaGFubmVsICdDbGlwYm9hcmQnIGRpc3BsYXlzIGEgbm90aWZpY2F0aW9uIG1lc3NhZ2UsIHRvb1wiKVxyXG4gICAgICAgICAgICAuc2V0RGVzYyhcIklmIGEgc2hlbGwgY29tbWFuZCdzIG91dHB1dCBpcyBkaXJlY3RlZCB0byB0aGUgY2xpcGJvYXJkLCBhbHNvIHNob3cgdGhlIG91dHB1dCBpbiBhIHBvcHVwIGJveCBvbiB0aGUgdG9wIHJpZ2h0IGNvcm5lci4gVGhpcyBoZWxwcyB0byBub3RpY2Ugd2hhdCB3YXMgaW5zZXJ0ZWQgaW50byBjbGlwYm9hcmQuXCIpXHJcbiAgICAgICAgICAgIC5hZGRUb2dnbGUoY2hlY2tib3ggPT4gY2hlY2tib3hcclxuICAgICAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnBsdWdpbi5zZXR0aW5ncy5vdXRwdXRfY2hhbm5lbF9jbGlwYm9hcmRfYWxzb19vdXRwdXRzX3RvX25vdGlmaWNhdGlvbilcclxuICAgICAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAodmFsdWU6IGJvb2xlYW4pID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5vdXRwdXRfY2hhbm5lbF9jbGlwYm9hcmRfYWxzb19vdXRwdXRzX3RvX25vdGlmaWNhdGlvbiA9IHZhbHVlO1xyXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBjcmVhdGVOb3RpZmljYXRpb25EdXJhdGlvbkZpZWxkKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCwgdGl0bGU6IHN0cmluZywgZGVzY3JpcHRpb246IHN0cmluZywgc2V0dGluZ19uYW1lOiBcImVycm9yX21lc3NhZ2VfZHVyYXRpb25cIiB8IFwibm90aWZpY2F0aW9uX21lc3NhZ2VfZHVyYXRpb25cIikge1xyXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lcl9lbGVtZW50KVxyXG4gICAgICAgICAgICAuc2V0TmFtZSh0aXRsZSlcclxuICAgICAgICAgICAgLnNldERlc2MoZGVzY3JpcHRpb24gKyBcIiBJbiBzZWNvbmRzLCBiZXR3ZWVuIDEgYW5kIDE4MC5cIilcclxuICAgICAgICAgICAgLmFkZFRleHQoZmllbGQgPT4gZmllbGRcclxuICAgICAgICAgICAgICAgIC5zZXRWYWx1ZShTdHJpbmcodGhpcy5wbHVnaW4uc2V0dGluZ3Nbc2V0dGluZ19uYW1lXSkpXHJcbiAgICAgICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKGR1cmF0aW9uX3N0cmluZzogc3RyaW5nKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZHVyYXRpb246IG51bWJlciA9IHBhcnNlSW50KGR1cmF0aW9uX3N0cmluZyk7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKGR1cmF0aW9uID49IDEgJiYgZHVyYXRpb24gPD0gMTgwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiQ2hhbmdlIFwiICsgc2V0dGluZ19uYW1lICsgXCIgZnJvbSBcIiArIHRoaXMucGx1Z2luLnNldHRpbmdzW3NldHRpbmdfbmFtZV0gKyBcIiB0byBcIiArIGR1cmF0aW9uKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3Nbc2V0dGluZ19uYW1lXSA9IGR1cmF0aW9uO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgZGVidWdMb2coXCJDaGFuZ2VkLlwiKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gRG9uJ3Qgc2hvdyBhIG5vdGljZSBpZiBkdXJhdGlvbiBpcyBub3QgYmV0d2VlbiAxIGFuZCAxODAsIGJlY2F1c2UgdGhpcyBmdW5jdGlvbiBpcyBjYWxsZWQgZXZlcnkgdGltZSBhIHVzZXIgdHlwZXMgaW4gdGhpcyBmaWVsZCwgc28gdGhlIHZhbHVlIG1pZ2h0IG5vdCBiZSBmaW5hbC5cclxuICAgICAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICAgIClcclxuICAgICAgICA7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBsYXN0X3Bvc2l0aW9uOiB7XHJcbiAgICAgICAgc2Nyb2xsX3Bvc2l0aW9uOiBudW1iZXI7XHJcbiAgICAgICAgdGFiX25hbWU6IHN0cmluZztcclxuICAgIH0gPSB7XHJcbiAgICAgICAgc2Nyb2xsX3Bvc2l0aW9uOiAwLFxyXG4gICAgICAgIHRhYl9uYW1lOiBcIm1haW4tc2hlbGwtY29tbWFuZHNcIixcclxuICAgIH07XHJcbiAgICBwcml2YXRlIHJlbWVtYmVyTGFzdFBvc2l0aW9uKGNvbnRhaW5lcl9lbGVtZW50OiBIVE1MRWxlbWVudCkge1xyXG4gICAgICAgIGNvbnN0IGxhc3RfcG9zaXRpb24gPSB0aGlzLmxhc3RfcG9zaXRpb247XHJcblxyXG4gICAgICAgIC8vIEdvIHRvIGxhc3QgcG9zaXRpb24gbm93XHJcbiAgICAgICAgdGhpcy50YWJfc3RydWN0dXJlLmJ1dHRvbnNbbGFzdF9wb3NpdGlvbi50YWJfbmFtZV0uY2xpY2soKTtcclxuICAgICAgICB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB7IC8vIE5lZWQgdG8gZGVsYXkgdGhlIHNjcm9sbGluZyBhIGJpdC4gV2l0aG91dCB0aGlzLCBzb21ldGhpbmcgZWxzZSB3b3VsZCBvdmVycmlkZSBzY3JvbGxpbmcgYW5kIHNjcm9sbCBiYWNrIHRvIDAuXHJcbiAgICAgICAgICAgIGNvbnRhaW5lcl9lbGVtZW50LnNjcm9sbFRvKHtcclxuICAgICAgICAgICAgICAgIHRvcDogdGhpcy5sYXN0X3Bvc2l0aW9uLnNjcm9sbF9wb3NpdGlvbixcclxuICAgICAgICAgICAgICAgIGJlaGF2aW9yOiBcImF1dG9cIixcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfSwgMCk7IC8vICd0aW1lb3V0JyBjYW4gYmUgMCBtcywgbm8gbmVlZCB0byB3YWl0IGFueSBsb25nZXIuXHJcblxyXG4gICAgICAgIC8vIExpc3RlbiB0byBjaGFuZ2VzXHJcbiAgICAgICAgY29udGFpbmVyX2VsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcInNjcm9sbFwiLCAoZXZlbnQpID0+IHtcclxuICAgICAgICAgICAgdGhpcy5sYXN0X3Bvc2l0aW9uLnNjcm9sbF9wb3NpdGlvbiA9IGNvbnRhaW5lcl9lbGVtZW50LnNjcm9sbFRvcDtcclxuICAgICAgICB9KTtcclxuICAgICAgICBmb3IgKGNvbnN0IHRhYl9uYW1lIGluIHRoaXMudGFiX3N0cnVjdHVyZS5idXR0b25zKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGJ1dHRvbiA9IHRoaXMudGFiX3N0cnVjdHVyZS5idXR0b25zW3RhYl9uYW1lXTtcclxuICAgICAgICAgICAgYnV0dG9uLm9uQ2xpY2tFdmVudCgoZXZlbnQ6IE1vdXNlRXZlbnQpID0+IHtcclxuICAgICAgICAgICAgICAgIGxhc3RfcG9zaXRpb24udGFiX25hbWUgPSB0YWJfbmFtZTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFNldHRpbmdGaWVsZEdyb3VwIHtcclxuICAgIG5hbWVfc2V0dGluZzogU2V0dGluZztcclxuICAgIHNoZWxsX2NvbW1hbmRfc2V0dGluZzogU2V0dGluZztcclxuICAgIHByZXZpZXdfc2V0dGluZzogU2V0dGluZztcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBTZXR0aW5nRmllbGRHcm91cENvbnRhaW5lciB7XHJcbiAgICBba2V5OiBzdHJpbmddOiBTZXR0aW5nRmllbGRHcm91cCxcclxufSIsIi8qKlxyXG4gKiBDb3BpZWQgMjAyMS0xMC0yOSBmcm9tIGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL1RoZURpc3RhbnRTZWEvODAyMTM1OVxyXG4gKiBNb2RpZmljYXRpb25zOlxyXG4gKiAgLSBNYWRlIGNvbXBhdGlibGUgd2l0aCBUeXBlU2NyaXB0IGJ5IGFkZGluZyB0eXBlIGRlZmluaXRpb25zLlxyXG4gKiAgLSBDaGFuZ2VkIHZhciB0byBsZXQuXHJcbiAqXHJcbiAqIENvbXBhcmVzIHR3byBzb2Z0d2FyZSB2ZXJzaW9uIG51bWJlcnMgKGUuZy4gXCIxLjcuMVwiIG9yIFwiMS4yYlwiKS5cclxuICpcclxuICogVGhpcyBmdW5jdGlvbiB3YXMgYm9ybiBpbiBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS82ODMyNzIxLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdjEgVGhlIGZpcnN0IHZlcnNpb24gdG8gYmUgY29tcGFyZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB2MiBUaGUgc2Vjb25kIHZlcnNpb24gdG8gYmUgY29tcGFyZWQuXHJcbiAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc10gT3B0aW9uYWwgZmxhZ3MgdGhhdCBhZmZlY3QgY29tcGFyaXNvbiBiZWhhdmlvcjpcclxuICogPHVsPlxyXG4gKiAgICAgPGxpPlxyXG4gKiAgICAgICAgIDx0dD5sZXhpY29ncmFwaGljYWw6IHRydWU8L3R0PiBjb21wYXJlcyBlYWNoIHBhcnQgb2YgdGhlIHZlcnNpb24gc3RyaW5ncyBsZXhpY29ncmFwaGljYWxseSBpbnN0ZWFkIG9mXHJcbiAqICAgICAgICAgbmF0dXJhbGx5OyB0aGlzIGFsbG93cyBzdWZmaXhlcyBzdWNoIGFzIFwiYlwiIG9yIFwiZGV2XCIgYnV0IHdpbGwgY2F1c2UgXCIxLjEwXCIgdG8gYmUgY29uc2lkZXJlZCBzbWFsbGVyIHRoYW5cclxuICogICAgICAgICBcIjEuMlwiLlxyXG4gKiAgICAgPC9saT5cclxuICogICAgIDxsaT5cclxuICogICAgICAgICA8dHQ+emVyb0V4dGVuZDogdHJ1ZTwvdHQ+IGNoYW5nZXMgdGhlIHJlc3VsdCBpZiBvbmUgdmVyc2lvbiBzdHJpbmcgaGFzIGxlc3MgcGFydHMgdGhhbiB0aGUgb3RoZXIuIEluXHJcbiAqICAgICAgICAgdGhpcyBjYXNlIHRoZSBzaG9ydGVyIHN0cmluZyB3aWxsIGJlIHBhZGRlZCB3aXRoIFwiemVyb1wiIHBhcnRzIGluc3RlYWQgb2YgYmVpbmcgY29uc2lkZXJlZCBzbWFsbGVyLlxyXG4gKiAgICAgPC9saT5cclxuICogPC91bD5cclxuICogQHJldHVybnMge251bWJlcnxOYU59XHJcbiAqIDx1bD5cclxuICogICAgPGxpPjAgaWYgdGhlIHZlcnNpb25zIGFyZSBlcXVhbDwvbGk+XHJcbiAqICAgIDxsaT5hIG5lZ2F0aXZlIGludGVnZXIgaWZmIHYxIDwgdjI8L2xpPlxyXG4gKiAgICA8bGk+YSBwb3NpdGl2ZSBpbnRlZ2VyIGlmZiB2MSA+IHYyPC9saT5cclxuICogICAgPGxpPk5hTiBpZiBlaXRoZXIgdmVyc2lvbiBzdHJpbmcgaXMgaW4gdGhlIHdyb25nIGZvcm1hdDwvbGk+XHJcbiAqIDwvdWw+XHJcbiAqXHJcbiAqIEBjb3B5cmlnaHQgYnkgSm9uIFBhcGFpb2Fubm91IChbXCJqb2huXCIsIFwicGFwYWlvYW5ub3VcIl0uam9pbihcIi5cIikgKyBcIkBnbWFpbC5jb21cIilcclxuICogQGxpY2Vuc2UgVGhpcyBmdW5jdGlvbiBpcyBpbiB0aGUgcHVibGljIGRvbWFpbi4gRG8gd2hhdCB5b3Ugd2FudCB3aXRoIGl0LCBubyBzdHJpbmdzIGF0dGFjaGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHZlcnNpb25Db21wYXJlKHYxOiBzdHJpbmcsIHYyOiBzdHJpbmcsIG9wdGlvbnM6IHtsZXhpY29ncmFwaGljYWw/OiBib29sZWFuLCB6ZXJvRXh0ZW5kPzogYm9vbGVhbn0gPSB7fSkge1xyXG4gICAgbGV0IGxleGljb2dyYXBoaWNhbCA9IG9wdGlvbnMgJiYgb3B0aW9ucy5sZXhpY29ncmFwaGljYWwsXHJcbiAgICAgICAgemVyb0V4dGVuZCA9IG9wdGlvbnMgJiYgb3B0aW9ucy56ZXJvRXh0ZW5kLFxyXG4gICAgICAgIHYxcGFydHM6IGFueSA9IHYxLnNwbGl0KCcuJyksXHJcbiAgICAgICAgdjJwYXJ0czogYW55ID0gdjIuc3BsaXQoJy4nKTtcclxuXHJcbiAgICBmdW5jdGlvbiBpc1ZhbGlkUGFydCh4OiBzdHJpbmcpIHtcclxuICAgICAgICByZXR1cm4gKGxleGljb2dyYXBoaWNhbCA/IC9eXFxkK1tBLVphLXpdKiQvIDogL15cXGQrJC8pLnRlc3QoeCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCF2MXBhcnRzLmV2ZXJ5KGlzVmFsaWRQYXJ0KSB8fCAhdjJwYXJ0cy5ldmVyeShpc1ZhbGlkUGFydCkpIHtcclxuICAgICAgICByZXR1cm4gTmFOO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh6ZXJvRXh0ZW5kKSB7XHJcbiAgICAgICAgd2hpbGUgKHYxcGFydHMubGVuZ3RoIDwgdjJwYXJ0cy5sZW5ndGgpIHYxcGFydHMucHVzaChcIjBcIik7XHJcbiAgICAgICAgd2hpbGUgKHYycGFydHMubGVuZ3RoIDwgdjFwYXJ0cy5sZW5ndGgpIHYycGFydHMucHVzaChcIjBcIik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFsZXhpY29ncmFwaGljYWwpIHtcclxuICAgICAgICB2MXBhcnRzID0gdjFwYXJ0cy5tYXAoTnVtYmVyKTtcclxuICAgICAgICB2MnBhcnRzID0gdjJwYXJ0cy5tYXAoTnVtYmVyKTtcclxuICAgIH1cclxuXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHYxcGFydHMubGVuZ3RoOyArK2kpIHtcclxuICAgICAgICBpZiAodjJwYXJ0cy5sZW5ndGggPT0gaSkge1xyXG4gICAgICAgICAgICByZXR1cm4gMTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICh2MXBhcnRzW2ldID09IHYycGFydHNbaV0pIHtcclxuICAgICAgICAgICAgY29udGludWU7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2UgaWYgKHYxcGFydHNbaV0gPiB2MnBhcnRzW2ldKSB7XHJcbiAgICAgICAgICAgIHJldHVybiAxO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIC0xO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBpZiAodjFwYXJ0cy5sZW5ndGggIT0gdjJwYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICByZXR1cm4gLTE7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIDA7XHJcbn0iLCIvKlxyXG4gKiAnU2hlbGwgY29tbWFuZHMnIHBsdWdpbiBmb3IgT2JzaWRpYW4uXHJcbiAqIENvcHlyaWdodCAoQykgMjAyMSAtIDIwMjMgSmFya2tvIExpbm5hbnZpcnRhXHJcbiAqXHJcbiAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XHJcbiAqIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XHJcbiAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIHZlcnNpb24gMy4wIG9mIHRoZSBMaWNlbnNlLlxyXG4gKlxyXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcclxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcclxuICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiBTZWUgdGhlXHJcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXHJcbiAqXHJcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXHJcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiBJZiBub3QsIHNlZSA8aHR0cHM6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxyXG4gKlxyXG4gKiBDb250YWN0IHRoZSBhdXRob3IgKEphcmtrbyBMaW5uYW52aXJ0YSk6IGh0dHBzOi8vZ2l0aHViLmNvbS9UYWl0YXZhL1xyXG4gKi9cclxuXHJcbmltcG9ydCB7XHJcblx0Q3VzdG9tVmFyaWFibGUsXHJcblx0Q3VzdG9tVmFyaWFibGVJbnN0YW5jZU1hcCxcclxuXHRDdXN0b21WYXJpYWJsZU1vZGVsLFxyXG5cdEN1c3RvbVZhcmlhYmxlVmlldyxcclxuXHRnZXRJREdlbmVyYXRvcixcclxuXHRnZXRNb2RlbCxcclxuXHRpbnRyb2R1Y2VNb2RlbHMsXHJcblx0UHJvbXB0TWFwLFxyXG5cdFByb21wdE1vZGVsLFxyXG5cdFNoZWxsQ29tbWFuZEV4ZWN1dG9yLFxyXG59IGZyb20gXCIuL2ltcG9ydHNcIjtcclxuaW1wb3J0IHtcclxuICAgIENvbW1hbmQsXHJcbiAgICBOb3RpY2UsXHJcbiAgICBPYnNpZGlhblByb3RvY29sRGF0YSxcclxuICAgIFBsdWdpbixcclxuICAgIHNldEljb24sXHJcbiAgICBXb3Jrc3BhY2VMZWFmLFxyXG59IGZyb20gJ29ic2lkaWFuJztcclxuaW1wb3J0IHtcclxuXHRjb21iaW5lT2JqZWN0cyxcclxuXHRnZW5lcmF0ZU9ic2lkaWFuQ29tbWFuZE5hbWUsXHJcblx0Z2V0T3BlcmF0aW5nU3lzdGVtLFxyXG5cdGdldFBsdWdpbkFic29sdXRlUGF0aCxcclxufSBmcm9tIFwiLi9Db21tb25cIjtcclxuaW1wb3J0IHtSdW5NaWdyYXRpb25zfSBmcm9tIFwiLi9NaWdyYXRpb25zXCI7XHJcbmltcG9ydCB7XHJcbiAgICBuZXdTaGVsbENvbW1hbmRDb25maWd1cmF0aW9uLFxyXG4gICAgU2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbixcclxufSBmcm9tIFwiLi9zZXR0aW5ncy9TaGVsbENvbW1hbmRDb25maWd1cmF0aW9uXCI7XHJcbmltcG9ydCB7XHJcblx0Z2V0RGVmYXVsdFNldHRpbmdzLFxyXG5cdFNldHRpbmdzVmVyc2lvblN0cmluZyxcclxuXHRTQ19NYWluU2V0dGluZ3MsXHJcbn0gZnJvbSBcIi4vc2V0dGluZ3MvU0NfTWFpblNldHRpbmdzXCI7XHJcbmltcG9ydCB7T2JzaWRpYW5Db21tYW5kc0NvbnRhaW5lcn0gZnJvbSBcIi4vT2JzaWRpYW5Db21tYW5kc0NvbnRhaW5lclwiO1xyXG5pbXBvcnQge1NDX01haW5TZXR0aW5nc1RhYn0gZnJvbSBcIi4vc2V0dGluZ3MvU0NfTWFpblNldHRpbmdzVGFiXCI7XHJcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcInBhdGhcIjtcclxuaW1wb3J0ICogYXMgZnMgZnJvbSBcImZzXCI7XHJcbmltcG9ydCB7U2hlbGxDb21tYW5kUGFyc2luZ1Byb2Nlc3MsIFRTaGVsbENvbW1hbmQsIFRTaGVsbENvbW1hbmRDb250YWluZXJ9IGZyb20gXCIuL1RTaGVsbENvbW1hbmRcIjtcclxuaW1wb3J0IHtnZXRVc2Vyc0RlZmF1bHRTaGVsbH0gZnJvbSBcIi4vU2hlbGxcIjtcclxuaW1wb3J0IHt2ZXJzaW9uQ29tcGFyZX0gZnJvbSBcIi4vbGliL3ZlcnNpb25fY29tcGFyZVwiO1xyXG5pbXBvcnQge2RlYnVnTG9nLCBzZXRERUJVR19PTn0gZnJvbSBcIi4vRGVidWdcIjtcclxuaW1wb3J0IHthZGRDdXN0b21BdXRvY29tcGxldGVJdGVtc30gZnJvbSBcIi4vc2V0dGluZ3Mvc2V0dGluZ19lbGVtZW50cy9BdXRvY29tcGxldGVcIjtcclxuaW1wb3J0IHtnZXRTQ19FdmVudHN9IGZyb20gXCIuL2V2ZW50cy9TQ19FdmVudExpc3RcIjtcclxuaW1wb3J0IHtTQ19FdmVudH0gZnJvbSBcIi4vZXZlbnRzL1NDX0V2ZW50XCI7XHJcbmltcG9ydCB7XHJcblx0bG9hZFZhcmlhYmxlcyxcclxuXHRWYXJpYWJsZVNldCxcclxufSBmcm9tIFwiLi92YXJpYWJsZXMvbG9hZFZhcmlhYmxlc1wiO1xyXG5pbXBvcnQge1xyXG4gICAgT3V0cHV0V3JhcHBlck1hcCxcclxuICAgIE91dHB1dFdyYXBwZXJNb2RlbCxcclxufSBmcm9tIFwiLi9tb2RlbHMvb3V0cHV0X3dyYXBwZXIvT3V0cHV0V3JhcHBlck1vZGVsXCI7XHJcbmltcG9ydCB7UGFyc2luZ1Jlc3VsdH0gZnJvbSBcIi4vdmFyaWFibGVzL3BhcnNlVmFyaWFibGVzXCI7XHJcbmltcG9ydCB7QXV0b2NvbXBsZXRlUmVzdWx0fSBmcm9tIFwiYXV0b2NvbXBsZXRlci9hdXRvY29tcGxldGVcIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFNDX1BsdWdpbiBleHRlbmRzIFBsdWdpbiB7XHJcblx0LyoqXHJcblx0ICogRGVmaW5lcyB0aGUgc2V0dGluZ3Mgc3RydWN0dXJlIHZlcnNpb24uIENoYW5nZSB0aGlzIHdoZW4gYSBuZXcgcGx1Z2luIHZlcnNpb24gaXMgcmVsZWFzZWQsIGJ1dCBvbmx5IGlmIHRoYXQgcGx1Z2luXHJcblx0ICogdmVyc2lvbiBpbnRyb2R1Y2VzIGNoYW5nZXMgdG8gdGhlIHNldHRpbmdzIHN0cnVjdHVyZS4gRG8gbm90IGNoYW5nZSBpZiB0aGUgc2V0dGluZ3Mgc3RydWN0dXJlIHN0YXlzIHVuY2hhbmdlZC5cclxuXHQgKi9cclxuXHRwdWJsaWMgc3RhdGljIFNldHRpbmdzVmVyc2lvbjogU2V0dGluZ3NWZXJzaW9uU3RyaW5nID0gXCIwLjE4LjBcIjtcclxuXHJcblx0cHVibGljIHNldHRpbmdzOiBTQ19NYWluU2V0dGluZ3M7IC8vIFRPRE86IFJlbmFtZSB0byAnY29uZmlndXJhdGlvbicuXHJcblx0cHVibGljIG9ic2lkaWFuX2NvbW1hbmRzOiBPYnNpZGlhbkNvbW1hbmRzQ29udGFpbmVyID0ge307XHJcblx0cHJpdmF0ZSB0X3NoZWxsX2NvbW1hbmRzOiBUU2hlbGxDb21tYW5kQ29udGFpbmVyID0ge307XHJcblx0cHJpdmF0ZSBwcm9tcHRzOiBQcm9tcHRNYXA7XHJcblx0cHJpdmF0ZSBjdXN0b21fdmFyaWFibGVfaW5zdGFuY2VzOiBDdXN0b21WYXJpYWJsZUluc3RhbmNlTWFwO1xyXG5cdHByaXZhdGUgdmFyaWFibGVzOiBWYXJpYWJsZVNldDtcclxuICAgIHByaXZhdGUgb3V0cHV0X3dyYXBwZXJzOiBPdXRwdXRXcmFwcGVyTWFwO1xyXG5cclxuXHQvKipcclxuXHQgKiBIb2xkZXIgZm9yIHNoZWxsIGNvbW1hbmRzIGFuZCBhbGlhc2VzLCB3aG9zZSB2YXJpYWJsZXMgYXJlIHBhcnNlZCBiZWZvcmUgdGhlIGFjdHVhbCBleGVjdXRpb24gZHVyaW5nIGNvbW1hbmRcclxuXHQgKiBwYWxldHRlIHByZXZpZXcuIFRoaXMgYXJyYXkgZ2V0cyBlbXB0aWVkIGFmdGVyIGV2ZXJ5IHRpbWUgYSBzaGVsbCBjb21tYW5kIGlzIGV4ZWN1dGVkIHZpYSB0aGUgY29tbWFuZCBwYWxldHRlLlxyXG5cdCAqXHJcblx0ICogVGhpcyBpcyBvbmx5IHVzZWQgZm9yIGNvbW1hbmQgcGFsZXR0ZSwgbm90IHdoZW4gZXhlY3V0aW5nIGEgc2hlbGwgY29tbWFuZCBmcm9tIHRoZSBzZXR0aW5ncyBwYW5lbCwgbm9yIHdoZW5cclxuXHQgKiBleGVjdXRpbmcgc2hlbGwgY29tbWFuZHMgdmlhIFNDX0V2ZW50cy5cclxuXHQgKlxyXG5cdCAqIEBwcml2YXRlXHJcblx0ICovXHJcblx0cHJpdmF0ZSBjYWNoZWRfcGFyc2luZ19wcm9jZXNzZXM6IHtcclxuXHRcdFtrZXk6IHN0cmluZ106IFNoZWxsQ29tbWFuZFBhcnNpbmdQcm9jZXNzIHwgdW5kZWZpbmVkLFxyXG5cdH0gPSB7fTtcclxuXHJcblx0cHVibGljIHN0YXRpYyByZWFkb25seSBTSEVMTF9DT01NQU5EU19VUklfQUNUSU9OID0gXCJzaGVsbC1jb21tYW5kc1wiO1xyXG5cclxuICAgIC8qKiBAc2VlIGdldE91dHB1dFN0YXR1c0JhckVsZW1lbnQoKSAqL1xyXG4gICAgcHJpdmF0ZSBzdGF0dXNCYXJFbGVtZW50OiBIVE1MRWxlbWVudDtcclxuXHJcbiAgICBwcml2YXRlIGF1dG9jb21wbGV0ZU1lbnVzOiBBdXRvY29tcGxldGVSZXN1bHRbXSA9IFtdO1xyXG5cclxuXHRwdWJsaWMgYXN5bmMgb25sb2FkKCkge1xyXG5cdFx0ZGVidWdMb2coJ2xvYWRpbmcgcGx1Z2luJyk7XHJcblxyXG5cdFx0Ly8gTG9hZCBzZXR0aW5nc1xyXG5cdFx0aWYgKCFhd2FpdCB0aGlzLmxvYWRTZXR0aW5ncygpKSB7XHJcblx0XHRcdC8vIExvYWRpbmcgdGhlIHNldHRpbmdzIGhhcyBmYWlsZWQgZHVlIHRvIGFuIHVuc3VwcG9ydGVkIHNldHRpbmdzIGZpbGUgdmVyc2lvbi5cclxuXHRcdFx0Ly8gVGhlIHBsdWdpbiBzaG91bGQgbm90IGJlIHVzZWQsIGFuZCBpdCBoYXMgYWN0dWFsbHkgZGlzYWJsZWQgaXRzZWxmLCBidXQgdGhlIGNvZGUgZXhlY3V0aW9uIG5lZWRzIHRvIGJlXHJcblx0XHRcdC8vIHN0b3BwZWQgbWFudWFsbHkuXHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBEZWZpbmUgbW9kZWxzXHJcblx0XHRpbnRyb2R1Y2VNb2RlbHModGhpcyk7XHJcblxyXG5cdFx0Ly8gUnVuIHBvc3NpYmxlIGNvbmZpZ3VyYXRpb24gbWlncmF0aW9uc1xyXG5cdFx0YXdhaXQgUnVuTWlncmF0aW9ucyh0aGlzKTtcclxuXHJcblx0XHQvLyBHZW5lcmF0ZSBUU2hlbGxDb21tYW5kIG9iamVjdHMgZnJvbSBjb25maWd1cmF0aW9uIChvbmx5IGFmdGVyIGNvbmZpZ3VyYXRpb24gbWlncmF0aW9ucyBhcmUgZG9uZSlcclxuXHRcdHRoaXMubG9hZFRTaGVsbENvbW1hbmRzKCk7XHJcblxyXG5cdFx0Ly8gTG9hZCBQcm9tcHRzXHJcblx0XHRjb25zdCBwcm9tcHRfbW9kZWwgPSBnZXRNb2RlbDxQcm9tcHRNb2RlbD4oUHJvbXB0TW9kZWwubmFtZSk7XHJcblx0XHR0aGlzLnByb21wdHMgPSBwcm9tcHRfbW9kZWwubG9hZEluc3RhbmNlcyh0aGlzLnNldHRpbmdzKTtcclxuXHJcblx0XHQvLyBMb2FkIEN1c3RvbVZhcmlhYmxlcyAoY29uZmlndXJhdGlvbiBpbnN0YW5jZXMpXHJcblx0XHRjb25zdCBjdXN0b21fdmFyaWFibGVfbW9kZWwgPSBnZXRNb2RlbDxDdXN0b21WYXJpYWJsZU1vZGVsPihDdXN0b21WYXJpYWJsZU1vZGVsLm5hbWUpO1xyXG5cdFx0dGhpcy5jdXN0b21fdmFyaWFibGVfaW5zdGFuY2VzID0gY3VzdG9tX3ZhcmlhYmxlX21vZGVsLmxvYWRJbnN0YW5jZXModGhpcy5zZXR0aW5ncyk7XHJcblxyXG5cdFx0Ly8gTG9hZCB2YXJpYWJsZXMgKGJvdGggYnVpbHQtaW4gYW5kIGN1c3RvbSBvbmVzKS4gRG8gdGhpcyBBRlRFUiBsb2FkaW5nIGNvbmZpZ3MgZm9yIGN1c3RvbSB2YXJpYWJsZXMhXHJcblx0XHR0aGlzLnZhcmlhYmxlcyA9IGxvYWRWYXJpYWJsZXModGhpcyk7XHJcblxyXG4gICAgICAgIC8vIExvYWQgb3V0cHV0IHdyYXBwZXJzXHJcbiAgICAgICAgY29uc3Qgb3V0cHV0X3dyYXBwZXJfbW9kZWwgPSBnZXRNb2RlbDxPdXRwdXRXcmFwcGVyTW9kZWw+KE91dHB1dFdyYXBwZXJNb2RlbC5uYW1lKTtcclxuICAgICAgICB0aGlzLm91dHB1dF93cmFwcGVycyA9IG91dHB1dF93cmFwcGVyX21vZGVsLmxvYWRJbnN0YW5jZXModGhpcy5zZXR0aW5ncyk7XHJcblxyXG5cdFx0Ly8gTWFrZSBhbGwgZGVmaW5lZCBzaGVsbCBjb21tYW5kcyB0byBhcHBlYXIgaW4gdGhlIE9ic2lkaWFuIGNvbW1hbmQgcGFsZXR0ZS5cclxuXHRcdGNvbnN0IHNoZWxsX2NvbW1hbmRzID0gdGhpcy5nZXRUU2hlbGxDb21tYW5kcygpO1xyXG5cdFx0Zm9yIChjb25zdCBzaGVsbF9jb21tYW5kX2lkIGluIHNoZWxsX2NvbW1hbmRzKSB7XHJcblx0XHRcdGNvbnN0IHRfc2hlbGxfY29tbWFuZCA9IHNoZWxsX2NvbW1hbmRzW3NoZWxsX2NvbW1hbmRfaWRdO1xyXG5cdFx0XHRpZiAodF9zaGVsbF9jb21tYW5kLmNhbkFkZFRvQ29tbWFuZFBhbGV0dGUoKSkge1xyXG5cdFx0XHRcdHRoaXMucmVnaXN0ZXJTaGVsbENvbW1hbmQodF9zaGVsbF9jb21tYW5kKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFBlcmZvcm0gZXZlbnQgcmVnaXN0cmF0aW9ucywgaWYgZW5hYmxlZC5cclxuXHRcdGlmICh0aGlzLnNldHRpbmdzLmVuYWJsZV9ldmVudHMpIHtcclxuXHRcdFx0dGhpcy5yZWdpc3RlclNDX0V2ZW50cyhmYWxzZSk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gTG9hZCBhIGN1c3RvbSBhdXRvY29tcGxldGUgbGlzdCBpZiBpdCBleGlzdHMuXHJcblx0XHR0aGlzLmxvYWRDdXN0b21BdXRvY29tcGxldGVMaXN0KCk7XHJcblxyXG5cdFx0Ly8gQ3JlYXRlIGEgU2V0dGluZ3NUYWIuXHJcblx0XHR0aGlzLmFkZFNldHRpbmdUYWIobmV3IFNDX01haW5TZXR0aW5nc1RhYih0aGlzLmFwcCwgdGhpcykpO1xyXG5cclxuXHRcdC8vIE1ha2UgaXQgcG9zc2libGUgdG8gY3JlYXRlIEN1c3RvbVZhcmlhYmxlVmlld3MuXHJcblx0XHR0aGlzLnJlZ2lzdGVyVmlldyhDdXN0b21WYXJpYWJsZVZpZXcuVmlld1R5cGUsIChsZWFmOiBXb3Jrc3BhY2VMZWFmKSA9PiBuZXcgQ3VzdG9tVmFyaWFibGVWaWV3KHRoaXMsIGxlYWYpKTtcclxuXHJcblx0XHQvLyBEZWJ1ZyByZXNlcnZlZCBJRHNcclxuXHRcdGRlYnVnTG9nKFwiSURHZW5lcmF0b3IncyByZXNlcnZlZCBJRHM6XCIpO1xyXG5cdFx0ZGVidWdMb2coZ2V0SURHZW5lcmF0b3IoKS5nZXRSZXNlcnZlZElEcygpKTtcclxuXHJcblx0XHQvLyBSZWdpc3RlciBhbiBVUkkgaGFuZGxlci5cclxuXHRcdHRoaXMucmVnaXN0ZXJVUklIYW5kbGVyKCk7XHJcblx0fVxyXG5cclxuXHRwcml2YXRlIGxvYWRUU2hlbGxDb21tYW5kcygpIHtcclxuXHRcdHRoaXMudF9zaGVsbF9jb21tYW5kcyA9IHt9OyAvLyBUT0RPOiBDb25zaWRlciBjaGFuZ2luZyB0aGlzIHRvIGVpdGhlciBhbiBhcnJheSBvciBhIE1hcC5cclxuXHRcdGNvbnN0IHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbnMgPSB0aGlzLmdldFNoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb25zKCk7XHJcblxyXG5cdFx0Zm9yIChjb25zdCBzaGVsbF9jb21tYW5kX2NvbmZpZ3VyYXRpb24gb2Ygc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9ucykge1xyXG5cdFx0XHR0aGlzLnRfc2hlbGxfY29tbWFuZHNbc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uLmlkXSA9IG5ldyBUU2hlbGxDb21tYW5kKHRoaXMsIHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbik7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRwdWJsaWMgZ2V0VFNoZWxsQ29tbWFuZHMoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy50X3NoZWxsX2NvbW1hbmRzO1xyXG5cdH1cclxuXHJcblx0cHVibGljIGdldFZhcmlhYmxlcygpIHtcclxuXHRcdHJldHVybiB0aGlzLnZhcmlhYmxlcztcclxuXHR9XHJcblxyXG5cdHB1YmxpYyBnZXRQcm9tcHRzKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMucHJvbXB0cztcclxuXHR9XHJcblxyXG5cdHB1YmxpYyBnZXRDdXN0b21WYXJpYWJsZUluc3RhbmNlcygpOiBDdXN0b21WYXJpYWJsZUluc3RhbmNlTWFwIHtcclxuXHRcdHJldHVybiB0aGlzLmN1c3RvbV92YXJpYWJsZV9pbnN0YW5jZXM7XHJcblx0fVxyXG5cclxuXHRwcml2YXRlIGdldFNoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb25zKCk6IFNoZWxsQ29tbWFuZENvbmZpZ3VyYXRpb25bXSB7XHJcblx0XHRyZXR1cm4gdGhpcy5zZXR0aW5ncy5zaGVsbF9jb21tYW5kcztcclxuXHR9XHJcblxyXG5cdHB1YmxpYyBnZXRPdXRwdXRXcmFwcGVycygpIHtcclxuXHRcdHJldHVybiB0aGlzLm91dHB1dF93cmFwcGVycztcclxuXHR9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBUcmllcyB0byBmaW5kIGFuIGluZGV4IGF0IHdoaWNoIGEgU2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbiBvYmplY3QgaXMgbG9jYXRlZCBpbiB0aGlzLnNldHRpbmdzLnNoZWxsX2NvbW1hbmRzLlxyXG4gICAgICogUmV0dXJucyB1bmRlZmluZWQsIGlmIGl0J3Mgbm90IGZvdW5kLlxyXG4gICAgICpcclxuICAgICAqIERPIE5PVCBFWFBPU0UgVEhFIElOREVYIE9VVFNJREUgVEhFIFBMVUdJTiEgSXQncyBub3QgYSBzdGFibGUgcmVmZXJlbmNlIHRvIGEgc2hlbGwgY29tbWFuZCwgYmVjYXVzZSBzaGVsbCBjb21tYW5kc1xyXG4gICAgICogY2FuIGJlIHJlb3JkZXJlZCAod2VsbCwgYXQgbGVhc3QgaW4gc29tZSBmdXR1cmUgdmVyc2lvbiBvZiB0aGUgcGx1Z2luKS4gQWx3YXlzIHVzZSB0aGUgSUQgYXMgYSBzdGFibGUsIGV4dGVybmFsbHlcclxuICAgICAqIHNhZmUgcmVmZXJlbmNlIVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBzaGVsbF9jb21tYW5kX2lkXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBnZXRTaGVsbENvbW1hbmRDb25maWd1cmF0aW9uSW5kZXgoc2hlbGxfY29tbWFuZF9pZDogc3RyaW5nKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5zZXR0aW5ncy5zaGVsbF9jb21tYW5kcy5maW5kSW5kZXgoKHNoZWxsX2NvbW1hbmRfY29uZmlndXJhdGlvbjogU2hlbGxDb21tYW5kQ29uZmlndXJhdGlvbikgPT4ge1xyXG4gICAgICAgICAgICByZXR1cm4gc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uLmlkID09IHNoZWxsX2NvbW1hbmRfaWQ7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBSZXR1cm5zIGFuIE9ic2lkaWFuIFVSSSB0aGF0IGNvbXBsaWVzIHdpdGggdGhlIGZvcm1hdCBvYnNpZGlhbjovL2FjdGlvbi8/dmF1bHQ9WFlaIGFuZCB0aGF0IG1heSBjb250YWluIHBvc3NpYmxlXHJcbiAgICAgKiBjdXN0b20gYXJndW1lbnRzIGF0IHRoZSBlbmQuXHJcbiAgICAgKlxyXG4gICAgICogTm90ZSB0aGF0IGlmICdhY3Rpb24nIGlzICdvcGVuJyBhbmQgYSAnZmlsZScgYXJndW1lbnQgaXMgcHJlc2VudCBpbiAndXJpX2FyZ3VtZW50cycsIHRoZSBVUkkgd2lsbCB1c2UgdGhlIHNob3J0aGFuZCBzeW50YXggZGVzY3JpYmVkIGhlcmU6IGh0dHBzOi8vaGVscC5vYnNpZGlhbi5tZC9BZHZhbmNlZCt0b3BpY3MvVXNpbmcrb2JzaWRpYW4rVVJJI1Nob3J0aGFuZCtmb3JtYXRzXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIGFjdGlvblxyXG4gICAgICogQHBhcmFtIHVyaV9hcmd1bWVudHNcclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldE9ic2lkaWFuVVJJKGFjdGlvbjogc3RyaW5nLCB1cmlfYXJndW1lbnRzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge30pOiBzdHJpbmcge1xyXG4gICAgICAgIGNvbnN0IGVuY29kZWRfdmF1bHRfbmFtZTogc3RyaW5nID0gZW5jb2RlVVJJQ29tcG9uZW50KHRoaXMuYXBwLnZhdWx0LmdldE5hbWUoKSk7XHJcbiAgICAgICAgbGV0IGJhc2VfdXJpOiBzdHJpbmc7XHJcblxyXG4gICAgICAgIC8vIENoZWNrIHdoaWNoIGtpbmQgb2YgdXJpIHR5cGUgc2hvdWxkIGJlIHVzZWQ6IHNob3J0aGFuZCBvciBub3JtYWxcclxuICAgICAgICBpZiAoXCJvcGVuXCIgPT09IGFjdGlvbiAmJiB1cmlfYXJndW1lbnRzLmZpbGUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgICAvLyBVc2Ugc2hvcnRoYW5kIHVyaSB0eXBlIGZvciBvcGVuaW5nIGEgZmlsZS5cclxuICAgICAgICAgICAgY29uc3QgZW5jb2RlZF9maWxlID0gZW5jb2RlVVJJQ29tcG9uZW50KHVyaV9hcmd1bWVudHMuZmlsZSk7XHJcbiAgICAgICAgICAgIGJhc2VfdXJpID0gYG9ic2lkaWFuOi8vdmF1bHQvJHtlbmNvZGVkX3ZhdWx0X25hbWV9LyR7ZW5jb2RlZF9maWxlfWA7XHJcbiAgICAgICAgICAgIGRlbGV0ZSB1cmlfYXJndW1lbnRzLmZpbGU7IC8vIFByZXZlbnQgYWRkaW5nIGFuIGV4dHJhICcmZmlsZT0nIGFyZ3VtZW50IHRvIHRoZSBlbmQgb2YgdGhlIFVSSS5cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBVc2Ugbm9ybWFsIHVyaSB0eXBlIGZvciBldmVyeXRoaW5nIGVsc2UuXHJcbiAgICAgICAgICAgIGJhc2VfdXJpID0gYG9ic2lkaWFuOi8vJHthY3Rpb259Lz92YXVsdD0ke2VuY29kZWRfdmF1bHRfbmFtZX1gO1xyXG4gICAgICAgIH1cclxuICAgICAgICBsZXQgY29uY2F0ZW5hdGVkX3VyaV9hcmd1bWVudHMgPSBcIlwiO1xyXG4gICAgICAgIGZvciAoY29uc3QgdXJpX2FyZ3VtZW50X25hbWUgaW4gdXJpX2FyZ3VtZW50cykge1xyXG4gICAgICAgICAgICBjb25zdCB1cmlfYXJndW1lbnRfdmFsdWUgPSBlbmNvZGVVUklDb21wb25lbnQodXJpX2FyZ3VtZW50c1t1cmlfYXJndW1lbnRfbmFtZV0pO1xyXG4gICAgICAgICAgICBjb25jYXRlbmF0ZWRfdXJpX2FyZ3VtZW50cyArPSBgJiR7dXJpX2FyZ3VtZW50X25hbWV9PSR7dXJpX2FyZ3VtZW50X3ZhbHVlfWA7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBiYXNlX3VyaSArIGNvbmNhdGVuYXRlZF91cmlfYXJndW1lbnRzO1xyXG4gICAgfVxyXG5cclxuXHQvKipcclxuXHQgKiBDcmVhdGVzIGEgbmV3IHNoZWxsIGNvbW1hbmQgb2JqZWN0IGFuZCByZWdpc3RlcnMgaXQgdG8gT2JzaWRpYW4ncyBjb21tYW5kIHBhbGV0dGUsIGJ1dCBkb2VzIG5vdCBzYXZlIHRoZSBtb2RpZmllZFxyXG5cdCAqIGNvbmZpZ3VyYXRpb24gdG8gZGlzay4gVG8gc2F2ZSB0aGUgYWRkaXRpb24sIGNhbGwgc2F2ZVNldHRpbmdzKCkuXHJcblx0ICovXHJcblx0cHVibGljIG5ld1RTaGVsbENvbW1hbmQoKSB7XHJcblx0XHRjb25zdCBzaGVsbF9jb21tYW5kX2lkID0gZ2V0SURHZW5lcmF0b3IoKS5nZW5lcmF0ZUlEKCk7XHJcblx0XHRjb25zdCBzaGVsbF9jb21tYW5kX2NvbmZpZ3VyYXRpb24gPSBuZXdTaGVsbENvbW1hbmRDb25maWd1cmF0aW9uKHNoZWxsX2NvbW1hbmRfaWQpO1xyXG4gICAgICAgIHRoaXMuc2V0dGluZ3Muc2hlbGxfY29tbWFuZHMucHVzaChzaGVsbF9jb21tYW5kX2NvbmZpZ3VyYXRpb24pO1xyXG5cdFx0Y29uc3QgdF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kID0gbmV3IFRTaGVsbENvbW1hbmQodGhpcywgc2hlbGxfY29tbWFuZF9jb25maWd1cmF0aW9uKTtcclxuXHRcdHRoaXMudF9zaGVsbF9jb21tYW5kc1tzaGVsbF9jb21tYW5kX2lkXSA9IHRfc2hlbGxfY29tbWFuZDtcclxuXHRcdGlmICh0X3NoZWxsX2NvbW1hbmQuY2FuQWRkVG9Db21tYW5kUGFsZXR0ZSgpKSB7IC8vIFRoaXMgaXMgcHJvYmFibHkgYWx3YXlzIHRydWUsIGJlY2F1c2UgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBlbmFibGVzIGFkZGluZyB0byB0aGUgY29tbWFuZCBwYWxldHRlLCBidXQgY2hlY2sganVzdCBpbiBjYXNlLlxyXG5cdFx0XHR0aGlzLnJlZ2lzdGVyU2hlbGxDb21tYW5kKHRfc2hlbGxfY29tbWFuZCk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdF9zaGVsbF9jb21tYW5kO1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogVE9ETzogTW92ZSB0byBUU2hlbGxDb21tYW5kLnJlZ2lzdGVyVG9Db21tYW5kUGFsZXR0ZSgpLCBidXQgc3BsaXQgdG8gbXVsdGlwbGUgbWV0aG9kcy5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB0X3NoZWxsX2NvbW1hbmRcclxuXHQgKi9cclxuXHRwdWJsaWMgcmVnaXN0ZXJTaGVsbENvbW1hbmQodF9zaGVsbF9jb21tYW5kOiBUU2hlbGxDb21tYW5kKSB7XHJcblx0XHRjb25zdCBzaGVsbF9jb21tYW5kX2lkID0gdF9zaGVsbF9jb21tYW5kLmdldElkKCk7XHJcblx0XHRkZWJ1Z0xvZyhcIlJlZ2lzdGVyaW5nIHNoZWxsIGNvbW1hbmQgI1wiICsgc2hlbGxfY29tbWFuZF9pZCArIFwiLi4uXCIpO1xyXG5cclxuXHRcdC8vIERlZmluZSBhIGZ1bmN0aW9uIGZvciBleGVjdXRpbmcgdGhlIHNoZWxsIGNvbW1hbmQuXHJcblx0XHRjb25zdCBleGVjdXRvciA9IGFzeW5jIChwYXJzaW5nX3Byb2Nlc3M6IFNoZWxsQ29tbWFuZFBhcnNpbmdQcm9jZXNzIHwgdW5kZWZpbmVkKSA9PiB7XHJcblx0XHRcdGlmICghcGFyc2luZ19wcm9jZXNzKSB7XHJcblx0XHRcdFx0cGFyc2luZ19wcm9jZXNzID0gdF9zaGVsbF9jb21tYW5kLmNyZWF0ZVBhcnNpbmdQcm9jZXNzKG51bGwpOyAvLyBObyBTQ19FdmVudCBpcyBhdmFpbGFibGUgd2hlbiBleGVjdXRpbmcgc2hlbGwgY29tbWFuZHMgdmlhIHRoZSBjb21tYW5kIHBhbGV0dGUgLyBob3RrZXlzLlxyXG5cdFx0XHRcdC8vIFRyeSB0byBwcm9jZXNzIHZhcmlhYmxlcyB0aGF0IGNhbiBiZSBwcm9jZXNzZWQgYmVmb3JlIHBlcmZvcm1pbmcgcHJlYWN0aW9ucy5cclxuXHRcdFx0XHRhd2FpdCBwYXJzaW5nX3Byb2Nlc3MucHJvY2VzcygpO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmIChwYXJzaW5nX3Byb2Nlc3MuZ2V0UGFyc2luZ1Jlc3VsdHMoKS5zaGVsbF9jb21tYW5kPy5zdWNjZWVkZWQpIHsgLy8gLnNoZWxsX2NvbW1hbmQgc2hvdWxkIGFsd2F5cyBiZSBwcmVzZW50IChldmVuIGlmIHBhcnNpbmcgZGlkIG5vdCBzdWNjZWVkKSwgYnV0IGlmIGl0J3Mgbm90LCBzaG93IGVycm9ycyBpbiB0aGUgZWxzZSBibG9jay5cclxuXHRcdFx0XHQvLyBUaGUgY29tbWFuZCB3YXMgcGFyc2VkIGNvcnJlY3RseS5cclxuXHRcdFx0XHRjb25zdCBleGVjdXRvcl9pbnN0YW5jZSA9IG5ldyBTaGVsbENvbW1hbmRFeGVjdXRvciggLy8gTmFtZWQgJ2V4ZWN1dG9yX2luc3RhbmNlJyBiZWNhdXNlICdleGVjdXRvcicgaXMgYW5vdGhlciBjb25zdGFudC5cclxuXHRcdFx0XHRcdHRoaXMsXHJcblx0XHRcdFx0XHR0X3NoZWxsX2NvbW1hbmQsXHJcblx0XHRcdFx0XHRudWxsIC8vIE5vIFNDX0V2ZW50IGlzIGF2YWlsYWJsZSB3aGVuIGV4ZWN1dGluZyB2aWEgY29tbWFuZCBwYWxldHRlIG9yIGhvdGtleS5cclxuXHRcdFx0XHQpO1xyXG5cdFx0XHRcdGF3YWl0IGV4ZWN1dG9yX2luc3RhbmNlLmRvUHJlYWN0aW9uc0FuZEV4ZWN1dGVTaGVsbENvbW1hbmQocGFyc2luZ19wcm9jZXNzKTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHQvLyBUaGUgY29tbWFuZCBjb3VsZCBub3QgYmUgcGFyc2VkIGNvcnJlY3RseS5cclxuXHRcdFx0XHQvLyBEaXNwbGF5IGVycm9yIG1lc3NhZ2VzXHJcblx0XHRcdFx0cGFyc2luZ19wcm9jZXNzLmRpc3BsYXlFcnJvck1lc3NhZ2VzKCk7XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblxyXG5cdFx0Ly8gUmVnaXN0ZXIgYW4gT2JzaWRpYW4gY29tbWFuZFxyXG5cdFx0Y29uc3Qgb2JzaWRpYW5fY29tbWFuZDogQ29tbWFuZCA9IHtcclxuXHRcdFx0aWQ6IHRoaXMuZ2VuZXJhdGVPYnNpZGlhbkNvbW1hbmRJZChzaGVsbF9jb21tYW5kX2lkKSxcclxuXHRcdFx0bmFtZTogZ2VuZXJhdGVPYnNpZGlhbkNvbW1hbmROYW1lKHRoaXMsIHRfc2hlbGxfY29tbWFuZC5nZXRTaGVsbENvbW1hbmQoKSwgdF9zaGVsbF9jb21tYW5kLmdldEFsaWFzKCkpLCAvLyBXaWxsIGJlIG92ZXJyaWRkZW4gaW4gY29tbWFuZCBwYWxldHRlLCBidXQgdGhpcyB3aWxsIHByb2JhYmx5IHNob3cgdXAgaW4gaG90a2V5IHNldHRpbmdzIHBhbmVsLlxyXG5cdFx0XHQvLyBVc2UgJ2NoZWNrQ2FsbGJhY2snIGluc3RlYWQgb2Ygbm9ybWFsICdjYWxsYmFjaycgYmVjYXVzZSB3ZSBhbHNvIHdhbnQgdG8gZ2V0IGNhbGxlZCB3aGVuIHRoZSBjb21tYW5kIHBhbGV0dGUgaXMgb3BlbmVkLlxyXG5cdFx0XHRjaGVja0NhbGxiYWNrOiAoaXNfb3BlbmluZ19jb21tYW5kX3BhbGV0dGUpOiBib29sZWFuIHwgdm9pZCA9PiB7IC8vIElmIGlzX29wZW5pbmdfY29tbWFuZF9wYWxldHRlIGlzIHRydWUsIHRoZW4gdGhlIHJldHVybiB0eXBlIGlzIGJvb2xlYW4sIG90aGVyd2lzZSB2b2lkLlxyXG5cdFx0XHRcdGlmIChpc19vcGVuaW5nX2NvbW1hbmRfcGFsZXR0ZSkge1xyXG5cdFx0XHRcdFx0Ly8gVGhlIHVzZXIgaXMgY3VycmVudGx5IG9wZW5pbmcgdGhlIGNvbW1hbmQgcGFsZXR0ZS5cclxuXHJcblx0XHRcdFx0XHQvLyBDaGVjayBjYW4gdGhlIHNoZWxsIGNvbW1hbmQgYmUgc2hvd24gaW4gY29tbWFuZCBwYWxldHRlXHJcblx0XHRcdFx0XHRpZiAoIXRfc2hlbGxfY29tbWFuZC5jYW5TaG93SW5Db21tYW5kUGFsZXR0ZSgpKSB7XHJcblx0XHRcdFx0XHRcdC8vIENhbmNlbCBwcmV2aWV3IGFuZCBkZW55IHNob3dpbmcgaW4gY29tbWFuZCBwYWxldHRlLlxyXG5cdFx0XHRcdFx0XHRkZWJ1Z0xvZyhcIlNoZWxsIGNvbW1hbmQgI1wiICsgdF9zaGVsbF9jb21tYW5kLmdldElkKCkgKyBcIiB3b24ndCBiZSBzaG93biBpbiBjb21tYW5kIHBhbGV0dGUuXCIpO1xyXG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Ly8gRG8gbm90IGV4ZWN1dGUgdGhlIGNvbW1hbmQgeWV0LCBidXQgcGFyc2UgdmFyaWFibGVzIGZvciBwcmV2aWV3LCBpZiBlbmFibGVkIGluIHRoZSBzZXR0aW5ncy5cclxuXHRcdFx0XHRcdGRlYnVnTG9nKFwiR2V0dGluZyBjb21tYW5kIHBhbGV0dGUgcHJldmlldyBmb3Igc2hlbGwgY29tbWFuZCAjXCIgKyB0X3NoZWxsX2NvbW1hbmQuZ2V0SWQoKSk7XHJcblx0XHRcdFx0XHRpZiAodGhpcy5zZXR0aW5ncy5wcmV2aWV3X3ZhcmlhYmxlc19pbl9jb21tYW5kX3BhbGV0dGUpIHtcclxuXHRcdFx0XHRcdFx0Ly8gUHJlcGFyc2UgdmFyaWFibGVzXHJcblx0XHRcdFx0XHRcdGNvbnN0IHBhcnNpbmdfcHJvY2VzcyA9IHRfc2hlbGxfY29tbWFuZC5jcmVhdGVQYXJzaW5nUHJvY2VzcyhudWxsKTsgLy8gTm8gU0NfRXZlbnQgaXMgYXZhaWxhYmxlIHdoZW4gZXhlY3V0aW5nIHNoZWxsIGNvbW1hbmRzIHZpYSB0aGUgY29tbWFuZCBwYWxldHRlIC8gaG90a2V5cy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyc2luZ19wcm9jZXNzLnByb2Nlc3MoKS50aGVuKChwYXJzaW5nX3N1Y2NlZWRlZCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhcnNpbmdfc3VjY2VlZGVkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUGFyc2luZyBzdWNjZWVkZWRcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmVuYW1lIE9ic2lkaWFuIGNvbW1hbmRcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwYXJzaW5nUmVzdWx0cyA9IHBhcnNpbmdfcHJvY2Vzcy5nZXRQYXJzaW5nUmVzdWx0cygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8qKiBEb24ndCBjb25mdXNlIHRoaXMgbmFtZSB3aXRoIFNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQgaW50ZXJmYWNlISBUaGUgcHJvcGVydGllcyBhcmUgdmVyeSBkaWZmZXJlbnQuIFRPRE86IFJlbmFtZSBTaGVsbENvbW1hbmRQYXJzaW5nUmVzdWx0IHRvIHNvbWV0aGluZyBlbHNlLiAqL1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQ6IFBhcnNpbmdSZXN1bHQgPSBwYXJzaW5nUmVzdWx0c1tcInNoZWxsX2NvbW1hbmRcIl0gYXMgUGFyc2luZ1Jlc3VsdDsgLy8gVXNlICdhcycgdG8gZGVub3RlIHRoYXQgcHJvcGVydGllcyBleGlzdCBvbiB0aGlzIGxpbmUgYW5kIGJlbG93LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGFsaWFzUGFyc2luZ1Jlc3VsdDogUGFyc2luZ1Jlc3VsdCA9IHBhcnNpbmdSZXN1bHRzW1wiYWxpYXNcIl0gYXMgUGFyc2luZ1Jlc3VsdDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwYXJzZWRTaGVsbENvbW1hbmQ6IHN0cmluZyA9IHNoZWxsQ29tbWFuZFBhcnNpbmdSZXN1bHQucGFyc2VkX2NvbnRlbnQgYXMgc3RyaW5nO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhcnNlZEFsaWFzOiBzdHJpbmcgPSBhbGlhc1BhcnNpbmdSZXN1bHQucGFyc2VkX2NvbnRlbnQgYXMgc3RyaW5nO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRfc2hlbGxfY29tbWFuZC5yZW5hbWVPYnNpZGlhbkNvbW1hbmQocGFyc2VkU2hlbGxDb21tYW5kLHBhcnNlZEFsaWFzKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3RvcmUgdGhlIHByZXBhcnNlZCB2YXJpYWJsZXMgc28gdGhhdCB0aGV5IHdpbGwgYmUgdXNlZCBpZiB0aGlzIHNoZWxsIGNvbW1hbmQgZ2V0cyBleGVjdXRlZC5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNhY2hlZF9wYXJzaW5nX3Byb2Nlc3Nlc1t0X3NoZWxsX2NvbW1hbmQuZ2V0SWQoKV0gPSBwYXJzaW5nX3Byb2Nlc3M7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBhcnNpbmcgZmFpbGVkLCBzbyB1c2UgdW5wYXJzZWQgdF9zaGVsbF9jb21tYW5kLmdldFNoZWxsQ29tbWFuZCgpIGFuZCB0X3NoZWxsX2NvbW1hbmQuZ2V0QWxpYXMoKS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0X3NoZWxsX2NvbW1hbmQucmVuYW1lT2JzaWRpYW5Db21tYW5kKHRfc2hlbGxfY29tbWFuZC5nZXRTaGVsbENvbW1hbmQoKSwgdF9zaGVsbF9jb21tYW5kLmdldEFsaWFzKCkpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FjaGVkX3BhcnNpbmdfcHJvY2Vzc2VzW3Rfc2hlbGxfY29tbWFuZC5nZXRJZCgpXSA9IHVuZGVmaW5lZDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUGFyc2luZyBpcyBkaXNhYmxlZCwgc28gdXNlIHVucGFyc2VkIHRfc2hlbGxfY29tbWFuZC5nZXRTaGVsbENvbW1hbmQoKSBhbmQgdF9zaGVsbF9jb21tYW5kLmdldEFsaWFzKCkuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRfc2hlbGxfY29tbWFuZC5yZW5hbWVPYnNpZGlhbkNvbW1hbmQodF9zaGVsbF9jb21tYW5kLmdldFNoZWxsQ29tbWFuZCgpLCB0X3NoZWxsX2NvbW1hbmQuZ2V0QWxpYXMoKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FjaGVkX3BhcnNpbmdfcHJvY2Vzc2VzW3Rfc2hlbGxfY29tbWFuZC5nZXRJZCgpXSA9IHVuZGVmaW5lZDtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlOyAvLyBUZWxsIE9ic2lkaWFuIHRoaXMgY29tbWFuZCBjYW4gYmUgc2hvd24gaW4gY29tbWFuZCBwYWxldHRlLlxyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0Ly8gVGhlIHVzZXIgaGFzIGluc3RydWN0ZWQgdG8gZXhlY3V0ZSB0aGUgY29tbWFuZC5cclxuICAgICAgICAgICAgICAgICAgICBleGVjdXRvcihcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jYWNoZWRfcGFyc2luZ19wcm9jZXNzZXNbdF9zaGVsbF9jb21tYW5kLmdldElkKCldLCAvLyBDYW4gYmUgdW5kZWZpbmVkLCBpZiBubyBwcmVwYXJzaW5nIHdhcyBkb25lLiBleGVjdXRvcigpIHdpbGwgaGFuZGxlIGNyZWF0aW5nIHRoZSBwYXJzaW5nIHByb2Nlc3MgdGhlbi5cclxuICAgICAgICAgICAgICAgICAgICApLnRoZW4oKCkgPT4ge1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGVsZXRlIHRoZSB3aG9sZSBhcnJheSBvZiBwcmVwYXJzZWQgY29tbWFuZHMuIEV2ZW4gdGhvdWdoIHdlIG9ubHkgdXNlZCBqdXN0IG9uZSBjb21tYW5kIGZyb20gaXQsIHdlIG5lZWQgdG8gbm90aWNlIHRoYXQgb3BlbmluZyBhIGNvbW1hbmRcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcGFsZXR0ZSBtaWdodCBnZW5lcmF0ZSBtdWx0aXBsZSBwcmVwYXJzZWQgY29tbWFuZHMgaW4gdGhlIGFycmF5LCBidXQgYXMgdGhlIHVzZXIgc2VsZWN0cyBhbmQgZXhlY3V0ZXMgb25seSBvbmUgY29tbWFuZCwgYWxsIHRoZXNlIHRlbXBvcmFyeVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBjb21tYW5kcyBhcmUgbm93IG9ic29sZXRlLiBEZWxldGUgdGhlbSBqdXN0IGluIGNhc2UgdGhlIHVzZXIgdG9nZ2xlcyB0aGUgdmFyaWFibGUgcHJldmlldyBmZWF0dXJlIG9mZiBpbiB0aGUgc2V0dGluZ3MsIG9yIGV4ZWN1dGVzIGNvbW1hbmRzIHZpYSBob3RrZXlzLiBXZSBkbyBub3Qgd2FudCB0b1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBleGVjdXRlIG9ic29sZXRlIGNvbW1hbmRzIGFjY2lkZW50YWxseS5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyBkZWxldGlvbiBhbHNvIG5lZWRzIHRvIGJlIGRvbmUgZXZlbiBpZiB0aGUgZXhlY3V0ZWQgY29tbWFuZCB3YXMgbm90IGEgcHJlcGFyc2VkIGNvbW1hbmQsIGJlY2F1c2VcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXZlbiB3aGVuIHByZXBhcnNpbmcgaXMgdHVybmVkIG9uIGluIHRoZSBzZXR0aW5ncywgc29tZSBjb21tYW5kcyBtYXkgZmFpbCB0byBwYXJzZSwgYW5kIHRoZXJlZm9yZSB0aGV5IHdvdWxkIG5vdCBiZSBpbiB0aGlzIGFycmF5LCBidXQgb3RoZXJcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29tbWFuZHMgbWlnaHQgYmUuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FjaGVkX3BhcnNpbmdfcHJvY2Vzc2VzID0ge307IC8vIFJlbW92ZXMgb2Jzb2xldGUgcHJlcGFyc2VkIHZhcmlhYmxlcyBmcm9tIGFsbCBzaGVsbCBjb21tYW5kcy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuOyAvLyBXaGVuIHdlIGFyZSBub3QgaW4gdGhlIGNvbW1hbmQgcGFsZXR0ZSBjaGVjayBwaGFzZSwgdGhlcmUncyBubyBuZWVkIHRvIHJldHVybiBhIHZhbHVlLiBKdXN0IGhhdmUgdGhpcyAncmV0dXJuJyBzdGF0ZW1lbnQgYmVjYXVzZSBhbGwgb3RoZXIgcmV0dXJuIHBvaW50cyBoYXZlIGEgJ3JldHVybicgdG9vLlxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHRcdHRoaXMuYWRkQ29tbWFuZChvYnNpZGlhbl9jb21tYW5kKTtcclxuXHRcdHRoaXMub2JzaWRpYW5fY29tbWFuZHNbc2hlbGxfY29tbWFuZF9pZF0gPSBvYnNpZGlhbl9jb21tYW5kOyAvLyBTdG9yZSB0aGUgcmVmZXJlbmNlIHNvIHRoYXQgd2UgY2FuIGVkaXQgdGhlIGNvbW1hbmQgbGF0ZXIgaW4gU2hlbGxDb21tYW5kc1NldHRpbmdzVGFiIGlmIG5lZWRlZC4gVE9ETzogVXNlIHRTaGVsbENvbW1hbmQgaW5zdGVhZC5cclxuXHRcdHRfc2hlbGxfY29tbWFuZC5zZXRPYnNpZGlhbkNvbW1hbmQob2JzaWRpYW5fY29tbWFuZCk7XHJcblx0XHRkZWJ1Z0xvZyhcIlJlZ2lzdGVyZWQuXCIpO1xyXG5cdH1cclxuXHJcblxyXG5cdC8qKlxyXG5cdCAqIEdvZXMgdGhyb3VnaCBhbGwgZXZlbnRzIGFuZCBhbGwgc2hlbGwgY29tbWFuZHMsIGFuZCBmb3IgZWFjaCBzaGVsbCBjb21tYW5kLCByZWdpc3RlcnMgYWxsIHRoZSBldmVudHMgdGhhdCB0aGUgc2hlbGxcclxuXHQgKiBjb21tYW5kIGFzIGVuYWJsZWQgaW4gaXRzIGNvbmZpZ3VyYXRpb24uIERvZXMgbm90IG1vZGlmeSB0aGUgY29uZmlndXJhdGlvbnMuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gY2FsbGVkX2FmdGVyX2NoYW5naW5nX3NldHRpbmdzIFNldCB0bzogdHJ1ZSwgaWYgdGhpcyBoYXBwZW5zIGFmdGVyIGNoYW5naW5nIGNvbmZpZ3VyYXRpb247IGZhbHNlLCBpZiB0aGlzIGhhcHBlbnMgZHVyaW5nIGxvYWRpbmcgdGhlIHBsdWdpbi5cclxuXHQgKi9cclxuXHRwdWJsaWMgcmVnaXN0ZXJTQ19FdmVudHMoY2FsbGVkX2FmdGVyX2NoYW5naW5nX3NldHRpbmdzOiBib29sZWFuKSB7XHJcblx0XHQvLyBNYWtlIHN1cmUgdGhhdCBPYnNpZGlhbiBpcyBmdWxseSBsb2FkZWQgYmVmb3JlIGFsbG93aW5nIGFueSBldmVudHMgdG8gdHJpZ2dlci5cclxuXHRcdHRoaXMuYXBwLndvcmtzcGFjZS5vbkxheW91dFJlYWR5KCgpID0+IHtcclxuXHRcdFx0Ly8gRXZlbiBhZnRlciBPYnNpZGlhbiBpcyBmdWxseSBsb2FkZWQsIHdhaXQgYSB3aGlsZSBpbiBvcmRlciB0byBwcmV2ZW50IFNDX0V2ZW50X29uQWN0aXZlTGVhZkNoYW5nZWQgdHJpZ2dlcmluZyByaWdodCBhZnRlciBzdGFydC11cC5cclxuXHRcdFx0Ly8gQXQgbGVhc3Qgb24gT2JzaWRpYW4gMC4xMi4xOSBpdCdzIG5vdCBlbm91Z2ggdG8gZGVsYXkgdW50aWwgb25MYXlvdXRSZWFkeSwgbmVlZCB0byB3YWl0IGEgYml0IG1vcmUgaW4gb3JkZXIgdG8gYXZvaWQgdGhlIG1pc3MtdHJpZ2dlcmluZy5cclxuXHRcdFx0d2luZG93LnNldFRpbWVvdXQoKCkgPT4geyAvLyBzZXRUaW1lb3V0KCkgc2hvdWxkIG5vdCBuZWVkIHJlZ2lzdGVyaW5nIHRvIE9ic2lkaWFuIEFQSSwgSSBndWVzcy5cclxuXHRcdFx0XHQvLyBJdGVyYXRlIGFsbCBzaGVsbCBjb21tYW5kcyBhbmQgcmVnaXN0ZXIgcG9zc2libGUgZXZlbnRzLlxyXG5cdFx0XHRcdGNvbnN0IHNoZWxsX2NvbW1hbmRzID0gdGhpcy5nZXRUU2hlbGxDb21tYW5kcygpO1xyXG5cdFx0XHRcdGZvciAoY29uc3Qgc2hlbGxfY29tbWFuZF9pZCBpbiBzaGVsbF9jb21tYW5kcykge1xyXG5cdFx0XHRcdFx0Y29uc3QgdF9zaGVsbF9jb21tYW5kID0gc2hlbGxfY29tbWFuZHNbc2hlbGxfY29tbWFuZF9pZF07XHJcblx0XHRcdFx0XHR0X3NoZWxsX2NvbW1hbmQucmVnaXN0ZXJTQ19FdmVudHMoY2FsbGVkX2FmdGVyX2NoYW5naW5nX3NldHRpbmdzKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH0sIDApOyAvLyAwIG1lYW5zIHRvIGNhbGwgdGhlIGNhbGxiYWNrIG9uIFwidGhlIG5leHQgZXZlbnQgY3ljbGVcIiwgYWNjb3JkaW5nIHRvIHdpbmRvdy5zZXRUaW1lb3V0KCkgZG9jdW1lbnRhdGlvbi4gSXQgc2hvdWxkIGJlIGEgbG9uZyBlbm91Z2ggZGVsYXkuIEJ1dCBpZiBTQ19FdmVudF9vbkFjdGl2ZUxlYWZDaGFuZ2VkIHN0aWxsIGdldHMgdHJpZ2dlcmVkIGR1cmluZyBzdGFydC11cCwgdGhpcyB2YWx1ZSBjYW4gYmUgcmFpc2VkIHRvIGZvciBleGFtcGxlIDEwMDAgKD0gb25lIHNlY29uZCkuXHJcblx0XHR9KTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdvZXMgdGhyb3VnaCBhbGwgZXZlbnRzIGFuZCBhbGwgc2hlbGwgY29tbWFuZHMsIGFuZCBtYWtlcyBzdXJlIGFsbCBvZiB0aGVtIGFyZSB1bnJlZ2lzdGVyZWQsIGUuZy4gd2lsbCBub3QgdHJpZ2dlclxyXG5cdCAqIGF1dG9tYXRpY2FsbHkuIERvZXMgbm90IG1vZGlmeSB0aGUgY29uZmlndXJhdGlvbnMuXHJcblx0ICovXHJcblx0cHVibGljIHVucmVnaXN0ZXJTQ19FdmVudHMoKSB7XHJcblx0XHQvLyBJdGVyYXRlIGFsbCBldmVudHNcclxuXHRcdGdldFNDX0V2ZW50cyh0aGlzKS5mb3JFYWNoKChzY19ldmVudDogU0NfRXZlbnQpID0+IHtcclxuXHRcdFx0Ly8gSXRlcmF0ZSBhbGwgc2hlbGwgY29tbWFuZHNcclxuXHRcdFx0Y29uc3Qgc2hlbGxfY29tbWFuZHMgPSB0aGlzLmdldFRTaGVsbENvbW1hbmRzKCk7XHJcblx0XHRcdGZvciAoY29uc3Qgc2hlbGxfY29tbWFuZF9pZCBpbiBzaGVsbF9jb21tYW5kcykge1xyXG5cdFx0XHRcdGNvbnN0IHRfc2hlbGxfY29tbWFuZCA9IHNoZWxsX2NvbW1hbmRzW3NoZWxsX2NvbW1hbmRfaWRdO1xyXG5cdFx0XHRcdHNjX2V2ZW50LnVucmVnaXN0ZXIodF9zaGVsbF9jb21tYW5kKTtcclxuXHRcdFx0fVxyXG5cdFx0fSk7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBEZWZpbmVzIGFuIE9ic2lkaWFuIHByb3RvY29sIGhhbmRsZXIgdGhhdCBhbGxvd3MgcmVjZWl2aW5nIHJlcXVlc3RzIHZpYSBvYnNpZGlhbjovL3NoZWxsLWNvbW1hbmRzIFVSSS5cclxuXHQgKiBAcHJpdmF0ZVxyXG5cdCAqL1xyXG5cdHByaXZhdGUgcmVnaXN0ZXJVUklIYW5kbGVyKCkge1xyXG5cdFx0dGhpcy5yZWdpc3Rlck9ic2lkaWFuUHJvdG9jb2xIYW5kbGVyKFNDX1BsdWdpbi5TSEVMTF9DT01NQU5EU19VUklfQUNUSU9OLCBhc3luYyAocGFyYW1ldGVyczogT2JzaWRpYW5Qcm90b2NvbERhdGEpID0+IHtcclxuXHRcdFx0Y29uc3QgcGFyYW1ldGVyX25hbWVzOiBzdHJpbmdbXSA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHBhcmFtZXRlcnMpO1xyXG5cclxuXHRcdFx0Ly8gQXNzaWduIHZhbHVlcyB0byBjdXN0b20gdmFyaWFibGVzIChhbHNvIGRlbGV0ZSBzb21lIHVubmVlZGVkIGVudHJpZXMgZnJvbSBwYXJhbWV0ZXJfbmFtZXMpXHJcblx0XHRcdGxldCBjdXN0b21fdmFyaWFibGVfYXNzaWdubWVudHNfZmFpbGVkID0gZmFsc2U7XHJcblx0XHRcdGZvciAoY29uc3QgcGFyYW1ldGVyX2luZGV4IGluIHBhcmFtZXRlcl9uYW1lcykge1xyXG5cdFx0XHRcdGNvbnN0IHBhcmFtZXRlcl9uYW1lID0gcGFyYW1ldGVyX25hbWVzW3BhcmFtZXRlcl9pbmRleF07XHJcblxyXG5cdFx0XHRcdC8vIENoZWNrIGlmIHRoZSBwYXJhbWV0ZXIgbmFtZSBpcyBhIGN1c3RvbSB2YXJpYWJsZVxyXG5cdFx0XHRcdGlmIChwYXJhbWV0ZXJfbmFtZS5tYXRjaCgvXl8vKSkge1xyXG5cdFx0XHRcdFx0Ly8gVGhpcyBwYXJhbWV0ZXIgZGVmaW5lcyBhIHZhbHVlIGZvciBhIGN1c3RvbSB2YXJpYWJsZVxyXG5cdFx0XHRcdFx0Ly8gRmluZCB0aGUgdmFyaWFibGUuXHJcblx0XHRcdFx0XHRsZXQgZm91bmRfY3VzdG9tX3ZhcmlhYmxlID0gZmFsc2U7XHJcblx0XHRcdFx0XHRmb3IgKGNvbnN0IHZhcmlhYmxlIG9mIHRoaXMuZ2V0VmFyaWFibGVzKCkpIHtcclxuXHRcdFx0XHRcdFx0aWYgKHZhcmlhYmxlIGluc3RhbmNlb2YgQ3VzdG9tVmFyaWFibGUgJiYgdmFyaWFibGUudmFyaWFibGVfbmFtZSA9PT0gcGFyYW1ldGVyX25hbWUpIHtcclxuXHRcdFx0XHRcdFx0XHQvLyBGb3VuZCB0aGUgY29ycmVjdCB2YXJpYWJsZS5cclxuXHRcdFx0XHRcdFx0XHRmb3VuZF9jdXN0b21fdmFyaWFibGUgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdFx0XHQvLyBBc3NpZ24gdGhlIGdpdmVuIHZhbHVlIHRvIHRoZSBjdXN0b20gdmFyaWFibGUuXHJcblx0XHRcdFx0XHRcdFx0YXdhaXQgdmFyaWFibGUuc2V0VmFsdWUocGFyYW1ldGVyc1twYXJhbWV0ZXJfbmFtZV0pO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRpZiAoIWZvdW5kX2N1c3RvbV92YXJpYWJsZSkge1xyXG5cdFx0XHRcdFx0XHR0aGlzLm5ld0Vycm9yKFwiU2hlbGwgY29tbWFuZHMgVVJJOiBBIGN1c3RvbSB2YXJpYWJsZSBkb2VzIG5vdCBleGlzdDogXCIgKyBwYXJhbWV0ZXJfbmFtZSk7XHJcblx0XHRcdFx0XHRcdGN1c3RvbV92YXJpYWJsZV9hc3NpZ25tZW50c19mYWlsZWQgPSB0cnVlO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCFjdXN0b21fdmFyaWFibGVfYXNzaWdubWVudHNfZmFpbGVkKSB7XHJcblx0XHRcdFx0Ly8gRGV0ZXJtaW5lIGFjdGlvblxyXG5cdFx0XHRcdGlmICh1bmRlZmluZWQgIT09IHBhcmFtZXRlcnMuZXhlY3V0ZSkge1xyXG5cdFx0XHRcdFx0Ly8gRXhlY3V0ZSBhIHNoZWxsIGNvbW1hbmQuXHJcblx0XHRcdFx0XHRjb25zdCBleGVjdXRhYmxlX3NoZWxsX2NvbW1hbmRfaWQgPSBwYXJhbWV0ZXJzLmV4ZWN1dGU7XHJcblx0XHRcdFx0XHRwYXJhbWV0ZXJfbmFtZXMucmVtb3ZlKFwiZXhlY3V0ZVwiKTsgLy8gTWFyayB0aGUgcGFyYW1ldGVyIGFzIGhhbmRsZWQuIFByZXZlbnRzIHNob3dpbmcgYW4gZXJyb3IgbWVzc2FnZSBmb3IgYW4gdW5yZWNvZ25pc2VkIHBhcmFtZXRlci5cclxuXHJcblx0XHRcdFx0XHQvLyBGaW5kIHRoZSBleGVjdXRhYmxlIHNoZWxsIGNvbW1hbmRcclxuXHRcdFx0XHRcdGxldCBmb3VuZF90X3NoZWxsX2NvbW1hbmQgPSBmYWxzZTtcclxuXHRcdFx0XHRcdGNvbnN0IHNoZWxsX2NvbW1hbmRzID0gdGhpcy5nZXRUU2hlbGxDb21tYW5kcygpO1xyXG5cdFx0XHRcdFx0Zm9yIChjb25zdCBzaGVsbF9jb21tYW5kX2lkIGluIHNoZWxsX2NvbW1hbmRzKSB7XHJcblx0XHRcdFx0XHRcdGNvbnN0IHRfc2hlbGxfY29tbWFuZCA9IHNoZWxsX2NvbW1hbmRzW3NoZWxsX2NvbW1hbmRfaWRdO1xyXG5cdFx0XHRcdFx0XHRpZiAodF9zaGVsbF9jb21tYW5kLmdldElkKCkgPT09IGV4ZWN1dGFibGVfc2hlbGxfY29tbWFuZF9pZCkge1xyXG5cdFx0XHRcdFx0XHRcdC8vIFRoaXMgaXMgdGhlIGNvcnJlY3Qgc2hlbGwgY29tbWFuZC5cclxuXHRcdFx0XHRcdFx0XHRmb3VuZF90X3NoZWxsX2NvbW1hbmQgPSB0cnVlO1xyXG5cclxuXHRcdFx0XHRcdFx0XHQvLyBFeGVjdXRlIGl0LlxyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGV4ZWN1dG9yID0gbmV3IFNoZWxsQ29tbWFuZEV4ZWN1dG9yKHRoaXMsIHRfc2hlbGxfY29tbWFuZCwgbnVsbCk7XHJcblx0XHRcdFx0XHRcdFx0YXdhaXQgZXhlY3V0b3IuZG9QcmVhY3Rpb25zQW5kRXhlY3V0ZVNoZWxsQ29tbWFuZCgpO1xyXG5cclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0aWYgKCFmb3VuZF90X3NoZWxsX2NvbW1hbmQpIHtcclxuXHRcdFx0XHRcdFx0dGhpcy5uZXdFcnJvcihcIlNoZWxsIGNvbW1hbmRzIFVSSTogQSBzaGVsbCBjb21tYW5kIGlkIGRvZXMgbm90IGV4aXN0OiBcIiArIGV4ZWN1dGFibGVfc2hlbGxfY29tbWFuZF9pZCk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBSYWlzZSBlcnJvcnMgZm9yIGFueSBsZWZ0LW92ZXIgcGFyYW1ldGVycywgaWYgZXhpc3RzLlxyXG5cdFx0XHRmb3IgKGNvbnN0IHBhcmFtZXRlcl9uYW1lIG9mIHBhcmFtZXRlcl9uYW1lcykge1xyXG5cdFx0XHRcdHN3aXRjaCAocGFyYW1ldGVyX25hbWUpIHtcclxuXHRcdFx0XHRcdGNhc2UgXCJcIjogLy8gRm9yIHNvbWUgcmVhc29uIE9ic2lkaWFuIDAuMTQuNSBhZGRzIGFuIGVtcHR5LW5hbWVkIHBhcmFtZXRlciBpZiB0aGVyZSBhcmUgbm8gP3F1ZXJ5PXBhcmFtZXRlcnMgcHJlc2VudC5cclxuXHRcdFx0XHRcdGNhc2UgXCJhY3Rpb25cIjogLy8gT2JzaWRpYW4gcHJvdmlkZXMgdGhpcyBhbHdheXMuIERvbid0IHNob3cgYW4gZXJyb3IgbWVzc2FnZSBmb3IgdGhpcy5cclxuXHRcdFx0XHRcdGNhc2UgXCJ2YXVsdFwiOiAvLyBPYnNpZGlhbiBoYW5kbGVzIHRoaXMgcGFyYW1ldGVyIGF1dG9tYXRpY2FsbHkuIEp1c3QgbWFrZSBzdXJlIG5vIGVycm9yIG1lc3NhZ2UgaXMgZGlzcGxheWVkIHdoZW4gdGhpcyBpcyBwcmVzZW50LlxyXG5cdFx0XHRcdFx0XHQvLyBEbyBub3RoaW5nXHJcblx0XHRcdFx0XHRcdGJyZWFrO1xyXG5cdFx0XHRcdFx0ZGVmYXVsdDpcclxuXHRcdFx0XHRcdFx0aWYgKHBhcmFtZXRlcl9uYW1lLm1hdGNoKC9eXy8pKSB7XHJcblx0XHRcdFx0XHRcdFx0Ly8gQ3VzdG9tIHZhcmlhYmxlIHBhcmFtZXRlcnMgKGFuZCBhbnkgcG9zc2libGUgZXJyb3JzIHJlbGF0ZWQgdG8gdGhlbSkgYXJlIGFscmVhZHkgaGFuZGxlZCBhYm92ZS5cclxuXHRcdFx0XHRcdFx0XHQvLyBEbyBub3RoaW5nLlxyXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRcdC8vIFRocm93IGFuIGVycm9yIGZvciBldmVyeXRoaW5nIGVsc2UuXHJcblx0XHRcdFx0XHRcdFx0dGhpcy5uZXdFcnJvcihcIlNoZWxsIGNvbW1hbmRzIFVSSTogVW5yZWNvZ25pc2VkIHBhcmFtZXRlcjogXCIgKyBwYXJhbWV0ZXJfbmFtZSk7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHR9XHJcblx0XHR9KTtcclxuXHR9XHJcblxyXG5cdHB1YmxpYyBnZW5lcmF0ZU9ic2lkaWFuQ29tbWFuZElkKHNoZWxsX2NvbW1hbmRfaWQ6IHN0cmluZykge1xyXG5cdFx0cmV0dXJuIFwic2hlbGwtY29tbWFuZC1cIiArIHNoZWxsX2NvbW1hbmRfaWQ7XHJcblx0fVxyXG5cclxuXHRwdWJsaWMgb251bmxvYWQoKSB7XHJcblx0XHRkZWJ1Z0xvZygnVW5sb2FkaW5nIFNoZWxsIGNvbW1hbmRzIHBsdWdpbi4nKTtcclxuXHJcblx0XHQvLyBDbG9zZSBDdXN0b21WYXJpYWJsZVZpZXdzLlxyXG5cdFx0dGhpcy5hcHAud29ya3NwYWNlLmRldGFjaExlYXZlc09mVHlwZShDdXN0b21WYXJpYWJsZVZpZXcuVmlld1R5cGUpO1xyXG5cclxuICAgICAgICAvLyBDbG9zZSBhdXRvY29tcGxldGUgbWVudXMuXHJcbiAgICAgICAgZm9yIChjb25zdCBhdXRvY29tcGxldGVNZW51IG9mIHRoaXMuYXV0b2NvbXBsZXRlTWVudXMpIHtcclxuICAgICAgICAgICAgYXV0b2NvbXBsZXRlTWVudT8uZGVzdHJveSgpO1xyXG4gICAgICAgIH1cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIGN1cnJlbnRfc2V0dGluZ3NfdmVyc2lvblxyXG5cdCAqIEBwcml2YXRlXHJcblx0ICogQHJldHVybiBUcnVlIGlmIHRoZSBnaXZlbiBzZXR0aW5ncyB2ZXJzaW9uIGlzIHN1cHBvcnRlZCBieSB0aGlzIHBsdWdpbiB2ZXJzaW9uLCBvciBhbiBlcnJvciBtZXNzYWdlIHN0cmluZyBpZiBpdCdzIG5vdCBzdXBwb3J0ZWQuXHJcblx0ICovXHJcblx0cHJpdmF0ZSBpc1NldHRpbmdzVmVyc2lvblN1cHBvcnRlZChjdXJyZW50X3NldHRpbmdzX3ZlcnNpb246IFNldHRpbmdzVmVyc2lvblN0cmluZykge1xyXG5cdFx0aWYgKGN1cnJlbnRfc2V0dGluZ3NfdmVyc2lvbiA9PT0gXCJwcmlvci10by0wLjcuMFwiKSB7XHJcblx0XHRcdC8vIDAueC55IHN1cHBvcnRzIGFsbCBvbGQgc2V0dGluZ3MgZm9ybWF0cyB0aGF0IGRvIG5vdCBkZWZpbmUgYSB2ZXJzaW9uIG51bWJlci4gVGhpcyBzdXBwb3J0IHdpbGwgYmUgcmVtb3ZlZCBpbiAxLjAuMC5cclxuXHRcdFx0cmV0dXJuIHRydWU7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHQvLyBDb21wYXJlIHRoZSB2ZXJzaW9uIG51bWJlclxyXG5cdFx0XHQvKiogTm90ZSB0aGF0IHRoZSBwbHVnaW4gdmVyc2lvbiBtYXkgYmUgZGlmZmVyZW50IHRoYW4gd2hhdCB3aWxsIGJlIHVzZWQgaW4gdGhlIHZlcnNpb24gY29tcGFyaXNvbi4gVGhlIHBsdWdpbiB2ZXJzaW9uIHdpbGwgYmUgZGlzcGxheWVkIGluIHBvc3NpYmxlIGVycm9yIG1lc3NhZ2VzLiAqL1xyXG5cdFx0XHRjb25zdCBwbHVnaW5fdmVyc2lvbiA9IHRoaXMuZ2V0UGx1Z2luVmVyc2lvbigpO1xyXG5cdFx0XHRjb25zdCB2ZXJzaW9uX2NvbXBhcmlzb24gPSB2ZXJzaW9uQ29tcGFyZShTQ19QbHVnaW4uU2V0dGluZ3NWZXJzaW9uLCBjdXJyZW50X3NldHRpbmdzX3ZlcnNpb24pO1xyXG5cdFx0XHRpZiAodmVyc2lvbl9jb21wYXJpc29uID09PSAwKSB7XHJcblx0XHRcdFx0Ly8gVGhlIHZlcnNpb25zIGFyZSBlcXVhbC5cclxuXHRcdFx0XHQvLyBTdXBwb3J0ZWQuXHJcblx0XHRcdFx0cmV0dXJuIHRydWU7XHJcblx0XHRcdH0gZWxzZSBpZiAodmVyc2lvbl9jb21wYXJpc29uIDwgMCkge1xyXG5cdFx0XHRcdC8vIFRoZSBjb21wYXJlZCB2ZXJzaW9uIGlzIG5ld2VyIHRoYW4gd2hhdCB0aGUgcGx1Z2luIGNhbiBzdXBwb3J0LlxyXG5cdFx0XHRcdHJldHVybiBcIlRoZSBzZXR0aW5ncyBmaWxlIGlzIHNhdmVkIGJ5IGEgbmV3ZXIgdmVyc2lvbiBvZiB0aGlzIHBsdWdpbiwgc28gdGhpcyBwbHVnaW4gZG9lcyBub3Qgc3VwcG9ydCB0aGUgc3RydWN0dXJlIG9mIHRoZSBzZXR0aW5ncyBmaWxlLiBQbGVhc2UgdXBncmFkZSB0aGlzIHBsdWdpbiB0byBhdCBsZWFzdCB2ZXJzaW9uIFwiICsgY3VycmVudF9zZXR0aW5nc192ZXJzaW9uICsgXCIuIE5vdyB0aGUgcGx1Z2luIHZlcnNpb24gaXMgXCIgKyBwbHVnaW5fdmVyc2lvbjtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHQvLyBUaGUgY29tcGFyZWQgdmVyc2lvbiBpcyBvbGRlciB0aGFuIHRoZSB2ZXJzaW9uIHRoYXQgdGhlIHBsdWdpbiBjdXJyZW50bHkgdXNlcyB0byB3cml0ZSBzZXR0aW5ncy5cclxuXHRcdFx0XHQvLyAwLngueSBzdXBwb3J0cyBhbGwgb2xkIHNldHRpbmdzIHZlcnNpb25zLiBJbiAxLjAuMCwgc29tZSBvbGQgc2V0dGluZ3MgZm9ybWF0cyBtaWdodCBsb3NlIHRoZWlyIHN1cHBvcnQsIGJ1dCB0aGF0J3Mgbm90IHlldCBjZXJ0YWluLlxyXG5cdFx0XHRcdHJldHVybiB0cnVlO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0cHVibGljIGdldFBsdWdpblZlcnNpb24oKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5tYW5pZmVzdC52ZXJzaW9uO1xyXG5cdH1cclxuXHJcblx0cHJpdmF0ZSBhc3luYyBsb2FkU2V0dGluZ3MoKSB7XHJcblxyXG5cdFx0Ly8gVHJ5IHRvIHJlYWQgYSBzZXR0aW5ncyBmaWxlXHJcblx0XHRsZXQgYWxsX3NldHRpbmdzOiBTQ19NYWluU2V0dGluZ3M7XHJcblx0XHR0aGlzLnNldHRpbmdzID0gYXdhaXQgdGhpcy5sb2FkRGF0YSgpOyAvLyBNYXkgaGF2ZSBtaXNzaW5nIG1haW4gc2V0dGluZ3MgZmllbGRzLCBpZiB0aGUgc2V0dGluZ3MgZmlsZSBpcyBmcm9tIGFuIG9sZGVyIHZlcnNpb24gb2YgU0MuIEl0IHdpbGwgYmUgbWlncmF0ZWQgbGF0ZXIuXHJcblx0XHRpZiAobnVsbCA9PT0gdGhpcy5zZXR0aW5ncykge1xyXG5cdFx0XHQvLyBUaGUgc2V0dGluZ3MgZmlsZSBkb2VzIG5vdCBleGlzdC5cclxuXHRcdFx0Ly8gVXNlIGRlZmF1bHQgc2V0dGluZ3NcclxuXHRcdFx0dGhpcy5zZXR0aW5ncyA9IGdldERlZmF1bHRTZXR0aW5ncyh0cnVlKTtcclxuXHRcdFx0YWxsX3NldHRpbmdzID0gdGhpcy5zZXR0aW5ncztcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdC8vIFN1Y2NlZWRlZCB0byBsb2FkIGEgc2V0dGluZ3MgZmlsZS5cclxuXHRcdFx0Ly8gSW4gY2FzZSB0aGUgc2V0dGluZ3MgZmlsZSBkb2VzIG5vdCBoYXZlICdkZWJ1Zycgb3IgJ3NldHRpbmdzX3ZlcnNpb24nIGZpZWxkcywgY3JlYXRlIHRoZW0uXHJcblx0XHRcdGFsbF9zZXR0aW5ncyA9IGNvbWJpbmVPYmplY3RzKGdldERlZmF1bHRTZXR0aW5ncyhmYWxzZSksIHRoaXMuc2V0dGluZ3MpOyAvLyBUaGlzIHRlbXBvcmFyeSBzZXR0aW5ncyBvYmplY3QgYWx3YXlzIGhhcyBhbGwgZmllbGRzIGRlZmluZWQgKGV4Y2VwdCBzdWIgZmllbGRzLCBzdWNoIGFzIHNoZWxsIGNvbW1hbmQgc3BlY2lmaWMgZmllbGRzLCBtYXkgc3RpbGwgYmUgbWlzc2luZywgYnV0IHRoZXkgYXJlIG5vdCBuZWVkZWQgdGhpcyBlYXJseSkuIFRoaXMgaXMgdXNlZCBzbyB0aGF0IGl0J3MgY2VydGFpbiB0aGF0IHRoZSBmaWVsZHMgJ2RlYnVnJyBhbmQgJ3NldHRpbmdzX3ZlcnNpb24nIGV4aXN0LlxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFVwZGF0ZSBkZWJ1ZyBzdGF0dXMgLSBiZWZvcmUgdGhpcyBsaW5lIGRlYnVnZ2luZyBpcyBhbHdheXMgT0ZGIVxyXG5cdFx0c2V0REVCVUdfT04oYWxsX3NldHRpbmdzLmRlYnVnKTtcclxuXHJcblx0XHQvLyBFbnN1cmUgdGhhdCB0aGUgbG9hZGVkIHNldHRpbmdzIGZpbGUgaXMgc3VwcG9ydGVkLlxyXG5cdFx0Y29uc3QgdmVyc2lvbl9zdXBwb3J0ID0gdGhpcy5pc1NldHRpbmdzVmVyc2lvblN1cHBvcnRlZChhbGxfc2V0dGluZ3Muc2V0dGluZ3NfdmVyc2lvbik7XHJcblx0XHRpZiAodHlwZW9mIHZlcnNpb25fc3VwcG9ydCA9PT0gXCJzdHJpbmdcIikge1xyXG5cdFx0XHQvLyBUaGUgc2V0dGluZ3MgdmVyc2lvbiBpcyBub3Qgc3VwcG9ydGVkLlxyXG5cdFx0XHRuZXcgTm90aWNlKFwiU0hFTEwgQ09NTUFORFMgUExVR0lOIEhBUyBESVNBQkxFRCBJVFNFTEYgaW4gb3JkZXIgdG8gcHJldmVudCBtaXNpbnRlcnByZXRpbmcgc2V0dGluZ3MgLyBjb3JydXB0aW5nIHRoZSBzZXR0aW5ncyBmaWxlIVwiLCAxMjAqMTAwMCk7XHJcblx0XHRcdG5ldyBOb3RpY2UodmVyc2lvbl9zdXBwb3J0IGFzIHN0cmluZywgMTIwKjEwMDApO1xyXG5cdFx0XHRhd2FpdCB0aGlzLmRpc2FibGVQbHVnaW4oKTtcclxuXHRcdFx0cmV0dXJuIGZhbHNlOyAvLyBUaGUgcGx1Z2luIHNob3VsZCBub3QgYmUgdXNlZC5cclxuXHRcdH1cclxuXHRcdHJldHVybiB0cnVlOyAvLyBTZXR0aW5ncyBhcmUgbG9hZGVkIGFuZCB0aGUgcGx1Z2luIGNhbiBiZSB1c2VkLlxyXG5cdH1cclxuXHJcblx0cHVibGljIGFzeW5jIHNhdmVTZXR0aW5ncygpIHtcclxuXHRcdC8vIFVwZGF0ZSBzZXR0aW5ncyB2ZXJzaW9uIGluIGNhc2UgaXQncyBvbGQuXHJcblx0XHR0aGlzLnNldHRpbmdzLnNldHRpbmdzX3ZlcnNpb24gPSBTQ19QbHVnaW4uU2V0dGluZ3NWZXJzaW9uO1xyXG5cclxuXHRcdC8vIFdyaXRlIHNldHRpbmdzXHJcblx0XHRhd2FpdCB0aGlzLnNhdmVEYXRhKHRoaXMuc2V0dGluZ3MpO1xyXG5cdH1cclxuXHJcblx0cHJpdmF0ZSBsb2FkQ3VzdG9tQXV0b2NvbXBsZXRlTGlzdCgpIHtcclxuXHRcdGNvbnN0IGN1c3RvbV9hdXRvY29tcGxldGVfZmlsZV9uYW1lID0gXCJhdXRvY29tcGxldGUueWFtbFwiO1xyXG5cdFx0Y29uc3QgY3VzdG9tX2F1dG9jb21wbGV0ZV9maWxlX3BhdGggPSBwYXRoLmpvaW4oZ2V0UGx1Z2luQWJzb2x1dGVQYXRoKHRoaXMpLCBjdXN0b21fYXV0b2NvbXBsZXRlX2ZpbGVfbmFtZSk7XHJcblxyXG5cdFx0aWYgKGZzLmV4aXN0c1N5bmMoY3VzdG9tX2F1dG9jb21wbGV0ZV9maWxlX3BhdGgpKSB7XHJcblx0XHRcdGRlYnVnTG9nKFwibG9hZEN1c3RvbUF1dG9jb21wbGV0ZUxpc3QoKTogXCIgKyBjdXN0b21fYXV0b2NvbXBsZXRlX2ZpbGVfbmFtZSArIFwiIGV4aXN0cywgd2lsbCBsb2FkIGl0IG5vdy5cIik7XHJcblx0XHRcdGNvbnN0IGN1c3RvbV9hdXRvY29tcGxldGVfY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhjdXN0b21fYXV0b2NvbXBsZXRlX2ZpbGVfcGF0aCkudG9Mb2NhbGVTdHJpbmcoKTtcclxuXHRcdFx0Y29uc3QgcmVzdWx0ID0gYWRkQ3VzdG9tQXV0b2NvbXBsZXRlSXRlbXMoY3VzdG9tX2F1dG9jb21wbGV0ZV9jb250ZW50KTtcclxuXHRcdFx0aWYgKHRydWUgPT09IHJlc3VsdCkge1xyXG5cdFx0XHRcdC8vIE9LXHJcblx0XHRcdFx0ZGVidWdMb2coXCJsb2FkQ3VzdG9tQXV0b2NvbXBsZXRlTGlzdCgpOiBcIiArIGN1c3RvbV9hdXRvY29tcGxldGVfZmlsZV9uYW1lICsgXCIgbG9hZGVkLlwiKTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHQvLyBBbiBlcnJvciBoYXMgb2NjdXJyZWQuXHJcblx0XHRcdFx0ZGVidWdMb2coXCJsb2FkQ3VzdG9tQXV0b2NvbXBsZXRlTGlzdCgpOiBcIiArIHJlc3VsdCk7XHJcblx0XHRcdFx0dGhpcy5uZXdFcnJvcihcIlNoZWxsIGNvbW1hbmRzOiBVbmFibGUgdG8gcGFyc2UgXCIgKyBjdXN0b21fYXV0b2NvbXBsZXRlX2ZpbGVfbmFtZSArIFwiOiBcIiArIHJlc3VsdCk7XHJcblx0XHRcdH1cclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGRlYnVnTG9nKFwibG9hZEN1c3RvbUF1dG9jb21wbGV0ZUxpc3QoKTogXCIgKyBjdXN0b21fYXV0b2NvbXBsZXRlX2ZpbGVfbmFtZSArIFwiIGRvZXMgbm90IGV4aXN0cywgc28gd29uJ3QgbG9hZCBpdC4gVGhpcyBpcyBwZXJmZWN0bHkgb2suXCIpO1xyXG5cdFx0fVxyXG5cclxuXHR9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBQdXRzIHRoZSBnaXZlbiBBdXRvY29tcGxldGUgbWVudSBpbnRvIGEgbGlzdCBvZiBtZW51cyB0aGF0IHdpbGwgYmUgZGVzdHJveWVkIHdoZW4gdGhlIHBsdWdpbiB1bmxvYWRzLlxyXG4gICAgICogQHBhcmFtIGF1dG9jb21wbGV0ZU1lbnVcclxuICAgICAqL1xyXG4gICAgcHVibGljIHJlZ2lzdGVyQXV0b2NvbXBsZXRlTWVudShhdXRvY29tcGxldGVNZW51OiBBdXRvY29tcGxldGVSZXN1bHQpIHtcclxuICAgICAgICB0aGlzLmF1dG9jb21wbGV0ZU1lbnVzLnB1c2goYXV0b2NvbXBsZXRlTWVudSk7XHJcbiAgICB9XHJcblxyXG5cdHByaXZhdGUgYXN5bmMgZGlzYWJsZVBsdWdpbigpIHtcclxuXHRcdC8vIFRoaXMgdW5mb3J0dW5hdGVseSBhY2Nlc3NlcyBhIHByaXZhdGUgQVBJLlxyXG5cdFx0Ly8gQHRzLWlnbm9yZVxyXG5cdFx0YXdhaXQgdGhpcy5hcHAucGx1Z2lucy5kaXNhYmxlUGx1Z2luKHRoaXMubWFuaWZlc3QuaWQpO1xyXG5cdH1cclxuXHJcblx0cHVibGljIGdldFBsdWdpbklkKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMubWFuaWZlc3QuaWQ7XHJcblx0fVxyXG5cclxuXHRwdWJsaWMgZ2V0UGx1Z2luTmFtZSgpIHtcclxuXHRcdHJldHVybiB0aGlzLm1hbmlmZXN0Lm5hbWU7XHJcblx0fVxyXG5cclxuXHRwdWJsaWMgbmV3RXJyb3IoXHJcbiAgICAgICAgbWVzc2FnZTogc3RyaW5nLFxyXG4gICAgICAgIHRpbWVvdXQ6IG51bWJlciA9IHRoaXMuZ2V0RXJyb3JNZXNzYWdlRHVyYXRpb25NcygpLFxyXG4gICAgKSB7XHJcblx0XHRyZXR1cm4gbmV3IE5vdGljZShtZXNzYWdlLCB0aW1lb3V0KTtcclxuXHR9XHJcblxyXG5cdHB1YmxpYyBuZXdFcnJvcnMobWVzc2FnZXM6IHN0cmluZ1tdKSB7XHJcblx0XHRtZXNzYWdlcy5mb3JFYWNoKChtZXNzYWdlOiBzdHJpbmcpID0+IHtcclxuXHRcdFx0dGhpcy5uZXdFcnJvcihtZXNzYWdlKTtcclxuXHRcdH0pO1xyXG5cdH1cclxuXHJcbiAgICAvKipcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gbWVzc2FnZVxyXG4gICAgICogQHBhcmFtIHRpbWVvdXQgQ3VzdG9tIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzLiBJZiBub3Qgc2V0LCB0aGUgdGltZW91dCB3aWxsIGJlIGZldGNoZWQgZnJvbSB1c2VyIGNvbmZpZ3VyYWJsZSBzZXR0aW5ncy4gVXNlIDAgaWYgeW91IHdhbnQgdG8gZGlzYWJsZSB0aGUgdGltZW91dCwgaS5lLiBzaG93IHRoZSBub3RpZmljYXRpb24gdW50aWwgaXQncyBleHBsaWNpdGx5IGhpZGRlbiBieSBjbGlua2luZyBpdCwgb3IgdmlhIGNvZGUuXHJcbiAgICAgKi9cclxuXHRwdWJsaWMgbmV3Tm90aWZpY2F0aW9uKFxyXG4gICAgICAgIG1lc3NhZ2U6IHN0cmluZyxcclxuICAgICAgICB0aW1lb3V0ID0gdGhpcy5nZXROb3RpZmljYXRpb25NZXNzYWdlRHVyYXRpb25NcygpLFxyXG4gICAgKSB7XHJcblx0XHRyZXR1cm4gbmV3IE5vdGljZShtZXNzYWdlLCB0aW1lb3V0KTtcclxuXHR9XHJcblxyXG4gICAgcHVibGljIGdldE5vdGlmaWNhdGlvbk1lc3NhZ2VEdXJhdGlvbk1zKCk6IG51bWJlciB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc2V0dGluZ3Mubm90aWZpY2F0aW9uX21lc3NhZ2VfZHVyYXRpb24gKiAxMDAwOyAvLyAqIDEwMDAgPSBjb252ZXJ0IHNlY29uZHMgdG8gbWlsbGlzZWNvbmRzLlxyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBnZXRFcnJvck1lc3NhZ2VEdXJhdGlvbk1zKCk6IG51bWJlciB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc2V0dGluZ3MuZXJyb3JfbWVzc2FnZV9kdXJhdGlvbiAqIDEwMDA7IC8vICogMTAwMCA9IGNvbnZlcnQgc2Vjb25kcyB0byBtaWxsaXNlY29uZHMuXHJcbiAgICB9XHJcblxyXG5cdHB1YmxpYyBnZXREZWZhdWx0U2hlbGwoKTogc3RyaW5nIHtcclxuXHRcdGNvbnN0IG9wZXJhdGluZ19zeXN0ZW0gPSBnZXRPcGVyYXRpbmdTeXN0ZW0oKTtcclxuXHRcdGxldCBzaGVsbF9uYW1lID0gdGhpcy5zZXR0aW5ncy5kZWZhdWx0X3NoZWxsc1tvcGVyYXRpbmdfc3lzdGVtXTsgLy8gQ2FuIGFsc28gYmUgdW5kZWZpbmVkLlxyXG5cdFx0aWYgKHVuZGVmaW5lZCA9PT0gc2hlbGxfbmFtZSkge1xyXG5cdFx0XHRzaGVsbF9uYW1lID0gZ2V0VXNlcnNEZWZhdWx0U2hlbGwoKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiBzaGVsbF9uYW1lO1xyXG5cdH1cclxuXHJcblx0cHVibGljIGNyZWF0ZUN1c3RvbVZhcmlhYmxlVmlldygpOiB2b2lkIHtcclxuXHRcdGNvbnN0IGxlYWYgPSB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0UmlnaHRMZWFmKGZhbHNlKTtcclxuXHRcdGxlYWYuc2V0Vmlld1N0YXRlKHtcclxuXHRcdFx0dHlwZTogQ3VzdG9tVmFyaWFibGVWaWV3LlZpZXdUeXBlLFxyXG5cdFx0XHRhY3RpdmU6IHRydWUsXHJcblx0XHR9KS50aGVuKCk7XHJcblx0XHR0aGlzLmFwcC53b3Jrc3BhY2UucmV2ZWFsTGVhZihsZWFmKTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIENhbGxlZCB3aGVuIEN1c3RvbVZhcmlhYmxlIHZhbHVlcyBhcmUgY2hhbmdlZC5cclxuXHQgKi9cclxuXHRwdWJsaWMgYXN5bmMgdXBkYXRlQ3VzdG9tVmFyaWFibGVWaWV3cygpIHtcclxuXHRcdGZvciAoY29uc3QgbGVhZiBvZiB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0TGVhdmVzT2ZUeXBlKEN1c3RvbVZhcmlhYmxlVmlldy5WaWV3VHlwZSkpIHtcclxuXHRcdFx0YXdhaXQgKGxlYWYudmlldyBhcyBDdXN0b21WYXJpYWJsZVZpZXcpLnVwZGF0ZUNvbnRlbnQoKTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBVc2VkIGJ5IE91dHB1dENoYW5uZWxfU3RhdHVzQmFyLlxyXG4gICAgICogVE9ETzogTWFrZSBpdCBwb3NzaWJsZSB0byBoYXZlIG11bHRpcGxlIHN0YXR1cyBiYXIgZWxlbWVudHMuIEl0IHNob3VsZCBiZSBhIHNoZWxsIGNvbW1hbmQgbGV2ZWwgc2V0dGluZywgd2hlcmUgYSBzaGVsbCBjb21tYW5kIG9wdHMgZm9yIGVpdGhlciB0byB1c2UgdGhlaXIgb3duIHN0YXR1cyBiYXIgZWxlbWVudCwgb3IgYSBjb21tb24gb25lLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZ2V0T3V0cHV0U3RhdHVzQmFyRWxlbWVudCgpIHtcclxuICAgICAgICBpZiAoIXRoaXMuc3RhdHVzQmFyRWxlbWVudCkge1xyXG4gICAgICAgICAgICB0aGlzLnN0YXR1c0JhckVsZW1lbnQgPSB0aGlzLmFkZFN0YXR1c0Jhckl0ZW0oKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdHVzQmFyRWxlbWVudDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIENyZWF0ZXMgYW4gaWNvbiBidXR0b24gdGhhdCB3aGVuIGNsaWNrZWQsIHdpbGwgc2VuZCBhIHJlcXVlc3QgdG8gdGVybWluYXRlIHNoZWxsIGNvbW1hbmQgZXhlY3V0aW9uIGludGVybWl0dGVudGx5LlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBjb250YWluZXJFbGVtZW50XHJcbiAgICAgKiBAcGFyYW0gcHJvY2Vzc1Rlcm1pbmF0b3IgQSBjYWxsYmFjayB0aGF0IHdpbGwgYWN0dWFsbHkgdGVybWluYXRlIHRoZSBzaGVsbCBjb21tYW5kIGV4ZWN1dGlvbiBwcm9jZXNzLlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgY3JlYXRlUmVxdWVzdFRlcm1pbmF0aW5nQnV0dG9uKGNvbnRhaW5lckVsZW1lbnQ6IEhUTUxFbGVtZW50LCBwcm9jZXNzVGVybWluYXRvcjogKCkgPT4gdm9pZCkge1xyXG4gICAgICAgIGNvbnN0IGJ1dHRvbiA9IGNvbnRhaW5lckVsZW1lbnQuY3JlYXRlRWwoJ2EnLCB7XHJcbiAgICAgICAgICAgIHByZXBlbmQ6IHRydWUsXHJcbiAgICAgICAgICAgIGF0dHI6IHtcclxuICAgICAgICAgICAgICAgIFwiYXJpYS1sYWJlbFwiOiBcIlJlcXVlc3QgdG8gdGVybWluYXRlIHRoZSBwcm9jZXNzXCIsXHJcbiAgICAgICAgICAgICAgICBjbGFzczogXCJTQy1pY29uLXRlcm1pbmF0ZS1wcm9jZXNzXCIsXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgc2V0SWNvbihidXR0b24sIFwicG93ZXJcIik7XHJcbiAgICAgICAgYnV0dG9uLm9uY2xpY2sgPSAoZXZlbnQpID0+IHtcclxuICAgICAgICAgICAgcHJvY2Vzc1Rlcm1pbmF0b3IoKTtcclxuICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgICAgICAgfTtcclxuICAgIH1cclxufVxyXG5cclxuXHJcbiJdLCJuYW1lcyI6WyJNb2RhbCIsIlNldHRpbmciLCJGaWxlU3lzdGVtQWRhcHRlciIsInBhdGgiLCJwbGF0Zm9ybSIsIk1hcmtkb3duVmlldyIsIm5vcm1hbGl6ZVBhdGgiLCJzaGVsbCIsImNsaXBib2FyZCIsIkVPTCIsIk5vdGljZSIsIm1vbWVudCIsImdldEFsbFRhZ3MiLCJURm9sZGVyIiwiVEZpbGUiLCJQbGF0Zm9ybSIsImZzIiwiY2hpbGRfcHJvY2VzcyIsInNwYXduIiwidGhpcyIsInNldEljb24iLCJwYXJzZVlhbWwiLCJJdGVtVmlldyIsIlBsdWdpblNldHRpbmdUYWIiLCJQbHVnaW4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFpQkc7QUFLRyxNQUFnQixRQUFTLFNBQVFBLGNBQUssQ0FBQTtBQUl4QyxJQUFBLFdBQUEsQ0FDdUIsTUFBaUIsRUFBQTtBQUVwQyxRQUFBLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFGQyxJQUFNLENBQUEsTUFBQSxHQUFOLE1BQU0sQ0FBVztRQUhoQyxJQUFPLENBQUEsT0FBQSxHQUFHLEtBQUssQ0FBQztLQU12QjtJQUVNLE1BQU0sR0FBQTtBQUNULFFBQUEsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7O1FBR3BCLElBQUksQ0FBQyxPQUFPLENBQUMs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aUJBQWlCLEVBQUMsUUFBUSxFQUFDLFNBQVMsRUFBQyxXQUFXLEVBQUMsZUFBZSxFQUFDLFdBQVcsRUFBQyxZQUFZLEVBQUMsUUFBUSxFQUFDLGFBQWEsRUFBQyxVQUFVLEVBQUMsYUFBYSxFQUFDLFlBQVksRUFBQyxjQUFjLEVBQUMsV0FBVyxFQUFDLFFBQVEsRUFBQyxNQUFNLEVBQUMsVUFBVSxFQUFDLFFBQVEsRUFBQyxjQUFjLEVBQUMsWUFBWSxFQUFDLFFBQVEsRUFBQyxNQUFNLEVBQUMsUUFBUSxFQUFDLFNBQVMsRUFBQyxNQUFNLEVBQUMsU0FBUyxFQUFDLEtBQUssRUFBQyxZQUFZLEVBQUMsVUFBVSxFQUFDLFdBQVcsRUFBQyxLQUFLLEVBQUMsTUFBTSxFQUFDLGdCQUFnQixFQUFDLGdCQUFnQixFQUFDLFNBQVMsRUFBQyxLQUFLLEVBQUMsWUFBWSxFQUFDLFVBQVUsRUFBQyxjQUFjLEVBQUMsY0FBYyxFQUFDLE9BQU8sRUFBQyxhQUFhLEVBQUMsaUJBQWlCLEVBQUMsU0FBUyxFQUFDLE1BQU0sRUFBQyxpQkFBaUIsRUFBQyxlQUFlLEVBQUMsZUFBZSxFQUFDLFVBQVUsRUFBQyxpQkFBaUIsRUFBQyxxQkFBcUIsRUFBQyxlQUFlLEVBQUMsT0FBTyxFQUFDLGlCQUFpQixFQUFDLGVBQWUsRUFBQyxpQkFBaUIsRUFBQyxlQUFlLEVBQUMsTUFBTSxFQUFDLE9BQU8sRUFBQyxjQUFjLEVBQUMsWUFBWSxFQUFDLFNBQVMsRUFBQyxTQUFTLEVBQUMsUUFBUSxFQUFDLFNBQVMsRUFBQyxlQUFlLEVBQUMsZUFBZSxFQUFDLGNBQWMsRUFBQyxnQkFBZ0IsRUFBQyxXQUFXLEVBQUMsU0FBUyxFQUFDLFNBQVMsRUFBQyxVQUFVLEVBQUMsV0FBVyxFQUFDLGNBQWMsRUFBQyxlQUFlLEVBQUMsT0FBTyxFQUFDLFVBQVUsRUFBQyxlQUFlLEVBQUMsU0FBUyxFQUFDLGlCQUFpQixFQUFDLFlBQVksRUFBQyxpQkFBaUIsRUFBQyxnQkFBZ0IsRUFBQyxjQUFjLEVBQUMsV0FBVyxFQUFDLGdCQUFnQixFQUFDLE9B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