gtp2ogs
Version:
Wrapper to allow Gnu Go Text Protocol speaking Go engines to connect to Online-Go.com and play games
3,336 lines • 521 kB
JavaScript
#!/usr/bin/env node
require("source-map-support/register");
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/Bot.ts":
/*!********************!*\
!*** ./src/Bot.ts ***!
\********************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.Bot = void 0;
exports.gtpchar2num = gtpchar2num;
exports.move2gtpvertex = move2gtpvertex;
const trace_1 = __webpack_require__(/*! ./trace */ "./src/trace.ts");
const child_process_1 = __webpack_require__(/*! child_process */ "child_process");
const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts");
const split2 = __webpack_require__(/*! split2 */ "split2");
const goban_engine_1 = __webpack_require__(/*! goban-engine */ "goban-engine");
const config_1 = __webpack_require__(/*! ./config */ "./src/config.ts");
const PvOutputParser_1 = __webpack_require__(/*! ./PvOutputParser */ "./src/PvOutputParser.ts");
const socket_1 = __webpack_require__(/*! ./socket */ "./src/socket.ts");
const eventemitter3_1 = __webpack_require__(/*! eventemitter3 */ "eventemitter3");
const gtpCommandEndRegex = new RegExp("(\\r?\\n){2}$");
const gtpCommandSplitRegex = new RegExp("(\\r?\\n){2}");
let last_bot_id = 0;
/** Manages talking to a bot via the GTP interface */
class Bot extends eventemitter3_1.EventEmitter {
constructor(bot_config, is_ending_bot = false) {
super();
this.id = ++last_bot_id;
this.game = null;
this.available_commands = {
/* These are required by the GTP spec */
protocol_version: true,
name: true,
version: true,
known_command: true,
list_commands: true,
quit: true,
boardsize: true,
clear_board: true,
komi: true,
play: true,
genmove: true,
};
/** True if we are available for use by a Game. This flag is managed by the pool. */
this.available = true;
this.persistent_state_loaded = false;
this.persistent_moves_sent_count = 0;
this.persistent_idle_timeout = null;
/* These are affinity fields used by our pool to try and select good bots to use */
this.last_game_id = -1;
this.last_width = -1;
this.last_height = -1;
this.bot_config = bot_config;
this.persistent = bot_config.manager === "persistent" && !is_ending_bot;
const cmd = bot_config.command.map((x) => x.replace(/^~[/]/g, process.env.HOME + "/"));
this.log = trace_1.trace.log.bind(null, `[${this.is_ending_bot ? "resign bot" : "bot"} ${this.id}]`);
this.info = trace_1.trace.info.bind(null, `[${this.is_ending_bot ? "resign bot" : "bot"} ${this.id}]`);
this.trace = trace_1.trace.trace.bind(null, `[${this.is_ending_bot ? "resign bot" : "bot"} ${this.id}]`);
this.verbose = trace_1.trace.debug.bind(null, `[${this.is_ending_bot ? "resign bot" : "bot"} ${this.id}]`);
this.warn = trace_1.trace.warn.bind(null, `[${this.is_ending_bot ? "resign bot" : "bot"} ${this.id}]`);
this.error = trace_1.trace.error.bind(null, `[${this.is_ending_bot ? "resign bot" : "bot"} ${this.id}]`);
this.commands_sent = 0;
this.command_callbacks = [];
this.command_error_callbacks = [];
this.is_ending_bot = is_ending_bot;
this.first_move = true;
this.ignore = false; // Ignore output from bot ?
// Set to true when the bot process has died and needs to be restarted before it can be used again.
this.dead = false;
// Set to true when there is a command failure or a bot failure and the game fail counter should be incremented.
// After a few failures we stop retrying and resign the game.
this.failed = false;
this.pv_parser = new PvOutputParser_1.PvOutputParser();
this.verbose("Starting ", cmd.join(" "));
try {
this.proc = (0, child_process_1.spawn)(cmd[0], cmd.slice(1));
this.proc.on("exit", () => {
this.emit("terminated");
});
this.log = trace_1.trace.log.bind(null, `[${this.is_ending_bot ? "resign bot" : "bot"} ${this.id}:${this.pid}]`);
this.verbose = trace_1.trace.debug.bind(null, `[${this.is_ending_bot ? "resign bot" : "bot"} ${this.id}:${this.pid}]`);
this.warn = trace_1.trace.warn.bind(null, `[${this.is_ending_bot ? "resign bot" : "bot"} ${this.id}:${this.pid}]`);
this.error = trace_1.trace.error.bind(null, `[${this.is_ending_bot ? "resign bot" : "bot"} ${this.id}:${this.pid}]`);
}
catch (e) {
this.log("Failed to start the bot: ", e);
this.ignore = true;
this.dead = true;
this.failed = true;
return;
}
this.proc.stderr.pipe(split2()).on("data", (data) => {
if (this.ignore) {
return;
}
const err_line = data.toString().trim();
if (err_line === "") {
return;
}
this.log(`${err_line}`);
if (this.pv_parser) {
if (this.pv_parser.scanAndSendEngineAnalysis(this.game, err_line)) {
return;
}
}
if (this.bot_config.send_chats) {
const chat_match = /(DISCUSSION|MALKOVICH|MAIN):(.*)/.exec(err_line);
if (chat_match) {
const channel = /MALKOVICH:/i.test(err_line) ? "malkovich" : "main";
this.emit("chat", chat_match[2], channel);
}
}
});
let stdout_buffer = "";
this.proc.stdout.on("data", (data) => {
if (this.ignore) {
return;
}
stdout_buffer += data.toString();
if (!stdout_buffer || !gtpCommandEndRegex.test(stdout_buffer)) {
//this.log("Partial result received, buffering until the output ends with a newline");
return;
}
this.trace("<<<", stdout_buffer.trim());
const lines = stdout_buffer.split(gtpCommandSplitRegex);
stdout_buffer = "";
for (let i = 0; i < lines.length; ++i) {
const line = lines[i];
if (line.trim() === "") {
continue;
}
if (line[0] === "=") {
while (lines[i].trim() !== "") {
++i;
}
const cb = this.command_callbacks.shift();
this.command_error_callbacks.shift(); // discard;
if (cb) {
cb(line.substring(1).trim());
}
}
else if (line.trim()[0] === "?") {
this.log(line);
while (lines[i].trim() !== "") {
++i;
this.log(lines[i]);
}
this.failed = true;
this.command_callbacks.shift(); // discard;
const eb = this.command_error_callbacks.shift();
if (eb) {
eb(line.substring(1).trim());
}
}
else {
this.error("Unexpected output: ", line);
this.failed = true;
this.command_callbacks.shift(); // discard;
const eb = this.command_error_callbacks.shift();
if (eb) {
eb(line.trim());
}
}
}
});
this.proc.on("exit", (code) => {
const unexpected = !this.dead;
if (unexpected) {
if (code) {
this.log("Bot exited", code);
}
else {
this.log("Bot exited");
}
}
this.command_callbacks.shift(); // discard;
this.dead = true;
const eb = this.command_error_callbacks.shift();
if (unexpected && eb) {
eb(code);
}
});
this.proc.stdin.on("error", (code) => {
this.error("Bot stdin write error", code);
this.command_callbacks.shift(); // discard;
this.dead = true;
this.failed = true;
const eb = this.command_error_callbacks.shift();
if (eb) {
eb(code);
}
});
this.ready = this.command("list_commands");
this.ready
.then((commands) => {
commands
.split(/[\r\n]/)
.filter((x) => x)
.map((x) => (this.available_commands[x.replace(/^=/, "").trim()] = true));
this.emit("ready");
})
.catch((err) => {
trace_1.trace.error(err);
trace_1.trace.error("Failed to list bot commands, exiting.");
process.exit(1);
});
}
get pid() {
if (this.proc) {
return this.proc.pid;
}
else {
return -1;
}
}
loadClock(state) {
/* References:
http://www.lysator.liu.se/~gunnar/gtp/gtp2-spec-draft2/gtp2-spec.html#sec:time-handling
http://www.weddslist.com/kgs/how/kgsGtp.html
GTP v2 only supports Canadian Byoyomi, no timer (see spec above),
and absolute (period time zero).
kgs-time_settings adds support for Japanese Byoyomi.
The kgsGtp interface (http://www.weddslist.com/kgs/how/kgsGtp.html)
converts byoyomi to absolute time for bots that don't support
kgs-time_settings by using main_time plus periods * period_time.
But then the bot would view that as the total time left for entire rest of game...
Japanese Byoyomi with one period left could be viewed as a special case
of Canadian Byoyomi where the number of stones is always = 1
*/
if (!this.bot_config.enable_clock) {
return;
}
// clock_drift compensates for difference between server and client time, and latency.
const now = Date.now() - socket_1.socket.clock_drift;
let black_offset = 0;
let white_offset = 0;
// offset indicates how long we've had since last move. Ogs only communicates how much
// time the player had when last move was made.
if (state.clock.current_player === state.clock.black_player_id) {
black_offset = (now - state.clock.last_move) / 1000;
}
else {
white_offset = (now - state.clock.last_move) / 1000;
}
if (state.time_control.system === "byoyomi") {
let black_time = state.clock.black_time.thinking_time;
let white_time = state.clock.white_time.thinking_time;
let black_periods = state.clock.black_time.periods;
let white_periods = state.clock.white_time.periods;
let black_time_left = 0;
let white_time_left = 0;
if (this.kgs_time) {
if (black_time > 0) {
black_time_left = black_time - black_offset;
}
else {
black_time_left = state.time_control.period_time - black_offset;
}
if (white_time > 0) {
white_time_left = white_time - white_offset;
}
else {
white_time_left = state.time_control.period_time - white_offset;
}
// If we're so slow that time left - offset is negative, we need to roll over to period time.
while (black_time_left < 0 && black_periods > 1) {
black_time_left += state.clock.black_time.period_time;
if (black_time > 0) {
black_time = 0;
}
else {
black_periods--;
}
}
while (white_time_left < 0 && white_periods > 1) {
white_time_left += state.clock.white_time.period_time;
if (white_time > 0) {
white_time = 0;
}
else {
white_periods--;
}
}
(0, util_1.ignore_promise)(this.command(`kgs-time_settings byoyomi ${state.time_control.main_time} ${state.time_control.period_time} ${state.time_control.periods}`));
(0, util_1.ignore_promise)(this.command(`time_left black ${Math.floor(Math.max(black_time_left, 0))} ${black_time > 0 ? "0" : black_periods}`));
(0, util_1.ignore_promise)(this.command(`time_left white ${Math.floor(Math.max(white_time_left, 0))} ${white_time > 0 ? "0" : white_periods}`));
}
else {
/* Gtp does not support Japanese Byoyomi. We fake it as Canadian Byoyomi.
Let's pretend the final period is a Canadian Byoyomi of 1 stone.
This lets the bot know it can use the full period per move,
not try to fit the rest of the game into the time left.
*/
// add all periods to the main time.
// If we're already in overtime, exclude the current period.
if (black_time > 0) {
black_time_left =
black_time -
black_offset +
state.clock.black_time.period_time * black_periods;
}
else {
black_time_left =
state.time_control.period_time -
black_offset +
state.clock.black_time.period_time * (black_periods - 1);
}
if (white_time > 0) {
white_time_left =
white_time -
white_offset +
state.clock.black_time.period_time * black_periods;
}
else {
white_time_left =
state.time_control.period_time -
white_offset +
state.clock.black_time.period_time * (black_periods - 1);
}
(0, util_1.ignore_promise)(this.command(`time_settings ${state.time_control.main_time +
(state.time_control.periods - 1) * state.time_control.period_time} ${state.time_control.period_time} 1`));
// If we're in the last period, tell the bot. Otherwise pretend we're in main time.
if (black_time_left <= state.clock.black_time.period_time) {
(0, util_1.ignore_promise)(this.command(`time_left black ${Math.floor(Math.max(black_time_left, 0))} 1`));
}
else {
(0, util_1.ignore_promise)(this.command(`time_left black ${Math.floor(black_time_left - state.clock.black_time.period_time)} 0`));
}
if (white_time_left <= state.clock.white_time.period_time) {
(0, util_1.ignore_promise)(this.command(`time_left white ${Math.floor(Math.max(white_time_left, 0))} 1`));
}
else {
(0, util_1.ignore_promise)(this.command(`time_left white ${Math.floor(white_time_left - state.clock.white_time.period_time)} 0`));
}
}
}
else if (state.time_control.system === "canadian") {
/* Canadian Byoyomi is the only time controls GTP v2 officially supports.
*/
let black_time_left = state.clock.black_time.thinking_time - black_offset;
let white_time_left = state.clock.white_time.thinking_time - white_offset;
let black_stones = 0;
let white_stones = 0;
if (black_time_left <= 0) {
black_stones = state.clock.black_time.moves_left;
black_time_left += state.clock.black_time.block_time;
}
if (white_time_left <= 0) {
white_stones = state.clock.white_time.moves_left;
white_time_left += state.clock.white_time.block_time;
}
if (this.kgs_time) {
(0, util_1.ignore_promise)(this.command(`kgs-time_settings canadian ${state.time_control.main_time} ${state.time_control.period_time} ${state.time_control.stones_per_period}`));
}
else {
(0, util_1.ignore_promise)(this.command(`time_settings ${state.time_control.main_time} ${state.time_control.period_time} ${state.time_control.stones_per_period}`));
}
(0, util_1.ignore_promise)(this.command(`time_left black ${Math.floor(Math.max(black_time_left, 0))} ${black_stones}`));
(0, util_1.ignore_promise)(this.command(`time_left white ${Math.floor(Math.max(white_time_left, 0))} ${white_stones}`));
}
else if (state.time_control.system === "fischer") {
if (this.kata_fischer) {
const black_time_left = state.clock.black_time.thinking_time - black_offset;
const white_time_left = state.clock.white_time.thinking_time - white_offset;
(0, util_1.ignore_promise)(this.command(`kata-time_settings fischer-capped ${state.time_control.initial_time} ${state.time_control.time_increment} ${state.time_control.max_time} -1`));
(0, util_1.ignore_promise)(this.command(`time_left black ${Math.floor(Math.max(black_time_left, 0))} 0`));
(0, util_1.ignore_promise)(this.command(`time_left white ${Math.floor(Math.max(white_time_left, 0))} 0`));
}
else {
/* Not supported by kgs-time_settings and I assume most bots.
A better way than absolute is to handle this with
a fake Canadian Byoyomi. This should let the bot know
a good approximation of how to handle the time remaining.
*/
let black_time_left = state.clock.black_time.thinking_time -
black_offset -
state.time_control.time_increment;
let white_time_left = state.clock.white_time.thinking_time -
white_offset -
state.time_control.time_increment;
let black_periods = 0;
let white_periods = 0;
if (this.kgs_time) {
(0, util_1.ignore_promise)(this.command(`kgs-time_settings canadian ${state.time_control.initial_time - state.time_control.time_increment} ${state.time_control.time_increment} 1`));
}
else {
(0, util_1.ignore_promise)(this.command(`time_settings ${state.time_control.initial_time - state.time_control.time_increment} ${state.time_control.time_increment} 1`));
}
if (black_time_left <= 0) {
black_periods = 1;
black_time_left += state.time_control.time_increment;
}
if (white_time_left <= 0) {
white_periods = 1;
white_time_left += state.time_control.time_increment;
}
/* Always tell the bot we are in main time ('0') so it doesn't try
to think all of time_left per move.
But subtract the increment time above to avoid timeouts.
*/
(0, util_1.ignore_promise)(this.command(`time_left black ${Math.floor(Math.max(black_time_left, 0))} ${black_periods}`));
(0, util_1.ignore_promise)(this.command(`time_left white ${Math.floor(Math.max(white_time_left, 0))} ${white_periods}`));
}
}
else if (state.time_control.system === "simple") {
/* Simple could also be viewed as a Canadian Byoyomi that starts
immediately with # of stones = 1
*/
// for some reason ogs sends a timestamp (equal to state.clock.last_move) instead of our time.
// Luckily we can use state.time_control.per_move since simple time is always in overtime.
const black_time_left = state.time_control.per_move - black_offset;
const white_time_left = state.time_control.per_move - white_offset;
(0, util_1.ignore_promise)(this.command(`time_settings 0 ${state.time_control.per_move} 1`));
(0, util_1.ignore_promise)(this.command(`time_left black ${Math.floor(Math.max(black_time_left, 0))} 1`));
(0, util_1.ignore_promise)(this.command(`time_left white ${Math.floor(Math.max(white_time_left, 0))} 1`));
}
else if (state.time_control.system === "absolute") {
const black_time_left = state.clock.black_time.thinking_time - black_offset;
const white_time_left = state.clock.white_time.thinking_time - white_offset;
(0, util_1.ignore_promise)(this.command(`time_settings ${state.time_control.total_time} 0 0`));
(0, util_1.ignore_promise)(this.command(`time_left black ${Math.floor(Math.max(black_time_left, 0))} 0`));
(0, util_1.ignore_promise)(this.command(`time_left white ${Math.floor(Math.max(white_time_left, 0))} 0`));
}
/* OGS doesn't actually send 'none' time control type
else if (state.time_control.system === 'none') {
if (this.kgstime) {
this.command("kgs-time_settings none");
} else {
// GTP v2 says byoyomi time > 0 and stones = 0 means no time limits
//
this.command("time_settings 0 1 0");
}
}
*/
}
loadState(state) {
return __awaiter(this, void 0, void 0, function* () {
if (this.dead) {
this.failed = true;
this.error("Attempted to load state to a dead bot");
throw new Error("Attempting to load dead bot");
}
this.kgs_time = !!this.available_commands["kgs-time_settings"];
this.kata_time = !!this.available_commands["kata-list_time_settings"];
if (this.kata_time) {
const kataTimeSettings = yield this.command("kata-list_time_settings");
this.kata_fischer = kataTimeSettings.includes("fischer-capped");
}
else {
this.kata_fischer = false;
}
const do_initial_load = !this.persistent || !this.persistent_state_loaded;
let have_initial_state = false;
if (do_initial_load) {
// Update our affinity fields
this.last_game_id = state.game_id;
this.last_width = state.width;
this.last_height = state.height;
if (state.width === state.height) {
yield this.command(`boardsize ${state.width}`);
}
else {
yield this.command(`boardsize ${state.width} ${state.height}`);
}
yield this.command("clear_board");
yield this.command(`komi ${state.komi}`);
if (state.initial_state) {
const black = (0, goban_engine_1.decodeMoves)(state.initial_state.black, state.width, state.height);
const white = (0, goban_engine_1.decodeMoves)(state.initial_state.white, state.width, state.height);
have_initial_state = !!black.length || !!white.length;
for (let i = 0; i < black.length; ++i) {
yield this.command(`play black ${move2gtpvertex(black[i], state.width, state.height)}`);
}
for (let i = 0; i < white.length; ++i) {
yield this.command(`play white ${move2gtpvertex(white[i], state.width, state.height)}`);
}
}
}
// Replay moves made
let color = state.initial_player;
const doing_handicap = !have_initial_state && state.free_handicap_placement && state.handicap > 1;
const handicap_moves = [];
const moves = (0, goban_engine_1.decodeMoves)(state.moves, state.width, state.height);
for (let i = 0; i < moves.length; ++i) {
const move = moves[i];
// Use set_free_handicap for handicap stones, play otherwise.
if (doing_handicap && handicap_moves.length < state.handicap) {
handicap_moves.push(move);
if (handicap_moves.length === state.handicap) {
if (do_initial_load) {
(0, util_1.ignore_promise)(this.sendHandicapMoves(handicap_moves, state.width, state.height));
if (this.persistent) {
this.persistent_moves_sent_count += handicap_moves.length;
}
}
}
else {
continue;
} // don't switch color.
}
else {
if (do_initial_load || (this.persistent && this.persistent_moves_sent_count <= i)) {
if (this.persistent) {
++this.persistent_moves_sent_count;
}
yield this.command(`play ${color} ${move2gtpvertex(move, state.width, state.height)}`);
}
}
color = color === "black" ? "white" : "black";
}
if (this.persistent) {
this.persistent_state_loaded = true;
}
if (config_1.config.showboard) {
return yield this.command("showboard");
}
return "";
});
}
command(str, _final_command) {
const arr = str.trim().split(/\s+/);
if (arr.length > 0) {
const cmd = arr[0];
if (!this.available_commands[cmd]) {
this.warn(`Bot does not support command ${cmd}`);
//return Promise.reject(`Bot does not support command ${cmd}`);
return Promise.resolve("=");
}
}
return new Promise((resolve, reject) => {
if (this.dead) {
this.error("Attempting to send a command to dead bot:", str);
this.failed = true;
reject(`Attempting to send a command to dead bot: ${str}`);
return;
}
this.command_callbacks.push(resolve);
this.command_error_callbacks.push(reject);
this.trace(">>>", str);
try {
this.proc.stdin.write(`${str}\r\n`);
}
catch (e) {
// I think this does not normally happen, the exception will usually be raised in the async write handler
// and delivered through an 'error' event.
//
this.error("Failed to send command: ", str);
this.error(e);
this.dead = true;
this.failed = true;
// Already calling the callback!
this.command_error_callbacks.shift();
reject(e);
return;
}
});
}
// For commands like genmove, place_free_handicap ... :
// Send @cmd to engine and call @cb with returned moves.
getMoves(cmd, state) {
return __awaiter(this, void 0, void 0, function* () {
this.loadClock(state);
// Must be after loadClock() since loadClock() checks this.first_move!
this.first_move = false;
const line = yield this.command(cmd, true /* final command */);
const parts = line.toLowerCase().split(/ +/);
const moves = [];
for (let i = 0; i < parts.length; i++) {
const move = parts[i];
let resign = move === "resign";
const pass = move === "pass";
let x = -1;
let y = -1;
if (!resign && !pass) {
if (move && move[0]) {
x = gtpchar2num(move[0]);
y = state.height - parseInt(move.substring(1));
}
else {
this.log(`${cmd} failed, resigning`);
resign = true;
}
}
moves.push({ x, y, text: move, resign, pass });
if (this.persistent) {
++this.persistent_moves_sent_count;
}
}
if (config_1.config.showboard) {
yield this.command("showboard");
}
return moves;
});
}
kill() {
this.log("Stopping bot");
this.ignore = true; // Prevent race conditions / inconsistencies. Could be in the middle of genmove ...
// "quit" needs to be sent before we toggle this.dead since command() checks the status of this.dead
(0, util_1.ignore_promise)(this.command("quit"));
this.dead = true;
if (this.proc) {
setTimeout(() => {
if (this.proc.exitCode !== null) {
this.log("Bot exited with code", this.proc.exitCode);
return;
}
this.warn(`Bot didn't exit after ${this.bot_config.quit_grace_period}ms with "quit" message, killing forcefully`);
this.proc.kill("SIGTERM");
setTimeout(() => {
if (this.proc.exitCode !== null) {
this.log("Bot exited with code", this.proc.exitCode);
return;
}
this.proc.kill("SIGKILL");
}, this.bot_config.quit_grace_period);
}, this.bot_config.quit_grace_period);
}
}
sendMove(move, width, height, color) {
return __awaiter(this, void 0, void 0, function* () {
this.verbose("Calling sendMove with", move2gtpvertex(move, width, height));
yield this.command(`play ${color} ${move2gtpvertex(move, width, height)}`);
});
}
sendHandicapMoves(moves, width, height) {
return __awaiter(this, void 0, void 0, function* () {
let cmd = "set_free_handicap";
for (let i = 0; i < moves.length; i++) {
cmd += ` ${move2gtpvertex(moves[i], width, height)}`;
}
yield this.command(cmd);
});
}
// Called on game over, in case you need something special.
/*
gameOver() {
//
}
*/
setGame(game) {
this.game = game;
}
}
exports.Bot = Bot;
function gtpchar2num(ch) {
if (ch === "." || !ch) {
return -1;
}
return "abcdefghjklmnopqrstuvwxyz".indexOf(ch.toLowerCase());
}
function move2gtpvertex(move, _width, height) {
if (move.x < 0) {
return "pass";
}
return num2gtpchar(move["x"]) + (height - move["y"]);
}
function num2gtpchar(num) {
if (num === -1) {
return ".";
}
return "abcdefghjklmnopqrstuvwxyz"[num];
}
/***/ }),
/***/ "./src/Game.ts":
/*!*********************!*\
!*** ./src/Game.ts ***!
\*********************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.Game = void 0;
exports.handleChatLine = handleChatLine;
const goban_engine_1 = __webpack_require__(/*! goban-engine */ "goban-engine");
const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts");
const trace_1 = __webpack_require__(/*! ./trace */ "./src/trace.ts");
const socket_1 = __webpack_require__(/*! ./socket */ "./src/socket.ts");
const config_1 = __webpack_require__(/*! ./config */ "./src/config.ts");
const eventemitter3_1 = __webpack_require__(/*! eventemitter3 */ "eventemitter3");
const pools_1 = __webpack_require__(/*! ./pools */ "./src/pools.ts");
/** This manages a single game */
class Game extends eventemitter3_1.EventEmitter {
constructor(game_id) {
super();
this.using_opening_bot = false;
this.endbot_resign_count = 0;
if (!game_id) {
throw new Error(`Invalid game id: ${game_id}`);
}
this.game_id = game_id;
this.log = trace_1.trace.log.bind(null, `[game ${game_id}]`);
this.trace = trace_1.trace.trace.bind(null, `[game ${game_id}]`);
this.verbose = trace_1.trace.debug.bind(null, `[game ${game_id}]`);
this.warn = trace_1.trace.warn.bind(null, `[game ${game_id}]`);
this.error = trace_1.trace.error.bind(null, `[game ${game_id}]`);
this.startup_timestamp = Date.now() / 1000;
this.state = null;
this.opponent_evenodd = null;
this.greeted = false;
this.bot = undefined;
this.ending_bot = undefined;
this.bot_failures = 0;
this.my_color = null;
this.processing = false;
this.handicap_moves = []; // Handicap stones waiting to be sent when bot is playing black.
this.disconnect_timeout = null;
this.log("Connecting to game.");
// TODO: Command line options to allow undo?
//
const on_undo_requested = (undo_data) => {
this.log("Undo requested", JSON.stringify(undo_data, null, 4));
};
socket_1.socket.on(`game/${game_id}/undo_requested`, on_undo_requested);
this.on("disconnecting", () => {
socket_1.socket.off(`game/${game_id}/undo_requested`, on_undo_requested);
});
const on_gamedata = (gamedata) => {
if (!socket_1.socket.connected) {
return;
}
// Server has an issue that gamedata.clock.now will exist inconsistently. This will cause
// false positives for gamedata changes. We never use the field, so just remove it.
delete gamedata.clock.now;
// auto_score also sometimes inconsistent. We don't use it, so ignore it to avoid pointless
// restart.
/* TODO: check and see if auto_score is still sent, I don't think it is (anoek 2023-03-24) */
delete gamedata.auto_score;
// Only call game over handler if game really just finished.
// For some reason we get connected to already finished games once in a while ...
if (gamedata.phase === "finished") {
if (this.state && gamedata.phase !== this.state.phase) {
this.state = gamedata;
(0, util_1.ignore_promise)(this.gameOver());
}
return; // ignore -- it's either handled by gameOver or we already handled it before.
}
const gamedataChanged = this.state
? JSON.stringify(this.state) !== JSON.stringify(gamedata)
: false;
// If the gamedata is identical to current state, it's a duplicate. Ignore it and do nothing, unless
// bot is not running.
//
if (this.state && !gamedataChanged && this.bot && !this.bot.dead) {
this.log("Ignoring gamedata that matches current state");
return;
}
// If server has issues it might send us a new gamedata packet and not a move event. We could try to
// check if we're missing a move and send it to bot out of gamedata. For now as a safe fallback just
// restart the bot by killing it here if another gamedata comes in. There normally should only be one
// before we process any moves, and makeMove() is where a new Bot is created.
//
if (this.bot && gamedataChanged) {
this.log("Killing bot because of gamedata change after bot was started");
this.verbose("Previously seen gamedata:", this.state);
this.verbose("New gamedata:", gamedata);
(0, util_1.ignore_promise)(this.releaseBots());
if (this.processing) {
this.processing = false;
--Game.moves_processing;
}
}
//this.log("Gamedata:", JSON.stringify(gamedata, null, 4));
this.state = gamedata;
this.my_color = config_1.config.bot_id === this.state.players.black.id ? "black" : "white";
this.log(`gamedata ${this.header()}`);
// First handicap is just lower komi, more handicaps may change who is even or odd move #s.
//
if (this.state.free_handicap_placement && this.state.handicap > 1) {
//In Chinese, black makes multiple free moves.
//
this.opponent_evenodd = this.my_color === "black" ? 0 : 1;
this.opponent_evenodd = (this.opponent_evenodd + this.state.handicap - 1) % 2;
}
else if (this.state.handicap > 1) {
// In Japanese, white makes the first move.
//
this.opponent_evenodd = this.my_color === "black" ? 1 : 0;
}
else {
// If the game has a handicap, it can't be a fork and the above code works fine.
// If the game has no handicap, it's either a normal game or a fork. Forks may have reversed turn ordering.
//
if (this.state.clock.current_player === config_1.config.bot_id) {
this.opponent_evenodd = this.state.moves.length % 2;
}
else {
this.opponent_evenodd = (this.state.moves.length + 1) % 2;
}
}
// active_game isn't handling this for us any more. If it is our move, call makeMove.
//
if (this.state.phase === "play" && this.state.clock.current_player === config_1.config.bot_id) {
if (!this.bot || !this.processing) {
(0, util_1.ignore_promise)(this.makeMove(this.state.moves.length));
}
}
this.checkForPause();
};
socket_1.socket.on(`game/${game_id}/gamedata`, on_gamedata);
this.on("disconnecting", () => {
socket_1.socket.off(`game/${game_id}/gamedata`, on_gamedata);
});
const on_clock = (clock) => {
if (!socket_1.socket.connected) {
return;
}
// Server has an issue that gamedata.clock.now will exist inconsistently. This will cause
// false positives for gamedata changes. We never use the field, so just remove it.
delete clock.now;
if (this.state) {
this.state.clock = clock;
}
else {
this.error(`Received clock for ${this.game_id} but no state exists`);
}
this.checkForPause();
};
socket_1.socket.on(`game/${game_id}/clock`, on_clock);
this.on("disconnecting", () => {
socket_1.socket.off(`game/${game_id}/clock`, on_clock);
});
const on_phase = (phase) => {
if (!socket_1.socket.connected) {
return;
}
this.log("phase", phase);
//this.log("Move: ", move);
if (this.state) {
this.state.phase = phase;
}
else {
trace_1.trace.error(`Received phase for ${this.game_id} but no state exists`);
}
if (phase === "play") {
this.scheduleRetry();
}
};
socket_1.socket.on(`game/${game_id}/phase`, on_phase);
this.on("disconnecting", () => {
socket_1.socket.off(`game/${game_id}/phase`, on_phase);
});
const on_move = (move) => {
if (!socket_1.socket.connected) {
return;
}
this.trace(`game/${game_id}/move:`, move);
if (!this.state) {
trace_1.trace.error(`Received move for ${this.game_id} but no state exists`);
// Try to connect again, to get the server to send the gamedata over.
socket_1.socket.send("game/connect", {
game_id: game_id,
chat: config_1.config.log_game_chat,
});
return;
}
if (move.move_number !== this.state.moves.length + 1) {
trace_1.trace.error(`Received move for ${this.game_id} but move_number is invalid. ${move.move_number} !== ${this.state.moves.length + 1}`);
return;
}
try {
this.state.moves.push(move.move);
// Log opponent moves
const m = (0, goban_engine_1.decodeMoves)(move.move, this.state.width, this.state.height)[0];
if ((this.my_color === "white" && this.state.handicap >= this.state.moves.length) ||
move.move_number % 2 === this.opponent_evenodd) {
this.log(`Opponent played ${(0, util_1.move2gtpvertex)(m, this.state.width, this.state.height)}`);
}
}
catch (e) {
trace_1.trace.error(e);
}
// If we're in free placement handicap phase of the game, make extra moves or wait it out, as appropriate.
//
// If handicap === 1, no extra stones are played.
// If we are black, we played after initial gamedata and so handicap is not < length.
// If we are white, this.state.moves.length will be 1 and handicap is not < length.
//
// If handicap >= 1, we don't check for opponent_evenodd to move on our turns until handicaps are finished.
//
if (this.state.free_handicap_placement &&
this.state.handicap > this.state.moves.length) {
if (this.my_color === "black") {
// If we are black, we make extra moves.
//
(0, util_1.ignore_promise)(this.makeMove(this.state.moves.length));
}
else {
// If we are white, we wait for opponent to make extra moves.
if (this.bot) {
(0, util_1.ignore_promise)(this.bot.sendMove((0, goban_engine_1.decodeMoves)(move.move, this.state.width, this.state.height)[0], this.state.width, this.state.height, "black"));
}
if (this.ending_bot) {
(0, util_1.ignore_promise)(this.ending_bot.sendMove((0, goban_engine_1.decodeMoves)(move.move, this.state.width, this.state.height)[0], this.state.width, this.state.height, "black"));
}
this.verbose("Waiting for opponent to finish", this.state.handicap - this.state.moves.length, "more handicap moves");
if (this.state.moves.length === 1) {
// remind once, avoid spamming the reminder
this.sendChat("Waiting for opponent to place all handicap stones"); // reminding human player in in-game chat
}
}
}
else {
const opponent_color = this.my_color === "black" ? "white" : "black";
if (move.move_number % 2 === this.opponent_evenodd) {
// We just got a move from the opponent, so we can move immediately.
//
if (this.bot) {
(0, util_1.ignore_promise)(this.bot.sendMove((0, goban_engine_1.decodeMoves)(move.move, this.state.width, this.state.height)[0], this.state.width, this.state.height, opponent_color));
}
if (this.ending_bot) {
(0, util_1.ignore_promise)(this.ending_bot.sendMove((0, goban_engine_1.decodeMoves)(move.move, this.state.width, this.state.height)[0], this.state.width, this.state.height, opponent_color));
}
(0, util_1.ignore_promise)(this.makeMove(this.state.moves.length));
//this.makeMove(this.state.moves.length);
}
else {
//this.verbose("Ignoring our own move", move.move_number);
}
}
};
socket_1.socket.on(`game/${game_id}/move`, on_move);
this.on("disconnecting", () => {
socket_1.socket.off(`game/${game_id}/move`, on_move);
});
if (config_1.config.log_game_chat) {
socket_1.socket.send("chat/join", {
channel: `game-${game_id}`,
});
const on_chat = (d) => {
// Since there is no explicit tracking of which chats are
// "read", we assume anything from before we connected to the
// game has already been dealt with.
handleChatLine(game_id, d.line, this.startup_timestamp);
};
socket_1.socket.on(`game/${game_id}/chat`, on_chat);
this.on("disconnecting", () => {
socket_1.socket.off(`game/${game_id}/chat`, on_chat);
});
}
socket_1.socket.send("game/connect", {
game_id: game_id,
chat: config_1.config.log_game_chat,
});
/*
this.connect_timeout = setTimeout(() => {
if (!this.state) {
this.log("No gamedata after 1s, requesting again");
this.scheduleRetry();
}
}, 1000);
*/
this.connect_timeout = setTimeout(() => {
if (!this.state) {
this.warn("No gamedata received after 5s, still waiting");
}
}, 5000);
}
// Release the bot to the pool. Because we are interested in the STDERR output
// coming from a bot shortly after it's made a move, we don't release it right
// away when this is called.
releaseBots(final_release = false) {
const promises = [];
this.verbose("Releasing bot(s)");
this.verbose("Bot count available: " + pools_1.bot_pools.main.countAvailable());
if (this.bot) {
const bot = this.bot;
this.bot = undefined;
const using_opening_bot = this.using_opening_bot;
promises.push(new Promise((resolve, _reject) => {
console.log("Will release bots in ", bot.bot_config.release_delay, "ms");
setTimeout(() => {
try {
console.log("Releasing bot");
bot.off("chat");
if (using_opening_bot) {
console.log("Releasing opening bot");
pools_1.bot_pools.opening.release(bot);
}
else {
console.log("Releasing main bot");
pools_1.bot_pools.main.release(bot);
console.log("released, Bot count available: " +
pools_1.bot_pools.main.countAvailable());
}
resolve();
}
catch (e) {
console.error("Error releasing bot", e);
}
}, bot.bot_config.release_delay);
}));
}
if (this.ending_bot) {
const ending_bot = this.ending_bot;
this.ending_bot = undefined;
promises.push(new Promise((resolve, _reject) => {
setTimeout(() => {
ending_bot.off("chat");
pools_1.bot_pools.ending.release(ending_bot);
resolve();
}, ending_bot.bot_config.release_delay);
}));
}
return Promise.all(promises).then(() => {
var _a, _b;
if (final_release) {
pools_1.bot_pools.main.clearLastGameId(this.game_id);
(_a = pools_1.bot_pools.opening) === null || _a === void 0 ? void 0 : _a.clearLastGameId(this.game_id);
(_b = pools_1.bot_pools.ending) === null || _b === void 0 ? void 0 : _b.clearLastGameId(this.game_id);
}
return;
});
}
acquireBots() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
if (this.bot && this.bot.dead) {
yield this.releaseBots();
}
if (this.bot) {
throw new Error("acquireBots called but bot already acquired");
}
if (this.bot_failures >= 5) {
// This bot keeps on failing, give up on the game.
this.log("Bot has crashed too many times, resigning game");
this.sendChat("Bot has crashed too many times, resigning game"); // we notify user of this in in-game chat
socket_1.socket.send("game/resign", {
game_id: this.game_id,
});
throw new Error("Bot has crashed too many times, resigning game");
}
if (config_1.config.opening_bot &&
config_1.config.opening_bot.number_of_opening_moves_to_play >= this.state.moves.length) {
this.verbose("Acquiring opening bot instance");
this.bot = yield pools_1.bot_pools.opening.acquire(this.state.time_control.speed, parseInt(this.state.width.toString()), parseInt(this.state.height.toString()), parseInt(this.state.game_id.toString()));
this.using_opening_bot = true;
}
else {
this.verbose("Acquiring main bot instance");
this.bot = yield pools_1.bot_pools.main.acquire(this.state.time_control.speed, parseInt(this.state.width.toString()), parseInt(this.state.height.toString()), parseInt(this.state.game_id.toString()));
this.using_opening_bot = false;
}
this.bot.setGame(this);
this.bot.verbose(`[game ${this.game_id}] Acquired bot instance`);
this.bot.on("chat", (message, channel) => this.sendChat(message, this.state.moves.length + 1, channel));
//this.bot.log(`[game ${this.game_id}] Loading state`);
yield this.bot.loadState(this.state);
//this.bot.verbose(`[game ${this.game_id}] State loaded successfully`);
if ((_a = config_1.config.ending_bot) === null || _a === void 0 ? void 0 : _a.command) {
const move_to_start_checking_ending_bot = Math.ceil(this.state.width *
this.state.height *
config_1.config.ending_bot.moves_to_allow_before_checking_ratio);
if (this.state.moves.length >= move_to_start_checking_ending_bot) {
this.verbose(`[game ${this.game_id}] Acquiring ending bot: ${this.state.moves.length} moves played out of ${move_to_start_checking_ending_bot} necessary to begin consulting ending bot`);
this.ending_bot = yield pools_1.bot_pools.ending.acquire(this.state.time_control.speed, parseInt(this.state.width.toString()), parseInt(this.state.height.toString()), parseInt(this.state.game_id.toString()));
this.ending_bot.verbose(`[game ${this.game_id}] Acquired resign bot instance`);
this.ending_bot.setGame(this);
//this.ending_bot.log(`[game ${this.game_id}] Loading state`);
yield this.ending_bot.loadState(this.state);
//this.ending_bot.verbose(`[game ${this.game_id}] State loaded successfully`);
}
else {
this.verbose(`[game ${this.game_id}] Not starting ending bot yet, only ${this.state.moves.length} moves played, looking for ${move_to_start_checking_ending_bot}`);
}
}
});
}
// Send @cmd to bot and call @cb with returned moves.
//
getBotMoves(cmd) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
++Game.moves_processing;
this.processing = true;
const doneProcessing = () => {
this.processing = false;
--Game.moves_processing;
};
try {
yield this.acquireBots();
this.bot.verbose("Generating move for game", this.game_id);
this.log(cmd);
const [our_moves, end_moves] = yield Promise.all([
this.bot.getMoves(cmd, this.state),
(_a = this.ending_bot) === null || _a === void 0 ? void 0 : _a.getMoves(cmd, this.state),
]);
/*
this.verbose(
`Our moves: ${JSON.stringify(our_moves)} Resign bot: ${JSON.stringify(end_moves)}`,
);
*/
const endbot_pass = end_moves && end_moves.length > 0 && end_moves[0].pass;
const endbot_resign = end_moves && end_moves.length > 0 && end_moves[0].resign;
if (endbot_resign) {
++this.endbot_resign_count;
this.log(`Our resign bot has indicated we should resign ${this.endbot_resign_count} ` +
`times in a row, our threshold is ${config_1.config.ending_bot.allowed_resigns}`);
}
else {
this.endbot_resign_count = 0;
}
doneProcessing();
(0, util_1.ignore_promise)(this.releaseBots());
return end_moves &&
(endbot_pass || this.endbot_resign_count >= ((_b = config_1.config.ending_bot) === null || _b === void 0 ? void 0 : _b.allowed_resigns))
? end_moves
: our_moves;
}
catch (e) {
doneProcessing();
(0, util_1.ignore_promise)(this.releaseBots());
this.error("Failed to start the bot, can not make a move, trying to restart");
this.error(e);
this.sendChat("Failed to start the bot, can not make a move, trying to restart: " + e); // we notify user of this in in-game chat
throw e;
}
});
}
scheduleRetry() {
this.verbose("Unable to react correctly - re-connect to trigger action based on game state.");
socket_1.socket.send("game/disconnect", {
game_id: this.game_id,
});
setTimeout(() => {
socket_1.socket.send("game/connect", {
game_id: this.game_id,
});
}, 500);
}
// Send move to server.
//
uploadMove(move) {
if (move.resign) {
this.log("Resigning");
socket_1.socket.send("game/resign", {
game_id: this.game_id,
});
return;
}
if (config_1.config.verbosity) {
this.verbose(`Playing ${move.text}`, move);
}
else {
this.log(`Playing ${move.text}`);
}
socket_1.socket.send("game/move", {
game_id: this.game_id,
move: encodeMove(move),
});
}
// Get move from bot and upload to server.
// Handle handicap stones with bot as black transparently
// (we get all of them at once with place_free_handicap).
//
makeMove(move_number) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
if (!this.state || this.state.moves.length !== move_number) {
return;
}
if (this.state.phase !== "play") {
return;
}
if (!this.greeted && this.state.moves.length < 2 + this.state.handicap) {
this.greeted = true;
if ((_a = config_1.config.greeting) === null || _a === void 0 ? void 0 : _a.en) {
this.sendChat(config_1.config.greeting);
}
if (config_1.config.engine) {
this.sendChat({ en: `Engine: ${config_1.config.engine}`, engine: config_1.config.engine });
}
}
const doing_handicap = this.state.free_handicap_placement &&
this.state.handicap > 1 &&
this.state.moves.length < this.state.handicap;
if (!doing_handicap) {
// Regular genmove ...
const move_start = Date.now();
try {
const moves = yield this.getBotMoves(`genmove ${this.my_color}`);
const move_end = Date.now();
const move_time = move_end - move_start;
if (config_1.config.min_move_time && move_time < config_1.config.min_move_time) {
this.verbose("Min move time was ", config_1.config.min_move_time, "ms and we only took ", move_time, "ms. Waiting ", config_1.config.min_move_time - move_time, "ms before sending move");
setTimeout(() => {
this.uploadMove(moves[0]);
}, config_1.config.min_move_time - move_time);
}
else {
this.uploadMove(moves[0]);
}
}
catch (e) {
this.error(e);
this.scheduleRetry();
}
return;
}
// Already have handicap stones ? Return next one.
if (this.handicap_moves.length) {
this.uploadMove(this.handicap_moves.shift());
return;
}
const warnAndResign = (msg) => {
this.log(msg);
(0, util_1.ignore_promise)(this.releaseBots());
this.uploadMove({ resign: true });
};
// Get handicap stones from bot and return first one.
try {
const moves = yield this.getBotMoves(`place_free_handicap ${this.state.handicap}`);
if (moves.length !== this.state.handicap) {
// Sanity check
warnAndResign("place_free_handicap returned wrong number of handicap stones, resigning.");
return;
}
for (const i in moves) {
// Sanity check
if (moves[i].pass || moves[i].x < 0) {
warnAndResign("place_free_handicap returned a pass, resigning.");
return;
}
}
this.handicap_moves = moves;
this.uploadMove(this.handicap_moves.shift());
}
catch (e) {
this.error(e);
this.scheduleRetry();
}
});
}
disconnect() {
if (this.processing) {
this.processing = false;
--Game.moves_processing;
}
(0, util_1.ignore_promise)(this.releaseBots(true));
this.log("Disconnecting from game.");
if (socket_1.socket.connected) {
socket_1.socket.send("game/disconnect", {
game_id: this.game_id,
});
}
this.emit("disconnecting");
}
getRes(result) {
const m = this.state.outcome.match(/(.*) points/);
if (m) {
return m[1];
}
if (result === "Resignation") {
return "R";
}
if (result === "Cancellation") {
return "Can";
}
if (result === "Timeout") {
return "Time";
}
}
gameOver() {
return __awaiter(this, void 0, void 0, function* () {
if (config_1.config.farewell && this.state) {
this.sendChat(config_1.config.farewell);
}
// Display result
const col = this.state.winner === this.state.players.black.id ? "B" : "W";
const result = `${this.state.outcome[0].toUpperCase()}${this.state.outcome.substr(1)}`;
const res = this.getRes(result);
const winloss = this.state.winner === config_1.config.bot_id ? "W" : "L";
this.log(`Game over. Result: ${col}+${res} ${winloss}`);
// Notify bot of end of game and send score
if (config_1.config.farewellscore && this.bot) {
const score = yield this.bot.command("final_score", true); // allow bot to process end of game
if (score) {
this.log(`Bot thinks the score was ${score}`);
}
if (res !== "R" && res !== "Time" && res !== "Can") {
this.sendChat(`Final score was ${score} according to the bot.`);
}
}
if (this.bot) {
//this.bot.gameOver();
//this.ending_bot?.gameOver();
(0, util_1.ignore_promise)(this.releaseBots(true));
}
if (!this.disconnect_timeout) {
this.verbose(`Starting disconnect Timeout in Game ${this.game_id} gameOver()`);
this.disconnect_timeout = setTimeout(() => {
this.emit("disconnected", this.game_id);
}, 1000);
}
});
}
header() {
if (!this.state) {
return;
}
const botIsBlack = this.state.players.black.username === config_1.config.username;
const color = botIsBlack ? " B" : "W "; // Playing black / white against ...
const player = botIsBlack ? this.state.players.white : this.state.players.black;
const handicap = this.state && this.state.handicap ? `H${this.state.handicap}` : " ";
return `${color} ${player.username} [${this.state.width}x${this.state.height}] ${handicap}`;
}
sendChat(msg, move_number, channel = "main") {
if (!socket_1.socket.connected) {
return;
}
if (typeof msg === "object" && "en" in msg) {
msg.type = "translated";
}
socket_1.socket.send("game/chat", {
game_id: this.game_id,
body: msg,
move_number: move_number,
type: channel,
});
}
resumeGame() {
socket_1.socket.send("game/resume", {
game_id: this.game_id,
});
}
getOpponent() {
const player = this.state.players.white.id === config_1.config.bot_id
? this.state.players.black
: this.state.players.white;
return player;
}
checkForPause() {
var _a, _b, _c;
const clock = (_a = this.state) === null || _a === void 0 ? void 0 : _a.clock;
if (this.unpause_timeout) {
clearTimeout(this.unpause_timeout);
this.unpause_timeout = undefined;
}
if (!clock) {
return;
}
if (((_b = clock.pause) === null || _b === void 0 ? void 0 : _b.paused) && clock.paused_since) {
const pause_control = ((_c = clock.pause) === null || _c === void 0 ? void 0 : _c.pause_control) || this.state.pause_control;
// pause_control.paused comes from the human opponent, any other keys
// are system pauses, vacations, stone removal phase, weekend, etc.
if ((pause_control === null || pause_control === void 0 ? void 0 : pause_control.paused) && Object.keys(pause_control).length === 1) {
const pause_duration_s = (Date.now() - clock.paused_since) / 1000;
this.log("Clock has been paused for ", pause_duration_s, " seconds");
if (pause_duration_s > config_1.config.max_pause_time) {
this.sendChat("Maximum pause time reached, unpausing clock");
this.resumeGame();
}
else {
this.unpause_timeout = setTimeout(() => {
this.unpause_timeout = undefined;
this.sendChat("Maximum pause time reached, unpausing clock");
this.resumeGame();
}, (config_1.config.max_pause_time - pause_duration_s) * 1000);
}
}
}
}
}
exports.Game = Game;
function handleChatLine(game_id, line, cutoff_timestamp) {
if (typeof line.body !== "string") {
return;
}
if (line.username === config_1.config.username) {
return;
}
// Both are UNIX epoch times.
if (line.date < cutoff_timestamp) {
return;
}
trace_1.trace.info(`[game ${game_id}] Game chat from ${line.username}: ${line.body}`);
}
function num2char(num) {
if (num === -1) {
return ".";
}
return "abcdefghijklmnopqrstuvwxyz"[num];
}
function encodeMove(move) {
if (move["x"] === -1) {
return "..";
}
return num2char(move["x"]) + num2char(move["y"]);
}
Game.moves_processing = 0;
/***/ }),
/***/ "./src/PvOutputParser.ts":
/*!*******************************!*\
!*** ./src/PvOutputParser.ts ***!
\*******************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.PvOutputParser = void 0;
exports.gtpchar2num = gtpchar2num;
const goban_engine_1 = __webpack_require__(/*! goban-engine */ "goban-engine");
const trace_1 = __webpack_require__(/*! ./trace */ "./src/trace.ts");
/** Utility class to work with Principle Variations (PV) output for different bots. */
class PvOutputParser {
constructor() {
this.lookingForPv = false;
this.saiScore = false;
this.lookingForPv = false;
this.saiScore = false;
}
/** Scans the bot output for PVs and posts them to the chat. */
scanAndSendEngineAnalysis(game, line) {
this.game = game;
const engine = this.detected_engine;
this.detectEngine(line);
if (this.detected_engine !== engine) {
trace_1.trace.info("Detected engine: " + this.detected_engine);
}
return this.processLine(line);
}
checkPondering() {
var _a;
if (!(((_a = this.game) === null || _a === void 0 ? void 0 : _a.processing) || this.lookingForPv)) {
return true;
}
this.lookingForPv = true; // Once we are processing, we continue to look for pv even after processing stops.
return false;
}
createAnalysisMessage(name, pv_move, engine_analysis) {
var _a;
return {
type: "analysis",
engine_analysis: engine_analysis,
name: name,
from: ((_a = this.game) === null || _a === void 0 ? void 0 : _a.state.moves.length) || 0,
moves: pv_move,
marks: { circle: pv_move.substring(0, 2) },
};
}
/** Takes moves like "A19" => "aa" */
formatMove(str) {
return str
.trim()
.split(" ")
.map((s) => {
var _a;
return s === "pass"
? ".."
: (0, goban_engine_1.num2char)(gtpchar2num(s[0].toLowerCase())) +
(0, goban_engine_1.num2char)((((_a = this.game) === null || _a === void 0 ? void 0 : _a.state.height) || 0) - parseInt(s.slice(1)));
})
.join("");
}
/** This function scans through the stderr output of the bot until it
* finds a line that can be used to determine what bot is being used. */
detectEngine(line) {
if (this.detected_engine) {
return;
}
if (/KataGo/.test(line)) {
this.detected_engine = "katago";
return;
}
if (/EvalRoutine:.*init model done.*global_step/.test(line)) {
this.detected_engine = "phoenixgo";
return;
}
if (/^MC winrate=.*/.test(line)) {
this.detected_engine = "leela";
return;
}
if (/.*\(V:.*\) \(LCB:.*\) \(N:.*\) \(A:.*\) PV: .*/.test(line)) {
this.detected_engine = "sai";
return;
}
if (/.*\(V:.*\) \(LCB:.*\) \(N:.*\) PV: .*/.test(line)) {
this.detected_engine = "leela_zero";
return;
}
if (/move\s+visits\s+reuse\s+ppv\s+winrate\s+agent/.test(line)) {
this.detected_engine = "sai18";
return;
}
}
processLine(line) {
var _a, _b, _c, _d;
if (line.match(/^Alpha head: /)) {
this.saiScore = true;
}
if (!this.detected_engine) {
return;
}
if (this.checkPondering()) {
return;
}
/*
LEELAZERO : this.postPvToChatDualLine,
SAI : this.postPvToChatDualLine,
SAI18 : this.postPvToChatDualLine,
PHOENIXGO : this.postPvToChatDualLine,
KATAGO : this.postPvToChatSingleLine,
LEELA : this.postPvToChatSingleLine,
*/
let message = null;
switch (this.detected_engine) {
case "katago":
{
const match = line.match(/(CHAT|MALKOVICH):Visits (\d*) Winrate (\d+\.\d\d)% ScoreLead (-?\d+\.\d) ScoreStdev (-?\d+\.\d) (\(PDA (-?\d+.\d\d)\) )?PV (.*)/);
if (match) {
this.lookingForPv = false;
const visits = match[2];
const win_rate = parseFloat(match[3]).toFixed(1);
const scoreLead = match[4];
const PDA = match[6] ? ` PDA: ${match[7]}` : "";
const pv = this.formatMove(match[8]);
const name = `Win rate: ${win_rate}%, Score: ${scoreLead}${PDA}, Visits: ${visits}`;
message = this.createAnalysisMessage(name, pv, {
win_rate: parseFloat(win_rate),
score: parseFloat(scoreLead),
visits: parseInt(visits),
});
}
}
break;
case "leela":
{
const match = line.match(/(\d*) visits, score (\d+\.\d\d)% \(from.* PV: (.*)/);
if (match) {
const visits = match[1];
const win_rate = parseFloat(match[2]).toFixed(1);
const pv = this.formatMove(match[3]);
const name = `Win rate: ${win_rate}%, Visits: ${visits}`;
message = this.createAnalysisMessage(name, pv, {
win_rate: parseFloat(win_rate),
visits: parseInt(visits),
});
}
}
break;
case "leela_zero":
{
const pv_match = line.match(/([A-Z]\d+|pass) -> +(\d+) \(V: +(\d+.\d\d)%\) (\(LCB: +(\d+.\d\d)%\) )?\(N: +(\d+.\d\d)%\) PV:(( ([A-Z][0-9]+|pass)+)+)/);
if (!this.detected_pv && pv_match) {
this.detected_pv = pv_match;
break;
}
const match = line.match(/(\d+) visits, (\d+) nodes, (\d+) playouts, (\d+) n\/s/);
if (match && this.detected_pv) {
const win_rate = parseFloat(this.detected_pv[3]).toFixed(1);
const visits = match[1];
const playouts = match[3];
const name = `Win rate: ${win_rate}%, Visits: ${visits}, Playouts: ${playouts}`;
const pv = this.formatMove(this.detected_pv[7]);
delete this.detected_pv;
message = this.createAnalysisMessage(name, pv, {
win_rate: parseFloat(win_rate),
visits: parseInt(visits),
playouts: parseInt(playouts),
});
}
}
break;
case "sai":
{
const pv_match = line.match(/([A-Z]\d+|pass) -> +(\d+) \(V: +(\d+\.\d\d)%\) (\(LCB: +(-?\d+\.\d\d)%\) )?\(N: +(\d+\.\d\d)%\) \(A: +(-?\d+\.\d)\)( \(B: (-?\d+\.\d\d)\))? PV:(( ([A-Z][0-9]+|pass)+)+)/);
if (!this.detected_pv && pv_match) {
this.detected_pv = pv_match;
break;
}
const match = line.match(/(\d+) visits, (\d+) nodes, (\d+) playouts, (\d+) n\/s/);
if (match && this.detected_pv) {
const winrate = parseFloat(this.detected_pv[3]).toFixed(1);
const score = ((_a = this.game) === null || _a === void 0 ? void 0 : _a.my_color) === "black"
? parseFloat(this.detected_pv[7])
: -parseFloat(this.detected_pv[7]);
const scoreLine = this.saiScore ? `, Score: ${score.toFixed(1)}` : "";
const visits = match[1];
const playouts = match[3];
const name = `Win rate: ${winrate}%${scoreLine}, Visits: ${visits}, Playouts: ${playouts}`;
const pv = this.formatMove(this.detected_pv[10]);
delete this.detected_pv;
message = this.createAnalysisMessage(name, pv, {
win_rate: parseFloat(winrate),
score: score,
visits: parseInt(visits),
playouts: parseInt(playouts),
});
}
}
break;
case "sai18":
{
const pv_match = line.match(/([A-Z]\d+|pass) +(\d+) +(\d)+ +(\d)+ +(\d+\.\d\d)% +(\d+\.\d\d)% +(\d+\.\d\d)% +(\d+\.\d\d)% +(\d+\.\d\d)% +(\d+\.\d\d)% +(-?\d+\.\d) +(\d+)%(( ([A-Z][0-9]+|pass)+)+)/);
if (!this.detected_pv && pv_match) {
this.detected_pv = pv_match;
break;
}
const match = line.match(/(\d+) visits, (\d+) nodes, (\d+) playouts, (\d+) n\/s/);
if (match && this.detected_pv) {
const winrate = parseFloat(this.detected_pv[5]).toFixed(1);
const score = ((_b = this.game) === null || _b === void 0 ? void 0 : _b.my_color) === "black"
? parseFloat(this.detected_pv[11])
: -parseFloat(this.detected_pv[11]);
const scoreLine = this.saiScore ? `, Score: ${score.toFixed(1)}` : "";
const visits = match[1];
const playouts = match[3];
const name = `Win rate: ${winrate}%${scoreLine}, Visits: ${visits}, Playouts: ${playouts}`;
const pv = this.formatMove(this.detected_pv[13]);
delete this.detected_pv;
message = this.createAnalysisMessage(name, pv, {
win_rate: parseFloat(winrate),
score: score,
visits: parseInt(visits),
playouts: parseInt(playouts),
});
}
}
break;
case "phoenixgo":
{
const pv_match = line.match(/main move path: ((,?[a-z]{2}\(((\(ind\))|[^()])*\))+)/);
if (!this.detected_pv && pv_match) {
this.detected_pv = pv_match;
break;
}
const match = line.match(/[0-9]+.. move\([bw]\): [a-z]{2}, (winrate=([0-9]+\.[0-9]+)%, N=([0-9]+), Q=(-?[0-9]+\.[0-9]+), p=(-?[0-9]+\.[0-9]+), v=(-?[0-9]+\.[0-9]+), cost (-?[0-9]+\.[0-9]+)ms, sims=([0-9]+)), height=([0-9]+), avg_height=([0-9]+\.[0-9]+), global_step=([0-9]+)/);
if (match && this.detected_pv) {
const win_rate = parseFloat(match[2]).toFixed(1);
const N = parseInt(match[3]);
const Q = parseFloat(match[4]);
const p = parseFloat(match[5]);
const v = parseFloat(match[6]);
const cost = parseFloat(match[7]);
const sims = parseInt(match[8]);
//const name = match[1];
const name = `Win rate: ${win_rate}%, N: ${N}, Q: ${Q}, p: ${p}, v: ${v}, cost: ${Math.round(cost)}ms, sims: ${sims}`;
const pv = this.detected_pv[1]
.replace(/-nan\(ind\)/g, "")
.replace(/\([^()]*\)/g, "")
.split(",")
.map((s) => {
var _a;
return s === ".."
? ".."
: s[0] +
(0, goban_engine_1.num2char)((((_a = this.game) === null || _a === void 0 ? void 0 : _a.state.height) || 0) - (0, goban_engine_1.char2num)(s[1]) - 1);
})
.join("");
delete this.detected_pv;
message = this.createAnalysisMessage(name, pv, {
win_rate: parseFloat(win_rate),
N,
Q,
p,
v,
cost,
sims,
});
}
}
break;
}
if (message) {
(_c = this.game) === null || _c === void 0 ? void 0 : _c.sendChat(message, (((_d = this.game) === null || _d === void 0 ? void 0 : _d.state.moves.length) || 0) + 1, "malkovich");
return true;
}
return false;
}
}
exports.PvOutputParser = PvOutputParser;
function gtpchar2num(ch) {
if (ch === "." || !ch) {
return -1;
}
return "abcdefghjklmnopqrstuvwxyz".indexOf(ch.toLowerCase());
}
/***/ }),
/***/ "./src/config.ts":
/*!***********************!*\
!*** ./src/config.ts ***!
\***********************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.config = exports.config_event_emitter = void 0;
const fs = __webpack_require__(/*! fs */ "fs");
const JSON5 = __webpack_require__(/*! json5 */ "json5");
const yargs = __webpack_require__(/*! yargs */ "yargs");
const ConfigSchema = __webpack_require__(/*! ../schema/Config.schema.json */ "./schema/Config.schema.json");
const jsonschema_1 = __webpack_require__(/*! jsonschema */ "jsonschema");
const eventemitter3_1 = __webpack_require__(/*! eventemitter3 */ "eventemitter3");
exports.config_event_emitter = new eventemitter3_1.EventEmitter();
function defaults() {
return {
apikey: "",
server: "https://online-go.com",
verbosity: 1,
log_game_chat: false,
max_pause_time: 300,
status_update_frequency: 60000,
allowed_time_control_systems: ["fischer", "byoyomi", "simple"],
allowed_blitz_settings: null,
allowed_rapid_settings: {
simple: {
per_move_time_range: [5, 30],
},
byoyomi: {
main_time_range: [0, 3600],
period_time_range: [5, 30],
periods_range: [1, 10],
},
fischer: {
initial_time_range: [5, 600],
max_time_range: [5, 7200],
time_increment_range: [3, 30],
},
concurrent_games: 3,
},
allowed_live_settings: {
simple: {
per_move_time_range: [10, 300],
},
byoyomi: {
main_time_range: [0, 3600],
period_time_range: [10, 300],
periods_range: [1, 10],
},
fischer: {
initial_time_range: [10, 3600],
max_time_range: [5, 7200],
time_increment_range: [10, 300],
},
concurrent_games: 3,
},
allowed_correspondence_settings: {
simple: {
per_move_time_range: [43200, 604800],
},
byoyomi: {
main_time_range: [0, 604800],
period_time_range: [43200, 604800],
periods_range: [1, 10],
},
fischer: {
initial_time_range: [86400, 604800],
max_time_range: [86400, 604800],
time_increment_range: [43200, 604800],
},
concurrent_games: 500,
},
allowed_board_sizes: [9, 13, 19],
allow_ranked: true,
allow_unranked: true,
allowed_rank_range: ["30k", "9p"],
allow_ranked_handicap: true,
allow_unranked_handicap: true,
allowed_komi_range: [-99, 99],
hidden: false,
decline_new_challenges: false,
min_move_time: 1500,
max_games_per_player: 1,
greeting: {
en: "Hello, I am a bot. Good luck, have fun!",
fr: "Bonjour, je suis un bot. Bonne chance, amusez-vous bien!", // cspell: disable-line
de: "Hallo, ich bin ein Bot. Viel Glück, viel Spaß!", // cspell: disable-line
es: "Hola, soy un bot. ¡Buena suerte, que te diviertas!", // cspell: disable-line
it: "Ciao, sono un bot. Buona fortuna, divertiti!", // cspell: disable-line
ja: "こんにちは、私はボットです。 お疲れ様でした、楽しんでください!",
ko: "안녕하세요, 저는 봇입니다. 행운을 빕니다, 즐거운 시간 되세요!",
nl: "Hallo, ik ben een bot. Veel geluk, veel plezier!", // cspell: disable-line
pl: "Cześć, jestem botem. Powodzenia, baw się dobrze!", // cspell: disable-line
pt: "Olá, eu sou um bot. Boa sorte, divirta-se!", // cspell: disable-line
ru: "Привет, я бот. Удачи, приятной игры!", // cspell: disable-line
"zh-tw": "大家好,我是機器人。 祝你好運,玩得開心!",
"zh-cn": "大家好,我是机器人。 祝你好运,玩得开心!",
},
farewell: {
en: "Thank you for the game!",
fr: "Merci pour la partie!", // cspell: disable-line
de: "Danke für das Spiel!", // cspell: disable-line
es: "¡Gracias por el juego!", // cspell: disable-line
it: "Grazie per la partita!", // cspell: disable-line
ja: "ゲームありがとうございました!",
ko: "게임 감사합니다!",
nl: "Bedankt voor het spel!", // cspell: disable-line
pl: "Dziękuję za grę!", // cspell: disable-line
pt: "Obrigado pelo jogo!", // cspell: disable-line
ru: "Спасибо за игру!", // cspell: disable-line
"zh-tw": "謝謝你的遊戲!",
"zh-cn": "谢谢你的游戏!",
},
};
}
function bot_config_defaults() {
const base = {
manager: "persistent",
instances: 1,
send_chats: true,
send_pv_data: true,
release_delay: 100,
quit_grace_period: 5000,
persistent_idle_timeout: 600000,
};
return base;
}
function ending_bot_config_defaults() {
const base = Object.assign(Object.assign({}, bot_config_defaults()), { allowed_resigns: 3, moves_to_allow_before_checking_ratio: 0.8 });
return base;
}
function opening_bot_config_defaults() {
const base = Object.assign(Object.assign({}, bot_config_defaults()), { number_of_opening_moves_to_play: 8 });
return base;
}
exports.config = try_load_config();
function try_load_config() {
try {
return load_config_or_throw();
}
catch (e) {
console.error("Error loading config file:", e.message);
process.exit(1);
}
}
let reload_debounce = null;
function reload_config(config_path) {
if (reload_debounce) {
return;
}
console.info("Reloading config file ", config_path);
reload_debounce = setTimeout(() => {
reload_debounce = null;
try {
exports.config = load_config_or_throw();
exports.config_event_emitter.emit("reloaded");
}
catch (e) {
console.error("Error loading config file:", e.message);
return;
}
}, 100);
}
function load_config_or_throw() {
yargs(process.argv.slice(2))
.usage("# Usage: $0 -c <config.json5> [options]")
.usage("# $0 -c <config.json5> [options] -- <bot command>")
.describe("server", "URL of the OGS server to connect to, defaults to https://online-go.com")
.describe("beta", "Connect to the beta server. Overrides --server to https://beta.online-go.com")
.describe("config", "Path to configuration file")
.alias("config", "c")
.describe("disable-status-updates", "Disable the status update lines printed to the console")
.alias("disable-status-updates", "q")
.describe("apikey", "API key for the bot")
.describe("engine", "Version of the bot engine being used")
.describe("v", "Increase level (use multiple times for more logs)")
.count("v")
.strict()
.parseSync();
const args = yargs.argv;
if (args.beta) {
args.server = "https://beta.online-go.com";
}
const from_cli = {
server: args.server,
apikey: args.apikey,
verbosity: args.v || undefined,
status_update_frequency: args.q ? 0 : undefined,
engine: args.engine,
};
let cli_bot_command = args._.length > 0 ? args._ : undefined;
for (const key of Object.keys(from_cli)) {
if (from_cli[key] === undefined) {
delete from_cli[key];
}
}
const filename = args.config;
if (filename) {
fs.watch(filename, () => {
reload_config(filename);
});
}
/* @typescript-eslint/no-var-requires */
const contents = filename ? fs.readFileSync(filename, "utf8") : "{}";
const raw = JSON5.parse(contents);
const with_defaults = Object.assign(Object.assign(Object.assign({}, defaults()), raw), from_cli);
if (cli_bot_command) {
cli_bot_command = cli_bot_command.map((x) => x.toString().trim());
if (!("bot" in with_defaults)) {
with_defaults.bot = Object.assign(Object.assign({}, bot_config_defaults()), { command: cli_bot_command });
}
else {
with_defaults.bot.command = cli_bot_command;
}
}
if (!("bot" in with_defaults)) {
throw new Error("No bot configuration found");
}
if (with_defaults.allowed_blitz_settings) {
if (!with_defaults.allowed_blitz_settings.concurrent_games) {
with_defaults.allowed_blitz_settings.concurrent_games = 1;
}
}
if (raw.allowed_live_settings) {
with_defaults.allowed_live_settings = Object.assign(Object.assign({}, defaults().allowed_live_settings), raw.allowed_live_settings);
}
if (raw.allowed_correspondence_settings) {
with_defaults.allowed_correspondence_settings = Object.assign(Object.assign({}, defaults().allowed_correspondence_settings), raw.allowed_correspondence_settings);
}
if (with_defaults.bot) {
with_defaults.bot = Object.assign(Object.assign({}, bot_config_defaults()), with_defaults.bot);
}
if (with_defaults.ending_bot) {
with_defaults.ending_bot = Object.assign(Object.assign({}, ending_bot_config_defaults()), with_defaults.ending_bot);
}
if (with_defaults.opening_bot) {
with_defaults.opening_bot = Object.assign(Object.assign({}, opening_bot_config_defaults()), with_defaults.opening_bot);
}
const validator = new jsonschema_1.Validator();
const result = validator.validate(with_defaults, ConfigSchema);
if (!result.valid) {
console.error(``);
console.error(``);
console.error(`Invalid config file: ${filename}`);
for (const error of result.errors) {
console.error(`\t ${error.toString()}`);
}
console.error(``);
console.error(``);
throw new Error("Invalid config file");
}
//console.info(yargs.argv);
//console.info(with_defaults);
with_defaults._config_version = 2;
return sanity_check_and_patch_config(with_defaults);
}
function sanity_check_and_patch_config(config) {
if (config.decline_new_challenges) {
console.warn("Declining new challenges, hiding bot");
config.hidden = true;
}
return config;
}
/***/ }),
/***/ "./src/main.ts":
/*!*********************!*\
!*** ./src/main.ts ***!
\*********************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
//#!/usr/bin/env node
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
const ws_1 = __webpack_require__(/*! ws */ "ws");
global.WebSocket = ws_1.WebSocket;
const config_1 = __webpack_require__(/*! ./config */ "./src/config.ts");
const socket_1 = __webpack_require__(/*! ./socket */ "./src/socket.ts");
const trace_1 = __webpack_require__(/*! ./trace */ "./src/trace.ts");
const util_1 = __webpack_require__(/*! ./util */ "./src/util.ts");
const Game_1 = __webpack_require__(/*! ./Game */ "./src/Game.ts");
const pools_1 = __webpack_require__(/*! ./pools */ "./src/pools.ts");
//process.title = `gtp2ogs ${config.bot_command.join(" ")}`;
const ignorable_notifications = {
delete: true,
gameStarted: true,
gameEnded: true,
gameDeclined: true,
gameResumedFromStoneRemoval: true,
tournamentStarted: true,
tournamentEnded: true,
aiReviewDone: true,
};
/** This is the main class for the connection to the server. It is responsible
* for managing games in play, responding to challenges and notifications, and
* that sort of stuff. */
class Main {
constructor() {
this.last_status_update = {};
this.connected_games = {};
this.connected_finished_games = {};
//this.games_by_player = {}; // Keep track of connected games per player
this.connected = false;
if (config_1.config.status_update_frequency > 0) {
setInterval(this.dumpStatus.bind(this), config_1.config.status_update_frequency);
}
setInterval(this.sendStatusUpdate.bind(this), 100);
socket_1.socket.on("connect", () => __awaiter(this, void 0, void 0, function* () {
this.connected = true;
yield pools_1.bot_pools.main.ready;
if (pools_1.bot_pools.ending) {
yield pools_1.bot_pools.ending.ready;
}
if (pools_1.bot_pools.opening) {
yield pools_1.bot_pools.opening.ready;
}
socket_1.socket.send("authenticate", {
jwt: "",
bot_username: config_1.config.username,
bot_apikey: config_1.config.apikey,
}, (obj) => {
if (!obj) {
trace_1.trace.error(`ERROR: Authentication failed`);
process.exit(1);
}
this.bot_id = obj === null || obj === void 0 ? void 0 : obj.id;
this.bot_username = obj === null || obj === void 0 ? void 0 : obj.username;
config_1.config.bot_id = this.bot_id;
config_1.config.username = this.bot_username;
if (!this.bot_id) {
trace_1.trace.error(`ERROR: Bot account is unknown to the system: ${config_1.config.username}`);
process.exit(1);
}
config_1.config.bot_id = this.bot_id;
trace_1.trace.info("Bot is username: ", this.bot_username);
trace_1.trace.info("Bot is user id: ", this.bot_id);
const config_v2 = Object.assign(Object.assign({ hidden: false }, config_1.config), { _config_version: 2 });
socket_1.socket.send("bot/config", config_v2);
});
}));
config_1.config_event_emitter.on("reloaded", () => {
config_1.config.bot_id = this.bot_id;
config_1.config.username = this.bot_username;
if (socket_1.socket.connected) {
socket_1.socket.send("bot/config", Object.assign(Object.assign({ hidden: false }, config_1.config), { _config_version: 2 }));
}
});
socket_1.socket.on("disconnect", () => {
this.connected = false;
trace_1.trace.warn("Disconnected from server");
for (const game_id in this.connected_games) {
this.disconnectFromGame(parseInt(game_id));
}
});
socket_1.socket.on("notification", (notification) => this.handleNotification(notification));
socket_1.socket.on("active_game", (gamedata) => {
//trace.trace("active_game:", JSON.stringify(gamedata));
/* OGS auto scores bot games now, no removal processing is needed by the bot.
/ Eventually might want OGS to not auto score, or make it bot-optional to enforce.
/ Some bots can handle stone removal process.
/ if (gamedata.phase === 'stone removal'
/ && ((!gamedata.black.accepted && gamedata.black.id === this.bot_id)
/ || (!gamedata.white.accepted && gamedata.white.id === this.bot_id))
/ ) {
/ this.processMove(gamedata);
/ }*/
if (gamedata.phase === "finished") {
if (gamedata.id in this.connected_games) {
/* When a game ends, we don't get a "finished" active_game.phase. Probably since the game is no
/ longer active.(Update: We do get finished active_game events? Unclear why I added prior note.)
/ Note: active_game and gamedata events can arrive in either order.*/
trace_1.trace.debug(`game ${gamedata.id} is now finished`);
/* XXX We want to disconnect right away here, but there's a game over race condition
/ on server side: sometimes /gamedata event with game outcome is sent after
/ active_game, so it's lost since there's no game to handle it anymore...
/ Work around it with a timeout for now.*/
if (!this.connected_games[gamedata.id].disconnect_timeout) {
if (config_1.config.verbosity) {
trace_1.trace.log(`Starting disconnect Timeout in Connection active_game for ${gamedata.id}`);
}
this.connected_games[gamedata.id].disconnect_timeout = setTimeout(() => {
this.disconnectFromGame(gamedata.id);
}, 1000);
}
}
// Don't connect to finished games.
return;
}
// Set up the game so it can listen for events.
this.connectToGame(gamedata.id);
});
}
connectToGame(game_id) {
if (game_id in this.connected_games) {
return this.connected_games[game_id];
}
else {
trace_1.trace.info("Connecting to game ", game_id);
}
this.connected_games[game_id] = new Game_1.Game(game_id);
this.connected_games[game_id].on("disconnected", (game_id) => {
this.disconnectFromGame(game_id);
});
return this.connected_games[game_id];
}
disconnectFromGame(game_id) {
trace_1.trace.info("Disconnecting from game ", game_id);
if (game_id in this.connected_games) {
this.connected_games[game_id].disconnect();
delete this.connected_games[game_id];
}
}
dumpStatus() {
const blitz_count = this.countGames("blitz");
const rapid_count = this.countGames("rapid");
const live_count = this.countGames("live");
const corr_count = this.countGames("correspondence");
trace_1.trace.info(`Status: playing ${blitz_count} blitz, ${rapid_count} rapid, ${live_count} live, ${corr_count} correspondence games`);
let str = "Bot status: ";
for (const n of ["main", "ending", "opening"]) {
const pool = pools_1.bot_pools[n];
if (!pool) {
continue;
}
str += pool.stateString() + " ";
}
trace_1.trace.info(str);
}
/** Send the server our current status */
sendStatusUpdate() {
const update = {
ongoing_blitz_count: this.countGames("blitz"),
ongoing_rapid_count: this.countGames("rapid"),
ongoing_live_count: this.countGames("live"),
ongoing_correspondence_count: this.countGames("correspondence"),
};
if (update["ongoing_blitz_count"] !== this.last_status_update["ongoing_blitz_count"] ||
update["ongoing_rapid_count"] !== this.last_status_update["ongoing_rapid_count"] ||
update["ongoing_live_count"] !== this.last_status_update["ongoing_live_count"] ||
update["ongoing_correspondence_count"] !==
this.last_status_update["ongoing_correspondence_count"]) {
socket_1.socket.send("bot/status", update);
this.last_status_update = update;
}
}
countGames(speed) {
return Object.values(this.connected_games).filter((g) => { var _a, _b; return ((_b = (_a = g === null || g === void 0 ? void 0 : g.state) === null || _a === void 0 ? void 0 : _a.time_control) === null || _b === void 0 ? void 0 : _b.speed) === speed; }).length;
}
deleteNotification(notification) {
socket_1.socket.send("notification/delete", { notification_id: notification.id }, () => {
trace_1.trace.trace("Deleted notification ", notification.id);
});
}
handleNotification(notification) {
var _a;
switch (notification.type) {
case "friendRequest":
{
trace_1.trace.log("Friend request from ", notification.user.username);
(0, util_1.post)((0, util_1.api1)("me/friends/invitations"), { from_user: notification.user.id })
.then((obj) => trace_1.trace.info(obj.body))
.catch(trace_1.trace.info);
}
break;
case "challenge":
{
let reject = this.checkBlacklist(notification.user) ||
this.checkTimeControl(notification.time_control) ||
this.checkConcurrentGames(notification.time_control.speed) ||
this.checkBoardSize(notification.width, notification.height) ||
this.checkHandicap(notification.ranked, notification.handicap) ||
this.checkRanked(notification.ranked) ||
this.checkAllowedRank(notification.ranked, notification.min_ranking) ||
this.checkDeclineChallenges() ||
this.checkGamesPerPlayer((_a = notification.user) === null || _a === void 0 ? void 0 : _a.id) ||
this.checkKomi(notification.komi) ||
undefined;
if (this.checkWhitelist(notification.user)) {
reject = undefined;
}
if (!reject) {
(0, util_1.post)((0, util_1.api1)(`me/challenges/${notification.challenge_id}/accept`), {})
.then(ignore)
.catch(() => {
trace_1.trace.info("Error accepting challenge, declining it");
(0, util_1.post)((0, util_1.api1)(`me/challenges/${notification.challenge_id}`), {
delete: true,
message: "Error accepting game challenge, challenge has been removed.",
})
.then(ignore)
.catch(trace_1.trace.info);
this.deleteNotification(notification);
});
}
else {
trace_1.trace.info(`Rejecting challenge from ${notification.user.username} https://online-go.com/player/${notification.user.id}`, reject);
(0, util_1.post)((0, util_1.api1)(`me/challenges/${notification.challenge_id}`), {
delete: true,
message: reject.message,
rejection_details: reject,
})
.then(ignore)
.catch(trace_1.trace.info);
}
}
break;
case "lateChatReceivedInGame":
{
this.deleteNotification(notification);
if (!config_1.config.log_game_chat) {
break;
}
const game_id = notification.game_id;
if (game_id in this.connected_finished_games) {
// Already connected to the finished game.
break;
}
trace_1.trace.debug(`Connecting to ${game_id} to receive late chats`);
socket_1.socket.send("chat/join", {
channel: `game-${game_id}`,
});
const on_chat = (chat) => {
(0, Game_1.handleChatLine)(game_id, chat.line, notification.timestamp - 1);
};
socket_1.socket.on(`game/${game_id}/chat`, on_chat);
// Connecting to a game from outside Game deserves a little
// bit of care, but I think it should be OK, because
// lateChatReceivedInGame implies the game is over, so we
// should not be getting in the way of anything here.
//
// We could connect to the game as we usually do, but this
// would confuse the logic there that expects to handle an
// unfinished game.
this.connected_finished_games[game_id] = true;
socket_1.socket.send("game/connect", {
game_id: game_id,
chat: true,
});
setTimeout(() => {
trace_1.trace.debug(`Disconnecting from ${game_id} (chats)`);
delete this.connected_finished_games[game_id];
socket_1.socket.send("game/disconnect", {
game_id: game_id,
});
socket_1.socket.off(`game/${game_id}/chat`, on_chat);
}, 5000);
}
break;
default:
{
if (!(notification.type in ignorable_notifications)) {
trace_1.trace.log("Unhandled notification type: ", notification.type, notification);
}
if (notification.type !== "delete") {
this.deleteNotification(notification);
}
}
break;
}
}
checkBlacklist(user) {
if (!config_1.config.blacklist) {
return undefined;
}
if (config_1.config.blacklist.includes(user.id) || config_1.config.blacklist.includes(user.username)) {
return {
message: `The operator of this bot will not let you play against it.`,
rejection_code: "blacklisted",
details: {},
};
}
return undefined;
}
checkWhitelist(user) {
if (!config_1.config.whitelist) {
return false;
}
if (config_1.config.whitelist.includes(user.id) || config_1.config.whitelist.includes(user.username)) {
return true;
}
return false;
}
checkBoardSize(width, height) {
// handle explicit board size ranges
if (typeof config_1.config.allowed_board_sizes === "object" &&
"width_range" in config_1.config.allowed_board_sizes &&
"height_range" in config_1.config.allowed_board_sizes) {
if (width < config_1.config.allowed_board_sizes.width_range[0] ||
width > config_1.config.allowed_board_sizes.width_range[1] ||
height < config_1.config.allowed_board_sizes.height_range[0] ||
height > config_1.config.allowed_board_sizes.height_range[1]) {
return {
message: `This bot only supports board sizes between ` +
`${config_1.config.allowed_board_sizes.width_range[0]}x${config_1.config.allowed_board_sizes.height_range[0]} ` +
`and ${config_1.config.allowed_board_sizes.width_range[1]}x${config_1.config.allowed_board_sizes.height_range[1]}.`,
rejection_code: "board_size_not_allowed",
details: {
width,
height,
width_range: config_1.config.allowed_board_sizes.width_range,
height_range: config_1.config.allowed_board_sizes.height_range,
},
};
}
else {
return undefined;
}
}
// Handle normal sizes or special "all" | "square" cases
const allowed = Array.isArray(config_1.config.allowed_board_sizes)
? config_1.config.allowed_board_sizes
: [config_1.config.allowed_board_sizes];
if (allowed.includes("all")) {
return undefined;
}
if (allowed.includes("square") && width === height) {
return undefined;
}
if (width !== height) {
return {
message: `This bot only plays square boards.`,
rejection_code: "board_size_not_square",
details: { width, height },
};
}
if (!allowed.includes(width)) {
return {
message: `This bot only plays on these board sizes: ${allowed
.map((x) => `${x}x${x}`)
.join(", ")}.`,
rejection_code: "board_size_not_allowed",
details: { width, height },
};
}
return undefined;
}
checkHandicap(ranked, handicap) {
if (!(ranked ? config_1.config.allow_ranked_handicap : config_1.config.allow_unranked_handicap) &&
handicap !== 0) {
return {
message: `This bot only plays games with no handicap.`,
rejection_code: "handicap_not_allowed",
details: { handicap },
};
}
return undefined;
}
checkRanked(ranked) {
if (!ranked && !config_1.config.allow_unranked) {
return {
message: `This bot only plays ranked games.`,
rejection_code: "unranked_not_allowed",
details: { ranked },
};
}
if (ranked && !config_1.config.allow_ranked) {
return {
message: `This bot only plays unranked games.`,
rejection_code: "ranked_not_allowed",
details: { ranked },
};
}
return undefined;
}
checkConcurrentGames(speed) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
const count = this.countGames(speed);
switch (speed) {
case "blitz":
if (!((_a = config_1.config.allowed_blitz_settings) === null || _a === void 0 ? void 0 : _a.concurrent_games)) {
return {
message: `This bot does not play blitz games.`,
rejection_code: "blitz_not_allowed",
details: {},
};
}
if (count >= (((_b = config_1.config.allowed_blitz_settings) === null || _b === void 0 ? void 0 : _b.concurrent_games) || 0)) {
return {
message: `This bot is already playing ${count} of ${((_c = config_1.config.allowed_blitz_settings) === null || _c === void 0 ? void 0 : _c.concurrent_games) || 0} allowed blitz games.`,
rejection_code: "too_many_blitz_games",
details: {
count,
allowed: ((_d = config_1.config.allowed_blitz_settings) === null || _d === void 0 ? void 0 : _d.concurrent_games) || 0,
},
};
}
break;
case "rapid":
if (!((_e = config_1.config.allowed_rapid_settings) === null || _e === void 0 ? void 0 : _e.concurrent_games)) {
return {
message: `This bot does not play rapid games.`,
rejection_code: "rapid_not_allowed",
details: {},
};
}
if (count >= (((_f = config_1.config.allowed_rapid_settings) === null || _f === void 0 ? void 0 : _f.concurrent_games) || 0)) {
return {
message: `This bot is already playing ${count} of ${((_g = config_1.config.allowed_rapid_settings) === null || _g === void 0 ? void 0 : _g.concurrent_games) || 0} allowed rapid games.`,
rejection_code: "too_many_rapid_games",
details: {
count,
allowed: ((_h = config_1.config.allowed_rapid_settings) === null || _h === void 0 ? void 0 : _h.concurrent_games) || 0,
},
};
}
break;
case "live":
if (!((_j = config_1.config.allowed_live_settings) === null || _j === void 0 ? void 0 : _j.concurrent_games)) {
return {
message: `This bot does not play live games.`,
rejection_code: "live_not_allowed",
details: {},
};
}
if (count >= (((_k = config_1.config.allowed_live_settings) === null || _k === void 0 ? void 0 : _k.concurrent_games) || 0)) {
return {
message: `This bot is already playing ${count} of ${((_l = config_1.config.allowed_live_settings) === null || _l === void 0 ? void 0 : _l.concurrent_games) || 0} allowed live games.`,
rejection_code: "too_many_live_games",
details: {
count,
allowed: ((_m = config_1.config.allowed_live_settings) === null || _m === void 0 ? void 0 : _m.concurrent_games) || 0,
},
};
}
break;
case "correspondence":
if (!((_o = config_1.config.allowed_correspondence_settings) === null || _o === void 0 ? void 0 : _o.concurrent_games)) {
return {
message: `This bot does not play correspondence games.`,
rejection_code: "correspondence_not_allowed",
details: {},
};
}
if (count >= (((_p = config_1.config.allowed_correspondence_settings) === null || _p === void 0 ? void 0 : _p.concurrent_games) || 0)) {
return {
message: `This bot is already playing ${count} of ${((_q = config_1.config.allowed_correspondence_settings) === null || _q === void 0 ? void 0 : _q.concurrent_games) || 0} allowed correspondence games.`,
rejection_code: "too_many_correspondence_games",
details: {
count,
allowed: ((_r = config_1.config.allowed_correspondence_settings) === null || _r === void 0 ? void 0 : _r.concurrent_games) || 0,
},
};
}
break;
}
return undefined;
}
checkTimeControl(time_control) {
if (!config_1.config.allowed_time_control_systems.includes(time_control.system)) {
return {
message: `This bot only plays games with time control system ${config_1.config.allowed_time_control_systems.join(", ")}.`,
rejection_code: "time_control_system_not_allowed",
details: { time_control_system: time_control.system },
};
}
let settings;
switch (time_control.speed) {
case "blitz":
if (!config_1.config.allowed_blitz_settings) {
return {
message: `This bot does not play blitz games.`,
rejection_code: "blitz_not_allowed",
details: {},
};
}
settings = config_1.config.allowed_blitz_settings;
break;
case "rapid":
if (!config_1.config.allowed_rapid_settings) {
return {
message: `This bot does not play rapid games.`,
rejection_code: "rapid_not_allowed",
details: {},
};
}
settings = config_1.config.allowed_rapid_settings;
break;
case "live":
if (!config_1.config.allowed_live_settings) {
return {
message: `This bot does not play live games.`,
rejection_code: "live_not_allowed",
details: {},
};
}
settings = config_1.config.allowed_live_settings;
break;
case "correspondence":
if (!config_1.config.allowed_correspondence_settings) {
return {
message: `This bot does not play correspondence games.`,
rejection_code: "correspondence_not_allowed",
details: {},
};
}
settings = config_1.config.allowed_correspondence_settings;
break;
}
if (settings) {
switch (time_control.system) {
case "fischer":
if (time_control.max_time < settings.fischer.max_time_range[0] ||
time_control.max_time > settings.fischer.max_time_range[1]) {
return {
message: `Time increment is out of acceptable range`,
rejection_code: "max_time_out_of_range",
details: {
time_increment: time_control.time_increment,
range: settings.fischer.time_increment_range,
},
};
}
if (time_control.time_increment < settings.fischer.time_increment_range[0] ||
time_control.time_increment > settings.fischer.time_increment_range[1]) {
return {
message: `Time increment is out of acceptable range`,
rejection_code: "time_increment_out_of_range",
details: {
time_increment: time_control.time_increment,
range: settings.fischer.time_increment_range,
},
};
}
break;
case "byoyomi":
if (time_control.period_time < settings.byoyomi.period_time_range[0] ||
time_control.period_time > settings.byoyomi.period_time_range[1]) {
return {
message: `Period time is out of acceptable range`,
rejection_code: "period_time_out_of_range",
details: {
period_time: time_control.period_time,
range: settings.byoyomi.period_time_range,
},
};
}
if (time_control.periods < settings.byoyomi.periods_range[0] ||
time_control.periods > settings.byoyomi.periods_range[1]) {
return {
message: `Periods is out of acceptable range`,
rejection_code: "periods_out_of_range",
details: {
periods: time_control.periods,
range: settings.byoyomi.periods_range,
},
};
}
if (time_control.main_time < settings.byoyomi.main_time_range[0] ||
time_control.main_time > settings.byoyomi.main_time_range[1]) {
return {
message: `Main time is out of acceptable range`,
rejection_code: "main_time_out_of_range",
details: {
main_time: time_control.main_time,
range: settings.byoyomi.main_time_range,
},
};
}
break;
case "simple":
if (time_control.per_move < settings.simple.per_move_time_range[0] ||
time_control.per_move > settings.simple.per_move_time_range[1]) {
return {
message: `Per move time is out of acceptable range`,
rejection_code: "per_move_time_out_of_range",
details: {
per_move_time: time_control.per_move,
range: settings.simple.per_move_time_range,
},
};
}
break;
default:
return {
message: `This bot does not play games with time control system ${time_control.system}.`,
rejection_code: "time_control_system_not_allowed",
details: { time_control_system: time_control.system },
};
}
}
return undefined;
}
checkAllowedRank(game_is_ranked, player_rank) {
const min_rank = rankstr_to_number(config_1.config.allowed_rank_range[0]);
const max_rank = rankstr_to_number(config_1.config.allowed_rank_range[1]);
if (!game_is_ranked) {
return;
}
if (player_rank < min_rank || player_rank > max_rank) {
return {
rejection_code: "player_rank_out_of_range",
details: {
allowed_rank_range: config_1.config.allowed_rank_range,
},
message: player_rank < min_rank
? `Your rank is too low to play against this bot.`
: `Your rank is too high to play against this bot.`,
};
}
}
checkDeclineChallenges() {
if (config_1.config.decline_new_challenges) {
return {
rejection_code: "not_accepting_new_challenges",
details: {},
message: "This bot is not accepting new challenges at this time.",
};
}
}
checkGamesPerPlayer(player_id) {
trace_1.trace.log("Max games per player: ", config_1.config.max_games_per_player);
//config;
if (config_1.config.max_games_per_player) {
const game_count = Object.keys(this.connected_games).filter((game_id) => {
var _a;
const state = (_a = this.connected_games[game_id]) === null || _a === void 0 ? void 0 : _a.state;
if ((state === null || state === void 0 ? void 0 : state.player_pool) !== undefined) {
return !!state.player_pool[player_id];
}
return (state === null || state === void 0 ? void 0 : state.white_player_id) === player_id || (state === null || state === void 0 ? void 0 : state.black_player_id) === player_id;
}).length;
trace_1.trace.log("Game count: ", game_count, " for ", player_id);
if (game_count >= config_1.config.max_games_per_player) {
return {
rejection_code: "too_many_games_for_player",
details: {
games_being_played: game_count,
max_games_per_player: config_1.config.max_games_per_player,
},
message: `You already have ${game_count} games against this bot. This bot only allows ${config_1.config.max_games_per_player} games per player, please end your other games before starting a new one.`,
};
}
}
}
checkKomi(komi) {
if (komi < config_1.config.allowed_komi_range[0] || komi > config_1.config.allowed_komi_range[1]) {
return {
rejection_code: "komi_out_of_range",
details: {
allowed_komi_range: config_1.config.allowed_komi_range,
},
message: `Komi is out of acceptable range`,
};
}
}
terminate() {
clearTimeout(this.connect_timeout);
clearInterval(this.ping_interval);
clearInterval(this.notification_connect_interval);
}
}
function ignore() {
// do nothing
}
function rankstr_to_number(rank) {
const base = parseInt(rank);
const suffix = rank[rank.length - 1].toLowerCase();
switch (suffix) {
case "p":
return 999;
case "k":
return 30 - base;
case "d":
return 29 + base;
}
throw new Error(`Invalid rank string: ${rank}`);
}
new Main();
/***/ }),
/***/ "./src/pools.ts":
/*!**********************!*\
!*** ./src/pools.ts ***!
\**********************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var _a, _b, _c, _d;
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.bot_pools = exports.PersistentBotManager = exports.BotPoolManager = void 0;
const Bot_1 = __webpack_require__(/*! ./Bot */ "./src/Bot.ts");
const config_1 = __webpack_require__(/*! ./config */ "./src/config.ts");
const eventemitter3_1 = __webpack_require__(/*! eventemitter3 */ "eventemitter3");
const trace_1 = __webpack_require__(/*! ./trace */ "./src/trace.ts");
global.performance = global.performance || Date;
/** This class manages a pool of Bots */
class BotPoolManager extends eventemitter3_1.EventEmitter {
constructor(pool_name, bot_config) {
super();
this.instances = [];
this.queue = [];
this.log = trace_1.trace.log.bind(null, `[${pool_name} pool]`);
this.verbose = trace_1.trace.debug.bind(null, `[${pool_name} pool]`);
this.warn = trace_1.trace.warn.bind(null, `[${pool_name} pool]`);
this.error = trace_1.trace.error.bind(null, `[${pool_name} pool]`);
this.bot_config = bot_config;
this.pool_name = pool_name;
for (let i = 0; i < bot_config.instances; i++) {
this.addInstance(bot_config);
}
this.ready = Promise.all(this.instances.map((bot) => bot.ready));
this.ready
.then(() => {
trace_1.trace.info(`${this.pool_name} bot pool: ${this.instances.length} bots ready`);
})
.catch((err) => {
console.error(err);
process.exit(1);
});
}
addInstance(bot_config) {
const start_time = performance.now();
const bot = new Bot_1.Bot(bot_config, this.pool_name === "Ending");
this.instances.push(bot);
bot.on("terminated", () => {
this.instances.splice(this.instances.indexOf(bot), 1);
if (performance.now() - start_time < 1000) {
trace_1.trace.error(`Bot "${bot_config.command.join(" ")}" terminated too quickly`);
process.exit(1);
}
this.addInstance(bot_config);
});
bot.on("ready", () => {
this.emit("start", bot_config.command.join(" "), bot.pid);
trace_1.trace.info(`Bot "${bot_config.command.join(" ")}" started with PID ${bot.pid}. Ready in ${Math.round(performance.now() - start_time)}ms.`);
});
}
acquire(speed, width, height, game_id) {
return __awaiter(this, void 0, void 0, function* () {
trace_1.trace.info(`Acquiring bot for ${speed} game`);
yield this.ready;
for (const pass of ["game_id", "board_size", "any"]) {
for (let i = 0; i < this.instances.length; i++) {
const bot = this.instances[i];
/* We prioritize instances that have been playing this game, are already
* setup to play on this board size, or finally any that are available.
*/
const pass_check = (pass === "game_id" && bot.last_game_id === game_id) ||
(pass === "board_size" &&
bot.last_width === width &&
bot.last_height === height) ||
pass === "any";
if (bot.available && pass_check) {
bot.available = false;
trace_1.trace.info("Picked bot in " + pass + " pass");
return bot;
}
}
}
return new Promise((resolve) => {
this.queue.push([speed, width, height, resolve]);
});
});
}
countAvailable() {
return this.instances.filter((bot) => bot.available).length;
}
release(bot) {
bot.setGame(null);
if (this.queue.length > 0) {
for (const pass of ["board_size", "any"]) {
for (const target_speed of ["blitz", "rapid", "live", "correspondence"]) {
for (let i = 0; i < this.queue.length; i++) {
const [speed, width, height, resolve] = this.queue[i];
const pass_check = (pass === "board_size" &&
bot.last_width === width &&
bot.last_height === height) ||
pass === "any";
if (speed === target_speed && pass_check) {
this.log(`Releasing bot back to the ${speed} pool, queue length: ${this.queue.length}`);
this.queue.splice(i, 1);
resolve(bot);
return;
}
}
}
}
}
else {
bot.available = true;
}
}
clearLastGameId(game_id) {
for (const bot of this.instances) {
if (bot.last_game_id === game_id) {
bot.last_game_id = -1;
}
}
}
stateString() {
return `${this.pool_name}: ${this.countAvailable()}/${this.instances.length} available`;
}
}
exports.BotPoolManager = BotPoolManager;
class PersistentBotManager extends eventemitter3_1.EventEmitter {
constructor(pool_name, bot_config) {
super();
this.instances = [];
this.queue = [];
this.log = trace_1.trace.log.bind(null, `[${pool_name} bots]`);
this.verbose = trace_1.trace.debug.bind(null, `[${pool_name} bots]`);
this.warn = trace_1.trace.warn.bind(null, `[${pool_name} bots]`);
this.error = trace_1.trace.error.bind(null, `[${pool_name} bots]`);
this.bot_config = bot_config;
this.pool_name = pool_name;
this.ready = Promise.resolve([]);
trace_1.trace.info(`${this.pool_name} persistent bots ready`);
}
addInstance(bot_config, game_id) {
const start_time = performance.now();
const bot = new Bot_1.Bot(bot_config, this.pool_name === "Ending");
bot.last_game_id = game_id;
this.instances.push(bot);
bot.on("terminated", () => {
if (bot.persistent_idle_timeout) {
clearTimeout(bot.persistent_idle_timeout);
}
this.instances.splice(this.instances.indexOf(bot), 1);
if (performance.now() - start_time < 1000) {
trace_1.trace.error(`Bot "${bot_config.command.join(" ")}" terminated too quickly`);
process.exit(1);
}
if (bot.last_game_id !== -1) {
this.addInstance(bot_config, game_id);
}
});
bot.on("ready", () => {
this.emit("start", bot_config.command.join(" "), bot.pid);
trace_1.trace.info(`Bot "${bot_config.command.join(" ")}" started with PID ${bot.pid}. Ready in ${Math.round(performance.now() - start_time)}ms.`);
});
return bot;
}
acquire(_speed, _width, _height, game_id) {
return __awaiter(this, void 0, void 0, function* () {
const bot = this.instances.find((bot) => bot.last_game_id === game_id) ||
this.addInstance(this.bot_config, game_id);
if (bot.persistent_idle_timeout) {
clearTimeout(bot.persistent_idle_timeout);
}
return bot;
});
}
countAvailable() {
return 1;
}
release(bot) {
trace_1.trace.info("[persistent] Releasing bot, queue length: " + this.queue.length);
if (bot.persistent_idle_timeout) {
clearTimeout(bot.persistent_idle_timeout);
}
bot.persistent_idle_timeout = setTimeout(() => {
this.log(`Bot has been idle for ${this.bot_config.persistent_idle_timeout}ms, terminating`);
bot.persistent_idle_timeout = null;
bot.last_game_id = -1;
bot.kill();
}, this.bot_config.persistent_idle_timeout);
}
clearLastGameId(game_id) {
for (const bot of this.instances) {
if (bot.last_game_id === game_id) {
bot.last_game_id = -1;
bot.kill();
}
}
}
stateString() {
return `${this.pool_name}: ${this.instances.length} bots`;
}
}
exports.PersistentBotManager = PersistentBotManager;
exports.bot_pools = {
main: config_1.config.bot.manager === "pool"
? new BotPoolManager("Main", config_1.config.bot)
: new PersistentBotManager("Main", config_1.config.bot),
ending: ((_a = config_1.config.ending_bot) === null || _a === void 0 ? void 0 : _a.manager) === "pool"
? new BotPoolManager("Ending", config_1.config.ending_bot)
: ((_b = config_1.config.ending_bot) === null || _b === void 0 ? void 0 : _b.manager) === "persistent"
? new PersistentBotManager("Ending", config_1.config.ending_bot)
: null,
opening: ((_c = config_1.config.opening_bot) === null || _c === void 0 ? void 0 : _c.manager) === "pool"
? new BotPoolManager("Opening", config_1.config.opening_bot)
: ((_d = config_1.config.opening_bot) === null || _d === void 0 ? void 0 : _d.manager) === "persistent"
? new PersistentBotManager("Opening", config_1.config.opening_bot)
: null,
};
/***/ }),
/***/ "./src/socket.ts":
/*!***********************!*\
!*** ./src/socket.ts ***!
\***********************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.socket = void 0;
const config_1 = __webpack_require__(/*! ./config */ "./src/config.ts");
const goban_engine_1 = __webpack_require__(/*! goban-engine */ "goban-engine");
const trace_1 = __webpack_require__(/*! ./trace */ "./src/trace.ts");
global.performance = global.performance || Date;
const MIN_CONNECT_TIME = 1000;
exports.socket = new goban_engine_1.GobanSocket(config_1.config.server);
exports.socket.on("ERROR", (message) => {
trace_1.trace.error(message);
});
let connect_time = performance.now();
exports.socket.on("connect", () => {
connect_time = performance.now() - connect_time;
trace_1.trace.info(`Connected to ${config_1.config.server} in ${connect_time.toFixed(0)}ms`);
});
exports.socket.on("disconnect", () => {
if (performance.now() - connect_time < MIN_CONNECT_TIME) {
process.exit(1);
}
});
/***/ }),
/***/ "./src/trace.ts":
/*!**********************!*\
!*** ./src/trace.ts ***!
\**********************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.trace = void 0;
const fs = __webpack_require__(/*! fs */ "fs");
const tracer = __webpack_require__(/*! tracer */ "tracer");
const config_1 = __webpack_require__(/*! ./config */ "./src/config.ts");
const console_fmt = "{{timestamp}} {{title}} " +
(config_1.config.verbosity > 0 ? "{{file}}:{{line}}{{space}} " : "") +
"{{message}}";
const console_config = {
format: console_fmt,
dateformat: "mmm dd HH:MM:ss",
preprocess: (data) => {
switch (data.title) {
case "trace":
data.title = " ";
break;
case "debug":
data.title = " ";
break;
case "log":
data.title = " ";
break;
case "info":
data.title = " ";
break;
case "warn":
data.title = " ";
break;
case "error":
data.title = "!";
break;
}
if (config_1.config.verbosity > 0) {
data.space = " ".repeat(Math.max(0, 20 - `${data.file}:${data.line}`.length));
}
},
};
const orig_console = console;
console_config.transport = (data) => {
orig_console.log(data.output);
if (config_1.config.logfile) {
fs.open(config_1.config.logfile, "a", parseInt("0644", 8), (_e, id) => {
// strip color controls characters
const stripped = data.output.replace(
// eslint-disable-next-line no-control-regex
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
fs.write(id, stripped + "\n", null, "utf8", () => {
fs.close(id, () => {
// noop
});
});
});
}
};
exports.trace = tracer.colorConsole(console_config);
global.console = exports.trace;
if (config_1.config.verbosity <= 1) {
exports.trace.trace = (..._args) => {
return null;
};
}
if (config_1.config.verbosity <= 0) {
exports.trace.debug = (..._args) => {
return null;
};
exports.trace.verbose = (..._args) => {
return null;
};
}
/***/ }),
/***/ "./src/util.ts":
/*!*********************!*\
!*** ./src/util.ts ***!
\*********************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.gtpchar2num = gtpchar2num;
exports.move2gtpvertex = move2gtpvertex;
exports.request = request;
exports.post = post;
exports.api1 = api1;
exports.ignore_promise = ignore_promise;
const http = __webpack_require__(/*! http */ "http");
const https = __webpack_require__(/*! https */ "https");
const querystring = __webpack_require__(/*! querystring */ "querystring");
const config_1 = __webpack_require__(/*! ./config */ "./src/config.ts");
const trace_1 = __webpack_require__(/*! ./trace */ "./src/trace.ts");
function gtpchar2num(ch) {
if (ch === "." || !ch) {
return -1;
}
return "abcdefghjklmnopqrstuvwxyz".indexOf(ch.toLowerCase());
}
function move2gtpvertex(move, width, height) {
if (move.x < 0) {
return "pass";
}
return num2gtpchar(move["x"]) + (height - move["y"]);
}
function num2gtpchar(num) {
if (num === -1) {
return ".";
}
return "abcdefghjklmnopqrstuvwxyz"[num];
}
function request(method, path, data) {
const url = config_1.config.server;
const host = url.replace(/^https?:\/\//, "").replace(/\/.*$/, "");
const m = url.match(/:(\d+)$/);
const port = m ? m[1] : url.match(/^https/) ? 443 : 80;
const insecure = url.indexOf("https") !== 0;
trace_1.trace.debug(`${method} ${path} ${JSON.stringify(data)}`);
data.apikey = config_1.config.apikey;
data.bot_id = config_1.config.bot_id;
return new Promise((resolve, reject) => {
let enc_data_type = "application/x-www-form-urlencoded";
for (const k in data) {
if (typeof data[k] === "object") {
enc_data_type = "application/json";
}
}
let headers = null;
if (data._headers) {
data = JSON.parse(JSON.stringify(data));
headers = data._headers;
delete data._headers;
}
let enc_data = null;
if (enc_data_type === "application/json") {
enc_data = JSON.stringify(data);
}
else {
enc_data = querystring.stringify(data);
}
const options = {
host: host,
port: port,
path: path,
method: method,
headers: {
"Content-Type": enc_data_type,
"Content-Length": enc_data.length,
},
};
if (headers) {
for (const k in headers) {
options.headers[k] = headers[k];
}
}
const req = (insecure ? http : https).request(options, (res) => {
//test
res.setEncoding("utf8");
let body = "";
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
if (res.statusCode < 200 || res.statusCode > 299) {
reject({ error: `${res.statusCode} - ${body}`, response: res, body: body });
return;
}
resolve({ response: res, body: body });
});
});
req.on("error", (e) => {
reject({ error: e.message });
});
req.write(enc_data);
req.end();
});
}
function post(path, data) {
return request("POST", path, data);
}
function api1(str) {
return `/api/v1/${str}`;
}
function ignore_promise(promise) {
promise.catch((e) => {
trace_1.trace.error(e);
});
}
/***/ }),
/***/ "eventemitter3":
/*!********************************!*\
!*** external "eventemitter3" ***!
\********************************/
/***/ ((module) => {
module.exports = require("eventemitter3");
/***/ }),
/***/ "goban-engine":
/*!*******************************!*\
!*** external "goban-engine" ***!
\*******************************/
/***/ ((module) => {
module.exports = require("goban-engine");
/***/ }),
/***/ "json5":
/*!************************!*\
!*** external "json5" ***!
\************************/
/***/ ((module) => {
module.exports = require("json5");
/***/ }),
/***/ "jsonschema":
/*!*****************************!*\
!*** external "jsonschema" ***!
\*****************************/
/***/ ((module) => {
module.exports = require("jsonschema");
/***/ }),
/***/ "split2":
/*!*************************!*\
!*** external "split2" ***!
\*************************/
/***/ ((module) => {
module.exports = require("split2");
/***/ }),
/***/ "tracer":
/*!*************************!*\
!*** external "tracer" ***!
\*************************/
/***/ ((module) => {
module.exports = require("tracer");
/***/ }),
/***/ "ws":
/*!*********************!*\
!*** external "ws" ***!
\*********************/
/***/ ((module) => {
module.exports = require("ws");
/***/ }),
/***/ "yargs":
/*!************************!*\
!*** external "yargs" ***!
\************************/
/***/ ((module) => {
module.exports = require("yargs");
/***/ }),
/***/ "child_process":
/*!********************************!*\
!*** external "child_process" ***!
\********************************/
/***/ ((module) => {
module.exports = require("child_process");
/***/ }),
/***/ "fs":
/*!*********************!*\
!*** external "fs" ***!
\*********************/
/***/ ((module) => {
module.exports = require("fs");
/***/ }),
/***/ "http":
/*!***********************!*\
!*** external "http" ***!
\***********************/
/***/ ((module) => {
module.exports = require("http");
/***/ }),
/***/ "https":
/*!************************!*\
!*** external "https" ***!
\************************/
/***/ ((module) => {
module.exports = require("https");
/***/ }),
/***/ "querystring":
/*!******************************!*\
!*** external "querystring" ***!
\******************************/
/***/ ((module) => {
module.exports = require("querystring");
/***/ }),
/***/ "./schema/Config.schema.json":
/*!***********************************!*\
!*** ./schema/Config.schema.json ***!
\***********************************/
/***/ ((module) => {
module.exports = /*#__PURE__*/JSON.parse('{"$schema":"http://json-schema.org/draft-07/schema#","$ref":"#/definitions/Config","definitions":{"Config":{"type":"object","properties":{"apikey":{"type":"string","description":"API key for the bot."},"engine":{"type":"string","description":"Engine specifier of the bot, this is a plain text description of the bot\'s engine and network that will be recorded along with all games played."},"verbosity":{"type":"number","description":"Enable verbose logging.","default":0},"log_game_chat":{"type":"boolean","description":"Enable logging game chat.","default":false},"status_update_frequency":{"type":"number","description":"Sets how often the status lines are printed to the screen. Set to 0 to disable. units: milliseconds","default":60000},"server":{"type":"string","description":"Server URL to connect to, defaults to online-go.com","default":"https://online-go.com"},"max_pause_time":{"type":"number","description":"Maximum time to allow the game to be paused for in seconds.","default":300},"blacklist":{"type":"array","items":{"type":["number","string"]},"description":"Players who are not allowed to play the bot ever."},"whitelist":{"type":"array","items":{"type":["number","string"]},"description":"Players who are allowed to challenge the bot with any settings even when the bot is at the maximum number of simultaneous games"},"bot":{"$ref":"#/definitions/BotConfig","description":"Config for how to run your bot"},"opening_bot":{"$ref":"#/definitions/OpeningBotConfig","description":"Bot to use for playing opening moves. This can be useful for ensuring your bot plays at least a few reasonable joseki moves if it is a weak bot."},"ending_bot":{"$ref":"#/definitions/EndingBotConfig","description":"Secondary bot to use for ensuring your real bot passes or resigns appropriately. This bot will be consulted every move after . If the move it returns is a pass it will override the move your bot has made (unless your bot is resigning). If the move it returns is a resign, it will count the number of successive resigns and if it is more than the number of allowed resigns you\'ve set in this config (default of 3), it will override your bot\'s move with a resign."},"greeting":{"$ref":"#/definitions/TranslatableString","description":"Message to send to the player at the start of the game"},"farewell":{"$ref":"#/definitions/TranslatableString","description":"Message to send to the player when the game is over"},"farewellscore":{"type":"boolean","description":"Send a message saying what the bot thought the score was at the end of the game"},"logfile":{"type":"string","description":"File to write logs to. Logs will be sent to stdout as well."},"allowed_time_control_systems":{"type":"array","items":{"$ref":"#/definitions/BotTimeControlSystems"},"description":"Time control systems that we can work with","default":["fischer","byoyomi","simple"],"minItems":1},"allowed_blitz_settings":{"anyOf":[{"type":"null"},{"$ref":"#/definitions/TimeControlRanges"}],"description":"Allowed blitz times for the bot. Blitz is disabled by default, but you can enable it by providing acceptable time settings.","default":null},"allowed_rapid_settings":{"anyOf":[{"type":"null"},{"$ref":"#/definitions/TimeControlRanges"}],"description":"Allowed rapid game times for bot."},"allowed_live_settings":{"anyOf":[{"type":"null"},{"$ref":"#/definitions/TimeControlRanges"}],"description":"Allowed live game times for bot.","default":{"per_move_time_range":[10,300],"main_time_range":[0,3600],"periods_range":[1,10]}},"allowed_correspondence_settings":{"anyOf":[{"type":"null"},{"$ref":"#/definitions/TimeControlRanges"}],"description":"Allowed correspondence game times for bot.","default":{"per_move_time_range":[43200,259200],"main_time_range":[0,86400],"periods_range":[1,10]}},"allowed_board_sizes":{"anyOf":[{"type":"array","items":{"type":"number"}},{"type":"number"},{"type":"string","const":"all"},{"type":"string","const":"square"},{"$ref":"#/definitions/BoardSizeRanges"}],"description":"Allowed board sizes for the bot. If there are no restrictions, you can provide \\"all\\", or if you can play on any square board, you can provide \\"square\\".\\n\\nYou can also provide explicit width and height ranges for non square boards with `{width_range: [min, max], height_range: [min, max]}`.","default":[9,13,19]},"allow_ranked":{"type":"boolean","description":"Allowed ranked games","default":true},"allow_unranked":{"type":"boolean","description":"Allowed unranked games","default":true},"allowed_rank_range":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":2,"description":"Allowed range for ranked games","default":["30k","9p"]},"allow_ranked_handicap":{"type":"boolean","description":"Allow handicap games for ranked games","default":true},"allow_unranked_handicap":{"type":"boolean","description":"Allow handicap games for unranked games","default":true},"allowed_komi_range":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2,"description":"Allowed komi range. Negative numbers indicate reverse Komi.","default":[-99,99]},"hidden":{"type":"boolean","description":"Hide the bot from the public bot list","default":false},"decline_new_challenges":{"type":"boolean","description":"Decline all new challenges. This implies hidden.","default":false},"showboard":{"type":"boolean","description":"Used for debugging, will issue a showboard command when we\'ve loaded the board state into the bot","default":false},"min_move_time":{"type":"number","description":"If set, bot moves will be delayed when made before `min_move_time` ms. This is primarily a user experience thing as can make players feel rushed if the bots are responding too quickly.","default":1500},"max_games_per_player":{"type":"number","description":"Maximum amount of ongoing games to allow concurrently by the same player","default":1}},"required":["apikey"],"additionalProperties":false,"description":"Bot config"},"BotConfig":{"type":"object","properties":{"command":{"type":"array","items":{"type":"string"}},"manager":{"type":"string","enum":["pool","persistent"],"description":"Management method for managing bot instances. `pool` starts up a fixed `instances` number of bots and and reuses them for all games. `persistent` starts up a single bot instance per game and allows state re-use to allow things like pondering.","default":"persistent"},"instances":{"type":"number","description":"Number of instances of the bot to run in parallel. Exactly this many instances will be run at any given time, regardless of how many ongoing games there are. This is only applicable when using the pooling manager.","default":1},"enable_clock":{"type":"boolean","description":"Enabled clocks being sent to the bot. Clocks will only be sent when the applicable clock commands are detected from the bot anyways, so this is generally fine to leave turned on.","default":true},"send_chats":{"type":"boolean"},"send_pv_data":{"type":"boolean","description":"Send the principal variation (PV) values. Note that your bot must output this data in a way that can be parsed.","default":true},"release_delay":{"type":"number","description":"After a bot makes a move, some bots will continue writing to stderr relevant information (such as chats or PV data). This option controls how long we wait for the bot to finish writing to stderr before we release the bot back into the pool of available bots.","default":100},"quit_grace_period":{"type":"number","description":"When a bot is to shutdown we send a `quit` command to the bot. This grace period is the number of milliseconds to wait for the bot to quit gracefully before sending a `SIGTERM` to the bot. Furthermore, if the bot doesn\'t terminate after the `SIGTERM` for another grace period, we will send a `SIGKILL` to the bot.","default":5000},"persistent_idle_timeout":{"type":"number","description":"When the manager is set to \\"persistent\\", If no moves are made within this timeout, the bot process is terminated. If a new move is made a new process will be started to resume playing the game.","default":600000}},"required":["command","release_delay"],"additionalProperties":false,"description":"Bot config"},"OpeningBotConfig":{"type":"object","properties":{"command":{"type":"array","items":{"type":"string"}},"manager":{"type":"string","enum":["pool","persistent"],"description":"Management method for managing bot instances. `pool` starts up a fixed `instances` number of bots and and reuses them for all games. `persistent` starts up a single bot instance per game and allows state re-use to allow things like pondering.","default":"persistent"},"instances":{"type":"number","description":"Number of instances of the bot to run in parallel. Exactly this many instances will be run at any given time, regardless of how many ongoing games there are. This is only applicable when using the pooling manager.","default":1},"enable_clock":{"type":"boolean","description":"Enabled clocks being sent to the bot. Clocks will only be sent when the applicable clock commands are detected from the bot anyways, so this is generally fine to leave turned on.","default":true},"send_chats":{"type":"boolean"},"send_pv_data":{"type":"boolean","description":"Send the principal variation (PV) values. Note that your bot must output this data in a way that can be parsed.","default":true},"release_delay":{"type":"number","description":"After a bot makes a move, some bots will continue writing to stderr relevant information (such as chats or PV data). This option controls how long we wait for the bot to finish writing to stderr before we release the bot back into the pool of available bots.","default":100},"quit_grace_period":{"type":"number","description":"When a bot is to shutdown we send a `quit` command to the bot. This grace period is the number of milliseconds to wait for the bot to quit gracefully before sending a `SIGTERM` to the bot. Furthermore, if the bot doesn\'t terminate after the `SIGTERM` for another grace period, we will send a `SIGKILL` to the bot.","default":5000},"persistent_idle_timeout":{"type":"number","description":"When the manager is set to \\"persistent\\", If no moves are made within this timeout, the bot process is terminated. If a new move is made a new process will be started to resume playing the game.","default":600000},"number_of_opening_moves_to_play":{"type":"number","description":"Number of opening moves to play before switching to the main bot.","default":8}},"additionalProperties":false,"required":["command","release_delay"]},"EndingBotConfig":{"type":"object","properties":{"command":{"type":"array","items":{"type":"string"}},"manager":{"type":"string","enum":["pool","persistent"],"description":"Management method for managing bot instances. `pool` starts up a fixed `instances` number of bots and and reuses them for all games. `persistent` starts up a single bot instance per game and allows state re-use to allow things like pondering.","default":"persistent"},"instances":{"type":"number","description":"Number of instances of the bot to run in parallel. Exactly this many instances will be run at any given time, regardless of how many ongoing games there are. This is only applicable when using the pooling manager.","default":1},"enable_clock":{"type":"boolean","description":"Enabled clocks being sent to the bot. Clocks will only be sent when the applicable clock commands are detected from the bot anyways, so this is generally fine to leave turned on.","default":true},"send_chats":{"type":"boolean"},"send_pv_data":{"type":"boolean","description":"Send the principal variation (PV) values. Note that your bot must output this data in a way that can be parsed.","default":true},"release_delay":{"type":"number","description":"After a bot makes a move, some bots will continue writing to stderr relevant information (such as chats or PV data). This option controls how long we wait for the bot to finish writing to stderr before we release the bot back into the pool of available bots.","default":100},"quit_grace_period":{"type":"number","description":"When a bot is to shutdown we send a `quit` command to the bot. This grace period is the number of milliseconds to wait for the bot to quit gracefully before sending a `SIGTERM` to the bot. Furthermore, if the bot doesn\'t terminate after the `SIGTERM` for another grace period, we will send a `SIGKILL` to the bot.","default":5000},"persistent_idle_timeout":{"type":"number","description":"When the manager is set to \\"persistent\\", If no moves are made within this timeout, the bot process is terminated. If a new move is made a new process will be started to resume playing the game.","default":600000},"allowed_resigns":{"type":"number","description":"Number of successive resigns allowed before the bot will resign.","default":3},"moves_to_allow_before_checking_ratio":{"type":"number","description":"This is the ratio of the board size to the number of moves to allow before we will start checking the ending bot for passes and resigns. This is to prevent the bot from resigning too early in a game.\\n\\nThe move to start consulting the ending bot is calculated by taking\\n\\n ceil(board_height * board_width * ratio)","default":0.8}},"additionalProperties":false,"required":["command","release_delay"]},"TranslatableString":{"type":"object","properties":{"en":{"type":"string"}},"required":["en"],"additionalProperties":{"type":"string"}},"BotTimeControlSystems":{"type":"string","enum":["fischer","byoyomi","simple"]},"TimeControlRanges":{"type":"object","properties":{"simple":{"type":"object","properties":{"per_move_time_range":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2,"description":"Range of acceptable times per period in seconds","default":"[10, 300] for live, [43200, 259200] for correspondence"}},"required":["per_move_time_range"],"additionalProperties":false,"description":"Time control settings for Simple clocks"},"byoyomi":{"type":"object","properties":{"main_time_range":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2,"description":"Range of acceptable main times in seconds.","default":"[0, 3600] for live games, [0, 259200] for correspondence games"},"period_time_range":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2,"description":"Range of acceptable times per period in seconds","default":"[10, 300] for live, [43200, 259200] for correspondence"},"periods_range":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2,"description":"Range of acceptable number of periods.","default":[1,10]}},"required":["main_time_range","period_time_range","periods_range"],"additionalProperties":false,"description":"Time control settings for byo-yomi clocks"},"fischer":{"type":"object","properties":{"initial_time_range":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2,"description":"Range of acceptable initial times in seconds.","default":"[30, 600] for live games, [86400, 604800] for correspondence games"},"max_time_range":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2,"description":"Range of acceptable max times in seconds.","default":"[5, 7200] for live games, [86400, 604800] for correspondence games"},"time_increment_range":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2,"description":"range of acceptable times for the time increment","default":"[10, 300] for live, [43200, 259200] for correspondence"}},"required":["initial_time_range","max_time_range","time_increment_range"],"additionalProperties":false,"description":"Time control settings for fischer clocks"},"concurrent_games":{"type":"number","description":"Concurrent games to allow for this speed bracket","default":"1, 3, 500 for blitz, live, correspondence respectively"}},"required":["concurrent_games"],"additionalProperties":false},"BoardSizeRanges":{"type":"object","properties":{"width_range":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2,"description":"Specify the low and high range of acceptable board widths. This value is inclusive, so [5,19] would include 5, 19, and everything in between."},"height_range":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2,"description":"Specify the low and high range of acceptable board heights. This value is inclusive, so [5,19] would include 5, 19, and everything in between."}},"required":["width_range","height_range"],"additionalProperties":false,"description":"Range of acceptable custom board sizes"}}}');
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module is referenced by other modules so it can't be inlined
/******/ var __webpack_exports__ = __webpack_require__("./src/main.ts");
/******/
/******/ })()
;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,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Q0FBQyxRQUFRLENBQUMsQ0FBQztRQUNwQixHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDZCxDQUFDLENBQUMsQ0FBQztBQUNQLENBQUM7QUFFRCxTQUFnQixJQUFJLENBQUMsSUFBSSxFQUFFLElBQUk7SUFDM0IsT0FBTyxPQUFPLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztBQUN2QyxDQUFDO0FBRUQsU0FBZ0IsSUFBSSxDQUFDLEdBQUc7SUFDcEIsT0FBTyxXQUFXLEdBQUcsRUFBRSxDQUFDO0FBQzVCLENBQUM7QUFFRCxTQUFnQixjQUFjLENBQUMsT0FBcUI7SUFDaEQsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO1FBQ2hCLGFBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkIsQ0FBQyxDQUFDLENBQUM7QUFDUCxDQUFDOzs7Ozs7Ozs7OztBQ2hIRDs7Ozs7Ozs7OztBQ0FBOzs7Ozs7Ozs7O0FDQUE7Ozs7Ozs7Ozs7QUNBQTs7Ozs7Ozs7OztBQ0FBOzs7Ozs7Ozs7O0FDQUE7Ozs7Ozs7Ozs7QUNBQTs7Ozs7Ozs7OztBQ0FBOzs7Ozs7Ozs7O0FDQUE7Ozs7Ozs7Ozs7QUNBQTs7Ozs7Ozs7OztBQ0FBOzs7Ozs7Ozs7O0FDQUE7Ozs7Ozs7Ozs7QUNBQTs7Ozs7Ozs7Ozs7Ozs7OztVQ0FBO1VBQ0E7O1VBRUE7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7O1VBRUE7VUFDQTs7VUFFQTtVQUNBO1VBQ0E7Ozs7VUV0QkE7VUFDQTtVQUNBO1VBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ndHAyb2dzLy4vc3JjL0JvdC50cyIsIndlYnBhY2s6Ly9ndHAyb2dzLy4vc3JjL0dhbWUudHMiLCJ3ZWJwYWNrOi8vZ3RwMm9ncy8uL3NyYy9Qdk91dHB1dFBhcnNlci50cyIsIndlYnBhY2s6Ly9ndHAyb2dzLy4vc3JjL2NvbmZpZy50cyIsIndlYnBhY2s6Ly9ndHAyb2dzLy4vc3JjL21haW4udHMiLCJ3ZWJwYWNrOi8vZ3RwMm9ncy8uL3NyYy9wb29scy50cyIsIndlYnBhY2s6Ly9ndHAyb2dzLy4vc3JjL3NvY2tldC50cyIsIndlYnBhY2s6Ly9ndHAyb2dzLy4vc3JjL3RyYWNlLnRzIiwid2VicGFjazovL2d0cDJvZ3MvLi9zcmMvdXRpbC50cyIsIndlYnBhY2s6Ly9ndHAyb2dzL2V4dGVybmFsIGNvbW1vbmpzIFwiZXZlbnRlbWl0dGVyM1wiIiwid2VicGFjazovL2d0cDJvZ3MvZXh0ZXJuYWwgY29tbW9uanMgXCJnb2Jhbi1lbmdpbmVcIiIsIndlYnBhY2s6Ly9ndHAyb2dzL2V4dGVybmFsIGNvbW1vbmpzIFwianNvbjVcIiIsIndlYnBhY2s6Ly9ndHAyb2dzL2V4dGVybmFsIGNvbW1vbmpzIFwianNvbnNjaGVtYVwiIiwid2VicGFjazovL2d0cDJvZ3MvZXh0ZXJuYWwgY29tbW9uanMgXCJzcGxpdDJcIiIsIndlYnBhY2s6Ly9ndHAyb2dzL2V4dGVybmFsIGNvbW1vbmpzIFwidHJhY2VyXCIiLCJ3ZWJwYWNrOi8vZ3RwMm9ncy9leHRlcm5hbCBjb21tb25qcyBcIndzXCIiLCJ3ZWJwYWNrOi8vZ3RwMm9ncy9leHRlcm5hbCBjb21tb25qcyBcInlhcmdzXCIiLCJ3ZWJwYWNrOi8vZ3RwMm9ncy9leHRlcm5hbCBub2RlLWNvbW1vbmpzIFwiY2hpbGRfcHJvY2Vzc1wiIiwid2VicGFjazovL2d0cDJvZ3MvZXh0ZXJuYWwgbm9kZS1jb21tb25qcyBcImZzXCIiLCJ3ZWJwYWNrOi8vZ3RwMm9ncy9leHRlcm5hbCBub2RlLWNvbW1vbmpzIFwiaHR0cFwiIiwid2VicGFjazovL2d0cDJvZ3MvZXh0ZXJuYWwgbm9kZS1jb21tb25qcyBcImh0dHBzXCIiLCJ3ZWJwYWNrOi8vZ3RwMm9ncy9leHRlcm5hbCBub2RlLWNvbW1vbmpzIFwicXVlcnlzdHJpbmdcIiIsIndlYnBhY2s6Ly9ndHAyb2dzL3dlYnBhY2svYm9vdHN0cmFwIiwid2VicGFjazovL2d0cDJvZ3Mvd2VicGFjay9iZWZvcmUtc3RhcnR1cCIsIndlYnBhY2s6Ly9ndHAyb2dzL3dlYnBhY2svc3RhcnR1cCIsIndlYnBhY2s6Ly9ndHAyb2dzL3dlYnBhY2svYWZ0ZXItc3RhcnR1cCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB0cmFjZSB9IGZyb20gXCIuL3RyYWNlXCI7XG5pbXBvcnQgeyBzcGF3biB9IGZyb20gXCJjaGlsZF9wcm9jZXNzXCI7XG5pbXBvcnQgeyBpZ25vcmVfcHJvbWlzZSB9IGZyb20gXCIuL3V0aWxcIjtcbmltcG9ydCAqIGFzIHNwbGl0MiBmcm9tIFwic3BsaXQyXCI7XG5cbmltcG9ydCB7IE1vdmUgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgZGVjb2RlTW92ZXMgfSBmcm9tIFwiZ29iYW4tZW5naW5lXCI7XG5pbXBvcnQgeyBjb25maWcsIEJvdENvbmZpZyB9IGZyb20gXCIuL2NvbmZpZ1wiO1xuaW1wb3J0IHsgUHZPdXRwdXRQYXJzZXIgfSBmcm9tIFwiLi9Qdk91dHB1dFBhcnNlclwiO1xuaW1wb3J0IHsgc29ja2V0IH0gZnJvbSBcIi4vc29ja2V0XCI7XG5pbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tIFwiZXZlbnRlbWl0dGVyM1wiO1xuaW1wb3J0IHR5cGUgeyBHYW1lIH0gZnJvbSBcIi4vR2FtZVwiO1xuXG5jb25zdCBndHBDb21tYW5kRW5kUmVnZXggPSBuZXcgUmVnRXhwKFwiKFxcXFxyP1xcXFxuKXsyfSRcIik7XG5jb25zdCBndHBDb21tYW5kU3BsaXRSZWdleCA9IG5ldyBSZWdFeHAoXCIoXFxcXHI/XFxcXG4pezJ9XCIpO1xuXG50eXBlIGNiX3R5cGUgPSAob3V0cHV0Pzogc3RyaW5nKSA9PiB2b2lkO1xudHlwZSBlYl90eXBlID0gKGVycj86IGFueSkgPT4gdm9pZDtcblxuaW50ZXJmYWNlIEV2ZW50cyB7XG4gICAgY2hhdDogKG1lc3NhZ2U6IHN0cmluZywgY2hhbm5lbDogXCJtYWluXCIgfCBcIm1hbGtvdmljaFwiKSA9PiB2b2lkO1xuICAgIHRlcm1pbmF0ZWQ6ICgpID0+IHZvaWQ7XG4gICAgcmVhZHk6ICgpID0+IHZvaWQ7XG59XG5cbmxldCBsYXN0X2JvdF9pZCA9IDA7XG4vKiogTWFuYWdlcyB0YWxraW5nIHRvIGEgYm90IHZpYSB0aGUgR1RQIGludGVyZmFjZSAqL1xuZXhwb3J0IGNsYXNzIEJvdCBleHRlbmRzIEV2ZW50RW1pdHRlcjxFdmVudHM+IHtcbiAgICByZWFkb25seSBpZDogbnVtYmVyID0gKytsYXN0X2JvdF9pZDtcbiAgICByZWFkb25seSBwZXJzaXN0ZW50OiBib29sZWFuO1xuICAgIGdhbWU6IEdhbWUgfCBudWxsID0gbnVsbDtcbiAgICBib3RfY29uZmlnOiBCb3RDb25maWc7XG4gICAgY29tbWFuZHNfc2VudDogbnVtYmVyO1xuICAgIGNvbW1hbmRfY2FsbGJhY2tzOiBBcnJheTxjYl90eXBlPjtcbiAgICBjb21tYW5kX2Vycm9yX2NhbGxiYWNrczogQXJyYXk8ZWJfdHlwZT47XG4gICAgZmlyc3RfbW92ZTogYm9vbGVhbjtcbiAgICBpZ25vcmU6IGJvb2xlYW47XG4gICAgZGVhZDogYm9vbGVhbjtcbiAgICBmYWlsZWQ6IGJvb2xlYW47XG4gICAgcHZfcGFyc2VyOiBQdk91dHB1dFBhcnNlcjtcbiAgICBwcm9jOiBSZXR1cm5UeXBlPHR5cGVvZiBzcGF3bj47XG4gICAga2dzX3RpbWU6IGJvb2xlYW47XG4gICAga2F0YV9maXNjaGVyOiBib29sZWFuO1xuICAgIGthdGFfdGltZTogYm9vbGVhbjtcbiAgICBqc29uX2luaXRpYWxpemVkOiBib29sZWFuO1xuICAgIGlzX2VuZGluZ19ib3Q6IGJvb2xlYW47XG4gICAgYXZhaWxhYmxlX2NvbW1hbmRzOiB7IFtrZXk6IHN0cmluZ106IGJvb2xlYW4gfSA9IHtcbiAgICAgICAgLyogVGhlc2UgYXJlIHJlcXVpcmVkIGJ5IHRoZSBHVFAgc3BlYyAqL1xuICAgICAgICBwcm90b2NvbF92ZXJzaW9uOiB0cnVlLFxuICAgICAgICBuYW1lOiB0cnVlLFxuICAgICAgICB2ZXJzaW9uOiB0cnVlLFxuICAgICAgICBrbm93bl9jb21tYW5kOiB0cnVlLFxuICAgICAgICBsaXN0X2NvbW1hbmRzOiB0cnVlLFxuICAgICAgICBxdWl0OiB0cnVlLFxuICAgICAgICBib2FyZHNpemU6IHRydWUsXG4gICAgICAgIGNsZWFyX2JvYXJkOiB0cnVlLFxuICAgICAgICBrb21pOiB0cnVlLFxuICAgICAgICBwbGF5OiB0cnVlLFxuICAgICAgICBnZW5tb3ZlOiB0cnVlLFxuICAgIH07XG4gICAgcmVhZHk6IFByb21pc2U8c3RyaW5nPjtcbiAgICAvKiogVHJ1ZSBpZiB3ZSBhcmUgYXZhaWxhYmxlIGZvciB1c2UgYnkgYSBHYW1lLiBUaGlzIGZsYWcgaXMgbWFuYWdlZCBieSB0aGUgcG9vbC4gKi9cbiAgICBhdmFpbGFibGU6IGJvb2xlYW4gPSB0cnVlO1xuICAgIHBlcnNpc3RlbnRfc3RhdGVfbG9hZGVkOiBib29sZWFuID0gZmFsc2U7XG4gICAgcGVyc2lzdGVudF9tb3Zlc19zZW50X2NvdW50OiBudW1iZXIgPSAwO1xuICAgIHBlcnNpc3RlbnRfaWRsZV90aW1lb3V0OiBOb2RlSlMuVGltZW91dCB8IG51bGwgPSBudWxsO1xuXG4gICAgLyogVGhlc2UgYXJlIGFmZmluaXR5IGZpZWxkcyB1c2VkIGJ5IG91ciBwb29sIHRvIHRyeSBhbmQgc2VsZWN0IGdvb2QgYm90cyB0byB1c2UgKi9cbiAgICBsYXN0X2dhbWVfaWQ6IG51bWJlciA9IC0xO1xuICAgIGxhc3Rfd2lkdGg6IG51bWJlciA9IC0xO1xuICAgIGxhc3RfaGVpZ2h0OiBudW1iZXIgPSAtMTtcblxuICAgIGxvZzogKC4uLmFycjogYW55W10pID0+IGFueTtcbiAgICBpbmZvOiAoLi4uYXJyOiBhbnlbXSkgPT4gYW55O1xuICAgIHRyYWNlOiAoLi4uYXJyOiBhbnlbXSkgPT4gYW55O1xuICAgIHZlcmJvc2U6ICguLi5hcnI6IGFueVtdKSA9PiBhbnk7XG4gICAgZXJyb3I6ICguLi5hcnI6IGFueVtdKSA9PiBhbnk7XG4gICAgd2FybjogKC4uLmFycjogYW55W10pID0+IGFueTtcblxuICAgIGNvbnN0cnVjdG9yKGJvdF9jb25maWc6IEJvdENvbmZpZywgaXNfZW5kaW5nX2JvdDogYm9vbGVhbiA9IGZhbHNlKSB7XG4gICAgICAgIHN1cGVyKCk7XG5cbiAgICAgICAgdGhpcy5ib3RfY29uZmlnID0gYm90X2NvbmZpZztcbiAgICAgICAgdGhpcy5wZXJzaXN0ZW50ID0gYm90X2NvbmZpZy5tYW5hZ2VyID09PSBcInBlcnNpc3RlbnRcIiAmJiAhaXNfZW5kaW5nX2JvdDtcblxuICAgICAgICBjb25zdCBjbWQgPSBib3RfY29uZmlnLmNvbW1hbmQubWFwKCh4KSA9PiB4LnJlcGxhY2UoL15+Wy9dL2csIHByb2Nlc3MuZW52LkhPTUUgKyBcIi9cIikpO1xuXG4gICAgICAgIHRoaXMubG9nID0gdHJhY2UubG9nLmJpbmQoXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgYFske3RoaXMuaXNfZW5kaW5nX2JvdCA/IFwicmVzaWduIGJvdFwiIDogXCJib3RcIn0gJHt0aGlzLmlkfV1gLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmluZm8gPSB0cmFjZS5pbmZvLmJpbmQoXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgYFske3RoaXMuaXNfZW5kaW5nX2JvdCA/IFwicmVzaWduIGJvdFwiIDogXCJib3RcIn0gJHt0aGlzLmlkfV1gLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLnRyYWNlID0gdHJhY2UudHJhY2UuYmluZChcbiAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICBgWyR7dGhpcy5pc19lbmRpbmdfYm90ID8gXCJyZXNpZ24gYm90XCIgOiBcImJvdFwifSAke3RoaXMuaWR9XWAsXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMudmVyYm9zZSA9IHRyYWNlLmRlYnVnLmJpbmQoXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgYFske3RoaXMuaXNfZW5kaW5nX2JvdCA/IFwicmVzaWduIGJvdFwiIDogXCJib3RcIn0gJHt0aGlzLmlkfV1gLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLndhcm4gPSB0cmFjZS53YXJuLmJpbmQoXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgYFske3RoaXMuaXNfZW5kaW5nX2JvdCA/IFwicmVzaWduIGJvdFwiIDogXCJib3RcIn0gJHt0aGlzLmlkfV1gLFxuICAgICAgICApO1xuICAgICAgICB0aGlzLmVycm9yID0gdHJhY2UuZXJyb3IuYmluZChcbiAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICBgWyR7dGhpcy5pc19lbmRpbmdfYm90ID8gXCJyZXNpZ24gYm90XCIgOiBcImJvdFwifSAke3RoaXMuaWR9XWAsXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5jb21tYW5kc19zZW50ID0gMDtcbiAgICAgICAgdGhpcy5jb21tYW5kX2NhbGxiYWNrcyA9IFtdO1xuICAgICAgICB0aGlzLmNvbW1hbmRfZXJyb3JfY2FsbGJhY2tzID0gW107XG4gICAgICAgIHRoaXMuaXNfZW5kaW5nX2JvdCA9IGlzX2VuZGluZ19ib3Q7XG4gICAgICAgIHRoaXMuZmlyc3RfbW92ZSA9IHRydWU7XG4gICAgICAgIHRoaXMuaWdub3JlID0gZmFsc2U7IC8vIElnbm9yZSBvdXRwdXQgZnJvbSBib3QgP1xuICAgICAgICAvLyBTZXQgdG8gdHJ1ZSB3aGVuIHRoZSBib3QgcHJvY2VzcyBoYXMgZGllZCBhbmQgbmVlZHMgdG8gYmUgcmVzdGFydGVkIGJlZm9yZSBpdCBjYW4gYmUgdXNlZCBhZ2Fpbi5cbiAgICAgICAgdGhpcy5kZWFkID0gZmFsc2U7XG4gICAgICAgIC8vIFNldCB0byB0cnVlIHdoZW4gdGhlcmUgaXMgYSBjb21tYW5kIGZhaWx1cmUgb3IgYSBib3QgZmFpbHVyZSBhbmQgdGhlIGdhbWUgZmFpbCBjb3VudGVyIHNob3VsZCBiZSBpbmNyZW1lbnRlZC5cbiAgICAgICAgLy8gQWZ0ZXIgYSBmZXcgZmFpbHVyZXMgd2Ugc3RvcCByZXRyeWluZyBhbmQgcmVzaWduIHRoZSBnYW1lLlxuICAgICAgICB0aGlzLmZhaWxlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLnB2X3BhcnNlciA9IG5ldyBQdk91dHB1dFBhcnNlcigpO1xuXG4gICAgICAgIHRoaXMudmVyYm9zZShcIlN0YXJ0aW5nIFwiLCBjbWQuam9pbihcIiBcIikpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgdGhpcy5wcm9jID0gc3Bhd24oY21kWzBdLCBjbWQuc2xpY2UoMSkpO1xuICAgICAgICAgICAgdGhpcy5wcm9jLm9uKFwiZXhpdFwiLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0KFwidGVybWluYXRlZFwiKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhpcy5sb2cgPSB0cmFjZS5sb2cuYmluZChcbiAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgIGBbJHt0aGlzLmlzX2VuZGluZ19ib3QgPyBcInJlc2lnbiBib3RcIiA6IFwiYm90XCJ9ICAke3RoaXMuaWR9OiR7dGhpcy5waWR9XWAsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy52ZXJib3NlID0gdHJhY2UuZGVidWcuYmluZChcbiAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgIGBbJHt0aGlzLmlzX2VuZGluZ19ib3QgPyBcInJlc2lnbiBib3RcIiA6IFwiYm90XCJ9ICAke3RoaXMuaWR9OiR7dGhpcy5waWR9XWAsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy53YXJuID0gdHJhY2Uud2Fybi5iaW5kKFxuICAgICAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICAgICAgYFske3RoaXMuaXNfZW5kaW5nX2JvdCA/IFwicmVzaWduIGJvdFwiIDogXCJib3RcIn0gICR7dGhpcy5pZH06JHt0aGlzLnBpZH1dYCxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICB0aGlzLmVycm9yID0gdHJhY2UuZXJyb3IuYmluZChcbiAgICAgICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgICAgIGBbJHt0aGlzLmlzX2VuZGluZ19ib3QgPyBcInJlc2lnbiBib3RcIiA6IFwiYm90XCJ9ICAke3RoaXMuaWR9OiR7dGhpcy5waWR9XWAsXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICB0aGlzLmxvZyhcIkZhaWxlZCB0byBzdGFydCB0aGUgYm90OiBcIiwgZSk7XG4gICAgICAgICAgICB0aGlzLmlnbm9yZSA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmRlYWQgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy5mYWlsZWQgPSB0cnVlO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5wcm9jLnN0ZGVyci5waXBlKHNwbGl0MigpKS5vbihcImRhdGFcIiwgKGRhdGEpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmlnbm9yZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGVycl9saW5lID0gZGF0YS50b1N0cmluZygpLnRyaW0oKTtcbiAgICAgICAgICAgIGlmIChlcnJfbGluZSA9PT0gXCJcIikge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMubG9nKGAke2Vycl9saW5lfWApO1xuXG4gICAgICAgICAgICBpZiAodGhpcy5wdl9wYXJzZXIpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5wdl9wYXJzZXIuc2NhbkFuZFNlbmRFbmdpbmVBbmFseXNpcyh0aGlzLmdhbWUsIGVycl9saW5lKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRoaXMuYm90X2NvbmZpZy5zZW5kX2NoYXRzKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgY2hhdF9tYXRjaCA9IC8oRElTQ1VTU0lPTnxNQUxLT1ZJQ0h8TUFJTik6KC4qKS8uZXhlYyhlcnJfbGluZSk7XG4gICAgICAgICAgICAgICAgaWYgKGNoYXRfbWF0Y2gpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY2hhbm5lbCA9IC9NQUxLT1ZJQ0g6L2kudGVzdChlcnJfbGluZSkgPyBcIm1hbGtvdmljaFwiIDogXCJtYWluXCI7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZW1pdChcImNoYXRcIiwgY2hhdF9tYXRjaFsyXSwgY2hhbm5lbCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBsZXQgc3Rkb3V0X2J1ZmZlciA9IFwiXCI7XG4gICAgICAgIHRoaXMucHJvYy5zdGRvdXQub24oXCJkYXRhXCIsIChkYXRhKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5pZ25vcmUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzdGRvdXRfYnVmZmVyICs9IGRhdGEudG9TdHJpbmcoKTtcblxuICAgICAgICAgICAgaWYgKCFzdGRvdXRfYnVmZmVyIHx8ICFndHBDb21tYW5kRW5kUmVnZXgudGVzdChzdGRvdXRfYnVmZmVyKSkge1xuICAgICAgICAgICAgICAgIC8vdGhpcy5sb2coXCJQYXJ0aWFsIHJlc3VsdCByZWNlaXZlZCwgYnVmZmVyaW5nIHVudGlsIHRoZSBvdXRwdXQgZW5kcyB3aXRoIGEgbmV3bGluZVwiKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnRyYWNlKFwiPDw8XCIsIHN0ZG91dF9idWZmZXIudHJpbSgpKTtcblxuICAgICAgICAgICAgY29uc3QgbGluZXMgPSBzdGRvdXRfYnVmZmVyLnNwbGl0KGd0cENvbW1hbmRTcGxpdFJlZ2V4KTtcbiAgICAgICAgICAgIHN0ZG91dF9idWZmZXIgPSBcIlwiO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGxpbmUgPSBsaW5lc1tpXTtcbiAgICAgICAgICAgICAgICBpZiAobGluZS50cmltKCkgPT09IFwiXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChsaW5lWzBdID09PSBcIj1cIikge1xuICAgICAgICAgICAgICAgICAgICB3aGlsZSAobGluZXNbaV0udHJpbSgpICE9PSBcIlwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICArK2k7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY2IgPSB0aGlzLmNvbW1hbmRfY2FsbGJhY2tzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZF9lcnJvcl9jYWxsYmFja3Muc2hpZnQoKTsgLy8gZGlzY2FyZDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYihsaW5lLnN1YnN0cmluZygxKS50cmltKCkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChsaW5lLnRyaW0oKVswXSA9PT0gXCI/XCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2cobGluZSk7XG4gICAgICAgICAgICAgICAgICAgIHdoaWxlIChsaW5lc1tpXS50cmltKCkgIT09IFwiXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICsraTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKGxpbmVzW2ldKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmZhaWxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZF9jYWxsYmFja3Muc2hpZnQoKTsgLy8gZGlzY2FyZDtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZWIgPSB0aGlzLmNvbW1hbmRfZXJyb3JfY2FsbGJhY2tzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlYikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZWIobGluZS5zdWJzdHJpbmcoMSkudHJpbSgpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZXJyb3IoXCJVbmV4cGVjdGVkIG91dHB1dDogXCIsIGxpbmUpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmZhaWxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZF9jYWxsYmFja3Muc2hpZnQoKTsgLy8gZGlzY2FyZDtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZWIgPSB0aGlzLmNvbW1hbmRfZXJyb3JfY2FsbGJhY2tzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlYikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZWIobGluZS50cmltKCkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5wcm9jLm9uKFwiZXhpdFwiLCAoY29kZSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgdW5leHBlY3RlZCA9ICF0aGlzLmRlYWQ7XG4gICAgICAgICAgICBpZiAodW5leHBlY3RlZCkge1xuICAgICAgICAgICAgICAgIGlmIChjb2RlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9nKFwiQm90IGV4aXRlZFwiLCBjb2RlKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhcIkJvdCBleGl0ZWRcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aGlzLmNvbW1hbmRfY2FsbGJhY2tzLnNoaWZ0KCk7IC8vIGRpc2NhcmQ7XG4gICAgICAgICAgICB0aGlzLmRlYWQgPSB0cnVlO1xuICAgICAgICAgICAgY29uc3QgZWIgPSB0aGlzLmNvbW1hbmRfZXJyb3JfY2FsbGJhY2tzLnNoaWZ0KCk7XG4gICAgICAgICAgICBpZiAodW5leHBlY3RlZCAmJiBlYikge1xuICAgICAgICAgICAgICAgIGViKGNvZGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5wcm9jLnN0ZGluLm9uKFwiZXJyb3JcIiwgKGNvZGUpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZXJyb3IoXCJCb3Qgc3RkaW4gd3JpdGUgZXJyb3JcIiwgY29kZSk7XG4gICAgICAgICAgICB0aGlzLmNvbW1hbmRfY2FsbGJhY2tzLnNoaWZ0KCk7IC8vIGRpc2NhcmQ7XG4gICAgICAgICAgICB0aGlzLmRlYWQgPSB0cnVlO1xuICAgICAgICAgICAgdGhpcy5mYWlsZWQgPSB0cnVlO1xuICAgICAgICAgICAgY29uc3QgZWIgPSB0aGlzLmNvbW1hbmRfZXJyb3JfY2FsbGJhY2tzLnNoaWZ0KCk7XG4gICAgICAgICAgICBpZiAoZWIpIHtcbiAgICAgICAgICAgICAgICBlYihjb2RlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5yZWFkeSA9IHRoaXMuY29tbWFuZChcImxpc3RfY29tbWFuZHNcIik7XG5cbiAgICAgICAgdGhpcy5yZWFkeVxuICAgICAgICAgICAgLnRoZW4oKGNvbW1hbmRzKSA9PiB7XG4gICAgICAgICAgICAgICAgY29tbWFuZHNcbiAgICAgICAgICAgICAgICAgICAgLnNwbGl0KC9bXFxyXFxuXS8pXG4gICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoKHgpID0+IHgpXG4gICAgICAgICAgICAgICAgICAgIC5tYXAoKHgpID0+ICh0aGlzLmF2YWlsYWJsZV9jb21tYW5kc1t4LnJlcGxhY2UoL149LywgXCJcIikudHJpbSgpXSA9IHRydWUpKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVtaXQoXCJyZWFkeVwiKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgICAgICAgIHRyYWNlLmVycm9yKGVycik7XG4gICAgICAgICAgICAgICAgdHJhY2UuZXJyb3IoXCJGYWlsZWQgdG8gbGlzdCBib3QgY29tbWFuZHMsIGV4aXRpbmcuXCIpO1xuICAgICAgICAgICAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cbiAgICBnZXQgcGlkKCk6IG51bWJlciB7XG4gICAgICAgIGlmICh0aGlzLnByb2MpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnByb2MucGlkO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgbG9hZENsb2NrKHN0YXRlKTogdm9pZCB7XG4gICAgICAgIC8qIFJlZmVyZW5jZXM6XG4gICAgICAgICAgIGh0dHA6Ly93d3cubHlzYXRvci5saXUuc2Uvfmd1bm5hci9ndHAvZ3RwMi1zcGVjLWRyYWZ0Mi9ndHAyLXNwZWMuaHRtbCNzZWM6dGltZS1oYW5kbGluZ1xuICAgICAgICAgICBodHRwOi8vd3d3LndlZGRzbGlzdC5jb20va2dzL2hvdy9rZ3NHdHAuaHRtbFxuXG4gICAgICAgICAgIEdUUCB2MiBvbmx5IHN1cHBvcnRzIENhbmFkaWFuIEJ5b3lvbWksIG5vIHRpbWVyIChzZWUgc3BlYyBhYm92ZSksXG4gICAgICAgICAgIGFuZCBhYnNvbHV0ZSAocGVyaW9kIHRpbWUgemVybykuXG5cbiAgICAgICAgICAga2dzLXRpbWVfc2V0dGluZ3MgYWRkcyBzdXBwb3J0IGZvciBKYXBhbmVzZSBCeW95b21pLlxuXG4gICAgICAgICAgIFRoZSBrZ3NHdHAgaW50ZXJmYWNlIChodHRwOi8vd3d3LndlZGRzbGlzdC5jb20va2dzL2hvdy9rZ3NHdHAuaHRtbClcbiAgICAgICAgICAgY29udmVydHMgYnlveW9taSB0byBhYnNvbHV0ZSB0aW1lIGZvciBib3RzIHRoYXQgZG9uJ3Qgc3VwcG9ydFxuICAgICAgICAgICBrZ3MtdGltZV9zZXR0aW5ncyBieSB1c2luZyBtYWluX3RpbWUgcGx1cyBwZXJpb2RzICogcGVyaW9kX3RpbWUuXG4gICAgICAgICAgIEJ1dCB0aGVuIHRoZSBib3Qgd291bGQgdmlldyB0aGF0IGFzIHRoZSB0b3RhbCB0aW1lIGxlZnQgZm9yIGVudGlyZSByZXN0IG9mIGdhbWUuLi5cblxuICAgICAgICAgICBKYXBhbmVzZSBCeW95b21pIHdpdGggb25lIHBlcmlvZCBsZWZ0IGNvdWxkIGJlIHZpZXdlZCBhcyBhIHNwZWNpYWwgY2FzZVxuICAgICAgICAgICBvZiBDYW5hZGlhbiBCeW95b21pIHdoZXJlIHRoZSBudW1iZXIgb2Ygc3RvbmVzIGlzIGFsd2F5cyA9IDFcbiAgICAgICAgKi9cbiAgICAgICAgaWYgKCF0aGlzLmJvdF9jb25maWcuZW5hYmxlX2Nsb2NrKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBjbG9ja19kcmlmdCBjb21wZW5zYXRlcyBmb3IgZGlmZmVyZW5jZSBiZXR3ZWVuIHNlcnZlciBhbmQgY2xpZW50IHRpbWUsIGFuZCBsYXRlbmN5LlxuICAgICAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpIC0gc29ja2V0LmNsb2NrX2RyaWZ0O1xuXG4gICAgICAgIGxldCBibGFja19vZmZzZXQgPSAwO1xuICAgICAgICBsZXQgd2hpdGVfb2Zmc2V0ID0gMDtcblxuICAgICAgICAvLyBvZmZzZXQgaW5kaWNhdGVzIGhvdyBsb25nIHdlJ3ZlIGhhZCBzaW5jZSBsYXN0IG1vdmUuIE9ncyBvbmx5IGNvbW11bmljYXRlcyBob3cgbXVjaFxuICAgICAgICAvLyB0aW1lIHRoZSBwbGF5ZXIgaGFkIHdoZW4gbGFzdCBtb3ZlIHdhcyBtYWRlLlxuICAgICAgICBpZiAoc3RhdGUuY2xvY2suY3VycmVudF9wbGF5ZXIgPT09IHN0YXRlLmNsb2NrLmJsYWNrX3BsYXllcl9pZCkge1xuICAgICAgICAgICAgYmxhY2tfb2Zmc2V0ID0gKG5vdyAtIHN0YXRlLmNsb2NrLmxhc3RfbW92ZSkgLyAxMDAwO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgd2hpdGVfb2Zmc2V0ID0gKG5vdyAtIHN0YXRlLmNsb2NrLmxhc3RfbW92ZSkgLyAxMDAwO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHN0YXRlLnRpbWVfY29udHJvbC5zeXN0ZW0gPT09IFwiYnlveW9taVwiKSB7XG4gICAgICAgICAgICBsZXQgYmxhY2tfdGltZSA9IHN0YXRlLmNsb2NrLmJsYWNrX3RpbWUudGhpbmtpbmdfdGltZTtcbiAgICAgICAgICAgIGxldCB3aGl0ZV90aW1lID0gc3RhdGUuY2xvY2sud2hpdGVfdGltZS50aGlua2luZ190aW1lO1xuICAgICAgICAgICAgbGV0IGJsYWNrX3BlcmlvZHMgPSBzdGF0ZS5jbG9jay5ibGFja190aW1lLnBlcmlvZHM7XG4gICAgICAgICAgICBsZXQgd2hpdGVfcGVyaW9kcyA9IHN0YXRlLmNsb2NrLndoaXRlX3RpbWUucGVyaW9kcztcbiAgICAgICAgICAgIGxldCBibGFja190aW1lX2xlZnQgPSAwO1xuICAgICAgICAgICAgbGV0IHdoaXRlX3RpbWVfbGVmdCA9IDA7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLmtnc190aW1lKSB7XG4gICAgICAgICAgICAgICAgaWYgKGJsYWNrX3RpbWUgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGJsYWNrX3RpbWVfbGVmdCA9IGJsYWNrX3RpbWUgLSBibGFja19vZmZzZXQ7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgYmxhY2tfdGltZV9sZWZ0ID0gc3RhdGUudGltZV9jb250cm9sLnBlcmlvZF90aW1lIC0gYmxhY2tfb2Zmc2V0O1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh3aGl0ZV90aW1lID4gMCkge1xuICAgICAgICAgICAgICAgICAgICB3aGl0ZV90aW1lX2xlZnQgPSB3aGl0ZV90aW1lIC0gd2hpdGVfb2Zmc2V0O1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHdoaXRlX3RpbWVfbGVmdCA9IHN0YXRlLnRpbWVfY29udHJvbC5wZXJpb2RfdGltZSAtIHdoaXRlX29mZnNldDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBJZiB3ZSdyZSBzbyBzbG93IHRoYXQgdGltZSBsZWZ0IC0gb2Zmc2V0IGlzIG5lZ2F0aXZlLCB3ZSBuZWVkIHRvIHJvbGwgb3ZlciB0byBwZXJpb2QgdGltZS5cbiAgICAgICAgICAgICAgICB3aGlsZSAoYmxhY2tfdGltZV9sZWZ0IDwgMCAmJiBibGFja19wZXJpb2RzID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBibGFja190aW1lX2xlZnQgKz0gc3RhdGUuY2xvY2suYmxhY2tfdGltZS5wZXJpb2RfdGltZTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGJsYWNrX3RpbWUgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBibGFja190aW1lID0gMDtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJsYWNrX3BlcmlvZHMtLTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB3aGlsZSAod2hpdGVfdGltZV9sZWZ0IDwgMCAmJiB3aGl0ZV9wZXJpb2RzID4gMSkge1xuICAgICAgICAgICAgICAgICAgICB3aGl0ZV90aW1lX2xlZnQgKz0gc3RhdGUuY2xvY2sud2hpdGVfdGltZS5wZXJpb2RfdGltZTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHdoaXRlX3RpbWUgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB3aGl0ZV90aW1lID0gMDtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaXRlX3BlcmlvZHMtLTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbW1hbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICBga2dzLXRpbWVfc2V0dGluZ3MgYnlveW9taSAke3N0YXRlLnRpbWVfY29udHJvbC5tYWluX3RpbWV9ICR7c3RhdGUudGltZV9jb250cm9sLnBlcmlvZF90aW1lfSAke3N0YXRlLnRpbWVfY29udHJvbC5wZXJpb2RzfWAsXG4gICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21tYW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgYHRpbWVfbGVmdCBibGFjayAke01hdGguZmxvb3IoTWF0aC5tYXgoYmxhY2tfdGltZV9sZWZ0LCAwKSl9ICR7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYmxhY2tfdGltZSA+IDAgPyBcIjBcIiA6IGJsYWNrX3BlcmlvZHNcbiAgICAgICAgICAgICAgICAgICAgICAgIH1gLFxuICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgaWdub3JlX3Byb21pc2UoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZChcbiAgICAgICAgICAgICAgICAgICAgICAgIGB0aW1lX2xlZnQgd2hpdGUgJHtNYXRoLmZsb29yKE1hdGgubWF4KHdoaXRlX3RpbWVfbGVmdCwgMCkpfSAke1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaXRlX3RpbWUgPiAwID8gXCIwXCIgOiB3aGl0ZV9wZXJpb2RzXG4gICAgICAgICAgICAgICAgICAgICAgICB9YCxcbiAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvKiBHdHAgZG9lcyBub3Qgc3VwcG9ydCBKYXBhbmVzZSBCeW95b21pLiBXZSBmYWtlIGl0IGFzIENhbmFkaWFuIEJ5b3lvbWkuXG4gICAgICAgICAgICAgICAgICAgTGV0J3MgcHJldGVuZCB0aGUgZmluYWwgcGVyaW9kIGlzIGEgQ2FuYWRpYW4gQnlveW9taSBvZiAxIHN0b25lLlxuICAgICAgICAgICAgICAgICAgIFRoaXMgbGV0cyB0aGUgYm90IGtub3cgaXQgY2FuIHVzZSB0aGUgZnVsbCBwZXJpb2QgcGVyIG1vdmUsXG4gICAgICAgICAgICAgICAgICAgbm90IHRyeSB0byBmaXQgdGhlIHJlc3Qgb2YgdGhlIGdhbWUgaW50byB0aGUgdGltZSBsZWZ0LlxuICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgLy8gYWRkIGFsbCBwZXJpb2RzIHRvIHRoZSBtYWluIHRpbWUuXG4gICAgICAgICAgICAgICAgLy8gSWYgd2UncmUgYWxyZWFkeSBpbiBvdmVydGltZSwgZXhjbHVkZSB0aGUgY3VycmVudCBwZXJpb2QuXG4gICAgICAgICAgICAgICAgaWYgKGJsYWNrX3RpbWUgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGJsYWNrX3RpbWVfbGVmdCA9XG4gICAgICAgICAgICAgICAgICAgICAgICBibGFja190aW1lIC1cbiAgICAgICAgICAgICAgICAgICAgICAgIGJsYWNrX29mZnNldCArXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5jbG9jay5ibGFja190aW1lLnBlcmlvZF90aW1lICogYmxhY2tfcGVyaW9kcztcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBibGFja190aW1lX2xlZnQgPVxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGUudGltZV9jb250cm9sLnBlcmlvZF90aW1lIC1cbiAgICAgICAgICAgICAgICAgICAgICAgIGJsYWNrX29mZnNldCArXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5jbG9jay5ibGFja190aW1lLnBlcmlvZF90aW1lICogKGJsYWNrX3BlcmlvZHMgLSAxKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHdoaXRlX3RpbWUgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHdoaXRlX3RpbWVfbGVmdCA9XG4gICAgICAgICAgICAgICAgICAgICAgICB3aGl0ZV90aW1lIC1cbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaXRlX29mZnNldCArXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5jbG9jay5ibGFja190aW1lLnBlcmlvZF90aW1lICogYmxhY2tfcGVyaW9kcztcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB3aGl0ZV90aW1lX2xlZnQgPVxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGUudGltZV9jb250cm9sLnBlcmlvZF90aW1lIC1cbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaXRlX29mZnNldCArXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS5jbG9jay5ibGFja190aW1lLnBlcmlvZF90aW1lICogKGJsYWNrX3BlcmlvZHMgLSAxKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21tYW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgYHRpbWVfc2V0dGluZ3MgJHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZS50aW1lX2NvbnRyb2wubWFpbl90aW1lICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAoc3RhdGUudGltZV9jb250cm9sLnBlcmlvZHMgLSAxKSAqIHN0YXRlLnRpbWVfY29udHJvbC5wZXJpb2RfdGltZVxuICAgICAgICAgICAgICAgICAgICAgICAgfSAke3N0YXRlLnRpbWVfY29udHJvbC5wZXJpb2RfdGltZX0gMWAsXG4gICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAvLyBJZiB3ZSdyZSBpbiB0aGUgbGFzdCBwZXJpb2QsIHRlbGwgdGhlIGJvdC4gT3RoZXJ3aXNlIHByZXRlbmQgd2UncmUgaW4gbWFpbiB0aW1lLlxuICAgICAgICAgICAgICAgIGlmIChibGFja190aW1lX2xlZnQgPD0gc3RhdGUuY2xvY2suYmxhY2tfdGltZS5wZXJpb2RfdGltZSkge1xuICAgICAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBgdGltZV9sZWZ0IGJsYWNrICR7TWF0aC5mbG9vcihNYXRoLm1heChibGFja190aW1lX2xlZnQsIDApKX0gMWAsXG4gICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21tYW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGB0aW1lX2xlZnQgYmxhY2sgJHtNYXRoLmZsb29yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBibGFja190aW1lX2xlZnQgLSBzdGF0ZS5jbG9jay5ibGFja190aW1lLnBlcmlvZF90aW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICl9IDBgLFxuICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHdoaXRlX3RpbWVfbGVmdCA8PSBzdGF0ZS5jbG9jay53aGl0ZV90aW1lLnBlcmlvZF90aW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21tYW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGB0aW1lX2xlZnQgd2hpdGUgJHtNYXRoLmZsb29yKE1hdGgubWF4KHdoaXRlX3RpbWVfbGVmdCwgMCkpfSAxYCxcbiAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgaWdub3JlX3Byb21pc2UoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbW1hbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYHRpbWVfbGVmdCB3aGl0ZSAke01hdGguZmxvb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaXRlX3RpbWVfbGVmdCAtIHN0YXRlLmNsb2NrLndoaXRlX3RpbWUucGVyaW9kX3RpbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKX0gMGAsXG4gICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChzdGF0ZS50aW1lX2NvbnRyb2wuc3lzdGVtID09PSBcImNhbmFkaWFuXCIpIHtcbiAgICAgICAgICAgIC8qIENhbmFkaWFuIEJ5b3lvbWkgaXMgdGhlIG9ubHkgdGltZSBjb250cm9scyBHVFAgdjIgb2ZmaWNpYWxseSBzdXBwb3J0cy5cbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgbGV0IGJsYWNrX3RpbWVfbGVmdCA9IHN0YXRlLmNsb2NrLmJsYWNrX3RpbWUudGhpbmtpbmdfdGltZSAtIGJsYWNrX29mZnNldDtcbiAgICAgICAgICAgIGxldCB3aGl0ZV90aW1lX2xlZnQgPSBzdGF0ZS5jbG9jay53aGl0ZV90aW1lLnRoaW5raW5nX3RpbWUgLSB3aGl0ZV9vZmZzZXQ7XG4gICAgICAgICAgICBsZXQgYmxhY2tfc3RvbmVzID0gMDtcbiAgICAgICAgICAgIGxldCB3aGl0ZV9zdG9uZXMgPSAwO1xuXG4gICAgICAgICAgICBpZiAoYmxhY2tfdGltZV9sZWZ0IDw9IDApIHtcbiAgICAgICAgICAgICAgICBibGFja19zdG9uZXMgPSBzdGF0ZS5jbG9jay5ibGFja190aW1lLm1vdmVzX2xlZnQ7XG4gICAgICAgICAgICAgICAgYmxhY2tfdGltZV9sZWZ0ICs9IHN0YXRlLmNsb2NrLmJsYWNrX3RpbWUuYmxvY2tfdGltZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh3aGl0ZV90aW1lX2xlZnQgPD0gMCkge1xuICAgICAgICAgICAgICAgIHdoaXRlX3N0b25lcyA9IHN0YXRlLmNsb2NrLndoaXRlX3RpbWUubW92ZXNfbGVmdDtcbiAgICAgICAgICAgICAgICB3aGl0ZV90aW1lX2xlZnQgKz0gc3RhdGUuY2xvY2sud2hpdGVfdGltZS5ibG9ja190aW1lO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5rZ3NfdGltZSkge1xuICAgICAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbW1hbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICBga2dzLXRpbWVfc2V0dGluZ3MgY2FuYWRpYW4gJHtzdGF0ZS50aW1lX2NvbnRyb2wubWFpbl90aW1lfSAke3N0YXRlLnRpbWVfY29udHJvbC5wZXJpb2RfdGltZX0gJHtzdGF0ZS50aW1lX2NvbnRyb2wuc3RvbmVzX3Blcl9wZXJpb2R9YCxcbiAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21tYW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgYHRpbWVfc2V0dGluZ3MgJHtzdGF0ZS50aW1lX2NvbnRyb2wubWFpbl90aW1lfSAke3N0YXRlLnRpbWVfY29udHJvbC5wZXJpb2RfdGltZX0gJHtzdGF0ZS50aW1lX2NvbnRyb2wuc3RvbmVzX3Blcl9wZXJpb2R9YCxcbiAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICB0aGlzLmNvbW1hbmQoXG4gICAgICAgICAgICAgICAgICAgIGB0aW1lX2xlZnQgYmxhY2sgJHtNYXRoLmZsb29yKE1hdGgubWF4KGJsYWNrX3RpbWVfbGVmdCwgMCkpfSAke2JsYWNrX3N0b25lc31gLFxuICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgaWdub3JlX3Byb21pc2UoXG4gICAgICAgICAgICAgICAgdGhpcy5jb21tYW5kKFxuICAgICAgICAgICAgICAgICAgICBgdGltZV9sZWZ0IHdoaXRlICR7TWF0aC5mbG9vcihNYXRoLm1heCh3aGl0ZV90aW1lX2xlZnQsIDApKX0gJHt3aGl0ZV9zdG9uZXN9YCxcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIGlmIChzdGF0ZS50aW1lX2NvbnRyb2wuc3lzdGVtID09PSBcImZpc2NoZXJcIikge1xuICAgICAgICAgICAgaWYgKHRoaXMua2F0YV9maXNjaGVyKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYmxhY2tfdGltZV9sZWZ0ID0gc3RhdGUuY2xvY2suYmxhY2tfdGltZS50aGlua2luZ190aW1lIC0gYmxhY2tfb2Zmc2V0O1xuICAgICAgICAgICAgICAgIGNvbnN0IHdoaXRlX3RpbWVfbGVmdCA9IHN0YXRlLmNsb2NrLndoaXRlX3RpbWUudGhpbmtpbmdfdGltZSAtIHdoaXRlX29mZnNldDtcbiAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21tYW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgYGthdGEtdGltZV9zZXR0aW5ncyBmaXNjaGVyLWNhcHBlZCAke3N0YXRlLnRpbWVfY29udHJvbC5pbml0aWFsX3RpbWV9ICR7c3RhdGUudGltZV9jb250cm9sLnRpbWVfaW5jcmVtZW50fSAke3N0YXRlLnRpbWVfY29udHJvbC5tYXhfdGltZX0gLTFgLFxuICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgaWdub3JlX3Byb21pc2UoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZChgdGltZV9sZWZ0IGJsYWNrICR7TWF0aC5mbG9vcihNYXRoLm1heChibGFja190aW1lX2xlZnQsIDApKX0gMGApLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgaWdub3JlX3Byb21pc2UoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZChgdGltZV9sZWZ0IHdoaXRlICR7TWF0aC5mbG9vcihNYXRoLm1heCh3aGl0ZV90aW1lX2xlZnQsIDApKX0gMGApLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8qIE5vdCBzdXBwb3J0ZWQgYnkga2dzLXRpbWVfc2V0dGluZ3MgYW5kIEkgYXNzdW1lIG1vc3QgYm90cy5cbiAgICAgICAgICAgICAgICAgICBBIGJldHRlciB3YXkgdGhhbiBhYnNvbHV0ZSBpcyB0byBoYW5kbGUgdGhpcyB3aXRoXG4gICAgICAgICAgICAgICAgICAgYSBmYWtlIENhbmFkaWFuIEJ5b3lvbWkuIFRoaXMgc2hvdWxkIGxldCB0aGUgYm90IGtub3dcbiAgICAgICAgICAgICAgICAgICBhIGdvb2QgYXBwcm94aW1hdGlvbiBvZiBob3cgdG8gaGFuZGxlIHRoZSB0aW1lIHJlbWFpbmluZy5cbiAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGxldCBibGFja190aW1lX2xlZnQgPVxuICAgICAgICAgICAgICAgICAgICBzdGF0ZS5jbG9jay5ibGFja190aW1lLnRoaW5raW5nX3RpbWUgLVxuICAgICAgICAgICAgICAgICAgICBibGFja19vZmZzZXQgLVxuICAgICAgICAgICAgICAgICAgICBzdGF0ZS50aW1lX2NvbnRyb2wudGltZV9pbmNyZW1lbnQ7XG4gICAgICAgICAgICAgICAgbGV0IHdoaXRlX3RpbWVfbGVmdCA9XG4gICAgICAgICAgICAgICAgICAgIHN0YXRlLmNsb2NrLndoaXRlX3RpbWUudGhpbmtpbmdfdGltZSAtXG4gICAgICAgICAgICAgICAgICAgIHdoaXRlX29mZnNldCAtXG4gICAgICAgICAgICAgICAgICAgIHN0YXRlLnRpbWVfY29udHJvbC50aW1lX2luY3JlbWVudDtcbiAgICAgICAgICAgICAgICBsZXQgYmxhY2tfcGVyaW9kcyA9IDA7XG4gICAgICAgICAgICAgICAgbGV0IHdoaXRlX3BlcmlvZHMgPSAwO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMua2dzX3RpbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgaWdub3JlX3Byb21pc2UoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbW1hbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYGtncy10aW1lX3NldHRpbmdzIGNhbmFkaWFuICR7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlLnRpbWVfY29udHJvbC5pbml0aWFsX3RpbWUgLSBzdGF0ZS50aW1lX2NvbnRyb2wudGltZV9pbmNyZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9ICR7c3RhdGUudGltZV9jb250cm9sLnRpbWVfaW5jcmVtZW50fSAxYCxcbiAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgaWdub3JlX3Byb21pc2UoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbW1hbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYHRpbWVfc2V0dGluZ3MgJHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGUudGltZV9jb250cm9sLmluaXRpYWxfdGltZSAtIHN0YXRlLnRpbWVfY29udHJvbC50aW1lX2luY3JlbWVudFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gJHtzdGF0ZS50aW1lX2NvbnRyb2wudGltZV9pbmNyZW1lbnR9IDFgLFxuICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoYmxhY2tfdGltZV9sZWZ0IDw9IDApIHtcbiAgICAgICAgICAgICAgICAgICAgYmxhY2tfcGVyaW9kcyA9IDE7XG4gICAgICAgICAgICAgICAgICAgIGJsYWNrX3RpbWVfbGVmdCArPSBzdGF0ZS50aW1lX2NvbnRyb2wudGltZV9pbmNyZW1lbnQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICh3aGl0ZV90aW1lX2xlZnQgPD0gMCkge1xuICAgICAgICAgICAgICAgICAgICB3aGl0ZV9wZXJpb2RzID0gMTtcbiAgICAgICAgICAgICAgICAgICAgd2hpdGVfdGltZV9sZWZ0ICs9IHN0YXRlLnRpbWVfY29udHJvbC50aW1lX2luY3JlbWVudDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvKiBBbHdheXMgdGVsbCB0aGUgYm90IHdlIGFyZSBpbiBtYWluIHRpbWUgKCcwJykgc28gaXQgZG9lc24ndCB0cnlcbiAgICAgICAgICAgICAgICAgIHRvIHRoaW5rIGFsbCBvZiB0aW1lX2xlZnQgcGVyIG1vdmUuXG4gICAgICAgICAgICAgICAgICBCdXQgc3VidHJhY3QgdGhlIGluY3JlbWVudCB0aW1lIGFib3ZlIHRvIGF2b2lkIHRpbWVvdXRzLlxuICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21tYW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgYHRpbWVfbGVmdCBibGFjayAke01hdGguZmxvb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgTWF0aC5tYXgoYmxhY2tfdGltZV9sZWZ0LCAwKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICl9ICR7YmxhY2tfcGVyaW9kc31gLFxuICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgaWdub3JlX3Byb21pc2UoXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZChcbiAgICAgICAgICAgICAgICAgICAgICAgIGB0aW1lX2xlZnQgd2hpdGUgJHtNYXRoLmZsb29yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hdGgubWF4KHdoaXRlX3RpbWVfbGVmdCwgMCksXG4gICAgICAgICAgICAgICAgICAgICAgICApfSAke3doaXRlX3BlcmlvZHN9YCxcbiAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHN0YXRlLnRpbWVfY29udHJvbC5zeXN0ZW0gPT09IFwic2ltcGxlXCIpIHtcbiAgICAgICAgICAgIC8qIFNpbXBsZSBjb3VsZCBhbHNvIGJlIHZpZXdlZCBhcyBhIENhbmFkaWFuIEJ5b3lvbWkgdGhhdCBzdGFydHNcbiAgICAgICAgICAgICAgIGltbWVkaWF0ZWx5IHdpdGggIyBvZiBzdG9uZXMgPSAxXG4gICAgICAgICAgICAqL1xuXG4gICAgICAgICAgICAvLyBmb3Igc29tZSByZWFzb24gb2dzIHNlbmRzIGEgdGltZXN0YW1wIChlcXVhbCB0byBzdGF0ZS5jbG9jay5sYXN0X21vdmUpIGluc3RlYWQgb2Ygb3VyIHRpbWUuXG4gICAgICAgICAgICAvLyBMdWNraWx5IHdlIGNhbiB1c2Ugc3RhdGUudGltZV9jb250cm9sLnBlcl9tb3ZlIHNpbmNlIHNpbXBsZSB0aW1lIGlzIGFsd2F5cyBpbiBvdmVydGltZS5cbiAgICAgICAgICAgIGNvbnN0IGJsYWNrX3RpbWVfbGVmdCA9IHN0YXRlLnRpbWVfY29udHJvbC5wZXJfbW92ZSAtIGJsYWNrX29mZnNldDtcbiAgICAgICAgICAgIGNvbnN0IHdoaXRlX3RpbWVfbGVmdCA9IHN0YXRlLnRpbWVfY29udHJvbC5wZXJfbW92ZSAtIHdoaXRlX29mZnNldDtcblxuICAgICAgICAgICAgaWdub3JlX3Byb21pc2UodGhpcy5jb21tYW5kKGB0aW1lX3NldHRpbmdzIDAgJHtzdGF0ZS50aW1lX2NvbnRyb2wucGVyX21vdmV9IDFgKSk7XG5cbiAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKFxuICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZChgdGltZV9sZWZ0IGJsYWNrICR7TWF0aC5mbG9vcihNYXRoLm1heChibGFja190aW1lX2xlZnQsIDApKX0gMWApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKFxuICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZChgdGltZV9sZWZ0IHdoaXRlICR7TWF0aC5mbG9vcihNYXRoLm1heCh3aGl0ZV90aW1lX2xlZnQsIDApKX0gMWApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIGlmIChzdGF0ZS50aW1lX2NvbnRyb2wuc3lzdGVtID09PSBcImFic29sdXRlXCIpIHtcbiAgICAgICAgICAgIGNvbnN0IGJsYWNrX3RpbWVfbGVmdCA9IHN0YXRlLmNsb2NrLmJsYWNrX3RpbWUudGhpbmtpbmdfdGltZSAtIGJsYWNrX29mZnNldDtcbiAgICAgICAgICAgIGNvbnN0IHdoaXRlX3RpbWVfbGVmdCA9IHN0YXRlLmNsb2NrLndoaXRlX3RpbWUudGhpbmtpbmdfdGltZSAtIHdoaXRlX29mZnNldDtcblxuICAgICAgICAgICAgaWdub3JlX3Byb21pc2UodGhpcy5jb21tYW5kKGB0aW1lX3NldHRpbmdzICR7c3RhdGUudGltZV9jb250cm9sLnRvdGFsX3RpbWV9IDAgMGApKTtcbiAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKFxuICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZChgdGltZV9sZWZ0IGJsYWNrICR7TWF0aC5mbG9vcihNYXRoLm1heChibGFja190aW1lX2xlZnQsIDApKX0gMGApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKFxuICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZChgdGltZV9sZWZ0IHdoaXRlICR7TWF0aC5mbG9vcihNYXRoLm1heCh3aGl0ZV90aW1lX2xlZnQsIDApKX0gMGApLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICAvKiAgT0dTIGRvZXNuJ3QgYWN0dWFsbHkgc2VuZCAnbm9uZScgdGltZSBjb250cm9sIHR5cGVcbiAgICAgICAgICAgIGVsc2UgaWYgKHN0YXRlLnRpbWVfY29udHJvbC5zeXN0ZW0gPT09ICdub25lJykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmtnc3RpbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb21tYW5kKFwia2dzLXRpbWVfc2V0dGluZ3Mgbm9uZVwiKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBHVFAgdjIgc2F5cyBieW95b21pIHRpbWUgPiAwIGFuZCBzdG9uZXMgPSAwIG1lYW5zIG5vIHRpbWUgbGltaXRzXG4gICAgICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29tbWFuZChcInRpbWVfc2V0dGluZ3MgMCAxIDBcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAqL1xuICAgIH1cblxuICAgIGFzeW5jIGxvYWRTdGF0ZShzdGF0ZSk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgICAgIGlmICh0aGlzLmRlYWQpIHtcbiAgICAgICAgICAgIHRoaXMuZmFpbGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuZXJyb3IoXCJBdHRlbXB0ZWQgdG8gbG9hZCBzdGF0ZSB0byBhIGRlYWQgYm90XCIpO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQXR0ZW1wdGluZyB0byBsb2FkIGRlYWQgYm90XCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5rZ3NfdGltZSA9ICEhdGhpcy5hdmFpbGFibGVfY29tbWFuZHNbXCJrZ3MtdGltZV9zZXR0aW5nc1wiXTtcbiAgICAgICAgdGhpcy5rYXRhX3RpbWUgPSAhIXRoaXMuYXZhaWxhYmxlX2NvbW1hbmRzW1wia2F0YS1saXN0X3RpbWVfc2V0dGluZ3NcIl07XG4gICAgICAgIGlmICh0aGlzLmthdGFfdGltZSkge1xuICAgICAgICAgICAgY29uc3Qga2F0YVRpbWVTZXR0aW5ncyA9IGF3YWl0IHRoaXMuY29tbWFuZChcImthdGEtbGlzdF90aW1lX3NldHRpbmdzXCIpO1xuICAgICAgICAgICAgdGhpcy5rYXRhX2Zpc2NoZXIgPSBrYXRhVGltZVNldHRpbmdzLmluY2x1ZGVzKFwiZmlzY2hlci1jYXBwZWRcIik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmthdGFfZmlzY2hlciA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZG9faW5pdGlhbF9sb2FkID0gIXRoaXMucGVyc2lzdGVudCB8fCAhdGhpcy5wZXJzaXN0ZW50X3N0YXRlX2xvYWRlZDtcbiAgICAgICAgbGV0IGhhdmVfaW5pdGlhbF9zdGF0ZSA9IGZhbHNlO1xuXG4gICAgICAgIGlmIChkb19pbml0aWFsX2xvYWQpIHtcbiAgICAgICAgICAgIC8vIFVwZGF0ZSBvdXIgYWZmaW5pdHkgZmllbGRzXG4gICAgICAgICAgICB0aGlzLmxhc3RfZ2FtZV9pZCA9IHN0YXRlLmdhbWVfaWQ7XG4gICAgICAgICAgICB0aGlzLmxhc3Rfd2lkdGggPSBzdGF0ZS53aWR0aDtcbiAgICAgICAgICAgIHRoaXMubGFzdF9oZWlnaHQgPSBzdGF0ZS5oZWlnaHQ7XG5cbiAgICAgICAgICAgIGlmIChzdGF0ZS53aWR0aCA9PT0gc3RhdGUuaGVpZ2h0KSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5jb21tYW5kKGBib2FyZHNpemUgJHtzdGF0ZS53aWR0aH1gKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5jb21tYW5kKGBib2FyZHNpemUgJHtzdGF0ZS53aWR0aH0gJHtzdGF0ZS5oZWlnaHR9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmNvbW1hbmQoXCJjbGVhcl9ib2FyZFwiKTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuY29tbWFuZChga29taSAke3N0YXRlLmtvbWl9YCk7XG5cbiAgICAgICAgICAgIGlmIChzdGF0ZS5pbml0aWFsX3N0YXRlKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYmxhY2sgPSBkZWNvZGVNb3ZlcyhzdGF0ZS5pbml0aWFsX3N0YXRlLmJsYWNrLCBzdGF0ZS53aWR0aCwgc3RhdGUuaGVpZ2h0KTtcbiAgICAgICAgICAgICAgICBjb25zdCB3aGl0ZSA9IGRlY29kZU1vdmVzKHN0YXRlLmluaXRpYWxfc3RhdGUud2hpdGUsIHN0YXRlLndpZHRoLCBzdGF0ZS5oZWlnaHQpO1xuICAgICAgICAgICAgICAgIGhhdmVfaW5pdGlhbF9zdGF0ZSA9ICEhYmxhY2subGVuZ3RoIHx8ICEhd2hpdGUubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBibGFjay5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmNvbW1hbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICBgcGxheSBibGFjayAke21vdmUyZ3RwdmVydGV4KGJsYWNrW2ldLCBzdGF0ZS53aWR0aCwgc3RhdGUuaGVpZ2h0KX1gLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHdoaXRlLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuY29tbWFuZChcbiAgICAgICAgICAgICAgICAgICAgICAgIGBwbGF5IHdoaXRlICR7bW92ZTJndHB2ZXJ0ZXgod2hpdGVbaV0sIHN0YXRlLndpZHRoLCBzdGF0ZS5oZWlnaHQpfWAsXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVwbGF5IG1vdmVzIG1hZGVcbiAgICAgICAgbGV0IGNvbG9yID0gc3RhdGUuaW5pdGlhbF9wbGF5ZXI7XG4gICAgICAgIGNvbnN0IGRvaW5nX2hhbmRpY2FwID1cbiAgICAgICAgICAgICFoYXZlX2luaXRpYWxfc3RhdGUgJiYgc3RhdGUuZnJlZV9oYW5kaWNhcF9wbGFjZW1lbnQgJiYgc3RhdGUuaGFuZGljYXAgPiAxO1xuICAgICAgICBjb25zdCBoYW5kaWNhcF9tb3ZlcyA9IFtdO1xuICAgICAgICBjb25zdCBtb3ZlcyA9IGRlY29kZU1vdmVzKHN0YXRlLm1vdmVzLCBzdGF0ZS53aWR0aCwgc3RhdGUuaGVpZ2h0KTtcblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1vdmVzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICBjb25zdCBtb3ZlID0gbW92ZXNbaV07XG5cbiAgICAgICAgICAgIC8vIFVzZSBzZXRfZnJlZV9oYW5kaWNhcCBmb3IgaGFuZGljYXAgc3RvbmVzLCBwbGF5IG90aGVyd2lzZS5cbiAgICAgICAgICAgIGlmIChkb2luZ19oYW5kaWNhcCAmJiBoYW5kaWNhcF9tb3Zlcy5sZW5ndGggPCBzdGF0ZS5oYW5kaWNhcCkge1xuICAgICAgICAgICAgICAgIGhhbmRpY2FwX21vdmVzLnB1c2gobW92ZSk7XG4gICAgICAgICAgICAgICAgaWYgKGhhbmRpY2FwX21vdmVzLmxlbmd0aCA9PT0gc3RhdGUuaGFuZGljYXApIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGRvX2luaXRpYWxfbG9hZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlX3Byb21pc2UoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zZW5kSGFuZGljYXBNb3ZlcyhoYW5kaWNhcF9tb3Zlcywgc3RhdGUud2lkdGgsIHN0YXRlLmhlaWdodCksXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMucGVyc2lzdGVudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucGVyc2lzdGVudF9tb3Zlc19zZW50X2NvdW50ICs9IGhhbmRpY2FwX21vdmVzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH0gLy8gZG9uJ3Qgc3dpdGNoIGNvbG9yLlxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoZG9faW5pdGlhbF9sb2FkIHx8ICh0aGlzLnBlcnNpc3RlbnQgJiYgdGhpcy5wZXJzaXN0ZW50X21vdmVzX3NlbnRfY291bnQgPD0gaSkpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMucGVyc2lzdGVudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgKyt0aGlzLnBlcnNpc3RlbnRfbW92ZXNfc2VudF9jb3VudDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmNvbW1hbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICBgcGxheSAke2NvbG9yfSAke21vdmUyZ3RwdmVydGV4KG1vdmUsIHN0YXRlLndpZHRoLCBzdGF0ZS5oZWlnaHQpfWAsXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb2xvciA9IGNvbG9yID09PSBcImJsYWNrXCIgPyBcIndoaXRlXCIgOiBcImJsYWNrXCI7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5wZXJzaXN0ZW50KSB7XG4gICAgICAgICAgICB0aGlzLnBlcnNpc3RlbnRfc3RhdGVfbG9hZGVkID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjb25maWcuc2hvd2JvYXJkKSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5jb21tYW5kKFwic2hvd2JvYXJkXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgfVxuXG4gICAgY29tbWFuZChzdHI6IHN0cmluZywgX2ZpbmFsX2NvbW1hbmQ/OiBib29sZWFuKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgY29uc3QgYXJyID0gc3RyLnRyaW0oKS5zcGxpdCgvXFxzKy8pO1xuICAgICAgICBpZiAoYXJyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IGNtZCA9IGFyclswXTtcbiAgICAgICAgICAgIGlmICghdGhpcy5hdmFpbGFibGVfY29tbWFuZHNbY21kXSkge1xuICAgICAgICAgICAgICAgIHRoaXMud2FybihgQm90IGRvZXMgbm90IHN1cHBvcnQgY29tbWFuZCAke2NtZH1gKTtcbiAgICAgICAgICAgICAgICAvL3JldHVybiBQcm9taXNlLnJlamVjdChgQm90IGRvZXMgbm90IHN1cHBvcnQgY29tbWFuZCAke2NtZH1gKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKFwiPVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZTxzdHJpbmc+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmRlYWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9yKFwiQXR0ZW1wdGluZyB0byBzZW5kIGEgY29tbWFuZCB0byBkZWFkIGJvdDpcIiwgc3RyKTtcbiAgICAgICAgICAgICAgICB0aGlzLmZhaWxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgcmVqZWN0KGBBdHRlbXB0aW5nIHRvIHNlbmQgYSBjb21tYW5kIHRvIGRlYWQgYm90OiAke3N0cn1gKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuY29tbWFuZF9jYWxsYmFja3MucHVzaChyZXNvbHZlKTtcbiAgICAgICAgICAgIHRoaXMuY29tbWFuZF9lcnJvcl9jYWxsYmFja3MucHVzaChyZWplY3QpO1xuICAgICAgICAgICAgdGhpcy50cmFjZShcIj4+PlwiLCBzdHIpO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB0aGlzLnByb2Muc3RkaW4ud3JpdGUoYCR7c3RyfVxcclxcbmApO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIC8vIEkgdGhpbmsgdGhpcyBkb2VzIG5vdCBub3JtYWxseSBoYXBwZW4sIHRoZSBleGNlcHRpb24gd2lsbCB1c3VhbGx5IGJlIHJhaXNlZCBpbiB0aGUgYXN5bmMgd3JpdGUgaGFuZGxlclxuICAgICAgICAgICAgICAgIC8vIGFuZCBkZWxpdmVyZWQgdGhyb3VnaCBhbiAnZXJyb3InIGV2ZW50LlxuICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvcihcIkZhaWxlZCB0byBzZW5kIGNvbW1hbmQ6IFwiLCBzdHIpO1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyb3IoZSk7XG4gICAgICAgICAgICAgICAgdGhpcy5kZWFkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLmZhaWxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgLy8gQWxyZWFkeSBjYWxsaW5nIHRoZSBjYWxsYmFjayFcbiAgICAgICAgICAgICAgICB0aGlzLmNvbW1hbmRfZXJyb3JfY2FsbGJhY2tzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gRm9yIGNvbW1hbmRzIGxpa2UgZ2VubW92ZSwgcGxhY2VfZnJlZV9oYW5kaWNhcCAuLi4gOlxuICAgIC8vIFNlbmQgQGNtZCB0byBlbmdpbmUgYW5kIGNhbGwgQGNiIHdpdGggcmV0dXJuZWQgbW92ZXMuXG4gICAgYXN5bmMgZ2V0TW92ZXMoY21kLCBzdGF0ZSk6IFByb21pc2U8TW92ZVtdPiB7XG4gICAgICAgIHRoaXMubG9hZENsb2NrKHN0YXRlKTtcblxuICAgICAgICAvLyBNdXN0IGJlIGFmdGVyIGxvYWRDbG9jaygpIHNpbmNlIGxvYWRDbG9jaygpIGNoZWNrcyB0aGlzLmZpcnN0X21vdmUhXG4gICAgICAgIHRoaXMuZmlyc3RfbW92ZSA9IGZhbHNlO1xuXG4gICAgICAgIGNvbnN0IGxpbmUgPSBhd2FpdCB0aGlzLmNvbW1hbmQoY21kLCB0cnVlIC8qIGZpbmFsIGNvbW1hbmQgKi8pO1xuXG4gICAgICAgIGNvbnN0IHBhcnRzID0gbGluZS50b0xvd2VyQ2FzZSgpLnNwbGl0KC8gKy8pO1xuICAgICAgICBjb25zdCBtb3ZlczogTW92ZVtdID0gW107XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwYXJ0cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgY29uc3QgbW92ZSA9IHBhcnRzW2ldO1xuXG4gICAgICAgICAgICBsZXQgcmVzaWduID0gbW92ZSA9PT0gXCJyZXNpZ25cIjtcbiAgICAgICAgICAgIGNvbnN0IHBhc3MgPSBtb3ZlID09PSBcInBhc3NcIjtcbiAgICAgICAgICAgIGxldCB4ID0gLTE7XG4gICAgICAgICAgICBsZXQgeSA9IC0xO1xuICAgICAgICAgICAgaWYgKCFyZXNpZ24gJiYgIXBhc3MpIHtcbiAgICAgICAgICAgICAgICBpZiAobW92ZSAmJiBtb3ZlWzBdKSB7XG4gICAgICAgICAgICAgICAgICAgIHggPSBndHBjaGFyMm51bShtb3ZlWzBdKTtcbiAgICAgICAgICAgICAgICAgICAgeSA9IHN0YXRlLmhlaWdodCAtIHBhcnNlSW50KG1vdmUuc3Vic3RyaW5nKDEpKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhgJHtjbWR9IGZhaWxlZCwgcmVzaWduaW5nYCk7XG4gICAgICAgICAgICAgICAgICAgIHJlc2lnbiA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbW92ZXMucHVzaCh7IHgsIHksIHRleHQ6IG1vdmUsIHJlc2lnbiwgcGFzcyB9KTtcblxuICAgICAgICAgICAgaWYgKHRoaXMucGVyc2lzdGVudCkge1xuICAgICAgICAgICAgICAgICsrdGhpcy5wZXJzaXN0ZW50X21vdmVzX3NlbnRfY291bnQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY29uZmlnLnNob3dib2FyZCkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5jb21tYW5kKFwic2hvd2JvYXJkXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG1vdmVzO1xuICAgIH1cblxuICAgIGtpbGwoKSB7XG4gICAgICAgIHRoaXMubG9nKFwiU3RvcHBpbmcgYm90XCIpO1xuICAgICAgICB0aGlzLmlnbm9yZSA9IHRydWU7IC8vIFByZXZlbnQgcmFjZSBjb25kaXRpb25zIC8gaW5jb25zaXN0ZW5jaWVzLiBDb3VsZCBiZSBpbiB0aGUgbWlkZGxlIG9mIGdlbm1vdmUgLi4uXG4gICAgICAgIC8vIFwicXVpdFwiIG5lZWRzIHRvIGJlIHNlbnQgYmVmb3JlIHdlIHRvZ2dsZSB0aGlzLmRlYWQgc2luY2UgY29tbWFuZCgpIGNoZWNrcyB0aGUgc3RhdHVzIG9mIHRoaXMuZGVhZFxuICAgICAgICBpZ25vcmVfcHJvbWlzZSh0aGlzLmNvbW1hbmQoXCJxdWl0XCIpKTtcbiAgICAgICAgdGhpcy5kZWFkID0gdHJ1ZTtcbiAgICAgICAgaWYgKHRoaXMucHJvYykge1xuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMucHJvYy5leGl0Q29kZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhcIkJvdCBleGl0ZWQgd2l0aCBjb2RlXCIsIHRoaXMucHJvYy5leGl0Q29kZSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy53YXJuKFxuICAgICAgICAgICAgICAgICAgICBgQm90IGRpZG4ndCBleGl0IGFmdGVyICR7dGhpcy5ib3RfY29uZmlnLnF1aXRfZ3JhY2VfcGVyaW9kfW1zIHdpdGggXCJxdWl0XCIgbWVzc2FnZSwga2lsbGluZyBmb3JjZWZ1bGx5YCxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHRoaXMucHJvYy5raWxsKFwiU0lHVEVSTVwiKTtcblxuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5wcm9jLmV4aXRDb2RlICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvZyhcIkJvdCBleGl0ZWQgd2l0aCBjb2RlXCIsIHRoaXMucHJvYy5leGl0Q29kZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wcm9jLmtpbGwoXCJTSUdLSUxMXCIpO1xuICAgICAgICAgICAgICAgIH0sIHRoaXMuYm90X2NvbmZpZy5xdWl0X2dyYWNlX3BlcmlvZCk7XG4gICAgICAgICAgICB9LCB0aGlzLmJvdF9jb25maWcucXVpdF9ncmFjZV9wZXJpb2QpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGFzeW5jIHNlbmRNb3ZlKG1vdmUsIHdpZHRoLCBoZWlnaHQsIGNvbG9yKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMudmVyYm9zZShcIkNhbGxpbmcgc2VuZE1vdmUgd2l0aFwiLCBtb3ZlMmd0cHZlcnRleChtb3ZlLCB3aWR0aCwgaGVpZ2h0KSk7XG4gICAgICAgIGF3YWl0IHRoaXMuY29tbWFuZChgcGxheSAke2NvbG9yfSAke21vdmUyZ3RwdmVydGV4KG1vdmUsIHdpZHRoLCBoZWlnaHQpfWApO1xuICAgIH1cbiAgICBhc3luYyBzZW5kSGFuZGljYXBNb3Zlcyhtb3Zlcywgd2lkdGgsIGhlaWdodCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgY21kID0gXCJzZXRfZnJlZV9oYW5kaWNhcFwiO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1vdmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjbWQgKz0gYCAke21vdmUyZ3RwdmVydGV4KG1vdmVzW2ldLCB3aWR0aCwgaGVpZ2h0KX1gO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHRoaXMuY29tbWFuZChjbWQpO1xuICAgIH1cbiAgICAvLyBDYWxsZWQgb24gZ2FtZSBvdmVyLCBpbiBjYXNlIHlvdSBuZWVkIHNvbWV0aGluZyBzcGVjaWFsLlxuICAgIC8qXG4gICAgZ2FtZU92ZXIoKSB7XG4gICAgICAgIC8vXG4gICAgfVxuICAgICovXG5cbiAgICBzZXRHYW1lKGdhbWU6IEdhbWUgfCBudWxsKSB7XG4gICAgICAgIHRoaXMuZ2FtZSA9IGdhbWU7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ3RwY2hhcjJudW0oY2g6IHN0cmluZyk6IG51bWJlciB7XG4gICAgaWYgKGNoID09PSBcIi5cIiB8fCAhY2gpIHtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cbiAgICByZXR1cm4gXCJhYmNkZWZnaGprbG1ub3BxcnN0dXZ3eHl6XCIuaW5kZXhPZihjaC50b0xvd2VyQ2FzZSgpKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG1vdmUyZ3RwdmVydGV4KG1vdmUsIF93aWR0aDogbnVtYmVyLCBoZWlnaHQ6IG51bWJlcik6IHN0cmluZyB7XG4gICAgaWYgKG1vdmUueCA8IDApIHtcbiAgICAgICAgcmV0dXJuIFwicGFzc1wiO1xuICAgIH1cbiAgICByZXR1cm4gbnVtMmd0cGNoYXIobW92ZVtcInhcIl0pICsgKGhlaWdodCAtIG1vdmVbXCJ5XCJdKTtcbn1cblxuZnVuY3Rpb24gbnVtMmd0cGNoYXIobnVtOiBudW1iZXIpOiBzdHJpbmcge1xuICAgIGlmIChudW0gPT09IC0xKSB7XG4gICAgICAgIHJldHVybiBcIi5cIjtcbiAgICB9XG4gICAgcmV0dXJuIFwiYWJjZGVmZ2hqa2xtbm9wcXJzdHV2d3h5elwiW251bV07XG59XG4iLCJpbXBvcnQgeyBkZWNvZGVNb3ZlcyB9IGZyb20gXCJnb2Jhbi1lbmdpbmVcIjtcbmltcG9ydCB7IEdvYmFuRW5naW5lQ29uZmlnIH0gZnJvbSBcImdvYmFuLWVuZ2luZVwiO1xuaW1wb3J0IHsgcHJvdG9jb2wgfSBmcm9tIFwiZ29iYW4tZW5naW5lXCI7XG5pbXBvcnQgeyBtb3ZlMmd0cHZlcnRleCwgaWdub3JlX3Byb21pc2UgfSBmcm9tIFwiLi91dGlsXCI7XG5pbXBvcnQgeyBNb3ZlIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IEJvdCB9IGZyb20gXCIuL0JvdFwiO1xuaW1wb3J0IHsgdHJhY2UgfSBmcm9tIFwiLi90cmFjZVwiO1xuaW1wb3J0IHsgc29ja2V0IH0gZnJvbSBcIi4vc29ja2V0XCI7XG5pbXBvcnQgeyBjb25maWcsIFRyYW5zbGF0YWJsZVN0cmluZyB9IGZyb20gXCIuL2NvbmZpZ1wiO1xuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSBcImV2ZW50ZW1pdHRlcjNcIjtcbmltcG9ydCB7IGJvdF9wb29scyB9IGZyb20gXCIuL3Bvb2xzXCI7XG4vL2ltcG9ydCB7IFB2T3V0cHV0UGFyc2VyIH0gZnJvbSBcIi4vUHZPdXRwdXRQYXJzZXJcIjtcblxuaW50ZXJmYWNlIEV2ZW50cyB7XG4gICAgZGlzY29ubmVjdGluZzogKCkgPT4gdm9pZDtcbiAgICBkaXNjb25uZWN0ZWQ6IChnYW1lX2lkOiBudW1iZXIpID0+IHZvaWQ7XG59XG5cbi8qKiBUaGlzIG1hbmFnZXMgYSBzaW5nbGUgZ2FtZSAqL1xuZXhwb3J0IGNsYXNzIEdhbWUgZXh0ZW5kcyBFdmVudEVtaXR0ZXI8RXZlbnRzPiB7XG4gICAgc3RhdGljIG1vdmVzX3Byb2Nlc3Npbmc6IGFueTtcblxuICAgIGNvbm5lY3RfdGltZW91dDogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD47XG5cbiAgICBnYW1lX2lkOiBudW1iZXI7XG4gICAgc3RhdGU6IEdvYmFuRW5naW5lQ29uZmlnO1xuICAgIG9wcG9uZW50X2V2ZW5vZGQ6IG51bGwgfCBudW1iZXI7XG4gICAgZ3JlZXRlZDogYm9vbGVhbjtcbiAgICBzdGFydHVwX3RpbWVzdGFtcDogbnVtYmVyO1xuICAgIGJvdD86IEJvdDtcbiAgICB1c2luZ19vcGVuaW5nX2JvdDogYm9vbGVhbiA9IGZhbHNlO1xuICAgIGVuZGluZ19ib3Q/OiBCb3Q7XG4gICAgZW5kYm90X3Jlc2lnbl9jb3VudDogbnVtYmVyID0gMDtcbiAgICBib3RfZmFpbHVyZXM6IG51bWJlcjtcbiAgICBlbmRpbmdfYm90X2ZhaWx1cmVzOiBudW1iZXI7XG4gICAgbXlfY29sb3I6IG51bGwgfCBzdHJpbmc7XG4gICAgcHJvY2Vzc2luZzogYm9vbGVhbjtcbiAgICBoYW5kaWNhcF9tb3ZlczogTW92ZVtdO1xuICAgIGRpc2Nvbm5lY3RfdGltZW91dDogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD47XG4gICAgdW5wYXVzZV90aW1lb3V0PzogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD47XG4gICAgbG9nOiAoLi4uYXJyOiBhbnlbXSkgPT4gYW55O1xuICAgIHRyYWNlOiAoLi4uYXJyOiBhbnlbXSkgPT4gYW55O1xuICAgIHZlcmJvc2U6ICguLi5hcnI6IGFueVtdKSA9PiBhbnk7XG4gICAgd2FybjogKC4uLmFycjogYW55W10pID0+IGFueTtcbiAgICBlcnJvcjogKC4uLmFycjogYW55W10pID0+IGFueTtcblxuICAgIGNvbnN0cnVjdG9yKGdhbWVfaWQpIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICBpZiAoIWdhbWVfaWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBnYW1lIGlkOiAke2dhbWVfaWR9YCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmdhbWVfaWQgPSBnYW1lX2lkO1xuICAgICAgICB0aGlzLmxvZyA9IHRyYWNlLmxvZy5iaW5kKG51bGwsIGBbZ2FtZSAke2dhbWVfaWR9XWApO1xuICAgICAgICB0aGlzLnRyYWNlID0gdHJhY2UudHJhY2UuYmluZChudWxsLCBgW2dhbWUgJHtnYW1lX2lkfV1gKTtcbiAgICAgICAgdGhpcy52ZXJib3NlID0gdHJhY2UuZGVidWcuYmluZChudWxsLCBgW2dhbWUgJHtnYW1lX2lkfV1gKTtcbiAgICAgICAgdGhpcy53YXJuID0gdHJhY2Uud2Fybi5iaW5kKG51bGwsIGBbZ2FtZSAke2dhbWVfaWR9XWApO1xuICAgICAgICB0aGlzLmVycm9yID0gdHJhY2UuZXJyb3IuYmluZChudWxsLCBgW2dhbWUgJHtnYW1lX2lkfV1gKTtcbiAgICAgICAgdGhpcy5zdGFydHVwX3RpbWVzdGFtcCA9IERhdGUubm93KCkgLyAxMDAwO1xuICAgICAgICB0aGlzLnN0YXRlID0gbnVsbDtcbiAgICAgICAgdGhpcy5vcHBvbmVudF9ldmVub2RkID0gbnVsbDtcbiAgICAgICAgdGhpcy5ncmVldGVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuYm90ID0gdW5kZWZpbmVkO1xuICAgICAgICB0aGlzLmVuZGluZ19ib3QgPSB1bmRlZmluZWQ7XG4gICAgICAgIHRoaXMuYm90X2ZhaWx1cmVzID0gMDtcbiAgICAgICAgdGhpcy5teV9jb2xvciA9IG51bGw7XG4gICAgICAgIHRoaXMucHJvY2Vzc2luZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLmhhbmRpY2FwX21vdmVzID0gW107IC8vIEhhbmRpY2FwIHN0b25lcyB3YWl0aW5nIHRvIGJlIHNlbnQgd2hlbiBib3QgaXMgcGxheWluZyBibGFjay5cbiAgICAgICAgdGhpcy5kaXNjb25uZWN0X3RpbWVvdXQgPSBudWxsO1xuXG4gICAgICAgIHRoaXMubG9nKFwiQ29ubmVjdGluZyB0byBnYW1lLlwiKTtcblxuICAgICAgICAvLyBUT0RPOiBDb21tYW5kIGxpbmUgb3B0aW9ucyB0byBhbGxvdyB1bmRvP1xuICAgICAgICAvL1xuICAgICAgICBjb25zdCBvbl91bmRvX3JlcXVlc3RlZCA9ICh1bmRvX2RhdGEpID0+IHtcbiAgICAgICAgICAgIHRoaXMubG9nKFwiVW5kbyByZXF1ZXN0ZWRcIiwgSlNPTi5zdHJpbmdpZnkodW5kb19kYXRhLCBudWxsLCA0KSk7XG4gICAgICAgIH07XG4gICAgICAgIHNvY2tldC5vbihgZ2FtZS8ke2dhbWVfaWR9L3VuZG9fcmVxdWVzdGVkYCwgb25fdW5kb19yZXF1ZXN0ZWQpO1xuICAgICAgICB0aGlzLm9uKFwiZGlzY29ubmVjdGluZ1wiLCAoKSA9PiB7XG4gICAgICAgICAgICBzb2NrZXQub2ZmKGBnYW1lLyR7Z2FtZV9pZH0vdW5kb19yZXF1ZXN0ZWRgLCBvbl91bmRvX3JlcXVlc3RlZCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IG9uX2dhbWVkYXRhID0gKGdhbWVkYXRhKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXNvY2tldC5jb25uZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFNlcnZlciBoYXMgYW4gaXNzdWUgdGhhdCBnYW1lZGF0YS5jbG9jay5ub3cgd2lsbCBleGlzdCBpbmNvbnNpc3RlbnRseS4gVGhpcyB3aWxsIGNhdXNlXG4gICAgICAgICAgICAvLyBmYWxzZSBwb3NpdGl2ZXMgZm9yIGdhbWVkYXRhIGNoYW5nZXMuIFdlIG5ldmVyIHVzZSB0aGUgZmllbGQsIHNvIGp1c3QgcmVtb3ZlIGl0LlxuICAgICAgICAgICAgZGVsZXRlIGdhbWVkYXRhLmNsb2NrLm5vdztcbiAgICAgICAgICAgIC8vIGF1dG9fc2NvcmUgYWxzbyBzb21ldGltZXMgaW5jb25zaXN0ZW50LiBXZSBkb24ndCB1c2UgaXQsIHNvIGlnbm9yZSBpdCB0byBhdm9pZCBwb2ludGxlc3NcbiAgICAgICAgICAgIC8vIHJlc3RhcnQuXG4gICAgICAgICAgICAvKiBUT0RPOiBjaGVjayBhbmQgc2VlIGlmIGF1dG9fc2NvcmUgaXMgc3RpbGwgc2VudCwgSSBkb24ndCB0aGluayBpdCBpcyAoYW5vZWsgMjAyMy0wMy0yNCkgKi9cbiAgICAgICAgICAgIGRlbGV0ZSAoZ2FtZWRhdGEgYXMgYW55KS5hdXRvX3Njb3JlO1xuXG4gICAgICAgICAgICAvLyBPbmx5IGNhbGwgZ2FtZSBvdmVyIGhhbmRsZXIgaWYgZ2FtZSByZWFsbHkganVzdCBmaW5pc2hlZC5cbiAgICAgICAgICAgIC8vIEZvciBzb21lIHJlYXNvbiB3ZSBnZXQgY29ubmVjdGVkIHRvIGFscmVhZHkgZmluaXNoZWQgZ2FtZXMgb25jZSBpbiBhIHdoaWxlIC4uLlxuICAgICAgICAgICAgaWYgKGdhbWVkYXRhLnBoYXNlID09PSBcImZpbmlzaGVkXCIpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZSAmJiBnYW1lZGF0YS5waGFzZSAhPT0gdGhpcy5zdGF0ZS5waGFzZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnN0YXRlID0gZ2FtZWRhdGE7XG4gICAgICAgICAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKHRoaXMuZ2FtZU92ZXIoKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybjsgLy8gaWdub3JlIC0tIGl0J3MgZWl0aGVyIGhhbmRsZWQgYnkgZ2FtZU92ZXIgb3Igd2UgYWxyZWFkeSBoYW5kbGVkIGl0IGJlZm9yZS5cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgZ2FtZWRhdGFDaGFuZ2VkID0gdGhpcy5zdGF0ZVxuICAgICAgICAgICAgICAgID8gSlNPTi5zdHJpbmdpZnkodGhpcy5zdGF0ZSkgIT09IEpTT04uc3RyaW5naWZ5KGdhbWVkYXRhKVxuICAgICAgICAgICAgICAgIDogZmFsc2U7XG4gICAgICAgICAgICAvLyBJZiB0aGUgZ2FtZWRhdGEgaXMgaWRlbnRpY2FsIHRvIGN1cnJlbnQgc3RhdGUsIGl0J3MgYSBkdXBsaWNhdGUuIElnbm9yZSBpdCBhbmQgZG8gbm90aGluZywgdW5sZXNzXG4gICAgICAgICAgICAvLyBib3QgaXMgbm90IHJ1bm5pbmcuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUgJiYgIWdhbWVkYXRhQ2hhbmdlZCAmJiB0aGlzLmJvdCAmJiAhdGhpcy5ib3QuZGVhZCkge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nKFwiSWdub3JpbmcgZ2FtZWRhdGEgdGhhdCBtYXRjaGVzIGN1cnJlbnQgc3RhdGVcIik7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiBzZXJ2ZXIgaGFzIGlzc3VlcyBpdCBtaWdodCBzZW5kIHVzIGEgbmV3IGdhbWVkYXRhIHBhY2tldCBhbmQgbm90IGEgbW92ZSBldmVudC4gV2UgY291bGQgdHJ5IHRvXG4gICAgICAgICAgICAvLyBjaGVjayBpZiB3ZSdyZSBtaXNzaW5nIGEgbW92ZSBhbmQgc2VuZCBpdCB0byBib3Qgb3V0IG9mIGdhbWVkYXRhLiBGb3Igbm93IGFzIGEgc2FmZSBmYWxsYmFjayBqdXN0XG4gICAgICAgICAgICAvLyByZXN0YXJ0IHRoZSBib3QgYnkga2lsbGluZyBpdCBoZXJlIGlmIGFub3RoZXIgZ2FtZWRhdGEgY29tZXMgaW4uIFRoZXJlIG5vcm1hbGx5IHNob3VsZCBvbmx5IGJlIG9uZVxuICAgICAgICAgICAgLy8gYmVmb3JlIHdlIHByb2Nlc3MgYW55IG1vdmVzLCBhbmQgbWFrZU1vdmUoKSBpcyB3aGVyZSBhIG5ldyBCb3QgaXMgY3JlYXRlZC5cbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICBpZiAodGhpcy5ib3QgJiYgZ2FtZWRhdGFDaGFuZ2VkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2coXCJLaWxsaW5nIGJvdCBiZWNhdXNlIG9mIGdhbWVkYXRhIGNoYW5nZSBhZnRlciBib3Qgd2FzIHN0YXJ0ZWRcIik7XG4gICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlKFwiUHJldmlvdXNseSBzZWVuIGdhbWVkYXRhOlwiLCB0aGlzLnN0YXRlKTtcbiAgICAgICAgICAgICAgICB0aGlzLnZlcmJvc2UoXCJOZXcgZ2FtZWRhdGE6XCIsIGdhbWVkYXRhKTtcbiAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZSh0aGlzLnJlbGVhc2VCb3RzKCkpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMucHJvY2Vzc2luZykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnByb2Nlc3NpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgLS1HYW1lLm1vdmVzX3Byb2Nlc3Npbmc7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvL3RoaXMubG9nKFwiR2FtZWRhdGE6XCIsIEpTT04uc3RyaW5naWZ5KGdhbWVkYXRhLCBudWxsLCA0KSk7XG4gICAgICAgICAgICB0aGlzLnN0YXRlID0gZ2FtZWRhdGE7XG4gICAgICAgICAgICB0aGlzLm15X2NvbG9yID0gY29uZmlnLmJvdF9pZCA9PT0gdGhpcy5zdGF0ZS5wbGF5ZXJzLmJsYWNrLmlkID8gXCJibGFja1wiIDogXCJ3aGl0ZVwiO1xuICAgICAgICAgICAgdGhpcy5sb2coYGdhbWVkYXRhICAgICAke3RoaXMuaGVhZGVyKCl9YCk7XG5cbiAgICAgICAgICAgIC8vIEZpcnN0IGhhbmRpY2FwIGlzIGp1c3QgbG93ZXIga29taSwgbW9yZSBoYW5kaWNhcHMgbWF5IGNoYW5nZSB3aG8gaXMgZXZlbiBvciBvZGQgbW92ZSAjcy5cbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5mcmVlX2hhbmRpY2FwX3BsYWNlbWVudCAmJiB0aGlzLnN0YXRlLmhhbmRpY2FwID4gMSkge1xuICAgICAgICAgICAgICAgIC8vSW4gQ2hpbmVzZSwgYmxhY2sgbWFrZXMgbXVsdGlwbGUgZnJlZSBtb3Zlcy5cbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgIHRoaXMub3Bwb25lbnRfZXZlbm9kZCA9IHRoaXMubXlfY29sb3IgPT09IFwiYmxhY2tcIiA/IDAgOiAxO1xuICAgICAgICAgICAgICAgIHRoaXMub3Bwb25lbnRfZXZlbm9kZCA9ICh0aGlzLm9wcG9uZW50X2V2ZW5vZGQgKyB0aGlzLnN0YXRlLmhhbmRpY2FwIC0gMSkgJSAyO1xuICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmhhbmRpY2FwID4gMSkge1xuICAgICAgICAgICAgICAgIC8vIEluIEphcGFuZXNlLCB3aGl0ZSBtYWtlcyB0aGUgZmlyc3QgbW92ZS5cbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgIHRoaXMub3Bwb25lbnRfZXZlbm9kZCA9IHRoaXMubXlfY29sb3IgPT09IFwiYmxhY2tcIiA/IDEgOiAwO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgZ2FtZSBoYXMgYSBoYW5kaWNhcCwgaXQgY2FuJ3QgYmUgYSBmb3JrIGFuZCB0aGUgYWJvdmUgY29kZSB3b3JrcyBmaW5lLlxuICAgICAgICAgICAgICAgIC8vIElmIHRoZSBnYW1lIGhhcyBubyBoYW5kaWNhcCwgaXQncyBlaXRoZXIgYSBub3JtYWwgZ2FtZSBvciBhIGZvcmsuIEZvcmtzIG1heSBoYXZlIHJldmVyc2VkIHR1cm4gb3JkZXJpbmcuXG4gICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5jbG9jay5jdXJyZW50X3BsYXllciA9PT0gY29uZmlnLmJvdF9pZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm9wcG9uZW50X2V2ZW5vZGQgPSB0aGlzLnN0YXRlLm1vdmVzLmxlbmd0aCAlIDI7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5vcHBvbmVudF9ldmVub2RkID0gKHRoaXMuc3RhdGUubW92ZXMubGVuZ3RoICsgMSkgJSAyO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gYWN0aXZlX2dhbWUgaXNuJ3QgaGFuZGxpbmcgdGhpcyBmb3IgdXMgYW55IG1vcmUuIElmIGl0IGlzIG91ciBtb3ZlLCBjYWxsIG1ha2VNb3ZlLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLnBoYXNlID09PSBcInBsYXlcIiAmJiB0aGlzLnN0YXRlLmNsb2NrLmN1cnJlbnRfcGxheWVyID09PSBjb25maWcuYm90X2lkKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmJvdCB8fCAhdGhpcy5wcm9jZXNzaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKHRoaXMubWFrZU1vdmUodGhpcy5zdGF0ZS5tb3Zlcy5sZW5ndGgpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuY2hlY2tGb3JQYXVzZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHNvY2tldC5vbihgZ2FtZS8ke2dhbWVfaWR9L2dhbWVkYXRhYCwgb25fZ2FtZWRhdGEpO1xuICAgICAgICB0aGlzLm9uKFwiZGlzY29ubmVjdGluZ1wiLCAoKSA9PiB7XG4gICAgICAgICAgICBzb2NrZXQub2ZmKGBnYW1lLyR7Z2FtZV9pZH0vZ2FtZWRhdGFgLCBvbl9nYW1lZGF0YSk7XG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBvbl9jbG9jayA9IChjbG9jaykgPT4ge1xuICAgICAgICAgICAgaWYgKCFzb2NrZXQuY29ubmVjdGVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBTZXJ2ZXIgaGFzIGFuIGlzc3VlIHRoYXQgZ2FtZWRhdGEuY2xvY2subm93IHdpbGwgZXhpc3QgaW5jb25zaXN0ZW50bHkuIFRoaXMgd2lsbCBjYXVzZVxuICAgICAgICAgICAgLy8gZmFsc2UgcG9zaXRpdmVzIGZvciBnYW1lZGF0YSBjaGFuZ2VzLiBXZSBuZXZlciB1c2UgdGhlIGZpZWxkLCBzbyBqdXN0IHJlbW92ZSBpdC5cbiAgICAgICAgICAgIGRlbGV0ZSBjbG9jay5ub3c7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5jbG9jayA9IGNsb2NrO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9yKGBSZWNlaXZlZCBjbG9jayBmb3IgJHt0aGlzLmdhbWVfaWR9IGJ1dCBubyBzdGF0ZSBleGlzdHNgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5jaGVja0ZvclBhdXNlKCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgc29ja2V0Lm9uKGBnYW1lLyR7Z2FtZV9pZH0vY2xvY2tgLCBvbl9jbG9jayk7XG4gICAgICAgIHRoaXMub24oXCJkaXNjb25uZWN0aW5nXCIsICgpID0+IHtcbiAgICAgICAgICAgIHNvY2tldC5vZmYoYGdhbWUvJHtnYW1lX2lkfS9jbG9ja2AsIG9uX2Nsb2NrKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IG9uX3BoYXNlID0gKHBoYXNlKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXNvY2tldC5jb25uZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmxvZyhcInBoYXNlXCIsIHBoYXNlKTtcblxuICAgICAgICAgICAgLy90aGlzLmxvZyhcIk1vdmU6IFwiLCBtb3ZlKTtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5waGFzZSA9IHBoYXNlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0cmFjZS5lcnJvcihgUmVjZWl2ZWQgcGhhc2UgZm9yICR7dGhpcy5nYW1lX2lkfSBidXQgbm8gc3RhdGUgZXhpc3RzYCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChwaGFzZSA9PT0gXCJwbGF5XCIpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNjaGVkdWxlUmV0cnkoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBzb2NrZXQub24oYGdhbWUvJHtnYW1lX2lkfS9waGFzZWAsIG9uX3BoYXNlKTtcbiAgICAgICAgdGhpcy5vbihcImRpc2Nvbm5lY3RpbmdcIiwgKCkgPT4ge1xuICAgICAgICAgICAgc29ja2V0Lm9mZihgZ2FtZS8ke2dhbWVfaWR9L3BoYXNlYCwgb25fcGhhc2UpO1xuICAgICAgICB9KTtcbiAgICAgICAgY29uc3Qgb25fbW92ZSA9IChtb3ZlKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXNvY2tldC5jb25uZWN0ZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnRyYWNlKGBnYW1lLyR7Z2FtZV9pZH0vbW92ZTpgLCBtb3ZlKTtcbiAgICAgICAgICAgIGlmICghdGhpcy5zdGF0ZSkge1xuICAgICAgICAgICAgICAgIHRyYWNlLmVycm9yKGBSZWNlaXZlZCBtb3ZlIGZvciAke3RoaXMuZ2FtZV9pZH0gYnV0IG5vIHN0YXRlIGV4aXN0c2ApO1xuICAgICAgICAgICAgICAgIC8vIFRyeSB0byBjb25uZWN0IGFnYWluLCB0byBnZXQgdGhlIHNlcnZlciB0byBzZW5kIHRoZSBnYW1lZGF0YSBvdmVyLlxuICAgICAgICAgICAgICAgIHNvY2tldC5zZW5kKFwiZ2FtZS9jb25uZWN0XCIsIHtcbiAgICAgICAgICAgICAgICAgICAgZ2FtZV9pZDogZ2FtZV9pZCxcbiAgICAgICAgICAgICAgICAgICAgY2hhdDogY29uZmlnLmxvZ19nYW1lX2NoYXQsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG1vdmUubW92ZV9udW1iZXIgIT09IHRoaXMuc3RhdGUubW92ZXMubGVuZ3RoICsgMSkge1xuICAgICAgICAgICAgICAgIHRyYWNlLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICBgUmVjZWl2ZWQgbW92ZSBmb3IgJHt0aGlzLmdhbWVfaWR9IGJ1dCBtb3ZlX251bWJlciBpcyBpbnZhbGlkLiAke1xuICAgICAgICAgICAgICAgICAgICAgICAgbW92ZS5tb3ZlX251bWJlclxuICAgICAgICAgICAgICAgICAgICB9ICE9PSAke3RoaXMuc3RhdGUubW92ZXMubGVuZ3RoICsgMX1gLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLm1vdmVzLnB1c2gobW92ZS5tb3ZlIGFzIGFueSk7XG5cbiAgICAgICAgICAgICAgICAvLyBMb2cgb3Bwb25lbnQgbW92ZXNcbiAgICAgICAgICAgICAgICBjb25zdCBtID0gZGVjb2RlTW92ZXMobW92ZS5tb3ZlLCB0aGlzLnN0YXRlLndpZHRoLCB0aGlzLnN0YXRlLmhlaWdodClbMF07XG4gICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAodGhpcy5teV9jb2xvciA9PT0gXCJ3aGl0ZVwiICYmIHRoaXMuc3RhdGUuaGFuZGljYXAgPj0gdGhpcy5zdGF0ZS5tb3Zlcy5sZW5ndGgpIHx8XG4gICAgICAgICAgICAgICAgICAgIG1vdmUubW92ZV9udW1iZXIgJSAyID09PSB0aGlzLm9wcG9uZW50X2V2ZW5vZGRcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgICAgICAgICAgICAgICBgT3Bwb25lbnQgcGxheWVkICR7bW92ZTJndHB2ZXJ0ZXgobSwgdGhpcy5zdGF0ZS53aWR0aCwgdGhpcy5zdGF0ZS5oZWlnaHQpfWAsXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIHRyYWNlLmVycm9yKGUpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJZiB3ZSdyZSBpbiBmcmVlIHBsYWNlbWVudCBoYW5kaWNhcCBwaGFzZSBvZiB0aGUgZ2FtZSwgbWFrZSBleHRyYSBtb3ZlcyBvciB3YWl0IGl0IG91dCwgYXMgYXBwcm9wcmlhdGUuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gSWYgaGFuZGljYXAgPT09IDEsIG5vIGV4dHJhIHN0b25lcyBhcmUgcGxheWVkLlxuICAgICAgICAgICAgLy8gSWYgd2UgYXJlIGJsYWNrLCB3ZSBwbGF5ZWQgYWZ0ZXIgaW5pdGlhbCBnYW1lZGF0YSBhbmQgc28gaGFuZGljYXAgaXMgbm90IDwgbGVuZ3RoLlxuICAgICAgICAgICAgLy8gSWYgd2UgYXJlIHdoaXRlLCB0aGlzLnN0YXRlLm1vdmVzLmxlbmd0aCB3aWxsIGJlIDEgYW5kIGhhbmRpY2FwIGlzIG5vdCA8IGxlbmd0aC5cbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyBJZiBoYW5kaWNhcCA+PSAxLCB3ZSBkb24ndCBjaGVjayBmb3Igb3Bwb25lbnRfZXZlbm9kZCB0byBtb3ZlIG9uIG91ciB0dXJucyB1bnRpbCBoYW5kaWNhcHMgYXJlIGZpbmlzaGVkLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLmZyZWVfaGFuZGljYXBfcGxhY2VtZW50ICYmXG4gICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5oYW5kaWNhcCA+IHRoaXMuc3RhdGUubW92ZXMubGVuZ3RoXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5teV9jb2xvciA9PT0gXCJibGFja1wiKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIElmIHdlIGFyZSBibGFjaywgd2UgbWFrZSBleHRyYSBtb3Zlcy5cbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgaWdub3JlX3Byb21pc2UodGhpcy5tYWtlTW92ZSh0aGlzLnN0YXRlLm1vdmVzLmxlbmd0aCkpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIElmIHdlIGFyZSB3aGl0ZSwgd2Ugd2FpdCBmb3Igb3Bwb25lbnQgdG8gbWFrZSBleHRyYSBtb3Zlcy5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuYm90KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmJvdC5zZW5kTW92ZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjb2RlTW92ZXMobW92ZS5tb3ZlLCB0aGlzLnN0YXRlLndpZHRoLCB0aGlzLnN0YXRlLmhlaWdodClbMF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUud2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUuaGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImJsYWNrXCIsIC8vIHdlIGFyZSB3aGl0ZSBzbyB3ZSBhcmUgcmVjb3JkaW5nIGJsYWNrJ3MgbW92ZXNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5lbmRpbmdfYm90KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVuZGluZ19ib3Quc2VuZE1vdmUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY29kZU1vdmVzKG1vdmUubW92ZSwgdGhpcy5zdGF0ZS53aWR0aCwgdGhpcy5zdGF0ZS5oZWlnaHQpWzBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLndpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLmhlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJibGFja1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZShcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiV2FpdGluZyBmb3Igb3Bwb25lbnQgdG8gZmluaXNoXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLmhhbmRpY2FwIC0gdGhpcy5zdGF0ZS5tb3Zlcy5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgICAgICBcIm1vcmUgaGFuZGljYXAgbW92ZXNcIixcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUubW92ZXMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyByZW1pbmQgb25jZSwgYXZvaWQgc3BhbW1pbmcgdGhlIHJlbWluZGVyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNlbmRDaGF0KFwiV2FpdGluZyBmb3Igb3Bwb25lbnQgdG8gcGxhY2UgYWxsIGhhbmRpY2FwIHN0b25lc1wiKTsgLy8gcmVtaW5kaW5nIGh1bWFuIHBsYXllciBpbiBpbi1nYW1lIGNoYXRcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgb3Bwb25lbnRfY29sb3IgPSB0aGlzLm15X2NvbG9yID09PSBcImJsYWNrXCIgPyBcIndoaXRlXCIgOiBcImJsYWNrXCI7XG4gICAgICAgICAgICAgICAgaWYgKG1vdmUubW92ZV9udW1iZXIgJSAyID09PSB0aGlzLm9wcG9uZW50X2V2ZW5vZGQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gV2UganVzdCBnb3QgYSBtb3ZlIGZyb20gdGhlIG9wcG9uZW50LCBzbyB3ZSBjYW4gbW92ZSBpbW1lZGlhdGVseS5cbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuYm90KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmJvdC5zZW5kTW92ZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjb2RlTW92ZXMobW92ZS5tb3ZlLCB0aGlzLnN0YXRlLndpZHRoLCB0aGlzLnN0YXRlLmhlaWdodClbMF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUud2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3RhdGUuaGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHBvbmVudF9jb2xvcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5lbmRpbmdfYm90KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVuZGluZ19ib3Quc2VuZE1vdmUoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY29kZU1vdmVzKG1vdmUubW92ZSwgdGhpcy5zdGF0ZS53aWR0aCwgdGhpcy5zdGF0ZS5oZWlnaHQpWzBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLndpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLmhlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3Bwb25lbnRfY29sb3IsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBpZ25vcmVfcHJvbWlzZSh0aGlzLm1ha2VNb3ZlKHRoaXMuc3RhdGUubW92ZXMubGVuZ3RoKSk7XG4gICAgICAgICAgICAgICAgICAgIC8vdGhpcy5tYWtlTW92ZSh0aGlzLnN0YXRlLm1vdmVzLmxlbmd0aCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy90aGlzLnZlcmJvc2UoXCJJZ25vcmluZyBvdXIgb3duIG1vdmVcIiwgbW92ZS5tb3ZlX251bWJlcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIHNvY2tldC5vbihgZ2FtZS8ke2dhbWVfaWR9L21vdmVgLCBvbl9tb3ZlKTtcbiAgICAgICAgdGhpcy5vbihcImRpc2Nvbm5lY3RpbmdcIiwgKCkgPT4ge1xuICAgICAgICAgICAgc29ja2V0Lm9mZihgZ2FtZS8ke2dhbWVfaWR9L21vdmVgLCBvbl9tb3ZlKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKGNvbmZpZy5sb2dfZ2FtZV9jaGF0KSB7XG4gICAgICAgICAgICBzb2NrZXQuc2VuZChcImNoYXQvam9pblwiLCB7XG4gICAgICAgICAgICAgICAgY2hhbm5lbDogYGdhbWUtJHtnYW1lX2lkfWAsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGNvbnN0IG9uX2NoYXQgPSAoZCkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIFNpbmNlIHRoZXJlIGlzIG5vIGV4cGxpY2l0IHRyYWNraW5nIG9mIHdoaWNoIGNoYXRzIGFyZVxuICAgICAgICAgICAgICAgIC8vIFwicmVhZFwiLCB3ZSBhc3N1bWUgYW55dGhpbmcgZnJvbSBiZWZvcmUgd2UgY29ubmVjdGVkIHRvIHRoZVxuICAgICAgICAgICAgICAgIC8vIGdhbWUgaGFzIGFscmVhZHkgYmVlbiBkZWFsdCB3aXRoLlxuICAgICAgICAgICAgICAgIGhhbmRsZUNoYXRMaW5lKGdhbWVfaWQsIGQubGluZSwgdGhpcy5zdGFydHVwX3RpbWVzdGFtcCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgc29ja2V0Lm9uKGBnYW1lLyR7Z2FtZV9pZH0vY2hhdGAsIG9uX2NoYXQpO1xuICAgICAgICAgICAgdGhpcy5vbihcImRpc2Nvbm5lY3RpbmdcIiwgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHNvY2tldC5vZmYoYGdhbWUvJHtnYW1lX2lkfS9jaGF0YCwgb25fY2hhdCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNvY2tldC5zZW5kKFwiZ2FtZS9jb25uZWN0XCIsIHtcbiAgICAgICAgICAgIGdhbWVfaWQ6IGdhbWVfaWQsXG4gICAgICAgICAgICBjaGF0OiBjb25maWcubG9nX2dhbWVfY2hhdCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLypcbiAgICAgICAgdGhpcy5jb25uZWN0X3RpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIGlmICghdGhpcy5zdGF0ZSkge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nKFwiTm8gZ2FtZWRhdGEgYWZ0ZXIgMXMsIHJlcXVlc3RpbmcgYWdhaW5cIik7XG4gICAgICAgICAgICAgICAgdGhpcy5zY2hlZHVsZVJldHJ5KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIDEwMDApO1xuICAgICAgICAqL1xuICAgICAgICB0aGlzLmNvbm5lY3RfdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy53YXJuKFwiTm8gZ2FtZWRhdGEgcmVjZWl2ZWQgYWZ0ZXIgNXMsIHN0aWxsIHdhaXRpbmdcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIDUwMDApO1xuICAgIH1cblxuICAgIC8vIFJlbGVhc2UgdGhlIGJvdCB0byB0aGUgcG9vbC4gQmVjYXVzZSB3ZSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgU1RERVJSIG91dHB1dFxuICAgIC8vIGNvbWluZyBmcm9tIGEgYm90IHNob3J0bHkgYWZ0ZXIgaXQncyBtYWRlIGEgbW92ZSwgd2UgZG9uJ3QgcmVsZWFzZSBpdCByaWdodFxuICAgIC8vIGF3YXkgd2hlbiB0aGlzIGlzIGNhbGxlZC5cbiAgICByZWxlYXNlQm90cyhmaW5hbF9yZWxlYXNlOiBib29sZWFuID0gZmFsc2UpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgcHJvbWlzZXM6IFByb21pc2U8dm9pZD5bXSA9IFtdO1xuXG4gICAgICAgIHRoaXMudmVyYm9zZShcIlJlbGVhc2luZyBib3QocylcIik7XG4gICAgICAgIHRoaXMudmVyYm9zZShcIkJvdCBjb3VudCBhdmFpbGFibGU6IFwiICsgYm90X3Bvb2xzLm1haW4uY291bnRBdmFpbGFibGUoKSk7XG5cbiAgICAgICAgaWYgKHRoaXMuYm90KSB7XG4gICAgICAgICAgICBjb25zdCBib3QgPSB0aGlzLmJvdDtcbiAgICAgICAgICAgIHRoaXMuYm90ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgY29uc3QgdXNpbmdfb3BlbmluZ19ib3QgPSB0aGlzLnVzaW5nX29wZW5pbmdfYm90O1xuICAgICAgICAgICAgcHJvbWlzZXMucHVzaChcbiAgICAgICAgICAgICAgICBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgX3JlamVjdCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIldpbGwgcmVsZWFzZSBib3RzIGluIFwiLCBib3QuYm90X2NvbmZpZy5yZWxlYXNlX2RlbGF5LCBcIm1zXCIpO1xuICAgICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJSZWxlYXNpbmcgYm90XCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdC5vZmYoXCJjaGF0XCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh1c2luZ19vcGVuaW5nX2JvdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIlJlbGVhc2luZyBvcGVuaW5nIGJvdFwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm90X3Bvb2xzLm9wZW5pbmcucmVsZWFzZShib3QpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiUmVsZWFzaW5nIG1haW4gYm90XCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3RfcG9vbHMubWFpbi5yZWxlYXNlKGJvdCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJyZWxlYXNlZCwgQm90IGNvdW50IGF2YWlsYWJsZTogXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdF9wb29scy5tYWluLmNvdW50QXZhaWxhYmxlKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgcmVsZWFzaW5nIGJvdFwiLCBlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSwgYm90LmJvdF9jb25maWcucmVsZWFzZV9kZWxheSk7XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuZW5kaW5nX2JvdCkge1xuICAgICAgICAgICAgY29uc3QgZW5kaW5nX2JvdCA9IHRoaXMuZW5kaW5nX2JvdDtcbiAgICAgICAgICAgIHRoaXMuZW5kaW5nX2JvdCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHByb21pc2VzLnB1c2goXG4gICAgICAgICAgICAgICAgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIF9yZWplY3QpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbmRpbmdfYm90Lm9mZihcImNoYXRcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICBib3RfcG9vbHMuZW5kaW5nLnJlbGVhc2UoZW5kaW5nX2JvdCk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgICAgIH0sIGVuZGluZ19ib3QuYm90X2NvbmZpZy5yZWxlYXNlX2RlbGF5KTtcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwocHJvbWlzZXMpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgaWYgKGZpbmFsX3JlbGVhc2UpIHtcbiAgICAgICAgICAgICAgICBib3RfcG9vbHMubWFpbi5jbGVhckxhc3RHYW1lSWQodGhpcy5nYW1lX2lkKTtcbiAgICAgICAgICAgICAgICBib3RfcG9vbHMub3BlbmluZz8uY2xlYXJMYXN0R2FtZUlkKHRoaXMuZ2FtZV9pZCk7XG4gICAgICAgICAgICAgICAgYm90X3Bvb2xzLmVuZGluZz8uY2xlYXJMYXN0R2FtZUlkKHRoaXMuZ2FtZV9pZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGFzeW5jIGFjcXVpcmVCb3RzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5ib3QgJiYgdGhpcy5ib3QuZGVhZCkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5yZWxlYXNlQm90cygpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuYm90KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJhY3F1aXJlQm90cyBjYWxsZWQgYnV0IGJvdCBhbHJlYWR5IGFjcXVpcmVkXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuYm90X2ZhaWx1cmVzID49IDUpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgYm90IGtlZXBzIG9uIGZhaWxpbmcsIGdpdmUgdXAgb24gdGhlIGdhbWUuXG4gICAgICAgICAgICB0aGlzLmxvZyhcIkJvdCBoYXMgY3Jhc2hlZCB0b28gbWFueSB0aW1lcywgcmVzaWduaW5nIGdhbWVcIik7XG4gICAgICAgICAgICB0aGlzLnNlbmRDaGF0KFwiQm90IGhhcyBjcmFzaGVkIHRvbyBtYW55IHRpbWVzLCByZXNpZ25pbmcgZ2FtZVwiKTsgLy8gd2Ugbm90aWZ5IHVzZXIgb2YgdGhpcyBpbiBpbi1nYW1lIGNoYXRcbiAgICAgICAgICAgIHNvY2tldC5zZW5kKFwiZ2FtZS9yZXNpZ25cIiwge1xuICAgICAgICAgICAgICAgIGdhbWVfaWQ6IHRoaXMuZ2FtZV9pZCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQm90IGhhcyBjcmFzaGVkIHRvbyBtYW55IHRpbWVzLCByZXNpZ25pbmcgZ2FtZVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIGNvbmZpZy5vcGVuaW5nX2JvdCAmJlxuICAgICAgICAgICAgY29uZmlnLm9wZW5pbmdfYm90Lm51bWJlcl9vZl9vcGVuaW5nX21vdmVzX3RvX3BsYXkgPj0gdGhpcy5zdGF0ZS5tb3Zlcy5sZW5ndGhcbiAgICAgICAgKSB7XG4gICAgICAgICAgICB0aGlzLnZlcmJvc2UoXCJBY3F1aXJpbmcgb3BlbmluZyBib3QgaW5zdGFuY2VcIik7XG4gICAgICAgICAgICB0aGlzLmJvdCA9IGF3YWl0IGJvdF9wb29scy5vcGVuaW5nLmFjcXVpcmUoXG4gICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS50aW1lX2NvbnRyb2wuc3BlZWQsXG4gICAgICAgICAgICAgICAgcGFyc2VJbnQodGhpcy5zdGF0ZS53aWR0aC50b1N0cmluZygpKSxcbiAgICAgICAgICAgICAgICBwYXJzZUludCh0aGlzLnN0YXRlLmhlaWdodC50b1N0cmluZygpKSxcbiAgICAgICAgICAgICAgICBwYXJzZUludCh0aGlzLnN0YXRlLmdhbWVfaWQudG9TdHJpbmcoKSksXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy51c2luZ19vcGVuaW5nX2JvdCA9IHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnZlcmJvc2UoXCJBY3F1aXJpbmcgbWFpbiBib3QgaW5zdGFuY2VcIik7XG4gICAgICAgICAgICB0aGlzLmJvdCA9IGF3YWl0IGJvdF9wb29scy5tYWluLmFjcXVpcmUoXG4gICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS50aW1lX2NvbnRyb2wuc3BlZWQsXG4gICAgICAgICAgICAgICAgcGFyc2VJbnQodGhpcy5zdGF0ZS53aWR0aC50b1N0cmluZygpKSxcbiAgICAgICAgICAgICAgICBwYXJzZUludCh0aGlzLnN0YXRlLmhlaWdodC50b1N0cmluZygpKSxcbiAgICAgICAgICAgICAgICBwYXJzZUludCh0aGlzLnN0YXRlLmdhbWVfaWQudG9TdHJpbmcoKSksXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy51c2luZ19vcGVuaW5nX2JvdCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuYm90LnNldEdhbWUodGhpcyk7XG4gICAgICAgIHRoaXMuYm90LnZlcmJvc2UoYFtnYW1lICR7dGhpcy5nYW1lX2lkfV0gQWNxdWlyZWQgYm90IGluc3RhbmNlYCk7XG4gICAgICAgIHRoaXMuYm90Lm9uKFwiY2hhdFwiLCAobWVzc2FnZSwgY2hhbm5lbCkgPT5cbiAgICAgICAgICAgIHRoaXMuc2VuZENoYXQobWVzc2FnZSwgdGhpcy5zdGF0ZS5tb3Zlcy5sZW5ndGggKyAxLCBjaGFubmVsKSxcbiAgICAgICAgKTtcblxuICAgICAgICAvL3RoaXMuYm90LmxvZyhgW2dhbWUgJHt0aGlzLmdhbWVfaWR9XSBMb2FkaW5nIHN0YXRlYCk7XG4gICAgICAgIGF3YWl0IHRoaXMuYm90LmxvYWRTdGF0ZSh0aGlzLnN0YXRlKTtcbiAgICAgICAgLy90aGlzLmJvdC52ZXJib3NlKGBbZ2FtZSAke3RoaXMuZ2FtZV9pZH1dIFN0YXRlIGxvYWRlZCBzdWNjZXNzZnVsbHlgKTtcblxuICAgICAgICBpZiAoY29uZmlnLmVuZGluZ19ib3Q/LmNvbW1hbmQpIHtcbiAgICAgICAgICAgIGNvbnN0IG1vdmVfdG9fc3RhcnRfY2hlY2tpbmdfZW5kaW5nX2JvdCA9IE1hdGguY2VpbChcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXRlLndpZHRoICpcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS5oZWlnaHQgKlxuICAgICAgICAgICAgICAgICAgICBjb25maWcuZW5kaW5nX2JvdC5tb3Zlc190b19hbGxvd19iZWZvcmVfY2hlY2tpbmdfcmF0aW8sXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5tb3Zlcy5sZW5ndGggPj0gbW92ZV90b19zdGFydF9jaGVja2luZ19lbmRpbmdfYm90KSB7XG4gICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlKFxuICAgICAgICAgICAgICAgICAgICBgW2dhbWUgJHt0aGlzLmdhbWVfaWR9XSBBY3F1aXJpbmcgZW5kaW5nIGJvdDogJHt0aGlzLnN0YXRlLm1vdmVzLmxlbmd0aH0gbW92ZXMgcGxheWVkIG91dCBvZiAke21vdmVfdG9fc3RhcnRfY2hlY2tpbmdfZW5kaW5nX2JvdH0gbmVjZXNzYXJ5IHRvIGJlZ2luIGNvbnN1bHRpbmcgZW5kaW5nIGJvdGAsXG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIHRoaXMuZW5kaW5nX2JvdCA9IGF3YWl0IGJvdF9wb29scy5lbmRpbmcuYWNxdWlyZShcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zdGF0ZS50aW1lX2NvbnRyb2wuc3BlZWQsXG4gICAgICAgICAgICAgICAgICAgIHBhcnNlSW50KHRoaXMuc3RhdGUud2lkdGgudG9TdHJpbmcoKSksXG4gICAgICAgICAgICAgICAgICAgIHBhcnNlSW50KHRoaXMuc3RhdGUuaGVpZ2h0LnRvU3RyaW5nKCkpLFxuICAgICAgICAgICAgICAgICAgICBwYXJzZUludCh0aGlzLnN0YXRlLmdhbWVfaWQudG9TdHJpbmcoKSksXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVuZGluZ19ib3QudmVyYm9zZShgW2dhbWUgJHt0aGlzLmdhbWVfaWR9XSBBY3F1aXJlZCByZXNpZ24gYm90IGluc3RhbmNlYCk7XG4gICAgICAgICAgICAgICAgdGhpcy5lbmRpbmdfYm90LnNldEdhbWUodGhpcyk7XG5cbiAgICAgICAgICAgICAgICAvL3RoaXMuZW5kaW5nX2JvdC5sb2coYFtnYW1lICR7dGhpcy5nYW1lX2lkfV0gTG9hZGluZyBzdGF0ZWApO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuZW5kaW5nX2JvdC5sb2FkU3RhdGUodGhpcy5zdGF0ZSk7XG4gICAgICAgICAgICAgICAgLy90aGlzLmVuZGluZ19ib3QudmVyYm9zZShgW2dhbWUgJHt0aGlzLmdhbWVfaWR9XSBTdGF0ZSBsb2FkZWQgc3VjY2Vzc2Z1bGx5YCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMudmVyYm9zZShcbiAgICAgICAgICAgICAgICAgICAgYFtnYW1lICR7dGhpcy5nYW1lX2lkfV0gTm90IHN0YXJ0aW5nIGVuZGluZyBib3QgeWV0LCBvbmx5ICR7dGhpcy5zdGF0ZS5tb3Zlcy5sZW5ndGh9IG1vdmVzIHBsYXllZCwgbG9va2luZyBmb3IgJHttb3ZlX3RvX3N0YXJ0X2NoZWNraW5nX2VuZGluZ19ib3R9YCxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gU2VuZCBAY21kIHRvIGJvdCBhbmQgY2FsbCBAY2Igd2l0aCByZXR1cm5lZCBtb3Zlcy5cbiAgICAvL1xuICAgIGFzeW5jIGdldEJvdE1vdmVzKGNtZCk6IFByb21pc2U8TW92ZVtdPiB7XG4gICAgICAgICsrR2FtZS5tb3Zlc19wcm9jZXNzaW5nO1xuICAgICAgICB0aGlzLnByb2Nlc3NpbmcgPSB0cnVlO1xuXG4gICAgICAgIGNvbnN0IGRvbmVQcm9jZXNzaW5nID0gKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5wcm9jZXNzaW5nID0gZmFsc2U7XG4gICAgICAgICAgICAtLUdhbWUubW92ZXNfcHJvY2Vzc2luZztcbiAgICAgICAgfTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5hY3F1aXJlQm90cygpO1xuXG4gICAgICAgICAgICB0aGlzLmJvdC52ZXJib3NlKFwiR2VuZXJhdGluZyBtb3ZlIGZvciBnYW1lXCIsIHRoaXMuZ2FtZV9pZCk7XG4gICAgICAgICAgICB0aGlzLmxvZyhjbWQpO1xuXG4gICAgICAgICAgICBjb25zdCBbb3VyX21vdmVzLCBlbmRfbW92ZXNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgICAgIHRoaXMuYm90LmdldE1vdmVzKGNtZCwgdGhpcy5zdGF0ZSksXG4gICAgICAgICAgICAgICAgdGhpcy5lbmRpbmdfYm90Py5nZXRNb3ZlcyhjbWQsIHRoaXMuc3RhdGUpLFxuICAgICAgICAgICAgXSk7XG5cbiAgICAgICAgICAgIC8qXG4gICAgICAgICAgICB0aGlzLnZlcmJvc2UoXG4gICAgICAgICAgICAgICAgYE91ciBtb3ZlczogJHtKU09OLnN0cmluZ2lmeShvdXJfbW92ZXMpfSAgUmVzaWduIGJvdDogJHtKU09OLnN0cmluZ2lmeShlbmRfbW92ZXMpfWAsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgKi9cblxuICAgICAgICAgICAgY29uc3QgZW5kYm90X3Bhc3MgPSBlbmRfbW92ZXMgJiYgZW5kX21vdmVzLmxlbmd0aCA+IDAgJiYgZW5kX21vdmVzWzBdLnBhc3M7XG4gICAgICAgICAgICBjb25zdCBlbmRib3RfcmVzaWduID0gZW5kX21vdmVzICYmIGVuZF9tb3Zlcy5sZW5ndGggPiAwICYmIGVuZF9tb3Zlc1swXS5yZXNpZ247XG5cbiAgICAgICAgICAgIGlmIChlbmRib3RfcmVzaWduKSB7XG4gICAgICAgICAgICAgICAgKyt0aGlzLmVuZGJvdF9yZXNpZ25fY291bnQ7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgICAgICAgICAgIGBPdXIgcmVzaWduIGJvdCBoYXMgaW5kaWNhdGVkIHdlIHNob3VsZCByZXNpZ24gJHt0aGlzLmVuZGJvdF9yZXNpZ25fY291bnR9IGAgK1xuICAgICAgICAgICAgICAgICAgICAgICAgYHRpbWVzIGluIGEgcm93LCBvdXIgdGhyZXNob2xkIGlzICR7Y29uZmlnLmVuZGluZ19ib3QuYWxsb3dlZF9yZXNpZ25zfWAsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lbmRib3RfcmVzaWduX2NvdW50ID0gMDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZG9uZVByb2Nlc3NpbmcoKTtcbiAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKHRoaXMucmVsZWFzZUJvdHMoKSk7XG5cbiAgICAgICAgICAgIHJldHVybiBlbmRfbW92ZXMgJiZcbiAgICAgICAgICAgICAgICAoZW5kYm90X3Bhc3MgfHwgdGhpcy5lbmRib3RfcmVzaWduX2NvdW50ID49IGNvbmZpZy5lbmRpbmdfYm90Py5hbGxvd2VkX3Jlc2lnbnMpXG4gICAgICAgICAgICAgICAgPyBlbmRfbW92ZXNcbiAgICAgICAgICAgICAgICA6IG91cl9tb3ZlcztcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgZG9uZVByb2Nlc3NpbmcoKTtcbiAgICAgICAgICAgIGlnbm9yZV9wcm9taXNlKHRoaXMucmVsZWFzZUJvdHMoKSk7XG5cbiAgICAgICAgICAgIHRoaXMuZXJyb3IoXCJGYWlsZWQgdG8gc3RhcnQgdGhlIGJvdCwgY2FuIG5vdCBtYWtlIGEgbW92ZSwgdHJ5aW5nIHRvIHJlc3RhcnRcIik7XG4gICAgICAgICAgICB0aGlzLmVycm9yKGUpO1xuICAgICAgICAgICAgdGhpcy5zZW5kQ2hhdChcIkZhaWxlZCB0byBzdGFydCB0aGUgYm90LCBjYW4gbm90IG1ha2UgYSBtb3ZlLCB0cnlpbmcgdG8gcmVzdGFydDogXCIgKyBlKTsgLy8gd2Ugbm90aWZ5IHVzZXIgb2YgdGhpcyBpbiBpbi1nYW1lIGNoYXRcbiAgICAgICAgICAgIHRocm93IGU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzY2hlZHVsZVJldHJ5KCk6IHZvaWQge1xuICAgICAgICB0aGlzLnZlcmJvc2UoXG4gICAgICAgICAgICBcIlVuYWJsZSB0byByZWFjdCBjb3JyZWN0bHkgLSByZS1jb25uZWN0IHRvIHRyaWdnZXIgYWN0aW9uIGJhc2VkIG9uIGdhbWUgc3RhdGUuXCIsXG4gICAgICAgICk7XG4gICAgICAgIHNvY2tldC5zZW5kKFwiZ2FtZS9kaXNjb25uZWN0XCIsIHtcbiAgICAgICAgICAgIGdhbWVfaWQ6IHRoaXMuZ2FtZV9pZCxcbiAgICAgICAgfSk7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgc29ja2V0LnNlbmQoXCJnYW1lL2Nvbm5lY3RcIiwge1xuICAgICAgICAgICAgICAgIGdhbWVfaWQ6IHRoaXMuZ2FtZV9pZCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LCA1MDApO1xuICAgIH1cbiAgICAvLyBTZW5kIG1vdmUgdG8gc2VydmVyLlxuICAgIC8vXG4gICAgdXBsb2FkTW92ZShtb3ZlOiBNb3ZlKTogdm9pZCB7XG4gICAgICAgIGlmIChtb3ZlLnJlc2lnbikge1xuICAgICAgICAgICAgdGhpcy5sb2coXCJSZXNpZ25pbmdcIik7XG4gICAgICAgICAgICBzb2NrZXQuc2VuZChcImdhbWUvcmVzaWduXCIsIHtcbiAgICAgICAgICAgICAgICBnYW1lX2lkOiB0aGlzLmdhbWVfaWQsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjb25maWcudmVyYm9zaXR5KSB7XG4gICAgICAgICAgICB0aGlzLnZlcmJvc2UoYFBsYXlpbmcgJHttb3ZlLnRleHR9YCwgbW92ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmxvZyhgUGxheWluZyAke21vdmUudGV4dH1gKTtcbiAgICAgICAgfVxuICAgICAgICBzb2NrZXQuc2VuZChcImdhbWUvbW92ZVwiLCB7XG4gICAgICAgICAgICBnYW1lX2lkOiB0aGlzLmdhbWVfaWQsXG4gICAgICAgICAgICBtb3ZlOiBlbmNvZGVNb3ZlKG1vdmUpLFxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBHZXQgbW92ZSBmcm9tIGJvdCBhbmQgdXBsb2FkIHRvIHNlcnZlci5cbiAgICAvLyBIYW5kbGUgaGFuZGljYXAgc3RvbmVzIHdpdGggYm90IGFzIGJsYWNrIHRyYW5zcGFyZW50bHlcbiAgICAvLyAod2UgZ2V0IGFsbCBvZiB0aGVtIGF0IG9uY2Ugd2l0aCBwbGFjZV9mcmVlX2hhbmRpY2FwKS5cbiAgICAvL1xuICAgIGFzeW5jIG1ha2VNb3ZlKG1vdmVfbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghdGhpcy5zdGF0ZSB8fCB0aGlzLnN0YXRlLm1vdmVzLmxlbmd0aCAhPT0gbW92ZV9udW1iZXIpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5waGFzZSAhPT0gXCJwbGF5XCIpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMuZ3JlZXRlZCAmJiB0aGlzLnN0YXRlLm1vdmVzLmxlbmd0aCA8IDIgKyB0aGlzLnN0YXRlLmhhbmRpY2FwKSB7XG4gICAgICAgICAgICB0aGlzLmdyZWV0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgaWYgKGNvbmZpZy5ncmVldGluZz8uZW4pIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRDaGF0KGNvbmZpZy5ncmVldGluZyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoY29uZmlnLmVuZ2luZSkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2VuZENoYXQoeyBlbjogYEVuZ2luZTogJHtjb25maWcuZW5naW5lfWAsIGVuZ2luZTogY29uZmlnLmVuZ2luZSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRvaW5nX2hhbmRpY2FwID1cbiAgICAgICAgICAgIHRoaXMuc3RhdGUuZnJlZV9oYW5kaWNhcF9wbGFjZW1lbnQgJiZcbiAgICAgICAgICAgIHRoaXMuc3RhdGUuaGFuZGljYXAgPiAxICYmXG4gICAgICAgICAgICB0aGlzLnN0YXRlLm1vdmVzLmxlbmd0aCA8IHRoaXMuc3RhdGUuaGFuZGljYXA7XG5cbiAgICAgICAgaWYgKCFkb2luZ19oYW5kaWNhcCkge1xuICAgICAgICAgICAgLy8gUmVndWxhciBnZW5tb3ZlIC4uLlxuICAgICAgICAgICAgY29uc3QgbW92ZV9zdGFydCA9IERhdGUubm93KCk7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IG1vdmVzID0gYXdhaXQgdGhpcy5nZXRCb3RNb3ZlcyhgZ2VubW92ZSAke3RoaXMubXlfY29sb3J9YCk7XG4gICAgICAgICAgICAgICAgY29uc3QgbW92ZV9lbmQgPSBEYXRlLm5vdygpO1xuICAgICAgICAgICAgICAgIGNvbnN0IG1vdmVfdGltZSA9IG1vdmVfZW5kIC0gbW92ZV9zdGFydDtcbiAgICAgICAgICAgICAgICBpZiAoY29uZmlnLm1pbl9tb3ZlX3RpbWUgJiYgbW92ZV90aW1lIDwgY29uZmlnLm1pbl9tb3ZlX3RpbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy52ZXJib3NlKFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJNaW4gbW92ZSB0aW1lIHdhcyBcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5taW5fbW92ZV90aW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJtcyBhbmQgd2Ugb25seSB0b29rIFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgbW92ZV90aW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJtcy4gV2FpdGluZyBcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5taW5fbW92ZV90aW1lIC0gbW92ZV90aW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJtcyBiZWZvcmUgc2VuZGluZyBtb3ZlXCIsXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy51cGxvYWRNb3ZlKG1vdmVzWzBdKTtcbiAgICAgICAgICAgICAgICAgICAgfSwgY29uZmlnLm1pbl9tb3ZlX3RpbWUgLSBtb3ZlX3RpbWUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudXBsb2FkTW92ZShtb3Zlc1swXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIHRoaXMuZXJyb3IoZSk7XG4gICAgICAgICAgICAgICAgdGhpcy5zY2hlZHVsZVJldHJ5KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBbHJlYWR5IGhhdmUgaGFuZGljYXAgc3RvbmVzID8gUmV0dXJuIG5leHQgb25lLlxuICAgICAgICBpZiAodGhpcy5oYW5kaWNhcF9tb3Zlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRoaXMudXBsb2FkTW92ZSh0aGlzLmhhbmRpY2FwX21vdmVzLnNoaWZ0KCkpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgd2FybkFuZFJlc2lnbiA9IChtc2cpID0+IHtcbiAgICAgICAgICAgIHRoaXMubG9nKG1zZyk7XG4gICAgICAgICAgICBpZ25vcmVfcHJvbWlzZSh0aGlzLnJlbGVhc2VCb3RzKCkpO1xuICAgICAgICAgICAgdGhpcy51cGxvYWRNb3ZlKHsgcmVzaWduOiB0cnVlIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEdldCBoYW5kaWNhcCBzdG9uZXMgZnJvbSBib3QgYW5kIHJldHVybiBmaXJzdCBvbmUuXG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IG1vdmVzID0gYXdhaXQgdGhpcy5nZXRCb3RNb3ZlcyhgcGxhY2VfZnJlZV9oYW5kaWNhcCAke3RoaXMuc3RhdGUuaGFuZGljYXB9YCk7XG4gICAgICAgICAgICBpZiAobW92ZXMubGVuZ3RoICE9PSB0aGlzLnN0YXRlLmhhbmRpY2FwKSB7XG4gICAgICAgICAgICAgICAgLy8gU2FuaXR5IGNoZWNrXG4gICAgICAgICAgICAgICAgd2FybkFuZFJlc2lnbihcbiAgICAgICAgICAgICAgICAgICAgXCJwbGFjZV9mcmVlX2hhbmRpY2FwIHJldHVybmVkIHdyb25nIG51bWJlciBvZiBoYW5kaWNhcCBzdG9uZXMsIHJlc2lnbmluZy5cIixcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAoY29uc3QgaSBpbiBtb3Zlcykge1xuICAgICAgICAgICAgICAgIC8vIFNhbml0eSBjaGVja1xuICAgICAgICAgICAgICAgIGlmIChtb3Zlc1tpXS5wYXNzIHx8IG1vdmVzW2ldLnggPCAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHdhcm5BbmRSZXNpZ24oXCJwbGFjZV9mcmVlX2hhbmRpY2FwIHJldHVybmVkIGEgcGFzcywgcmVzaWduaW5nLlwiKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuaGFuZGljYXBfbW92ZXMgPSBtb3ZlcztcbiAgICAgICAgICAgIHRoaXMudXBsb2FkTW92ZSh0aGlzLmhhbmRpY2FwX21vdmVzLnNoaWZ0KCkpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICB0aGlzLmVycm9yKGUpO1xuICAgICAgICAgICAgdGhpcy5zY2hlZHVsZVJldHJ5KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBkaXNjb25uZWN0KCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5wcm9jZXNzaW5nKSB7XG4gICAgICAgICAgICB0aGlzLnByb2Nlc3NpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIC0tR2FtZS5tb3Zlc19wcm9jZXNzaW5nO1xuICAgICAgICB9XG5cbiAgICAgICAgaWdub3JlX3Byb21pc2UodGhpcy5yZWxlYXNlQm90cyh0cnVlKSk7XG5cbiAgICAgICAgdGhpcy5sb2coXCJEaXNjb25uZWN0aW5nIGZyb20gZ2FtZS5cIik7XG4gICAgICAgIGlmIChzb2NrZXQuY29ubmVjdGVkKSB7XG4gICAgICAgICAgICBzb2NrZXQuc2VuZChcImdhbWUvZGlzY29ubmVjdFwiLCB7XG4gICAgICAgICAgICAgICAgZ2FtZV9pZDogdGhpcy5nYW1lX2lkLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5lbWl0KFwiZGlzY29ubmVjdGluZ1wiKTtcbiAgICB9XG4gICAgZ2V0UmVzKHJlc3VsdCk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IG0gPSB0aGlzLnN0YXRlLm91dGNvbWUubWF0Y2goLyguKikgcG9pbnRzLyk7XG4gICAgICAgIGlmIChtKSB7XG4gICAgICAgICAgICByZXR1cm4gbVsxXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyZXN1bHQgPT09IFwiUmVzaWduYXRpb25cIikge1xuICAgICAgICAgICAgcmV0dXJuIFwiUlwiO1xuICAgICAgICB9XG4gICAgICAgIGlmIChyZXN1bHQgPT09IFwiQ2FuY2VsbGF0aW9uXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBcIkNhblwiO1xuICAgICAgICB9XG4gICAgICAgIGlmIChyZXN1bHQgPT09IFwiVGltZW91dFwiKSB7XG4gICAgICAgICAgICByZXR1cm4gXCJUaW1lXCI7XG4gICAgICAgIH1cbiAgICB9XG4gICAgYXN5bmMgZ2FtZU92ZXIoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmIChjb25maWcuZmFyZXdlbGwgJiYgdGhpcy5zdGF0ZSkge1xuICAgICAgICAgICAgdGhpcy5zZW5kQ2hhdChjb25maWcuZmFyZXdlbGwpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRGlzcGxheSByZXN1bHRcbiAgICAgICAgY29uc3QgY29sID0gdGhpcy5zdGF0ZS53aW5uZXIgPT09IHRoaXMuc3RhdGUucGxheWVycy5ibGFjay5pZCA/IFwiQlwiIDogXCJXXCI7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGAke3RoaXMuc3RhdGUub3V0Y29tZVswXS50b1VwcGVyQ2FzZSgpfSR7dGhpcy5zdGF0ZS5vdXRjb21lLnN1YnN0cigxKX1gO1xuICAgICAgICBjb25zdCByZXMgPSB0aGlzLmdldFJlcyhyZXN1bHQpO1xuICAgICAgICBjb25zdCB3aW5sb3NzID0gdGhpcy5zdGF0ZS53aW5uZXIgPT09IGNvbmZpZy5ib3RfaWQgPyBcIldcIiA6IFwiTFwiO1xuICAgICAgICB0aGlzLmxvZyhgR2FtZSBvdmVyLiAgIFJlc3VsdDogJHtjb2x9KyR7cmVzfSAgJHt3aW5sb3NzfWApO1xuXG4gICAgICAgIC8vIE5vdGlmeSBib3Qgb2YgZW5kIG9mIGdhbWUgYW5kIHNlbmQgc2NvcmVcbiAgICAgICAgaWYgKGNvbmZpZy5mYXJld2VsbHNjb3JlICYmIHRoaXMuYm90KSB7XG4gICAgICAgICAgICBjb25zdCBzY29yZSA9IGF3YWl0IHRoaXMuYm90LmNvbW1hbmQoXCJmaW5hbF9zY29yZVwiLCB0cnVlKTsgLy8gYWxsb3cgYm90IHRvIHByb2Nlc3MgZW5kIG9mIGdhbWVcbiAgICAgICAgICAgIGlmIChzY29yZSkge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nKGBCb3QgdGhpbmtzIHRoZSBzY29yZSB3YXMgJHtzY29yZX1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChyZXMgIT09IFwiUlwiICYmIHJlcyAhPT0gXCJUaW1lXCIgJiYgcmVzICE9PSBcIkNhblwiKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kQ2hhdChgRmluYWwgc2NvcmUgd2FzICR7c2NvcmV9IGFjY29yZGluZyB0byB0aGUgYm90LmApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmJvdCkge1xuICAgICAgICAgICAgLy90aGlzLmJvdC5nYW1lT3ZlcigpO1xuICAgICAgICAgICAgLy90aGlzLmVuZGluZ19ib3Q/LmdhbWVPdmVyKCk7XG4gICAgICAgICAgICBpZ25vcmVfcHJvbWlzZSh0aGlzLnJlbGVhc2VCb3RzKHRydWUpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdGhpcy5kaXNjb25uZWN0X3RpbWVvdXQpIHtcbiAgICAgICAgICAgIHRoaXMudmVyYm9zZShgU3RhcnRpbmcgZGlzY29ubmVjdCBUaW1lb3V0IGluIEdhbWUgJHt0aGlzLmdhbWVfaWR9IGdhbWVPdmVyKClgKTtcbiAgICAgICAgICAgIHRoaXMuZGlzY29ubmVjdF90aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0KFwiZGlzY29ubmVjdGVkXCIsIHRoaXMuZ2FtZV9pZCk7XG4gICAgICAgICAgICB9LCAxMDAwKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBoZWFkZXIoKTogc3RyaW5nIHtcbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYm90SXNCbGFjayA9IHRoaXMuc3RhdGUucGxheWVycy5ibGFjay51c2VybmFtZSA9PT0gY29uZmlnLnVzZXJuYW1lO1xuICAgICAgICBjb25zdCBjb2xvciA9IGJvdElzQmxhY2sgPyBcIiAgQlwiIDogXCJXICBcIjsgLy8gUGxheWluZyBibGFjayAvIHdoaXRlIGFnYWluc3QgLi4uXG4gICAgICAgIGNvbnN0IHBsYXllciA9IGJvdElzQmxhY2sgPyB0aGlzLnN0YXRlLnBsYXllcnMud2hpdGUgOiB0aGlzLnN0YXRlLnBsYXllcnMuYmxhY2s7XG4gICAgICAgIGNvbnN0IGhhbmRpY2FwID0gdGhpcy5zdGF0ZSAmJiB0aGlzLnN0YXRlLmhhbmRpY2FwID8gYEgke3RoaXMuc3RhdGUuaGFuZGljYXB9YCA6IFwiICBcIjtcbiAgICAgICAgcmV0dXJuIGAke2NvbG9yfSAke3BsYXllci51c2VybmFtZX0gIFske3RoaXMuc3RhdGUud2lkdGh9eCR7dGhpcy5zdGF0ZS5oZWlnaHR9XSAgJHtoYW5kaWNhcH1gO1xuICAgIH1cbiAgICBzZW5kQ2hhdChcbiAgICAgICAgbXNnOiBzdHJpbmcgfCBUcmFuc2xhdGFibGVTdHJpbmcgfCBwcm90b2NvbC5HYW1lQ2hhdEFuYWx5c2lzTWVzc2FnZSxcbiAgICAgICAgbW92ZV9udW1iZXI/OiBudW1iZXIsXG4gICAgICAgIGNoYW5uZWw6IFwibWFpblwiIHwgXCJtYWxrb3ZpY2hcIiA9IFwibWFpblwiLFxuICAgICk6IHZvaWQge1xuICAgICAgICBpZiAoIXNvY2tldC5jb25uZWN0ZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgbXNnID09PSBcIm9iamVjdFwiICYmIFwiZW5cIiBpbiBtc2cpIHtcbiAgICAgICAgICAgIG1zZy50eXBlID0gXCJ0cmFuc2xhdGVkXCI7XG4gICAgICAgIH1cblxuICAgICAgICBzb2NrZXQuc2VuZChcImdhbWUvY2hhdFwiLCB7XG4gICAgICAgICAgICBnYW1lX2lkOiB0aGlzLmdhbWVfaWQsXG4gICAgICAgICAgICBib2R5OiBtc2cgYXMgYW55LFxuICAgICAgICAgICAgbW92ZV9udW1iZXI6IG1vdmVfbnVtYmVyLFxuICAgICAgICAgICAgdHlwZTogY2hhbm5lbCxcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHJlc3VtZUdhbWUoKTogdm9pZCB7XG4gICAgICAgIHNvY2tldC5zZW5kKFwiZ2FtZS9yZXN1bWVcIiwge1xuICAgICAgICAgICAgZ2FtZV9pZDogdGhpcy5nYW1lX2lkLFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgZ2V0T3Bwb25lbnQoKSB7XG4gICAgICAgIGNvbnN0IHBsYXllciA9XG4gICAgICAgICAgICB0aGlzLnN0YXRlLnBsYXllcnMud2hpdGUuaWQgPT09IGNvbmZpZy5ib3RfaWRcbiAgICAgICAgICAgICAgICA/IHRoaXMuc3RhdGUucGxheWVycy5ibGFja1xuICAgICAgICAgICAgICAgIDogdGhpcy5zdGF0ZS5wbGF5ZXJzLndoaXRlO1xuICAgICAgICByZXR1cm4gcGxheWVyO1xuICAgIH1cblxuICAgIHByaXZhdGUgY2hlY2tGb3JQYXVzZSgpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgY2xvY2sgPSB0aGlzLnN0YXRlPy5jbG9jaztcblxuICAgICAgICBpZiAodGhpcy51bnBhdXNlX3RpbWVvdXQpIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnVucGF1c2VfdGltZW91dCk7XG4gICAgICAgICAgICB0aGlzLnVucGF1c2VfdGltZW91dCA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghY2xvY2spIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjbG9jay5wYXVzZT8ucGF1c2VkICYmIGNsb2NrLnBhdXNlZF9zaW5jZSkge1xuICAgICAgICAgICAgY29uc3QgcGF1c2VfY29udHJvbCA9IGNsb2NrLnBhdXNlPy5wYXVzZV9jb250cm9sIHx8ICh0aGlzLnN0YXRlIGFzIGFueSkucGF1c2VfY29udHJvbDtcblxuICAgICAgICAgICAgLy8gcGF1c2VfY29udHJvbC5wYXVzZWQgY29tZXMgZnJvbSB0aGUgaHVtYW4gb3Bwb25lbnQsIGFueSBvdGhlciBrZXlzXG4gICAgICAgICAgICAvLyBhcmUgc3lzdGVtIHBhdXNlcywgdmFjYXRpb25zLCBzdG9uZSByZW1vdmFsIHBoYXNlLCB3ZWVrZW5kLCBldGMuXG4gICAgICAgICAgICBpZiAocGF1c2VfY29udHJvbD8ucGF1c2VkICYmIE9iamVjdC5rZXlzKHBhdXNlX2NvbnRyb2wpLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHBhdXNlX2R1cmF0aW9uX3MgPSAoRGF0ZS5ub3coKSAtIGNsb2NrLnBhdXNlZF9zaW5jZSkgLyAxMDAwO1xuICAgICAgICAgICAgICAgIHRoaXMubG9nKFwiQ2xvY2sgaGFzIGJlZW4gcGF1c2VkIGZvciBcIiwgcGF1c2VfZHVyYXRpb25fcywgXCIgc2Vjb25kc1wiKTtcbiAgICAgICAgICAgICAgICBpZiAocGF1c2VfZHVyYXRpb25fcyA+IGNvbmZpZy5tYXhfcGF1c2VfdGltZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNlbmRDaGF0KFwiTWF4aW11bSBwYXVzZSB0aW1lIHJlYWNoZWQsIHVucGF1c2luZyBjbG9ja1wiKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXN1bWVHYW1lKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy51bnBhdXNlX3RpbWVvdXQgPSBzZXRUaW1lb3V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudW5wYXVzZV90aW1lb3V0ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2VuZENoYXQoXCJNYXhpbXVtIHBhdXNlIHRpbWUgcmVhY2hlZCwgdW5wYXVzaW5nIGNsb2NrXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVzdW1lR2FtZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIChjb25maWcubWF4X3BhdXNlX3RpbWUgLSBwYXVzZV9kdXJhdGlvbl9zKSAqIDEwMDAsXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gaGFuZGxlQ2hhdExpbmUoZ2FtZV9pZDogc3RyaW5nLCBsaW5lOiBhbnksIGN1dG9mZl90aW1lc3RhbXA6IG51bWJlcikge1xuICAgIGlmICh0eXBlb2YgbGluZS5ib2R5ICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKGxpbmUudXNlcm5hbWUgPT09IGNvbmZpZy51c2VybmFtZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIEJvdGggYXJlIFVOSVggZXBvY2ggdGltZXMuXG4gICAgaWYgKGxpbmUuZGF0ZSA8IGN1dG9mZl90aW1lc3RhbXApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRyYWNlLmluZm8oYFtnYW1lICR7Z2FtZV9pZH1dIEdhbWUgY2hhdCBmcm9tICR7bGluZS51c2VybmFtZX06ICR7bGluZS5ib2R5fWApO1xufVxuXG5mdW5jdGlvbiBudW0yY2hhcihudW06IG51bWJlcik6IHN0cmluZyB7XG4gICAgaWYgKG51bSA9PT0gLTEpIHtcbiAgICAgICAgcmV0dXJuIFwiLlwiO1xuICAgIH1cbiAgICByZXR1cm4gXCJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5elwiW251bV07XG59XG5mdW5jdGlvbiBlbmNvZGVNb3ZlKG1vdmU6IE1vdmUpOiBzdHJpbmcge1xuICAgIGlmIChtb3ZlW1wieFwiXSA9PT0gLTEpIHtcbiAgICAgICAgcmV0dXJuIFwiLi5cIjtcbiAgICB9XG4gICAgcmV0dXJuIG51bTJjaGFyKG1vdmVbXCJ4XCJdKSArIG51bTJjaGFyKG1vdmVbXCJ5XCJdKTtcbn1cblxuR2FtZS5tb3Zlc19wcm9jZXNzaW5nID0gMDtcbiIsImltcG9ydCB7IGNoYXIybnVtLCBudW0yY2hhciB9IGZyb20gXCJnb2Jhbi1lbmdpbmVcIjtcbi8vaW1wb3J0IHsgZ3RwY2hhcjJudW0gfSBmcm9tIFwiLi9Cb3RcIjtcbmltcG9ydCB7IHByb3RvY29sIH0gZnJvbSBcImdvYmFuLWVuZ2luZVwiO1xuaW1wb3J0IHsgR2FtZSB9IGZyb20gXCIuL0dhbWVcIjtcbmltcG9ydCB7IHRyYWNlIH0gZnJvbSBcIi4vdHJhY2VcIjtcblxudHlwZSBTVVBQT1JURURfRU5HSU5FX1RZUEVTID0gXCJsZWVsYVwiIHwgXCJsZWVsYV96ZXJvXCIgfCBcImthdGFnb1wiIHwgXCJzYWlcIiB8IFwic2FpMThcIiB8IFwicGhvZW5peGdvXCI7XG5cbmludGVyZmFjZSBFbmdpbmVBbmFseXNpcyB7XG4gICAgd2luX3JhdGU6IG51bWJlcjtcbiAgICBzY29yZT86IG51bWJlcjtcbiAgICB2aXNpdHM/OiBudW1iZXI7XG4gICAgW2tleTogc3RyaW5nXTogbnVtYmVyIHwgdW5kZWZpbmVkO1xufVxuXG4vKiogVXRpbGl0eSBjbGFzcyB0byB3b3JrIHdpdGggUHJpbmNpcGxlIFZhcmlhdGlvbnMgKFBWKSBvdXRwdXQgZm9yIGRpZmZlcmVudCBib3RzLiAqL1xuZXhwb3J0IGNsYXNzIFB2T3V0cHV0UGFyc2VyIHtcbiAgICBnYW1lPzogR2FtZTtcbiAgICBsb29raW5nRm9yUHY6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBzYWlTY29yZTogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgZGV0ZWN0ZWRfZW5naW5lPzogU1VQUE9SVEVEX0VOR0lORV9UWVBFUztcbiAgICBkZXRlY3RlZF9wdj86IFJlZ0V4cE1hdGNoQXJyYXk7XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5sb29raW5nRm9yUHYgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zYWlTY29yZSA9IGZhbHNlO1xuICAgIH1cblxuICAgIC8qKiBTY2FucyB0aGUgYm90IG91dHB1dCBmb3IgUFZzIGFuZCBwb3N0cyB0aGVtIHRvIHRoZSBjaGF0LiAqL1xuICAgIHB1YmxpYyBzY2FuQW5kU2VuZEVuZ2luZUFuYWx5c2lzKGdhbWU6IEdhbWUgfCB1bmRlZmluZWQsIGxpbmU6IHN0cmluZykge1xuICAgICAgICB0aGlzLmdhbWUgPSBnYW1lO1xuICAgICAgICBjb25zdCBlbmdpbmUgPSB0aGlzLmRldGVjdGVkX2VuZ2luZTtcbiAgICAgICAgdGhpcy5kZXRlY3RFbmdpbmUobGluZSk7XG4gICAgICAgIGlmICh0aGlzLmRldGVjdGVkX2VuZ2luZSAhPT0gZW5naW5lKSB7XG4gICAgICAgICAgICB0cmFjZS5pbmZvKFwiRGV0ZWN0ZWQgZW5naW5lOiBcIiArIHRoaXMuZGV0ZWN0ZWRfZW5naW5lKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5wcm9jZXNzTGluZShsaW5lKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNoZWNrUG9uZGVyaW5nKCk6IGJvb2xlYW4ge1xuICAgICAgICBpZiAoISh0aGlzLmdhbWU/LnByb2Nlc3NpbmcgfHwgdGhpcy5sb29raW5nRm9yUHYpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmxvb2tpbmdGb3JQdiA9IHRydWU7IC8vIE9uY2Ugd2UgYXJlIHByb2Nlc3NpbmcsIHdlIGNvbnRpbnVlIHRvIGxvb2sgZm9yIHB2IGV2ZW4gYWZ0ZXIgcHJvY2Vzc2luZyBzdG9wcy5cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgY3JlYXRlQW5hbHlzaXNNZXNzYWdlKFxuICAgICAgICBuYW1lOiBzdHJpbmcsXG4gICAgICAgIHB2X21vdmU6IHN0cmluZyxcbiAgICAgICAgZW5naW5lX2FuYWx5c2lzOiBFbmdpbmVBbmFseXNpcyxcbiAgICApOiBwcm90b2NvbC5HYW1lQ2hhdEFuYWx5c2lzTWVzc2FnZSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0eXBlOiBcImFuYWx5c2lzXCIsXG4gICAgICAgICAgICBlbmdpbmVfYW5hbHlzaXM6IGVuZ2luZV9hbmFseXNpcyxcbiAgICAgICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgICAgICBmcm9tOiB0aGlzLmdhbWU/LnN0YXRlLm1vdmVzLmxlbmd0aCB8fCAwLFxuICAgICAgICAgICAgbW92ZXM6IHB2X21vdmUsXG4gICAgICAgICAgICBtYXJrczogeyBjaXJjbGU6IHB2X21vdmUuc3Vic3RyaW5nKDAsIDIpIH0sXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqIFRha2VzIG1vdmVzIGxpa2UgXCJBMTlcIiA9PiBcImFhXCIgKi9cbiAgICBwcml2YXRlIGZvcm1hdE1vdmUoc3RyOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gc3RyXG4gICAgICAgICAgICAudHJpbSgpXG4gICAgICAgICAgICAuc3BsaXQoXCIgXCIpXG4gICAgICAgICAgICAubWFwKChzKSA9PlxuICAgICAgICAgICAgICAgIHMgPT09IFwicGFzc1wiXG4gICAgICAgICAgICAgICAgICAgID8gXCIuLlwiXG4gICAgICAgICAgICAgICAgICAgIDogbnVtMmNoYXIoZ3RwY2hhcjJudW0oc1swXS50b0xvd2VyQ2FzZSgpKSkgK1xuICAgICAgICAgICAgICAgICAgICAgIG51bTJjaGFyKCh0aGlzLmdhbWU/LnN0YXRlLmhlaWdodCB8fCAwKSAtIHBhcnNlSW50KHMuc2xpY2UoMSkpKSxcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5qb2luKFwiXCIpO1xuICAgIH1cblxuICAgIC8qKiBUaGlzIGZ1bmN0aW9uIHNjYW5zIHRocm91Z2ggdGhlIHN0ZGVyciBvdXRwdXQgb2YgdGhlIGJvdCB1bnRpbCBpdFxuICAgICAqICBmaW5kcyBhIGxpbmUgdGhhdCBjYW4gYmUgdXNlZCB0byBkZXRlcm1pbmUgd2hhdCBib3QgaXMgYmVpbmcgdXNlZC4gKi9cbiAgICBwcml2YXRlIGRldGVjdEVuZ2luZShsaW5lOiBzdHJpbmcpIHtcbiAgICAgICAgaWYgKHRoaXMuZGV0ZWN0ZWRfZW5naW5lKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoL0thdGFHby8udGVzdChsaW5lKSkge1xuICAgICAgICAgICAgdGhpcy5kZXRlY3RlZF9lbmdpbmUgPSBcImthdGFnb1wiO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKC9FdmFsUm91dGluZTouKmluaXQgbW9kZWwgZG9uZS4qZ2xvYmFsX3N0ZXAvLnRlc3QobGluZSkpIHtcbiAgICAgICAgICAgIHRoaXMuZGV0ZWN0ZWRfZW5naW5lID0gXCJwaG9lbml4Z29cIjtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgvXk1DIHdpbnJhdGU9LiovLnRlc3QobGluZSkpIHtcbiAgICAgICAgICAgIHRoaXMuZGV0ZWN0ZWRfZW5naW5lID0gXCJsZWVsYVwiO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKC8uKlxcKFY6LipcXCkgXFwoTENCOi4qXFwpIFxcKE46LipcXCkgXFwoQTouKlxcKSBQVjogLiovLnRlc3QobGluZSkpIHtcbiAgICAgICAgICAgIHRoaXMuZGV0ZWN0ZWRfZW5naW5lID0gXCJzYWlcIjtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgvLipcXChWOi4qXFwpIFxcKExDQjouKlxcKSBcXChOOi4qXFwpIFBWOiAuKi8udGVzdChsaW5lKSkge1xuICAgICAgICAgICAgdGhpcy5kZXRlY3RlZF9lbmdpbmUgPSBcImxlZWxhX3plcm9cIjtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgvbW92ZVxccyt2aXNpdHNcXHMrcmV1c2VcXHMrcHB2XFxzK3dpbnJhdGVcXHMrYWdlbnQvLnRlc3QobGluZSkpIHtcbiAgICAgICAgICAgIHRoaXMuZGV0ZWN0ZWRfZW5naW5lID0gXCJzYWkxOFwiO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBwcm9jZXNzTGluZShsaW5lOiBzdHJpbmcpIHtcbiAgICAgICAgaWYgKGxpbmUubWF0Y2goL15BbHBoYSBoZWFkOiAvKSkge1xuICAgICAgICAgICAgdGhpcy5zYWlTY29yZSA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXRoaXMuZGV0ZWN0ZWRfZW5naW5lKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5jaGVja1BvbmRlcmluZygpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLypcbiAgICAgICAgICAgIExFRUxBWkVSTyA6IHRoaXMucG9zdFB2VG9DaGF0RHVhbExpbmUsXG4gICAgICAgICAgICBTQUkgICAgICAgOiB0aGlzLnBvc3RQdlRvQ2hhdER1YWxMaW5lLFxuICAgICAgICAgICAgU0FJMTggICAgIDogdGhpcy5wb3N0UHZUb0NoYXREdWFsTGluZSxcbiAgICAgICAgICAgIFBIT0VOSVhHTyA6IHRoaXMucG9zdFB2VG9DaGF0RHVhbExpbmUsXG4gICAgICAgICAgICBLQVRBR08gICAgOiB0aGlzLnBvc3RQdlRvQ2hhdFNpbmdsZUxpbmUsXG4gICAgICAgICAgICBMRUVMQSAgICAgOiB0aGlzLnBvc3RQdlRvQ2hhdFNpbmdsZUxpbmUsXG4gICAgICAgICovXG5cbiAgICAgICAgbGV0IG1lc3NhZ2U6IHByb3RvY29sLkdhbWVDaGF0QW5hbHlzaXNNZXNzYWdlIHwgbnVsbCA9IG51bGw7XG4gICAgICAgIHN3aXRjaCAodGhpcy5kZXRlY3RlZF9lbmdpbmUpIHtcbiAgICAgICAgICAgIGNhc2UgXCJrYXRhZ29cIjpcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG1hdGNoID0gbGluZS5tYXRjaChcbiAgICAgICAgICAgICAgICAgICAgICAgIC8oQ0hBVHxNQUxLT1ZJQ0gpOlZpc2l0cyAoXFxkKikgV2lucmF0ZSAoXFxkK1xcLlxcZFxcZCklIFNjb3JlTGVhZCAoLT9cXGQrXFwuXFxkKSBTY29yZVN0ZGV2ICgtP1xcZCtcXC5cXGQpIChcXChQREEgKC0/XFxkKy5cXGRcXGQpXFwpICk/UFYgKC4qKS8sXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChtYXRjaCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb29raW5nRm9yUHYgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHZpc2l0cyA9IG1hdGNoWzJdO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgd2luX3JhdGUgPSBwYXJzZUZsb2F0KG1hdGNoWzNdKS50b0ZpeGVkKDEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2NvcmVMZWFkID0gbWF0Y2hbNF07XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBQREEgPSBtYXRjaFs2XSA/IGAgUERBOiAke21hdGNoWzddfWAgOiBcIlwiO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcHYgPSB0aGlzLmZvcm1hdE1vdmUobWF0Y2hbOF0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbmFtZSA9IGBXaW4gcmF0ZTogJHt3aW5fcmF0ZX0lLCBTY29yZTogJHtzY29yZUxlYWR9JHtQREF9LCBWaXNpdHM6ICR7dmlzaXRzfWA7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSB0aGlzLmNyZWF0ZUFuYWx5c2lzTWVzc2FnZShuYW1lLCBwdiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbl9yYXRlOiBwYXJzZUZsb2F0KHdpbl9yYXRlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY29yZTogcGFyc2VGbG9hdChzY29yZUxlYWQpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpc2l0czogcGFyc2VJbnQodmlzaXRzKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlIFwibGVlbGFcIjpcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG1hdGNoID0gbGluZS5tYXRjaCgvKFxcZCopIHZpc2l0cywgc2NvcmUgKFxcZCtcXC5cXGRcXGQpJSBcXChmcm9tLiogUFY6ICguKikvKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB2aXNpdHMgPSBtYXRjaFsxXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHdpbl9yYXRlID0gcGFyc2VGbG9hdChtYXRjaFsyXSkudG9GaXhlZCgxKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHB2ID0gdGhpcy5mb3JtYXRNb3ZlKG1hdGNoWzNdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG5hbWUgPSBgV2luIHJhdGU6ICR7d2luX3JhdGV9JSwgVmlzaXRzOiAke3Zpc2l0c31gO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gdGhpcy5jcmVhdGVBbmFseXNpc01lc3NhZ2UobmFtZSwgcHYsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aW5fcmF0ZTogcGFyc2VGbG9hdCh3aW5fcmF0ZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlzaXRzOiBwYXJzZUludCh2aXNpdHMpLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgXCJsZWVsYV96ZXJvXCI6XG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBwdl9tYXRjaCA9IGxpbmUubWF0Y2goXG4gICAgICAgICAgICAgICAgICAgICAgICAvKFtBLVpdXFxkK3xwYXNzKSAtPiArKFxcZCspIFxcKFY6ICsoXFxkKy5cXGRcXGQpJVxcKSAoXFwoTENCOiArKFxcZCsuXFxkXFxkKSVcXCkgKT9cXChOOiArKFxcZCsuXFxkXFxkKSVcXCkgUFY6KCggKFtBLVpdWzAtOV0rfHBhc3MpKykrKS8sXG4gICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmRldGVjdGVkX3B2ICYmIHB2X21hdGNoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRldGVjdGVkX3B2ID0gcHZfbWF0Y2g7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG1hdGNoID0gbGluZS5tYXRjaChcbiAgICAgICAgICAgICAgICAgICAgICAgIC8oXFxkKykgdmlzaXRzLCAoXFxkKykgbm9kZXMsIChcXGQrKSBwbGF5b3V0cywgKFxcZCspIG5cXC9zLyxcbiAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAobWF0Y2ggJiYgdGhpcy5kZXRlY3RlZF9wdikge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgd2luX3JhdGUgPSBwYXJzZUZsb2F0KHRoaXMuZGV0ZWN0ZWRfcHZbM10pLnRvRml4ZWQoMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB2aXNpdHMgPSBtYXRjaFsxXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBsYXlvdXRzID0gbWF0Y2hbM107XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBuYW1lID0gYFdpbiByYXRlOiAke3dpbl9yYXRlfSUsIFZpc2l0czogJHt2aXNpdHN9LCBQbGF5b3V0czogJHtwbGF5b3V0c31gO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcHYgPSB0aGlzLmZvcm1hdE1vdmUodGhpcy5kZXRlY3RlZF9wdls3XSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmRldGVjdGVkX3B2O1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gdGhpcy5jcmVhdGVBbmFseXNpc01lc3NhZ2UobmFtZSwgcHYsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aW5fcmF0ZTogcGFyc2VGbG9hdCh3aW5fcmF0ZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlzaXRzOiBwYXJzZUludCh2aXNpdHMpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYXlvdXRzOiBwYXJzZUludChwbGF5b3V0cyksXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBcInNhaVwiOlxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcHZfbWF0Y2ggPSBsaW5lLm1hdGNoKFxuICAgICAgICAgICAgICAgICAgICAgICAgLyhbQS1aXVxcZCt8cGFzcykgLT4gKyhcXGQrKSBcXChWOiArKFxcZCtcXC5cXGRcXGQpJVxcKSAoXFwoTENCOiArKC0/XFxkK1xcLlxcZFxcZCklXFwpICk/XFwoTjogKyhcXGQrXFwuXFxkXFxkKSVcXCkgXFwoQTogKygtP1xcZCtcXC5cXGQpXFwpKCBcXChCOiAoLT9cXGQrXFwuXFxkXFxkKVxcKSk/IFBWOigoIChbQS1aXVswLTldK3xwYXNzKSspKykvLFxuICAgICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICghdGhpcy5kZXRlY3RlZF9wdiAmJiBwdl9tYXRjaCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kZXRlY3RlZF9wdiA9IHB2X21hdGNoO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBjb25zdCBtYXRjaCA9IGxpbmUubWF0Y2goXG4gICAgICAgICAgICAgICAgICAgICAgICAvKFxcZCspIHZpc2l0cywgKFxcZCspIG5vZGVzLCAoXFxkKykgcGxheW91dHMsIChcXGQrKSBuXFwvcy8sXG4gICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoICYmIHRoaXMuZGV0ZWN0ZWRfcHYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHdpbnJhdGUgPSBwYXJzZUZsb2F0KHRoaXMuZGV0ZWN0ZWRfcHZbM10pLnRvRml4ZWQoMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzY29yZSA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5nYW1lPy5teV9jb2xvciA9PT0gXCJibGFja1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gcGFyc2VGbG9hdCh0aGlzLmRldGVjdGVkX3B2WzddKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IC1wYXJzZUZsb2F0KHRoaXMuZGV0ZWN0ZWRfcHZbN10pO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2NvcmVMaW5lID0gdGhpcy5zYWlTY29yZSA/IGAsIFNjb3JlOiAke3Njb3JlLnRvRml4ZWQoMSl9YCA6IFwiXCI7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB2aXNpdHMgPSBtYXRjaFsxXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBsYXlvdXRzID0gbWF0Y2hbM107XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBuYW1lID0gYFdpbiByYXRlOiAke3dpbnJhdGV9JSR7c2NvcmVMaW5lfSwgVmlzaXRzOiAke3Zpc2l0c30sIFBsYXlvdXRzOiAke3BsYXlvdXRzfWA7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwdiA9IHRoaXMuZm9ybWF0TW92ZSh0aGlzLmRldGVjdGVkX3B2WzEwXSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmRldGVjdGVkX3B2O1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gdGhpcy5jcmVhdGVBbmFseXNpc01lc3NhZ2UobmFtZSwgcHYsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aW5fcmF0ZTogcGFyc2VGbG9hdCh3aW5yYXRlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY29yZTogc2NvcmUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlzaXRzOiBwYXJzZUludCh2aXNpdHMpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYXlvdXRzOiBwYXJzZUludChwbGF5b3V0cyksXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBcInNhaTE4XCI6XG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBwdl9tYXRjaCA9IGxpbmUubWF0Y2goXG4gICAgICAgICAgICAgICAgICAgICAgICAvKFtBLVpdXFxkK3xwYXNzKSArKFxcZCspICsoXFxkKSsgKyhcXGQpKyArKFxcZCtcXC5cXGRcXGQpJSArKFxcZCtcXC5cXGRcXGQpJSArKFxcZCtcXC5cXGRcXGQpJSArKFxcZCtcXC5cXGRcXGQpJSArKFxcZCtcXC5cXGRcXGQpJSArKFxcZCtcXC5cXGRcXGQpJSArKC0/XFxkK1xcLlxcZCkgKyhcXGQrKSUoKCAoW0EtWl1bMC05XSt8cGFzcykrKSspLyxcbiAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMuZGV0ZWN0ZWRfcHYgJiYgcHZfbWF0Y2gpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGV0ZWN0ZWRfcHYgPSBwdl9tYXRjaDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbWF0Y2ggPSBsaW5lLm1hdGNoKFxuICAgICAgICAgICAgICAgICAgICAgICAgLyhcXGQrKSB2aXNpdHMsIChcXGQrKSBub2RlcywgKFxcZCspIHBsYXlvdXRzLCAoXFxkKykgblxcL3MvLFxuICAgICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChtYXRjaCAmJiB0aGlzLmRldGVjdGVkX3B2KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB3aW5yYXRlID0gcGFyc2VGbG9hdCh0aGlzLmRldGVjdGVkX3B2WzVdKS50b0ZpeGVkKDEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2NvcmUgPVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZ2FtZT8ubXlfY29sb3IgPT09IFwiYmxhY2tcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/IHBhcnNlRmxvYXQodGhpcy5kZXRlY3RlZF9wdlsxMV0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogLXBhcnNlRmxvYXQodGhpcy5kZXRlY3RlZF9wdlsxMV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2NvcmVMaW5lID0gdGhpcy5zYWlTY29yZSA/IGAsIFNjb3JlOiAke3Njb3JlLnRvRml4ZWQoMSl9YCA6IFwiXCI7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB2aXNpdHMgPSBtYXRjaFsxXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBsYXlvdXRzID0gbWF0Y2hbM107XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBuYW1lID0gYFdpbiByYXRlOiAke3dpbnJhdGV9JSR7c2NvcmVMaW5lfSwgVmlzaXRzOiAke3Zpc2l0c30sIFBsYXlvdXRzOiAke3BsYXlvdXRzfWA7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwdiA9IHRoaXMuZm9ybWF0TW92ZSh0aGlzLmRldGVjdGVkX3B2WzEzXSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmRldGVjdGVkX3B2O1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gdGhpcy5jcmVhdGVBbmFseXNpc01lc3NhZ2UobmFtZSwgcHYsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aW5fcmF0ZTogcGFyc2VGbG9hdCh3aW5yYXRlKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY29yZTogc2NvcmUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlzaXRzOiBwYXJzZUludCh2aXNpdHMpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYXlvdXRzOiBwYXJzZUludChwbGF5b3V0cyksXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBcInBob2VuaXhnb1wiOlxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcHZfbWF0Y2ggPSBsaW5lLm1hdGNoKFxuICAgICAgICAgICAgICAgICAgICAgICAgL21haW4gbW92ZSBwYXRoOiAoKCw/W2Etel17Mn1cXCgoKFxcKGluZFxcKSl8W14oKV0pKlxcKSkrKS8sXG4gICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmRldGVjdGVkX3B2ICYmIHB2X21hdGNoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRldGVjdGVkX3B2ID0gcHZfbWF0Y2g7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG1hdGNoID0gbGluZS5tYXRjaChcbiAgICAgICAgICAgICAgICAgICAgICAgIC9bMC05XSsuLiBtb3ZlXFwoW2J3XVxcKTogW2Etel17Mn0sICh3aW5yYXRlPShbMC05XStcXC5bMC05XSspJSwgTj0oWzAtOV0rKSwgUT0oLT9bMC05XStcXC5bMC05XSspLCBwPSgtP1swLTldK1xcLlswLTldKyksIHY9KC0/WzAtOV0rXFwuWzAtOV0rKSwgY29zdCAoLT9bMC05XStcXC5bMC05XSspbXMsIHNpbXM9KFswLTldKykpLCBoZWlnaHQ9KFswLTldKyksIGF2Z19oZWlnaHQ9KFswLTldK1xcLlswLTldKyksIGdsb2JhbF9zdGVwPShbMC05XSspLyxcbiAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAobWF0Y2ggJiYgdGhpcy5kZXRlY3RlZF9wdikge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgd2luX3JhdGUgPSBwYXJzZUZsb2F0KG1hdGNoWzJdKS50b0ZpeGVkKDEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgTiA9IHBhcnNlSW50KG1hdGNoWzNdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IFEgPSBwYXJzZUZsb2F0KG1hdGNoWzRdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHAgPSBwYXJzZUZsb2F0KG1hdGNoWzVdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHYgPSBwYXJzZUZsb2F0KG1hdGNoWzZdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGNvc3QgPSBwYXJzZUZsb2F0KG1hdGNoWzddKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHNpbXMgPSBwYXJzZUludChtYXRjaFs4XSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vY29uc3QgbmFtZSA9IG1hdGNoWzFdO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgbmFtZSA9IGBXaW4gcmF0ZTogJHt3aW5fcmF0ZX0lLCBOOiAke059LCBROiAke1F9LCBwOiAke3B9LCB2OiAke3Z9LCBjb3N0OiAke01hdGgucm91bmQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICl9bXMsIHNpbXM6ICR7c2ltc31gO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcHYgPSB0aGlzLmRldGVjdGVkX3B2WzFdXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoLy1uYW5cXChpbmRcXCkvZywgXCJcIilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFwoW14oKV0qXFwpL2csIFwiXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLnNwbGl0KFwiLFwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAoKHMpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMgPT09IFwiLi5cIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyBcIi4uXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogc1swXSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bTJjaGFyKCh0aGlzLmdhbWU/LnN0YXRlLmhlaWdodCB8fCAwKSAtIGNoYXIybnVtKHNbMV0pIC0gMSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5qb2luKFwiXCIpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5kZXRlY3RlZF9wdjtcblxuICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IHRoaXMuY3JlYXRlQW5hbHlzaXNNZXNzYWdlKG5hbWUsIHB2LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2luX3JhdGU6IHBhcnNlRmxvYXQod2luX3JhdGUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIE4sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgUSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHYsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaW1zLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWVzc2FnZSkge1xuICAgICAgICAgICAgdGhpcy5nYW1lPy5zZW5kQ2hhdChtZXNzYWdlLCAodGhpcy5nYW1lPy5zdGF0ZS5tb3Zlcy5sZW5ndGggfHwgMCkgKyAxLCBcIm1hbGtvdmljaFwiKTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBndHBjaGFyMm51bShjaDogc3RyaW5nKTogbnVtYmVyIHtcbiAgICBpZiAoY2ggPT09IFwiLlwiIHx8ICFjaCkge1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgfVxuICAgIHJldHVybiBcImFiY2RlZmdoamtsbW5vcHFyc3R1dnd4eXpcIi5pbmRleE9mKGNoLnRvTG93ZXJDYXNlKCkpO1xufVxuIiwiaW1wb3J0ICogYXMgZnMgZnJvbSBcImZzXCI7XG5pbXBvcnQgKiBhcyBKU09ONSBmcm9tIFwianNvbjVcIjtcbmltcG9ydCAqIGFzIHlhcmdzIGZyb20gXCJ5YXJnc1wiO1xuaW1wb3J0ICogYXMgQ29uZmlnU2NoZW1hIGZyb20gXCIuLi9zY2hlbWEvQ29uZmlnLnNjaGVtYS5qc29uXCI7XG5pbXBvcnQgeyBWYWxpZGF0b3IgfSBmcm9tIFwianNvbnNjaGVtYVwiO1xuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSBcImV2ZW50ZW1pdHRlcjNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBFdmVudHMge1xuICAgIHJlbG9hZGVkOiAoKSA9PiB2b2lkO1xufVxuXG5leHBvcnQgY29uc3QgY29uZmlnX2V2ZW50X2VtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyPEV2ZW50cz4oKTtcbmV4cG9ydCB0eXBlIEJvdFRpbWVDb250cm9sU3lzdGVtcyA9IFwiZmlzY2hlclwiIHwgXCJieW95b21pXCIgfCBcInNpbXBsZVwiO1xuXG4vKiogQm90IGNvbmZpZyAqL1xuZXhwb3J0IGludGVyZmFjZSBDb25maWcge1xuICAgIC8qKiBBUEkga2V5IGZvciB0aGUgYm90LiAqL1xuICAgIGFwaWtleTogc3RyaW5nO1xuXG4gICAgLyoqIEVuZ2luZSBzcGVjaWZpZXIgb2YgdGhlIGJvdCwgdGhpcyBpcyBhIHBsYWluIHRleHQgZGVzY3JpcHRpb24gb2YgdGhlXG4gICAgICogYm90J3MgZW5naW5lIGFuZCBuZXR3b3JrIHRoYXQgd2lsbCBiZSByZWNvcmRlZCBhbG9uZyB3aXRoIGFsbCBnYW1lc1xuICAgICAqIHBsYXllZC4gKi9cbiAgICBlbmdpbmU/OiBzdHJpbmc7XG5cbiAgICAvKiogRW5hYmxlIHZlcmJvc2UgbG9nZ2luZy5cbiAgICAgKiAgQHZhbHVlcyAwLTJcbiAgICAgKiAgQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHZlcmJvc2l0eT86IG51bWJlcjtcblxuICAgIC8qKiBFbmFibGUgbG9nZ2luZyBnYW1lIGNoYXQuXG4gICAgICogIEBkZWZhdWx0IGZhbHNlXG4gICAgICovXG4gICAgbG9nX2dhbWVfY2hhdD86IGJvb2xlYW47XG5cbiAgICAvKiogU2V0cyBob3cgb2Z0ZW4gdGhlIHN0YXR1cyBsaW5lcyBhcmUgcHJpbnRlZCB0byB0aGUgc2NyZWVuLiBTZXQgdG8gMCB0b1xuICAgICAqIGRpc2FibGUuXG4gICAgICogdW5pdHM6IG1pbGxpc2Vjb25kc1xuICAgICAqIEBkZWZhdWx0IDYwMDAwXG4gICAgICovXG4gICAgc3RhdHVzX3VwZGF0ZV9mcmVxdWVuY3k/OiBudW1iZXI7XG5cbiAgICAvKipcbiAgICAgKiBTZXJ2ZXIgVVJMIHRvIGNvbm5lY3QgdG8sIGRlZmF1bHRzIHRvIG9ubGluZS1nby5jb21cbiAgICAgKiBAZGVmYXVsdCBodHRwczovL29ubGluZS1nby5jb21cbiAgICAgKi9cbiAgICBzZXJ2ZXI/OiBzdHJpbmc7XG5cbiAgICAvKiogTWF4aW11bSB0aW1lIHRvIGFsbG93IHRoZSBnYW1lIHRvIGJlIHBhdXNlZCBmb3IgaW4gc2Vjb25kcy5cbiAgICAgKiBAZGVmYXVsdCAzMDBcbiAgICAgKiBAcmFuZ2UgMzAwIC0gMTcyODAwXG4gICAgICovXG4gICAgbWF4X3BhdXNlX3RpbWU/OiBudW1iZXI7XG5cbiAgICAvKiogUGxheWVycyB3aG8gYXJlIG5vdCBhbGxvd2VkIHRvIHBsYXkgdGhlIGJvdCBldmVyLiAqL1xuICAgIGJsYWNrbGlzdD86IChudW1iZXIgfCBzdHJpbmcpW107XG5cbiAgICAvKiogUGxheWVycyB3aG8gYXJlIGFsbG93ZWQgdG8gY2hhbGxlbmdlIHRoZSBib3Qgd2l0aCBhbnkgc2V0dGluZ3MgZXZlblxuICAgICAqIHdoZW4gdGhlIGJvdCBpcyBhdCB0aGUgbWF4aW11bSBudW1iZXIgb2Ygc2ltdWx0YW5lb3VzIGdhbWVzICovXG4gICAgd2hpdGVsaXN0PzogKG51bWJlciB8IHN0cmluZylbXTtcblxuICAgIC8qKiBDb25maWcgZm9yIGhvdyB0byBydW4geW91ciBib3QgKi9cbiAgICBib3Q/OiBCb3RDb25maWc7XG5cbiAgICAvKiogQm90IHRvIHVzZSBmb3IgcGxheWluZyBvcGVuaW5nIG1vdmVzLiBUaGlzIGNhbiBiZSB1c2VmdWwgZm9yIGVuc3VyaW5nXG4gICAgICogeW91ciBib3QgcGxheXMgYXQgbGVhc3QgYSBmZXcgcmVhc29uYWJsZSBqb3Nla2kgbW92ZXMgaWYgaXQgaXMgYSB3ZWFrXG4gICAgICogYm90LiAqL1xuICAgIG9wZW5pbmdfYm90PzogT3BlbmluZ0JvdENvbmZpZztcblxuICAgIC8qKiBTZWNvbmRhcnkgYm90IHRvIHVzZSBmb3IgZW5zdXJpbmcgeW91ciByZWFsIGJvdCBwYXNzZXMgb3IgcmVzaWduc1xuICAgICAqIGFwcHJvcHJpYXRlbHkuIFRoaXMgYm90IHdpbGwgYmUgY29uc3VsdGVkIGV2ZXJ5IG1vdmUgYWZ0ZXIgLiBJZiB0aGUgbW92ZSBpdFxuICAgICAqIHJldHVybnMgaXMgYSBwYXNzIGl0IHdpbGwgb3ZlcnJpZGUgdGhlIG1vdmUgeW91ciBib3QgaGFzIG1hZGUgKHVubGVzc1xuICAgICAqIHlvdXIgYm90IGlzIHJlc2lnbmluZykuIElmIHRoZSBtb3ZlIGl0IHJldHVybnMgaXMgYSByZXNpZ24sIGl0IHdpbGxcbiAgICAgKiBjb3VudCB0aGUgbnVtYmVyIG9mIHN1Y2Nlc3NpdmUgcmVzaWducyBhbmQgaWYgaXQgaXMgbW9yZSB0aGFuIHRoZSBudW1iZXJcbiAgICAgKiBvZiBhbGxvd2VkIHJlc2lnbnMgeW91J3ZlIHNldCBpbiB0aGlzIGNvbmZpZyAoZGVmYXVsdCBvZiAzKSwgaXQgd2lsbFxuICAgICAqIG92ZXJyaWRlIHlvdXIgYm90J3MgbW92ZSB3aXRoIGEgcmVzaWduLlxuICAgICAqL1xuICAgIGVuZGluZ19ib3Q/OiBFbmRpbmdCb3RDb25maWc7XG5cbiAgICAvKiogTWVzc2FnZSB0byBzZW5kIHRvIHRoZSBwbGF5ZXIgYXQgdGhlIHN0YXJ0IG9mIHRoZSBnYW1lICovXG4gICAgZ3JlZXRpbmc/OiBUcmFuc2xhdGFibGVTdHJpbmc7XG5cbiAgICAvKiogTWVzc2FnZSB0byBzZW5kIHRvIHRoZSBwbGF5ZXIgd2hlbiB0aGUgZ2FtZSBpcyBvdmVyICovXG4gICAgZmFyZXdlbGw/OiBUcmFuc2xhdGFibGVTdHJpbmc7XG5cbiAgICAvKiogU2VuZCBhIG1lc3NhZ2Ugc2F5aW5nIHdoYXQgdGhlIGJvdCB0aG91Z2h0IHRoZSBzY29yZSB3YXMgYXQgdGhlIGVuZCBvZiB0aGUgZ2FtZSAqL1xuICAgIGZhcmV3ZWxsc2NvcmU/OiBib29sZWFuO1xuXG4gICAgLyoqIEZpbGUgdG8gd3JpdGUgbG9ncyB0by4gTG9ncyB3aWxsIGJlIHNlbnQgdG8gc3Rkb3V0IGFzIHdlbGwuICovXG4gICAgbG9nZmlsZT86IHN0cmluZztcblxuICAgIC8qKiBUaW1lIGNvbnRyb2wgc3lzdGVtcyB0aGF0IHdlIGNhbiB3b3JrIHdpdGhcbiAgICAgKiAgQGRlZmF1bHQgW1wiZmlzY2hlclwiLCBcImJ5b3lvbWlcIiwgXCJzaW1wbGVcIl1cbiAgICAgKiAgQGFsbG93ZWRWYWx1ZXMgW1wiZmlzY2hlclwiLCBcImJ5b3lvbWlcIiwgXCJzaW1wbGVcIl1cbiAgICAgKiAgQG1pbkl0ZW1zIDFcbiAgICAgKi9cbiAgICBhbGxvd2VkX3RpbWVfY29udHJvbF9zeXN0ZW1zPzogQm90VGltZUNvbnRyb2xTeXN0ZW1zW107XG5cbiAgICAvKipcbiAgICAgKiBBbGxvd2VkIGJsaXR6IHRpbWVzIGZvciB0aGUgYm90LiBCbGl0eiBpcyBkaXNhYmxlZCBieSBkZWZhdWx0LCBidXQgeW91XG4gICAgICogY2FuIGVuYWJsZSBpdCBieSBwcm92aWRpbmcgYWNjZXB0YWJsZSB0aW1lIHNldHRpbmdzLlxuICAgICAqXG4gICAgICogQGRlZmF1bHQgbnVsbFxuICAgICAqL1xuICAgIGFsbG93ZWRfYmxpdHpfc2V0dGluZ3M/OiBudWxsIHwgVGltZUNvbnRyb2xSYW5nZXM7XG5cbiAgICAvKiogQWxsb3dlZCByYXBpZCBnYW1lIHRpbWVzIGZvciBib3QuXG4gICAgICovXG4gICAgYWxsb3dlZF9yYXBpZF9zZXR0aW5ncz86IG51bGwgfCBUaW1lQ29udHJvbFJhbmdlcztcblxuICAgIC8qKiBBbGxvd2VkIGxpdmUgZ2FtZSB0aW1lcyBmb3IgYm90LlxuICAgICAqXG4gICAgICogIEBkZWZhdWx0IHtcInBlcl9tb3ZlX3RpbWVfcmFuZ2VcIjogWzEwLCAzMDBdLCBcIm1haW5fdGltZV9yYW5nZVwiOiBbMCwgMzYwMF0sIFwicGVyaW9kc19yYW5nZVwiOiBbMSwgMTBdfVxuICAgICAqL1xuICAgIGFsbG93ZWRfbGl2ZV9zZXR0aW5ncz86IG51bGwgfCBUaW1lQ29udHJvbFJhbmdlcztcblxuICAgIC8qKiBBbGxvd2VkIGNvcnJlc3BvbmRlbmNlIGdhbWUgdGltZXMgZm9yIGJvdC5cbiAgICAgKlxuICAgICAqICBAZGVmYXVsdCB7XCJwZXJfbW92ZV90aW1lX3JhbmdlXCI6IFs0MzIwMCwgMjU5MjAwXSwgXCJtYWluX3RpbWVfcmFuZ2VcIjogWzAsIDg2NDAwXSwgXCJwZXJpb2RzX3JhbmdlXCI6IFsxLCAxMF19XG4gICAgICovXG4gICAgYWxsb3dlZF9jb3JyZXNwb25kZW5jZV9zZXR0aW5ncz86IG51bGwgfCBUaW1lQ29udHJvbFJhbmdlcztcblxuICAgIC8qKiBBbGxvd2VkIGJvYXJkIHNpemVzIGZvciB0aGUgYm90LiBJZiB0aGVyZSBhcmUgbm8gcmVzdHJpY3Rpb25zLCB5b3UgY2FuXG4gICAgICogIHByb3ZpZGUgXCJhbGxcIiwgb3IgaWYgeW91IGNhbiBwbGF5IG9uIGFueSBzcXVhcmUgYm9hcmQsIHlvdSBjYW4gcHJvdmlkZSBcInNxdWFyZVwiLlxuICAgICAqXG4gICAgICogIFlvdSBjYW4gYWxzbyBwcm92aWRlIGV4cGxpY2l0IHdpZHRoIGFuZCBoZWlnaHQgcmFuZ2VzIGZvciBub24gc3F1YXJlIGJvYXJkc1xuICAgICAqICB3aXRoIGB7d2lkdGhfcmFuZ2U6IFttaW4sIG1heF0sIGhlaWdodF9yYW5nZTogW21pbiwgbWF4XX1gLlxuICAgICAqXG4gICAgICogIEBkZWZhdWx0IFs5LCAxMywgMTldXG4gICAgICovXG4gICAgYWxsb3dlZF9ib2FyZF9zaXplcz86IG51bWJlcltdIHwgKG51bWJlciB8IFwiYWxsXCIgfCBcInNxdWFyZVwiKSB8IEJvYXJkU2l6ZVJhbmdlcztcblxuICAgIC8qKiBBbGxvd2VkIHJhbmtlZCBnYW1lc1xuICAgICAqICBAZGVmYXVsdCB0cnVlXG4gICAgICovXG4gICAgYWxsb3dfcmFua2VkPzogYm9vbGVhbjtcblxuICAgIC8qKiBBbGxvd2VkIHVucmFua2VkIGdhbWVzXG4gICAgICogIEBkZWZhdWx0IHRydWVcbiAgICAgKi9cbiAgICBhbGxvd191bnJhbmtlZD86IGJvb2xlYW47XG5cbiAgICAvKiogQWxsb3dlZCByYW5nZSBmb3IgcmFua2VkIGdhbWVzXG4gICAgICogQGRlZmF1bHQgW1wiMzBrXCIsIFwiOXBcIl1cbiAgICAgKi9cbiAgICBhbGxvd2VkX3JhbmtfcmFuZ2U/OiBbc3RyaW5nLCBzdHJpbmddO1xuXG4gICAgLyoqIEFsbG93IGhhbmRpY2FwIGdhbWVzIGZvciByYW5rZWQgZ2FtZXNcbiAgICAgKiAgQGRlZmF1bHQgdHJ1ZVxuICAgICAqL1xuICAgIGFsbG93X3JhbmtlZF9oYW5kaWNhcD86IGJvb2xlYW47XG5cbiAgICAvKiogQWxsb3cgaGFuZGljYXAgZ2FtZXMgZm9yIHVucmFua2VkIGdhbWVzXG4gICAgICogIEBkZWZhdWx0IHRydWVcbiAgICAgKi9cbiAgICBhbGxvd191bnJhbmtlZF9oYW5kaWNhcD86IGJvb2xlYW47XG5cbiAgICAvKiogQWxsb3dlZCBrb21pIHJhbmdlLiBOZWdhdGl2ZSBudW1iZXJzIGluZGljYXRlIHJldmVyc2UgS29taS5cbiAgICAgKiAgQGRlZmF1bHQgWy05OSwgOTldXG4gICAgICovXG4gICAgYWxsb3dlZF9rb21pX3JhbmdlPzogW251bWJlciwgbnVtYmVyXTtcblxuICAgIC8qKiBIaWRlIHRoZSBib3QgZnJvbSB0aGUgcHVibGljIGJvdCBsaXN0XG4gICAgICogQGRlZmF1bHQgZmFsc2VcbiAgICAgKi9cbiAgICBoaWRkZW4/OiBib29sZWFuO1xuXG4gICAgLyoqIERlY2xpbmUgYWxsIG5ldyBjaGFsbGVuZ2VzLiBUaGlzIGltcGxpZXMgaGlkZGVuLlxuICAgICAqIEBkZWZhdWx0IGZhbHNlXG4gICAgICovXG4gICAgZGVjbGluZV9uZXdfY2hhbGxlbmdlcz86IGJvb2xlYW47XG5cbiAgICAvKiogVXNlZCBmb3IgZGVidWdnaW5nLCB3aWxsIGlzc3VlIGEgc2hvd2JvYXJkIGNvbW1hbmQgd2hlbiB3ZSd2ZSBsb2FkZWRcbiAgICAgKiB0aGUgYm9hcmQgc3RhdGUgaW50byB0aGUgYm90XG4gICAgICogQGRlZmF1bHQgZmFsc2VcbiAgICAgKi9cbiAgICBzaG93Ym9hcmQ/OiBib29sZWFuO1xuXG4gICAgLyoqIElmIHNldCwgYm90IG1vdmVzIHdpbGwgYmUgZGVsYXllZCB3aGVuIG1hZGUgYmVmb3JlIGBtaW5fbW92ZV90aW1lYCBtcy5cbiAgICAgKiBUaGlzIGlzIHByaW1hcmlseSBhIHVzZXIgZXhwZXJpZW5jZSB0aGluZyBhcyBjYW4gbWFrZSBwbGF5ZXJzIGZlZWwgcnVzaGVkXG4gICAgICogaWYgdGhlIGJvdHMgYXJlIHJlc3BvbmRpbmcgdG9vIHF1aWNrbHkuXG4gICAgICpcbiAgICAgKiBAZGVmYXVsdCAxNTAwXG4gICAgICovXG4gICAgbWluX21vdmVfdGltZT86IG51bWJlcjtcblxuICAgIC8qKiBNYXhpbXVtIGFtb3VudCBvZiBvbmdvaW5nIGdhbWVzIHRvIGFsbG93IGNvbmN1cnJlbnRseSBieSB0aGUgc2FtZSBwbGF5ZXJcbiAgICAgKiBAZGVmYXVsdCAxXG4gICAgICovXG4gICAgbWF4X2dhbWVzX3Blcl9wbGF5ZXI/OiBudW1iZXI7XG5cbiAgICAvKioqKioqKioqKi9cbiAgICAvKiBIaWRkZW4gKi9cbiAgICAvKioqKioqKioqKi9cbiAgICAvKiogQm90IHVzZXJuYW1lLiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgc2V0IHdoZW4gdGhlIGJvdCBhdXRoZW50aWNhdGVzIHdpdGggdGhlIEFQSSBLZXkuXG4gICAgICogQGhpZGRlblxuICAgICAqL1xuICAgIHVzZXJuYW1lPzogc3RyaW5nO1xuXG4gICAgLyoqIEJvdCBJRC4gVGhpcyBpcyBhdXRvbWF0aWNhbGx5IHNldCB3aGVuIHRoZSBib3QgYXV0aGVudGljYXRlcyB3aXRoIHRoZSBBUEkga2V5LlxuICAgICAqIEBoaWRkZW5cbiAgICAgKi9cbiAgICBib3RfaWQ/OiBudW1iZXI7XG5cbiAgICAvKiogQ29uZmlnIHZlcnNpb24gZm9yIGludGVybmFsIHVzZVxuICAgICAqIEBoaWRkZW5cbiAgICAgKi9cbiAgICBfY29uZmlnX3ZlcnNpb24/OiAyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRpbWVDb250cm9sUmFuZ2VzIHtcbiAgICAvKiogVGltZSBjb250cm9sIHNldHRpbmdzIGZvciBTaW1wbGUgY2xvY2tzICovXG4gICAgc2ltcGxlPzoge1xuICAgICAgICAvKiogUmFuZ2Ugb2YgYWNjZXB0YWJsZSB0aW1lcyBwZXIgcGVyaW9kIGluIHNlY29uZHNcbiAgICAgICAgICogQGRlZmF1bHQgWzEwLCAzMDBdIGZvciBsaXZlLCBbNDMyMDAsIDI1OTIwMF0gZm9yIGNvcnJlc3BvbmRlbmNlXG4gICAgICAgICAqL1xuICAgICAgICBwZXJfbW92ZV90aW1lX3JhbmdlOiBbbnVtYmVyLCBudW1iZXJdO1xuICAgIH07XG5cbiAgICAvKiogVGltZSBjb250cm9sIHNldHRpbmdzIGZvciBieW8teW9taSBjbG9ja3MgKi9cbiAgICBieW95b21pPzoge1xuICAgICAgICAvKiogUmFuZ2Ugb2YgYWNjZXB0YWJsZSBtYWluIHRpbWVzIGluIHNlY29uZHMuXG4gICAgICAgICAqIEBkZWZhdWx0IFswLCAzNjAwXSBmb3IgbGl2ZSBnYW1lcywgWzAsIDI1OTIwMF0gZm9yIGNvcnJlc3BvbmRlbmNlIGdhbWVzXG4gICAgICAgICAqL1xuICAgICAgICBtYWluX3RpbWVfcmFuZ2U6IFtudW1iZXIsIG51bWJlcl07XG5cbiAgICAgICAgLyoqIFJhbmdlIG9mIGFjY2VwdGFibGUgdGltZXMgcGVyIHBlcmlvZCBpbiBzZWNvbmRzXG4gICAgICAgICAqIEBkZWZhdWx0IFsxMCwgMzAwXSBmb3IgbGl2ZSwgWzQzMjAwLCAyNTkyMDBdIGZvciBjb3JyZXNwb25kZW5jZVxuICAgICAgICAgKi9cbiAgICAgICAgcGVyaW9kX3RpbWVfcmFuZ2U6IFtudW1iZXIsIG51bWJlcl07XG5cbiAgICAgICAgLyoqIFJhbmdlIG9mIGFjY2VwdGFibGUgbnVtYmVyIG9mIHBlcmlvZHMuXG4gICAgICAgICAqICBAZGVmYXVsdCBbMSwgMTBdXG4gICAgICAgICAqL1xuICAgICAgICBwZXJpb2RzX3JhbmdlOiBbbnVtYmVyLCBudW1iZXJdO1xuICAgIH07XG5cbiAgICAvKiogVGltZSBjb250cm9sIHNldHRpbmdzIGZvciBmaXNjaGVyIGNsb2NrcyAqL1xuICAgIGZpc2NoZXI/OiB7XG4gICAgICAgIC8qKiBSYW5nZSBvZiBhY2NlcHRhYmxlIGluaXRpYWwgdGltZXMgaW4gc2Vjb25kcy5cbiAgICAgICAgICogQGRlZmF1bHQgWzMwLCA2MDBdIGZvciBsaXZlIGdhbWVzLCBbODY0MDAsIDYwNDgwMF0gZm9yIGNvcnJlc3BvbmRlbmNlIGdhbWVzXG4gICAgICAgICAqL1xuICAgICAgICBpbml0aWFsX3RpbWVfcmFuZ2U6IFtudW1iZXIsIG51bWJlcl07XG5cbiAgICAgICAgLyoqIFJhbmdlIG9mIGFjY2VwdGFibGUgbWF4IHRpbWVzIGluIHNlY29uZHMuXG4gICAgICAgICAqIEBkZWZhdWx0IFs1LCA3MjAwXSBmb3IgbGl2ZSBnYW1lcywgWzg2NDAwLCA2MDQ4MDBdIGZvciBjb3JyZXNwb25kZW5jZSBnYW1lc1xuICAgICAgICAgKi9cbiAgICAgICAgbWF4X3RpbWVfcmFuZ2U6IFtudW1iZXIsIG51bWJlcl07XG5cbiAgICAgICAgLyoqIHJhbmdlIG9mIGFjY2VwdGFibGUgdGltZXMgZm9yIHRoZSB0aW1lIGluY3JlbWVudFxuICAgICAgICAgKiBAZGVmYXVsdCBbMTAsIDMwMF0gZm9yIGxpdmUsIFs0MzIwMCwgMjU5MjAwXSBmb3IgY29ycmVzcG9uZGVuY2VcbiAgICAgICAgICovXG4gICAgICAgIHRpbWVfaW5jcmVtZW50X3JhbmdlOiBbbnVtYmVyLCBudW1iZXJdO1xuICAgIH07XG5cbiAgICAvKiogQ29uY3VycmVudCBnYW1lcyB0byBhbGxvdyBmb3IgdGhpcyBzcGVlZCBicmFja2V0XG4gICAgICogQGRlZmF1bHQgMSwgMywgNTAwIGZvciBibGl0eiwgbGl2ZSwgY29ycmVzcG9uZGVuY2UgcmVzcGVjdGl2ZWx5XG4gICAgICovXG4gICAgY29uY3VycmVudF9nYW1lczogbnVtYmVyO1xufVxuXG4vKiogUmFuZ2Ugb2YgYWNjZXB0YWJsZSBjdXN0b20gYm9hcmQgc2l6ZXMgKi9cbmV4cG9ydCBpbnRlcmZhY2UgQm9hcmRTaXplUmFuZ2VzIHtcbiAgICAvKiogU3BlY2lmeSB0aGUgbG93IGFuZCBoaWdoIHJhbmdlIG9mIGFjY2VwdGFibGUgYm9hcmQgd2lkdGhzLiBUaGlzIHZhbHVlXG4gICAgICogaXMgaW5jbHVzaXZlLCBzbyBbNSwxOV0gd291bGQgaW5jbHVkZSA1LCAxOSwgYW5kIGV2ZXJ5dGhpbmcgaW4gYmV0d2Vlbi5cbiAgICAgKi9cbiAgICB3aWR0aF9yYW5nZTogW251bWJlciwgbnVtYmVyXTtcbiAgICAvKiogU3BlY2lmeSB0aGUgbG93IGFuZCBoaWdoIHJhbmdlIG9mIGFjY2VwdGFibGUgYm9hcmQgaGVpZ2h0cy4gVGhpcyB2YWx1ZVxuICAgICAqIGlzIGluY2x1c2l2ZSwgc28gWzUsMTldIHdvdWxkIGluY2x1ZGUgNSwgMTksIGFuZCBldmVyeXRoaW5nIGluIGJldHdlZW4uXG4gICAgICovXG4gICAgaGVpZ2h0X3JhbmdlOiBbbnVtYmVyLCBudW1iZXJdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zbGF0YWJsZVN0cmluZyB7XG4gICAgZW46IHN0cmluZztcbiAgICBbbGFuZzogc3RyaW5nXTogc3RyaW5nO1xufVxuXG4vKiogQm90IGNvbmZpZyAqL1xuZXhwb3J0IGludGVyZmFjZSBCb3RDb25maWcge1xuICAgIGNvbW1hbmQ6IHN0cmluZ1tdO1xuXG4gICAgLyoqIE1hbmFnZW1lbnQgbWV0aG9kIGZvciBtYW5hZ2luZyBib3QgaW5zdGFuY2VzLiBgcG9vbGAgc3RhcnRzIHVwXG4gICAgICogIGEgZml4ZWQgYGluc3RhbmNlc2AgbnVtYmVyIG9mIGJvdHMgYW5kIGFuZCByZXVzZXMgdGhlbSBmb3IgYWxsXG4gICAgICogIGdhbWVzLiBgcGVyc2lzdGVudGAgc3RhcnRzIHVwIGEgc2luZ2xlIGJvdCBpbnN0YW5jZSBwZXIgZ2FtZVxuICAgICAqICBhbmQgYWxsb3dzIHN0YXRlIHJlLXVzZSB0byBhbGxvdyB0aGluZ3MgbGlrZSBwb25kZXJpbmcuXG4gICAgICpcbiAgICAgKiAgQGRlZmF1bHQgXCJwZXJzaXN0ZW50XCJcbiAgICAgKi9cbiAgICBtYW5hZ2VyPzogXCJwb29sXCIgfCBcInBlcnNpc3RlbnRcIjtcblxuICAgIC8qKiBOdW1iZXIgb2YgaW5zdGFuY2VzIG9mIHRoZSBib3QgdG8gcnVuIGluIHBhcmFsbGVsLiBFeGFjdGx5IHRoaXMgbWFueVxuICAgICAqICBpbnN0YW5jZXMgd2lsbCBiZSBydW4gYXQgYW55IGdpdmVuIHRpbWUsIHJlZ2FyZGxlc3Mgb2YgaG93IG1hbnkgb25nb2luZ1xuICAgICAqICBnYW1lcyB0aGVyZSBhcmUuIFRoaXMgaXMgb25seSBhcHBsaWNhYmxlIHdoZW4gdXNpbmcgdGhlIHBvb2xpbmcgbWFuYWdlci5cbiAgICAgKlxuICAgICAqICBAZGVmYXVsdCAxXG4gICAgICovXG4gICAgaW5zdGFuY2VzPzogbnVtYmVyO1xuXG4gICAgLyoqIEVuYWJsZWQgY2xvY2tzIGJlaW5nIHNlbnQgdG8gdGhlIGJvdC4gQ2xvY2tzIHdpbGwgb25seSBiZSBzZW50IHdoZW5cbiAgICAgKiB0aGUgYXBwbGljYWJsZSBjbG9jayBjb21tYW5kcyBhcmUgZGV0ZWN0ZWQgZnJvbSB0aGUgYm90IGFueXdheXMsIHNvIHRoaXNcbiAgICAgKiBpcyBnZW5lcmFsbHkgZmluZSB0byBsZWF2ZSB0dXJuZWQgb24uXG4gICAgICpcbiAgICAgKiBAZGVmYXVsdCB0cnVlXG4gICAgICovXG4gICAgZW5hYmxlX2Nsb2NrPzogYm9vbGVhbjtcblxuICAgIC8qIFNlbmQgY2hhdHMgdGhhdCBhcmUgb3V0cHV0IGJ5IHRoZSBib3QgdG8gdGhlIGdhbWUgY2hhdFxuICAgICAqXG4gICAgICogR2FtZSBjaGF0cyBhcmUgc2Nhbm5lZCBmb3IgYnkgbG9va2luZyBhdCB0aGUgU1RERVJSIG91dHB1dCBvZiB0aGUgYm90XG4gICAgICogY2xpZW50IGFuZCBsb29raW5nIGZvciBsaW5lcyB0aGF0IHN0YXJ0IHdpdGggYE1BTEtPVklDSDogYCBvclxuICAgICAqIGBESVNDVVNTSU9OOiBgIG9yIGBNQUlOOiBgLiBOb3RlLCBNQUlOIGFuZCBESVNDVVNTSU9OIGFyZSBzeW5vbnltcy5cbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IHRydWVcbiAgICAgKi9cbiAgICBzZW5kX2NoYXRzPzogYm9vbGVhbjtcblxuICAgIC8qKiBTZW5kIHRoZSBwcmluY2lwYWwgdmFyaWF0aW9uIChQVikgdmFsdWVzLiBOb3RlIHRoYXQgeW91ciBib3QgbXVzdCBvdXRwdXQgdGhpc1xuICAgICAqIGRhdGEgaW4gYSB3YXkgdGhhdCBjYW4gYmUgcGFyc2VkLlxuICAgICAqXG4gICAgICogQGRlZmF1bHQgdHJ1ZVxuICAgICAqL1xuICAgIHNlbmRfcHZfZGF0YT86IGJvb2xlYW47XG5cbiAgICAvKiogQWZ0ZXIgYSBib3QgbWFrZXMgYSBtb3ZlLCBzb21lIGJvdHMgd2lsbCBjb250aW51ZSB3cml0aW5nIHRvIHN0ZGVyclxuICAgICAqICByZWxldmFudCBpbmZvcm1hdGlvbiAoc3VjaCBhcyBjaGF0cyBvciBQViBkYXRhKS4gVGhpcyBvcHRpb24gY29udHJvbHNcbiAgICAgKiAgaG93IGxvbmcgd2Ugd2FpdCBmb3IgdGhlIGJvdCB0byBmaW5pc2ggd3JpdGluZyB0byBzdGRlcnIgYmVmb3JlIHdlXG4gICAgICogIHJlbGVhc2UgdGhlIGJvdCBiYWNrIGludG8gdGhlIHBvb2wgb2YgYXZhaWxhYmxlIGJvdHMuXG4gICAgICpcbiAgICAgKiAgQHVuaXQgbWlsbGlzZWNvbmRzXG4gICAgICogIEBkZWZhdWx0IDEwMFxuICAgICAqL1xuICAgIHJlbGVhc2VfZGVsYXk6IG51bWJlcjtcblxuICAgIC8qKiBXaGVuIGEgYm90IGlzIHRvIHNodXRkb3duIHdlIHNlbmQgYSBgcXVpdGAgY29tbWFuZCB0byB0aGUgYm90LlxuICAgICAqICBUaGlzIGdyYWNlIHBlcmlvZCBpcyB0aGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciB0aGUgYm90IHRvXG4gICAgICogIHF1aXQgZ3JhY2VmdWxseSBiZWZvcmUgc2VuZGluZyBhIGBTSUdURVJNYCB0byB0aGUgYm90LiBGdXJ0aGVybW9yZSxcbiAgICAgKiAgaWYgdGhlIGJvdCBkb2Vzbid0IHRlcm1pbmF0ZSBhZnRlciB0aGUgYFNJR1RFUk1gIGZvciBhbm90aGVyIGdyYWNlXG4gICAgICogIHBlcmlvZCwgd2Ugd2lsbCBzZW5kIGEgYFNJR0tJTExgIHRvIHRoZSBib3QuXG4gICAgICpcbiAgICAgKiAgQHVuaXQgbWlsbGlzZWNvbmRzXG4gICAgICogIEBkZWZhdWx0IDUwMDBcbiAgICAgKi9cbiAgICBxdWl0X2dyYWNlX3BlcmlvZD86IG51bWJlcjtcblxuICAgIC8qKiBXaGVuIHRoZSBtYW5hZ2VyIGlzIHNldCB0byBcInBlcnNpc3RlbnRcIiwgSWYgbm8gbW92ZXMgYXJlIG1hZGUgd2l0aGluXG4gICAgICogIHRoaXMgdGltZW91dCwgdGhlIGJvdCBwcm9jZXNzIGlzIHRlcm1pbmF0ZWQuIElmIGEgbmV3IG1vdmUgaXMgbWFkZVxuICAgICAqICBhIG5ldyBwcm9jZXNzIHdpbGwgYmUgc3RhcnRlZCB0byByZXN1bWUgcGxheWluZyB0aGUgZ2FtZS5cbiAgICAgKlxuICAgICAqICBAdW5pdCBtaWxsaXNlY29uZHNcbiAgICAgKiAgQGRlZmF1bHQgNjAwMDAwICAgLy8gMTAgbWludXRlc1xuICAgICAqL1xuICAgIHBlcnNpc3RlbnRfaWRsZV90aW1lb3V0PzogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVuZGluZ0JvdENvbmZpZyBleHRlbmRzIEJvdENvbmZpZyB7XG4gICAgLyoqIE51bWJlciBvZiBzdWNjZXNzaXZlIHJlc2lnbnMgYWxsb3dlZCBiZWZvcmUgdGhlIGJvdCB3aWxsIHJlc2lnbi5cbiAgICAgKiBAZGVmYXVsdCAzXG4gICAgICovXG4gICAgYWxsb3dlZF9yZXNpZ25zPzogbnVtYmVyO1xuXG4gICAgLyoqIFRoaXMgaXMgdGhlIHJhdGlvIG9mIHRoZSBib2FyZCBzaXplIHRvIHRoZSBudW1iZXIgb2YgbW92ZXNcbiAgICAgKiB0byBhbGxvdyBiZWZvcmUgd2Ugd2lsbCBzdGFydCBjaGVja2luZyB0aGUgZW5kaW5nIGJvdCBmb3JcbiAgICAgKiBwYXNzZXMgYW5kIHJlc2lnbnMuIFRoaXMgaXMgdG8gcHJldmVudCB0aGUgYm90IGZyb20gcmVzaWduaW5nXG4gICAgICogdG9vIGVhcmx5IGluIGEgZ2FtZS5cbiAgICAgKlxuICAgICAqIFRoZSBtb3ZlIHRvIHN0YXJ0IGNvbnN1bHRpbmcgdGhlIGVuZGluZyBib3QgaXMgY2FsY3VsYXRlZCBieSB0YWtpbmdcbiAgICAgKlxuICAgICAqICAgIGNlaWwoYm9hcmRfaGVpZ2h0ICogYm9hcmRfd2lkdGggKiByYXRpbylcbiAgICAgKlxuICAgICAqIEBhbGxvd2VkIDAuMSAtIDEuMFxuICAgICAqIEBkZWZhdWx0IDAuOFxuICAgICAqL1xuICAgIG1vdmVzX3RvX2FsbG93X2JlZm9yZV9jaGVja2luZ19yYXRpbz86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBPcGVuaW5nQm90Q29uZmlnIGV4dGVuZHMgQm90Q29uZmlnIHtcbiAgICAvKiogTnVtYmVyIG9mIG9wZW5pbmcgbW92ZXMgdG8gcGxheSBiZWZvcmUgc3dpdGNoaW5nIHRvIHRoZSBtYWluIGJvdC5cbiAgICAgKiBAZGVmYXVsdCA4XG4gICAgICovXG4gICAgbnVtYmVyX29mX29wZW5pbmdfbW92ZXNfdG9fcGxheT86IG51bWJlcjtcbn1cblxuZnVuY3Rpb24gZGVmYXVsdHMoKTogQ29uZmlnIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBhcGlrZXk6IFwiXCIsXG4gICAgICAgIHNlcnZlcjogXCJodHRwczovL29ubGluZS1nby5jb21cIixcbiAgICAgICAgdmVyYm9zaXR5OiAxLFxuICAgICAgICBsb2dfZ2FtZV9jaGF0OiBmYWxzZSxcbiAgICAgICAgbWF4X3BhdXNlX3RpbWU6IDMwMCxcbiAgICAgICAgc3RhdHVzX3VwZGF0ZV9mcmVxdWVuY3k6IDYwMDAwLFxuICAgICAgICBhbGxvd2VkX3RpbWVfY29udHJvbF9zeXN0ZW1zOiBbXCJmaXNjaGVyXCIsIFwiYnlveW9taVwiLCBcInNpbXBsZVwiXSxcbiAgICAgICAgYWxsb3dlZF9ibGl0el9zZXR0aW5nczogbnVsbCxcblxuICAgICAgICBhbGxvd2VkX3JhcGlkX3NldHRpbmdzOiB7XG4gICAgICAgICAgICBzaW1wbGU6IHtcbiAgICAgICAgICAgICAgICBwZXJfbW92ZV90aW1lX3JhbmdlOiBbNSwgMzBdLFxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgYnlveW9taToge1xuICAgICAgICAgICAgICAgIG1haW5fdGltZV9yYW5nZTogWzAsIDM2MDBdLFxuICAgICAgICAgICAgICAgIHBlcmlvZF90aW1lX3JhbmdlOiBbNSwgMzBdLFxuICAgICAgICAgICAgICAgIHBlcmlvZHNfcmFuZ2U6IFsxLCAxMF0sXG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBmaXNjaGVyOiB7XG4gICAgICAgICAgICAgICAgaW5pdGlhbF90aW1lX3JhbmdlOiBbNSwgNjAwXSxcbiAgICAgICAgICAgICAgICBtYXhfdGltZV9yYW5nZTogWzUsIDcyMDBdLFxuICAgICAgICAgICAgICAgIHRpbWVfaW5jcmVtZW50X3JhbmdlOiBbMywgMzBdLFxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgY29uY3VycmVudF9nYW1lczogMyxcbiAgICAgICAgfSxcbiAgICAgICAgYWxsb3dlZF9saXZlX3NldHRpbmdzOiB7XG4gICAgICAgICAgICBzaW1wbGU6IHtcbiAgICAgICAgICAgICAgICBwZXJfbW92ZV90aW1lX3JhbmdlOiBbMTAsIDMwMF0sXG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBieW95b21pOiB7XG4gICAgICAgICAgICAgICAgbWFpbl90aW1lX3JhbmdlOiBbMCwgMzYwMF0sXG4gICAgICAgICAgICAgICAgcGVyaW9kX3RpbWVfcmFuZ2U6IFsxMCwgMzAwXSxcbiAgICAgICAgICAgICAgICBwZXJpb2RzX3JhbmdlOiBbMSwgMTBdLFxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgZmlzY2hlcjoge1xuICAgICAgICAgICAgICAgIGluaXRpYWxfdGltZV9yYW5nZTogWzEwLCAzNjAwXSxcbiAgICAgICAgICAgICAgICBtYXhfdGltZV9yYW5nZTogWzUsIDcyMDBdLFxuICAgICAgICAgICAgICAgIHRpbWVfaW5jcmVtZW50X3JhbmdlOiBbMTAsIDMwMF0sXG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBjb25jdXJyZW50X2dhbWVzOiAzLFxuICAgICAgICB9LFxuICAgICAgICBhbGxvd2VkX2NvcnJlc3BvbmRlbmNlX3NldHRpbmdzOiB7XG4gICAgICAgICAgICBzaW1wbGU6IHtcbiAgICAgICAgICAgICAgICBwZXJfbW92ZV90aW1lX3JhbmdlOiBbNDMyMDAsIDYwNDgwMF0sXG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBieW95b21pOiB7XG4gICAgICAgICAgICAgICAgbWFpbl90aW1lX3JhbmdlOiBbMCwgNjA0ODAwXSxcbiAgICAgICAgICAgICAgICBwZXJpb2RfdGltZV9yYW5nZTogWzQzMjAwLCA2MDQ4MDBdLFxuICAgICAgICAgICAgICAgIHBlcmlvZHNfcmFuZ2U6IFsxLCAxMF0sXG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBmaXNjaGVyOiB7XG4gICAgICAgICAgICAgICAgaW5pdGlhbF90aW1lX3JhbmdlOiBbODY0MDAsIDYwNDgwMF0sXG4gICAgICAgICAgICAgICAgbWF4X3RpbWVfcmFuZ2U6IFs4NjQwMCwgNjA0ODAwXSxcbiAgICAgICAgICAgICAgICB0aW1lX2luY3JlbWVudF9yYW5nZTogWzQzMjAwLCA2MDQ4MDBdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGNvbmN1cnJlbnRfZ2FtZXM6IDUwMCxcbiAgICAgICAgfSxcblxuICAgICAgICBhbGxvd2VkX2JvYXJkX3NpemVzOiBbOSwgMTMsIDE5XSxcbiAgICAgICAgYWxsb3dfcmFua2VkOiB0cnVlLFxuICAgICAgICBhbGxvd191bnJhbmtlZDogdHJ1ZSxcbiAgICAgICAgYWxsb3dlZF9yYW5rX3JhbmdlOiBbXCIzMGtcIiwgXCI5cFwiXSxcbiAgICAgICAgYWxsb3dfcmFua2VkX2hhbmRpY2FwOiB0cnVlLFxuICAgICAgICBhbGxvd191bnJhbmtlZF9oYW5kaWNhcDogdHJ1ZSxcbiAgICAgICAgYWxsb3dlZF9rb21pX3JhbmdlOiBbLTk5LCA5OV0sXG4gICAgICAgIGhpZGRlbjogZmFsc2UsXG4gICAgICAgIGRlY2xpbmVfbmV3X2NoYWxsZW5nZXM6IGZhbHNlLFxuICAgICAgICBtaW5fbW92ZV90aW1lOiAxNTAwLFxuICAgICAgICBtYXhfZ2FtZXNfcGVyX3BsYXllcjogMSxcblxuICAgICAgICBncmVldGluZzoge1xuICAgICAgICAgICAgZW46IFwiSGVsbG8sIEkgYW0gYSBib3QuIEdvb2QgbHVjaywgaGF2ZSBmdW4hXCIsXG4gICAgICAgICAgICBmcjogXCJCb25qb3VyLCBqZSBzdWlzIHVuIGJvdC4gQm9ubmUgY2hhbmNlLCBhbXVzZXotdm91cyBiaWVuIVwiLCAvLyBjc3BlbGw6IGRpc2FibGUtbGluZVxuICAgICAgICAgICAgZGU6IFwiSGFsbG8sIGljaCBiaW4gZWluIEJvdC4gVmllbCBHbMO8Y2ssIHZpZWwgU3Bhw58hXCIsIC8vIGNzcGVsbDogZGlzYWJsZS1saW5lXG4gICAgICAgICAgICBlczogXCJIb2xhLCBzb3kgdW4gYm90LiDCoUJ1ZW5hIHN1ZXJ0ZSwgcXVlIHRlIGRpdmllcnRhcyFcIiwgLy8gY3NwZWxsOiBkaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIGl0OiBcIkNpYW8sIHNvbm8gdW4gYm90LiBCdW9uYSBmb3J0dW5hLCBkaXZlcnRpdGkhXCIsIC8vIGNzcGVsbDogZGlzYWJsZS1saW5lXG4gICAgICAgICAgICBqYTogXCLjgZPjgpPjgavjgaHjga/jgIHnp4Hjga/jg5zjg4Pjg4jjgafjgZnjgIIg44GK55ay44KM5qeY44Gn44GX44Gf44CB5qW944GX44KT44Gn44GP44Gg44GV44GE77yBXCIsXG4gICAgICAgICAgICBrbzogXCLslYjrhZXtlZjshLjsmpQsIOyggOuKlCDrtIfsnoXri4jri6QuIO2WieyatOydhCDruZXri4jri6QsIOymkOqxsOyatCDsi5zqsIQg65CY7IS47JqUIVwiLFxuICAgICAgICAgICAgbmw6IFwiSGFsbG8sIGlrIGJlbiBlZW4gYm90LiBWZWVsIGdlbHVrLCB2ZWVsIHBsZXppZXIhXCIsIC8vIGNzcGVsbDogZGlzYWJsZS1saW5lXG4gICAgICAgICAgICBwbDogXCJDemXFm8SHLCBqZXN0ZW0gYm90ZW0uIFBvd29kemVuaWEsIGJhdyBzacSZIGRvYnJ6ZSFcIiwgLy8gY3NwZWxsOiBkaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIHB0OiBcIk9sw6EsIGV1IHNvdSB1bSBib3QuIEJvYSBzb3J0ZSwgZGl2aXJ0YS1zZSFcIiwgLy8gY3NwZWxsOiBkaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIHJ1OiBcItCf0YDQuNCy0LXRgiwg0Y8g0LHQvtGCLiDQo9C00LDRh9C4LCDQv9GA0LjRj9GC0L3QvtC5INC40LPRgNGLIVwiLCAvLyBjc3BlbGw6IGRpc2FibGUtbGluZVxuICAgICAgICAgICAgXCJ6aC10d1wiOiBcIuWkp+WutuWlve+8jOaIkeaYr+apn+WZqOS6uuOAgiDnpZ3kvaDlpb3pgYvvvIznjqnlvpfplovlv4PvvIFcIixcbiAgICAgICAgICAgIFwiemgtY25cIjogXCLlpKflrrblpb3vvIzmiJHmmK/mnLrlmajkurrjgIIg56Wd5L2g5aW96L+Q77yM546p5b6X5byA5b+D77yBXCIsXG4gICAgICAgIH0sXG5cbiAgICAgICAgZmFyZXdlbGw6IHtcbiAgICAgICAgICAgIGVuOiBcIlRoYW5rIHlvdSBmb3IgdGhlIGdhbWUhXCIsXG4gICAgICAgICAgICBmcjogXCJNZXJjaSBwb3VyIGxhIHBhcnRpZSFcIiwgLy8gY3NwZWxsOiBkaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIGRlOiBcIkRhbmtlIGbDvHIgZGFzIFNwaWVsIVwiLCAvLyBjc3BlbGw6IGRpc2FibGUtbGluZVxuICAgICAgICAgICAgZXM6IFwiwqFHcmFjaWFzIHBvciBlbCBqdWVnbyFcIiwgLy8gY3NwZWxsOiBkaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIGl0OiBcIkdyYXppZSBwZXIgbGEgcGFydGl0YSFcIiwgLy8gY3NwZWxsOiBkaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIGphOiBcIuOCsuODvOODoOOBguOCiuOBjOOBqOOBhuOBlOOBluOBhOOBvuOBl+OBn++8gVwiLFxuICAgICAgICAgICAga286IFwi6rKM7J6EIOqwkOyCrO2VqeuLiOuLpCFcIixcbiAgICAgICAgICAgIG5sOiBcIkJlZGFua3Qgdm9vciBoZXQgc3BlbCFcIiwgLy8gY3NwZWxsOiBkaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIHBsOiBcIkR6acSZa3VqxJkgemEgZ3LEmSFcIiwgLy8gY3NwZWxsOiBkaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIHB0OiBcIk9icmlnYWRvIHBlbG8gam9nbyFcIiwgLy8gY3NwZWxsOiBkaXNhYmxlLWxpbmVcbiAgICAgICAgICAgIHJ1OiBcItCh0L/QsNGB0LjQsdC+INC30LAg0LjQs9GA0YMhXCIsIC8vIGNzcGVsbDogZGlzYWJsZS1saW5lXG4gICAgICAgICAgICBcInpoLXR3XCI6IFwi6Kyd6Kyd5L2g55qE6YGK5oiy77yBXCIsXG4gICAgICAgICAgICBcInpoLWNuXCI6IFwi6LCi6LCi5L2g55qE5ri45oiP77yBXCIsXG4gICAgICAgIH0sXG4gICAgfTtcbn1cblxuZnVuY3Rpb24gYm90X2NvbmZpZ19kZWZhdWx0cygpOiBQYXJ0aWFsPEJvdENvbmZpZz4ge1xuICAgIGNvbnN0IGJhc2U6IFBhcnRpYWw8Qm90Q29uZmlnPiA9IHtcbiAgICAgICAgbWFuYWdlcjogXCJwZXJzaXN0ZW50XCIsXG4gICAgICAgIGluc3RhbmNlczogMSxcbiAgICAgICAgc2VuZF9jaGF0czogdHJ1ZSxcbiAgICAgICAgc2VuZF9wdl9kYXRhOiB0cnVlLFxuICAgICAgICByZWxlYXNlX2RlbGF5OiAxMDAsXG4gICAgICAgIHF1aXRfZ3JhY2VfcGVyaW9kOiA1MDAwLFxuICAgICAgICBwZXJzaXN0ZW50X2lkbGVfdGltZW91dDogNjAwMDAwLFxuICAgIH07XG5cbiAgICByZXR1cm4gYmFzZTtcbn1cblxuZnVuY3Rpb24gZW5kaW5nX2JvdF9jb25maWdfZGVmYXVsdHMoKTogUGFydGlhbDxCb3RDb25maWc+IHtcbiAgICBjb25zdCBiYXNlOiBQYXJ0aWFsPEVuZGluZ0JvdENvbmZpZz4gPSB7XG4gICAgICAgIC4uLmJvdF9jb25maWdfZGVmYXVsdHMoKSxcbiAgICAgICAgYWxsb3dlZF9yZXNpZ25zOiAzLFxuICAgICAgICBtb3Zlc190b19hbGxvd19iZWZvcmVfY2hlY2tpbmdfcmF0aW86IDAuOCxcbiAgICB9O1xuXG4gICAgcmV0dXJuIGJhc2U7XG59XG5cbmZ1bmN0aW9uIG9wZW5pbmdfYm90X2NvbmZpZ19kZWZhdWx0cygpOiBQYXJ0aWFsPEJvdENvbmZpZz4ge1xuICAgIGNvbnN0IGJhc2U6IFBhcnRpYWw8T3BlbmluZ0JvdENvbmZpZz4gPSB7XG4gICAgICAgIC4uLmJvdF9jb25maWdfZGVmYXVsdHMoKSxcbiAgICAgICAgbnVtYmVyX29mX29wZW5pbmdfbW92ZXNfdG9fcGxheTogOCxcbiAgICB9O1xuXG4gICAgcmV0dXJuIGJhc2U7XG59XG5cbmV4cG9ydCBsZXQgY29uZmlnOiBDb25maWcgPSB0cnlfbG9hZF9jb25maWcoKTtcblxuZnVuY3Rpb24gdHJ5X2xvYWRfY29uZmlnKCk6IENvbmZpZyB7XG4gICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGxvYWRfY29uZmlnX29yX3Rocm93KCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgbG9hZGluZyBjb25maWcgZmlsZTpcIiwgZS5tZXNzYWdlKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbn1cblxubGV0IHJlbG9hZF9kZWJvdW5jZSA9IG51bGw7XG5mdW5jdGlvbiByZWxvYWRfY29uZmlnKGNvbmZpZ19wYXRoOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAocmVsb2FkX2RlYm91bmNlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc29sZS5pbmZvKFwiUmVsb2FkaW5nIGNvbmZpZyBmaWxlIFwiLCBjb25maWdfcGF0aCk7XG4gICAgcmVsb2FkX2RlYm91bmNlID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHJlbG9hZF9kZWJvdW5jZSA9IG51bGw7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25maWcgPSBsb2FkX2NvbmZpZ19vcl90aHJvdygpO1xuICAgICAgICAgICAgY29uZmlnX2V2ZW50X2VtaXR0ZXIuZW1pdChcInJlbG9hZGVkXCIpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgbG9hZGluZyBjb25maWcgZmlsZTpcIiwgZS5tZXNzYWdlKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIH0sIDEwMCk7XG59XG5cbmZ1bmN0aW9uIGxvYWRfY29uZmlnX29yX3Rocm93KCk6IENvbmZpZyB7XG4gICAgeWFyZ3MocHJvY2Vzcy5hcmd2LnNsaWNlKDIpKVxuICAgICAgICAudXNhZ2UoXCIjIFVzYWdlOiAkMCAtYyA8Y29uZmlnLmpzb241PiBbb3B0aW9uc11cIilcbiAgICAgICAgLnVzYWdlKFwiIyAgICAgICAgJDAgLWMgPGNvbmZpZy5qc29uNT4gW29wdGlvbnNdIC0tIDxib3QgY29tbWFuZD5cIilcbiAgICAgICAgLmRlc2NyaWJlKFxuICAgICAgICAgICAgXCJzZXJ2ZXJcIixcbiAgICAgICAgICAgIFwiVVJMIG9mIHRoZSBPR1Mgc2VydmVyIHRvIGNvbm5lY3QgdG8sIGRlZmF1bHRzIHRvIGh0dHBzOi8vb25saW5lLWdvLmNvbVwiLFxuICAgICAgICApXG4gICAgICAgIC5kZXNjcmliZShcbiAgICAgICAgICAgIFwiYmV0YVwiLFxuICAgICAgICAgICAgXCJDb25uZWN0IHRvIHRoZSBiZXRhIHNlcnZlci4gT3ZlcnJpZGVzIC0tc2VydmVyIHRvIGh0dHBzOi8vYmV0YS5vbmxpbmUtZ28uY29tXCIsXG4gICAgICAgIClcbiAgICAgICAgLmRlc2NyaWJlKFwiY29uZmlnXCIsIFwiUGF0aCB0byBjb25maWd1cmF0aW9uIGZpbGVcIilcbiAgICAgICAgLmFsaWFzKFwiY29uZmlnXCIsIFwiY1wiKVxuICAgICAgICAuZGVzY3JpYmUoXG4gICAgICAgICAgICBcImRpc2FibGUtc3RhdHVzLXVwZGF0ZXNcIixcbiAgICAgICAgICAgIFwiRGlzYWJsZSB0aGUgc3RhdHVzIHVwZGF0ZSBsaW5lcyBwcmludGVkIHRvIHRoZSBjb25zb2xlXCIsXG4gICAgICAgIClcbiAgICAgICAgLmFsaWFzKFwiZGlzYWJsZS1zdGF0dXMtdXBkYXRlc1wiLCBcInFcIilcbiAgICAgICAgLmRlc2NyaWJlKFwiYXBpa2V5XCIsIFwiQVBJIGtleSBmb3IgdGhlIGJvdFwiKVxuICAgICAgICAuZGVzY3JpYmUoXCJlbmdpbmVcIiwgXCJWZXJzaW9uIG9mIHRoZSBib3QgZW5naW5lIGJlaW5nIHVzZWRcIilcbiAgICAgICAgLmRlc2NyaWJlKFwidlwiLCBcIkluY3JlYXNlIGxldmVsICh1c2UgbXVsdGlwbGUgdGltZXMgZm9yIG1vcmUgbG9ncylcIilcbiAgICAgICAgLmNvdW50KFwidlwiKVxuICAgICAgICAuc3RyaWN0KClcbiAgICAgICAgLnBhcnNlU3luYygpO1xuXG4gICAgY29uc3QgYXJnczogeyBbazogc3RyaW5nXTogYW55IH0gPSB5YXJncy5hcmd2O1xuXG4gICAgaWYgKGFyZ3MuYmV0YSkge1xuICAgICAgICBhcmdzLnNlcnZlciA9IFwiaHR0cHM6Ly9iZXRhLm9ubGluZS1nby5jb21cIjtcbiAgICB9XG5cbiAgICBjb25zdCBmcm9tX2NsaTogUGFydGlhbDxDb25maWc+ID0ge1xuICAgICAgICBzZXJ2ZXI6IGFyZ3Muc2VydmVyLFxuICAgICAgICBhcGlrZXk6IGFyZ3MuYXBpa2V5LFxuICAgICAgICB2ZXJib3NpdHk6IGFyZ3MudiB8fCB1bmRlZmluZWQsXG4gICAgICAgIHN0YXR1c191cGRhdGVfZnJlcXVlbmN5OiBhcmdzLnEgPyAwIDogdW5kZWZpbmVkLFxuICAgICAgICBlbmdpbmU6IGFyZ3MuZW5naW5lLFxuICAgIH07XG5cbiAgICBsZXQgY2xpX2JvdF9jb21tYW5kID0gYXJncy5fLmxlbmd0aCA+IDAgPyBhcmdzLl8gOiB1bmRlZmluZWQ7XG5cbiAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhmcm9tX2NsaSkpIHtcbiAgICAgICAgaWYgKGZyb21fY2xpW2tleV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZGVsZXRlIGZyb21fY2xpW2tleV07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBmaWxlbmFtZSA9IGFyZ3MuY29uZmlnO1xuXG4gICAgaWYgKGZpbGVuYW1lKSB7XG4gICAgICAgIGZzLndhdGNoKGZpbGVuYW1lLCAoKSA9PiB7XG4gICAgICAgICAgICByZWxvYWRfY29uZmlnKGZpbGVuYW1lKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyogQHR5cGVzY3JpcHQtZXNsaW50L25vLXZhci1yZXF1aXJlcyAqL1xuICAgIGNvbnN0IGNvbnRlbnRzID0gZmlsZW5hbWUgPyBmcy5yZWFkRmlsZVN5bmMoZmlsZW5hbWUsIFwidXRmOFwiKSA6IFwie31cIjtcbiAgICBjb25zdCByYXcgPSBKU09ONS5wYXJzZShjb250ZW50cyk7XG4gICAgY29uc3Qgd2l0aF9kZWZhdWx0cyA9IHsgLi4uZGVmYXVsdHMoKSwgLi4ucmF3LCAuLi5mcm9tX2NsaSB9O1xuXG4gICAgaWYgKGNsaV9ib3RfY29tbWFuZCkge1xuICAgICAgICBjbGlfYm90X2NvbW1hbmQgPSBjbGlfYm90X2NvbW1hbmQubWFwKCh4OiBzdHJpbmcgfCBudW1iZXIpID0+IHgudG9TdHJpbmcoKS50cmltKCkpO1xuXG4gICAgICAgIGlmICghKFwiYm90XCIgaW4gd2l0aF9kZWZhdWx0cykpIHtcbiAgICAgICAgICAgIHdpdGhfZGVmYXVsdHMuYm90ID0ge1xuICAgICAgICAgICAgICAgIC4uLmJvdF9jb25maWdfZGVmYXVsdHMoKSxcbiAgICAgICAgICAgICAgICBjb21tYW5kOiBjbGlfYm90X2NvbW1hbmQsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgd2l0aF9kZWZhdWx0cy5ib3QuY29tbWFuZCA9IGNsaV9ib3RfY29tbWFuZDtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoIShcImJvdFwiIGluIHdpdGhfZGVmYXVsdHMpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIGJvdCBjb25maWd1cmF0aW9uIGZvdW5kXCIpO1xuICAgIH1cblxuICAgIGlmICh3aXRoX2RlZmF1bHRzLmFsbG93ZWRfYmxpdHpfc2V0dGluZ3MpIHtcbiAgICAgICAgaWYgKCF3aXRoX2RlZmF1bHRzLmFsbG93ZWRfYmxpdHpfc2V0dGluZ3MuY29uY3VycmVudF9nYW1lcykge1xuICAgICAgICAgICAgd2l0aF9kZWZhdWx0cy5hbGxvd2VkX2JsaXR6X3NldHRpbmdzLmNvbmN1cnJlbnRfZ2FtZXMgPSAxO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHJhdy5hbGxvd2VkX2xpdmVfc2V0dGluZ3MpIHtcbiAgICAgICAgd2l0aF9kZWZhdWx0cy5hbGxvd2VkX2xpdmVfc2V0dGluZ3MgPSB7XG4gICAgICAgICAgICAuLi5kZWZhdWx0cygpLmFsbG93ZWRfbGl2ZV9zZXR0aW5ncyxcbiAgICAgICAgICAgIC4uLnJhdy5hbGxvd2VkX2xpdmVfc2V0dGluZ3MsXG4gICAgICAgIH07XG4gICAgfVxuICAgIGlmIChyYXcuYWxsb3dlZF9jb3JyZXNwb25kZW5jZV9zZXR0aW5ncykge1xuICAgICAgICB3aXRoX2RlZmF1bHRzLmFsbG93ZWRfY29ycmVzcG9uZGVuY2Vfc2V0dGluZ3MgPSB7XG4gICAgICAgICAgICAuLi5kZWZhdWx0cygpLmFsbG93ZWRfY29ycmVzcG9uZGVuY2Vfc2V0dGluZ3MsXG4gICAgICAgICAgICAuLi5yYXcuYWxsb3dlZF9jb3JyZXNwb25kZW5jZV9zZXR0aW5ncyxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAod2l0aF9kZWZhdWx0cy5ib3QpIHtcbiAgICAgICAgd2l0aF9kZWZhdWx0cy5ib3QgPSB7IC4uLmJvdF9jb25maWdfZGVmYXVsdHMoKSwgLi4ud2l0aF9kZWZhdWx0cy5ib3QgfTtcbiAgICB9XG4gICAgaWYgKHdpdGhfZGVmYXVsdHMuZW5kaW5nX2JvdCkge1xuICAgICAgICB3aXRoX2RlZmF1bHRzLmVuZGluZ19ib3QgPSB7XG4gICAgICAgICAgICAuLi5lbmRpbmdfYm90X2NvbmZpZ19kZWZhdWx0cygpLFxuICAgICAgICAgICAgLi4ud2l0aF9kZWZhdWx0cy5lbmRpbmdfYm90LFxuICAgICAgICB9O1xuICAgIH1cbiAgICBpZiAod2l0aF9kZWZhdWx0cy5vcGVuaW5nX2JvdCkge1xuICAgICAgICB3aXRoX2RlZmF1bHRzLm9wZW5pbmdfYm90ID0ge1xuICAgICAgICAgICAgLi4ub3BlbmluZ19ib3RfY29uZmlnX2RlZmF1bHRzKCksXG4gICAgICAgICAgICAuLi53aXRoX2RlZmF1bHRzLm9wZW5pbmdfYm90LFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIGNvbnN0IHZhbGlkYXRvciA9IG5ldyBWYWxpZGF0b3IoKTtcbiAgICBjb25zdCByZXN1bHQgPSB2YWxpZGF0b3IudmFsaWRhdGUod2l0aF9kZWZhdWx0cywgQ29uZmlnU2NoZW1hKTtcblxuICAgIGlmICghcmVzdWx0LnZhbGlkKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYGApO1xuICAgICAgICBjb25zb2xlLmVycm9yKGBgKTtcbiAgICAgICAgY29uc29sZS5lcnJvcihgSW52YWxpZCBjb25maWcgZmlsZTogJHtmaWxlbmFtZX1gKTtcblxuICAgICAgICBmb3IgKGNvbnN0IGVycm9yIG9mIHJlc3VsdC5lcnJvcnMpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYFxcdCAke2Vycm9yLnRvU3RyaW5nKCl9YCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc29sZS5lcnJvcihgYCk7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYGApO1xuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgY29uZmlnIGZpbGVcIik7XG4gICAgfVxuICAgIC8vY29uc29sZS5pbmZvKHlhcmdzLmFyZ3YpO1xuICAgIC8vY29uc29sZS5pbmZvKHdpdGhfZGVmYXVsdHMpO1xuXG4gICAgd2l0aF9kZWZhdWx0cy5fY29uZmlnX3ZlcnNpb24gPSAyO1xuXG4gICAgcmV0dXJuIHNhbml0eV9jaGVja19hbmRfcGF0Y2hfY29uZmlnKHdpdGhfZGVmYXVsdHMpO1xufVxuXG5mdW5jdGlvbiBzYW5pdHlfY2hlY2tfYW5kX3BhdGNoX2NvbmZpZyhjb25maWc6IENvbmZpZyk6IENvbmZpZyB7XG4gICAgaWYgKGNvbmZpZy5kZWNsaW5lX25ld19jaGFsbGVuZ2VzKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcIkRlY2xpbmluZyBuZXcgY2hhbGxlbmdlcywgaGlkaW5nIGJvdFwiKTtcbiAgICAgICAgY29uZmlnLmhpZGRlbiA9IHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvbmZpZztcbn1cbiIsIiMhL3Vzci9iaW4vZW52IG5vZGVcbmltcG9ydCB7IFdlYlNvY2tldCB9IGZyb20gXCJ3c1wiO1xuKGdsb2JhbCBhcyBhbnkpLldlYlNvY2tldCA9IFdlYlNvY2tldDtcblxuaW1wb3J0IHsgY29uZmlnLCBjb25maWdfZXZlbnRfZW1pdHRlciwgVGltZUNvbnRyb2xSYW5nZXMgfSBmcm9tIFwiLi9jb25maWdcIjtcbmltcG9ydCB7IHNvY2tldCB9IGZyb20gXCIuL3NvY2tldFwiO1xuaW1wb3J0IHsgdHJhY2UgfSBmcm9tIFwiLi90cmFjZVwiO1xuaW1wb3J0IHsgcG9zdCwgYXBpMSB9IGZyb20gXCIuL3V0aWxcIjtcbmltcG9ydCB7IEdhbWUsIGhhbmRsZUNoYXRMaW5lIH0gZnJvbSBcIi4vR2FtZVwiO1xuaW1wb3J0IHsgYm90X3Bvb2xzIH0gZnJvbSBcIi4vcG9vbHNcIjtcbmltcG9ydCB7IEpHT0ZUaW1lQ29udHJvbCwgcHJvdG9jb2wgfSBmcm9tIFwiZ29iYW4tZW5naW5lXCI7XG5pbXBvcnQgeyBTcGVlZCB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8vcHJvY2Vzcy50aXRsZSA9IGBndHAyb2dzICR7Y29uZmlnLmJvdF9jb21tYW5kLmpvaW4oXCIgXCIpfWA7XG5cbmNvbnN0IGlnbm9yYWJsZV9ub3RpZmljYXRpb25zID0ge1xuICAgIGRlbGV0ZTogdHJ1ZSxcbiAgICBnYW1lU3RhcnRlZDogdHJ1ZSxcbiAgICBnYW1lRW5kZWQ6IHRydWUsXG4gICAgZ2FtZURlY2xpbmVkOiB0cnVlLFxuICAgIGdhbWVSZXN1bWVkRnJvbVN0b25lUmVtb3ZhbDogdHJ1ZSxcbiAgICB0b3VybmFtZW50U3RhcnRlZDogdHJ1ZSxcbiAgICB0b3VybmFtZW50RW5kZWQ6IHRydWUsXG4gICAgYWlSZXZpZXdEb25lOiB0cnVlLFxufTtcblxuaW50ZXJmYWNlIFJlamVjdGlvbkRldGFpbHMge1xuICAgIG1lc3NhZ2U6IHN0cmluZztcbiAgICAvKiBOT1RFOiBJZiBhZGRpdGlvbmFsIHJlamVjdGlvbl9jb2RlcyBhcmUgYWRkZWQsIHlvdSBtdXN0IGFsc28gYWRkXG4gICAgICogdGhlbSBodHRwczovL2dpdGh1Yi5jb20vb25saW5lLWdvL29ubGluZS1nby5jb20vYmxvYi9kZXZlbC9zcmMvY29tcG9uZW50cy9DaGFsbGVuZ2VNb2RhbC9DaGFsbGVuZ2VNb2RhbC50c3hcbiAgICAgKiBzbyB0aGF0IGFwcHJvcHJpYXRlIHRyYW5zbGF0ZWQgbWVzc2FnZXMgYXJlIGRpc3BsYXllZCB0byB0aGUgdXNlci5cbiAgICAgKi9cbiAgICByZWplY3Rpb25fY29kZTpcbiAgICAgICAgfCBcImJsYWNrbGlzdGVkXCJcbiAgICAgICAgfCBcImJvYXJkX3NpemVfbm90X3NxdWFyZVwiXG4gICAgICAgIHwgXCJib2FyZF9zaXplX25vdF9hbGxvd2VkXCJcbiAgICAgICAgfCBcImhhbmRpY2FwX25vdF9hbGxvd2VkXCJcbiAgICAgICAgfCBcInVucmFua2VkX25vdF9hbGxvd2VkXCJcbiAgICAgICAgfCBcInJhbmtlZF9ub3RfYWxsb3dlZFwiXG4gICAgICAgIHwgXCJibGl0el9ub3RfYWxsb3dlZFwiXG4gICAgICAgIHwgXCJ0b29fbWFueV9ibGl0el9nYW1lc1wiXG4gICAgICAgIHwgXCJyYXBpZF9ub3RfYWxsb3dlZFwiXG4gICAgICAgIHwgXCJ0b29fbWFueV9yYXBpZF9nYW1lc1wiXG4gICAgICAgIHwgXCJsaXZlX25vdF9hbGxvd2VkXCJcbiAgICAgICAgfCBcInRvb19tYW55X2xpdmVfZ2FtZXNcIlxuICAgICAgICB8IFwiY29ycmVzcG9uZGVuY2Vfbm90X2FsbG93ZWRcIlxuICAgICAgICB8IFwidG9vX21hbnlfY29ycmVzcG9uZGVuY2VfZ2FtZXNcIlxuICAgICAgICB8IFwidGltZV9jb250cm9sX3N5c3RlbV9ub3RfYWxsb3dlZFwiXG4gICAgICAgIHwgXCJ0aW1lX2luY3JlbWVudF9vdXRfb2ZfcmFuZ2VcIlxuICAgICAgICB8IFwicGVyaW9kX3RpbWVfb3V0X29mX3JhbmdlXCJcbiAgICAgICAgfCBcInBlcmlvZHNfb3V0X29mX3JhbmdlXCJcbiAgICAgICAgfCBcIm1haW5fdGltZV9vdXRfb2ZfcmFuZ2VcIlxuICAgICAgICB8IFwibWF4X3RpbWVfb3V0X29mX3JhbmdlXCJcbiAgICAgICAgfCBcInBlcl9tb3ZlX3RpbWVfb3V0X29mX3JhbmdlXCJcbiAgICAgICAgfCBcInBsYXllcl9yYW5rX291dF9vZl9yYW5nZVwiXG4gICAgICAgIHwgXCJub3RfYWNjZXB0aW5nX25ld19jaGFsbGVuZ2VzXCJcbiAgICAgICAgfCBcInRvb19tYW55X2dhbWVzX2Zvcl9wbGF5ZXJcIlxuICAgICAgICB8IFwia29taV9vdXRfb2ZfcmFuZ2VcIjtcbiAgICBkZXRhaWxzOiB7XG4gICAgICAgIFtrZXk6IHN0cmluZ106IGFueTtcbiAgICB9O1xufVxuXG4vKiogVGhpcyBpcyB0aGUgbWFpbiBjbGFzcyBmb3IgdGhlIGNvbm5lY3Rpb24gdG8gdGhlIHNlcnZlci4gSXQgaXMgcmVzcG9uc2libGVcbiAqIGZvciBtYW5hZ2luZyBnYW1lcyBpbiBwbGF5LCByZXNwb25kaW5nIHRvIGNoYWxsZW5nZXMgYW5kIG5vdGlmaWNhdGlvbnMsIGFuZFxuICogdGhhdCBzb3J0IG9mIHN0dWZmLiAqL1xuY2xhc3MgTWFpbiB7XG4gICAgbm90aWZpY2F0aW9uX2Nvbm5lY3RfaW50ZXJ2YWw6IFJldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPjtcbiAgICBjb25uZWN0ZWRfZ2FtZXM6IHsgW2dhbWVfaWQ6IHN0cmluZ106IEdhbWUgfTtcbiAgICBjb25uZWN0ZWRfZmluaXNoZWRfZ2FtZXM6IHsgW2dhbWVfaWQ6IHN0cmluZ106IGJvb2xlYW4gfTtcblxuICAgIC8vZ2FtZXNfYnlfcGxheWVyOiB7IFtwbGF5ZXJfaWQ6IHN0cmluZ106IEdhbWVbXSB9O1xuICAgIGNvbm5lY3RlZDogYm9vbGVhbjtcbiAgICBjb25uZWN0X3RpbWVvdXQ6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+O1xuICAgIGlkbGVfdGltZW91dF9pbnRlcnZhbDogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0SW50ZXJ2YWw+O1xuICAgIHBpbmdfaW50ZXJ2YWw6IFJldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPjtcbiAgICBib3RfaWQ6IG51bWJlcjtcbiAgICBib3RfdXNlcm5hbWU6IHN0cmluZztcbiAgICBwcml2YXRlIGxhc3Rfc3RhdHVzX3VwZGF0ZTogeyBba2V5OiBzdHJpbmddOiBudW1iZXIgfSA9IHt9O1xuXG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuY29ubmVjdGVkX2dhbWVzID0ge307XG4gICAgICAgIHRoaXMuY29ubmVjdGVkX2ZpbmlzaGVkX2dhbWVzID0ge307XG4gICAgICAgIC8vdGhpcy5nYW1lc19ieV9wbGF5ZXIgPSB7fTsgLy8gS2VlcCB0cmFjayBvZiBjb25uZWN0ZWQgZ2FtZXMgcGVyIHBsYXllclxuICAgICAgICB0aGlzLmNvbm5lY3RlZCA9IGZhbHNlO1xuXG4gICAgICAgIGlmIChjb25maWcuc3RhdHVzX3VwZGF0ZV9mcmVxdWVuY3kgPiAwKSB7XG4gICAgICAgICAgICBzZXRJbnRlcnZhbCh0aGlzLmR1bXBTdGF0dXMuYmluZCh0aGlzKSwgY29uZmlnLnN0YXR1c191cGRhdGVfZnJlcXVlbmN5KTtcbiAgICAgICAgfVxuICAgICAgICBzZXRJbnRlcnZhbCh0aGlzLnNlbmRTdGF0dXNVcGRhdGUuYmluZCh0aGlzKSwgMTAwKTtcblxuICAgICAgICBzb2NrZXQub24oXCJjb25uZWN0XCIsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGVkID0gdHJ1ZTtcblxuICAgICAgICAgICAgYXdhaXQgYm90X3Bvb2xzLm1haW4ucmVhZHk7XG4gICAgICAgICAgICBpZiAoYm90X3Bvb2xzLmVuZGluZykge1xuICAgICAgICAgICAgICAgIGF3YWl0IGJvdF9wb29scy5lbmRpbmcucmVhZHk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoYm90X3Bvb2xzLm9wZW5pbmcpIHtcbiAgICAgICAgICAgICAgICBhd2FpdCBib3RfcG9vbHMub3BlbmluZy5yZWFkeTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc29ja2V0LnNlbmQoXG4gICAgICAgICAgICAgICAgXCJhdXRoZW50aWNhdGVcIixcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGp3dDogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgYm90X3VzZXJuYW1lOiBjb25maWcudXNlcm5hbWUsXG4gICAgICAgICAgICAgICAgICAgIGJvdF9hcGlrZXk6IGNvbmZpZy5hcGlrZXksXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAob2JqKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghb2JqKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFjZS5lcnJvcihgRVJST1I6IEF1dGhlbnRpY2F0aW9uIGZhaWxlZGApO1xuICAgICAgICAgICAgICAgICAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5ib3RfaWQgPSBvYmo/LmlkO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmJvdF91c2VybmFtZSA9IG9iaj8udXNlcm5hbWU7XG4gICAgICAgICAgICAgICAgICAgIGNvbmZpZy5ib3RfaWQgPSB0aGlzLmJvdF9pZDtcbiAgICAgICAgICAgICAgICAgICAgY29uZmlnLnVzZXJuYW1lID0gdGhpcy5ib3RfdXNlcm5hbWU7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmJvdF9pZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2UuZXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYEVSUk9SOiBCb3QgYWNjb3VudCBpcyB1bmtub3duIHRvIHRoZSBzeXN0ZW06ICR7Y29uZmlnLnVzZXJuYW1lfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNvbmZpZy5ib3RfaWQgPSB0aGlzLmJvdF9pZDtcbiAgICAgICAgICAgICAgICAgICAgdHJhY2UuaW5mbyhcIkJvdCBpcyB1c2VybmFtZTogXCIsIHRoaXMuYm90X3VzZXJuYW1lKTtcbiAgICAgICAgICAgICAgICAgICAgdHJhY2UuaW5mbyhcIkJvdCBpcyB1c2VyIGlkOiBcIiwgdGhpcy5ib3RfaWQpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBjb25maWdfdjI6IHByb3RvY29sLkJvdENvbmZpZ1YyID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaGlkZGVuOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLmNvbmZpZyxcbiAgICAgICAgICAgICAgICAgICAgICAgIF9jb25maWdfdmVyc2lvbjogMixcbiAgICAgICAgICAgICAgICAgICAgfSBhcyBwcm90b2NvbC5Cb3RDb25maWdWMjtcbiAgICAgICAgICAgICAgICAgICAgc29ja2V0LnNlbmQoXCJib3QvY29uZmlnXCIsIGNvbmZpZ192Mik7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbmZpZ19ldmVudF9lbWl0dGVyLm9uKFwicmVsb2FkZWRcIiwgKCkgPT4ge1xuICAgICAgICAgICAgY29uZmlnLmJvdF9pZCA9IHRoaXMuYm90X2lkO1xuICAgICAgICAgICAgY29uZmlnLnVzZXJuYW1lID0gdGhpcy5ib3RfdXNlcm5hbWU7XG5cbiAgICAgICAgICAgIGlmIChzb2NrZXQuY29ubmVjdGVkKSB7XG4gICAgICAgICAgICAgICAgc29ja2V0LnNlbmQoXCJib3QvY29uZmlnXCIsIHtcbiAgICAgICAgICAgICAgICAgICAgaGlkZGVuOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgLi4uY29uZmlnLFxuICAgICAgICAgICAgICAgICAgICBfY29uZmlnX3ZlcnNpb246IDIsXG4gICAgICAgICAgICAgICAgfSBhcyBwcm90b2NvbC5Cb3RDb25maWdWMik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNvY2tldC5vbihcImRpc2Nvbm5lY3RcIiwgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0ZWQgPSBmYWxzZTtcblxuICAgICAgICAgICAgdHJhY2Uud2FybihcIkRpc2Nvbm5lY3RlZCBmcm9tIHNlcnZlclwiKTtcblxuICAgICAgICAgICAgZm9yIChjb25zdCBnYW1lX2lkIGluIHRoaXMuY29ubmVjdGVkX2dhbWVzKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXNjb25uZWN0RnJvbUdhbWUocGFyc2VJbnQoZ2FtZV9pZCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBzb2NrZXQub24oXCJub3RpZmljYXRpb25cIiwgKG5vdGlmaWNhdGlvbikgPT4gdGhpcy5oYW5kbGVOb3RpZmljYXRpb24obm90aWZpY2F0aW9uKSk7XG5cbiAgICAgICAgc29ja2V0Lm9uKFwiYWN0aXZlX2dhbWVcIiwgKGdhbWVkYXRhKSA9PiB7XG4gICAgICAgICAgICAvL3RyYWNlLnRyYWNlKFwiYWN0aXZlX2dhbWU6XCIsIEpTT04uc3RyaW5naWZ5KGdhbWVkYXRhKSk7XG5cbiAgICAgICAgICAgIC8qIE9HUyBhdXRvIHNjb3JlcyBib3QgZ2FtZXMgbm93LCBubyByZW1vdmFsIHByb2Nlc3NpbmcgaXMgbmVlZGVkIGJ5IHRoZSBib3QuXG5cbiAgICAgICAgICAgIC8gIEV2ZW50dWFsbHkgbWlnaHQgd2FudCBPR1MgdG8gbm90IGF1dG8gc2NvcmUsIG9yIG1ha2UgaXQgYm90LW9wdGlvbmFsIHRvIGVuZm9yY2UuXG4gICAgICAgICAgICAvICBTb21lIGJvdHMgY2FuIGhhbmRsZSBzdG9uZSByZW1vdmFsIHByb2Nlc3MuXG5cbiAgICAgICAgICAgIC8gIGlmIChnYW1lZGF0YS5waGFzZSA9PT0gJ3N0b25lIHJlbW92YWwnXG4gICAgICAgICAgICAvICAgJiYgKCghZ2FtZWRhdGEuYmxhY2suYWNjZXB0ZWQgJiYgZ2FtZWRhdGEuYmxhY2suaWQgPT09IHRoaXMuYm90X2lkKVxuICAgICAgICAgICAgLyAgIHx8ICAoIWdhbWVkYXRhLndoaXRlLmFjY2VwdGVkICYmIGdhbWVkYXRhLndoaXRlLmlkID09PSB0aGlzLmJvdF9pZCkpXG4gICAgICAgICAgICAvICAgKSB7XG4gICAgICAgICAgICAvICAgdGhpcy5wcm9jZXNzTW92ZShnYW1lZGF0YSk7XG4gICAgICAgICAgICAvICAgfSovXG5cbiAgICAgICAgICAgIGlmIChnYW1lZGF0YS5waGFzZSA9PT0gXCJmaW5pc2hlZFwiKSB7XG4gICAgICAgICAgICAgICAgaWYgKGdhbWVkYXRhLmlkIGluIHRoaXMuY29ubmVjdGVkX2dhbWVzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8qIFdoZW4gYSBnYW1lIGVuZHMsIHdlIGRvbid0IGdldCBhIFwiZmluaXNoZWRcIiBhY3RpdmVfZ2FtZS5waGFzZS4gUHJvYmFibHkgc2luY2UgdGhlIGdhbWUgaXMgbm9cbiAgICAgICAgICAgICAgICAgICAgLyAgbG9uZ2VyIGFjdGl2ZS4oVXBkYXRlOiBXZSBkbyBnZXQgZmluaXNoZWQgYWN0aXZlX2dhbWUgZXZlbnRzPyBVbmNsZWFyIHdoeSBJIGFkZGVkIHByaW9yIG5vdGUuKVxuICAgICAgICAgICAgICAgICAgICAvICBOb3RlOiBhY3RpdmVfZ2FtZSBhbmQgZ2FtZWRhdGEgZXZlbnRzIGNhbiBhcnJpdmUgaW4gZWl0aGVyIG9yZGVyLiovXG5cbiAgICAgICAgICAgICAgICAgICAgdHJhY2UuZGVidWcoYGdhbWUgJHtnYW1lZGF0YS5pZH0gaXMgbm93IGZpbmlzaGVkYCk7XG5cbiAgICAgICAgICAgICAgICAgICAgLyogWFhYIFdlIHdhbnQgdG8gZGlzY29ubmVjdCByaWdodCBhd2F5IGhlcmUsIGJ1dCB0aGVyZSdzIGEgZ2FtZSBvdmVyIHJhY2UgY29uZGl0aW9uXG4gICAgICAgICAgICAgICAgICAgIC8gICAgICBvbiBzZXJ2ZXIgc2lkZTogc29tZXRpbWVzIC9nYW1lZGF0YSBldmVudCB3aXRoIGdhbWUgb3V0Y29tZSBpcyBzZW50IGFmdGVyXG4gICAgICAgICAgICAgICAgICAgIC8gICAgICBhY3RpdmVfZ2FtZSwgc28gaXQncyBsb3N0IHNpbmNlIHRoZXJlJ3Mgbm8gZ2FtZSB0byBoYW5kbGUgaXQgYW55bW9yZS4uLlxuICAgICAgICAgICAgICAgICAgICAvICAgICAgV29yayBhcm91bmQgaXQgd2l0aCBhIHRpbWVvdXQgZm9yIG5vdy4qL1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMuY29ubmVjdGVkX2dhbWVzW2dhbWVkYXRhLmlkXS5kaXNjb25uZWN0X3RpbWVvdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjb25maWcudmVyYm9zaXR5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2UubG9nKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgU3RhcnRpbmcgZGlzY29ubmVjdCBUaW1lb3V0IGluIENvbm5lY3Rpb24gYWN0aXZlX2dhbWUgZm9yICR7Z2FtZWRhdGEuaWR9YCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0ZWRfZ2FtZXNbZ2FtZWRhdGEuaWRdLmRpc2Nvbm5lY3RfdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGlzY29ubmVjdEZyb21HYW1lKGdhbWVkYXRhLmlkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sIDEwMDApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIERvbid0IGNvbm5lY3QgdG8gZmluaXNoZWQgZ2FtZXMuXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBTZXQgdXAgdGhlIGdhbWUgc28gaXQgY2FuIGxpc3RlbiBmb3IgZXZlbnRzLlxuICAgICAgICAgICAgdGhpcy5jb25uZWN0VG9HYW1lKGdhbWVkYXRhLmlkKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGNvbm5lY3RUb0dhbWUoZ2FtZV9pZDogbnVtYmVyKSB7XG4gICAgICAgIGlmIChnYW1lX2lkIGluIHRoaXMuY29ubmVjdGVkX2dhbWVzKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jb25uZWN0ZWRfZ2FtZXNbZ2FtZV9pZF07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0cmFjZS5pbmZvKFwiQ29ubmVjdGluZyB0byBnYW1lIFwiLCBnYW1lX2lkKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY29ubmVjdGVkX2dhbWVzW2dhbWVfaWRdID0gbmV3IEdhbWUoZ2FtZV9pZCk7XG4gICAgICAgIHRoaXMuY29ubmVjdGVkX2dhbWVzW2dhbWVfaWRdLm9uKFwiZGlzY29ubmVjdGVkXCIsIChnYW1lX2lkOiBudW1iZXIpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZGlzY29ubmVjdEZyb21HYW1lKGdhbWVfaWQpO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gdGhpcy5jb25uZWN0ZWRfZ2FtZXNbZ2FtZV9pZF07XG4gICAgfVxuICAgIGRpc2Nvbm5lY3RGcm9tR2FtZShnYW1lX2lkOiBudW1iZXIpIHtcbiAgICAgICAgdHJhY2UuaW5mbyhcIkRpc2Nvbm5lY3RpbmcgZnJvbSBnYW1lIFwiLCBnYW1lX2lkKTtcbiAgICAgICAgaWYgKGdhbWVfaWQgaW4gdGhpcy5jb25uZWN0ZWRfZ2FtZXMpIHtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGVkX2dhbWVzW2dhbWVfaWRdLmRpc2Nvbm5lY3QoKTtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmNvbm5lY3RlZF9nYW1lc1tnYW1lX2lkXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBkdW1wU3RhdHVzKCkge1xuICAgICAgICBjb25zdCBibGl0el9jb3VudCA9IHRoaXMuY291bnRHYW1lcyhcImJsaXR6XCIpO1xuICAgICAgICBjb25zdCByYXBpZF9jb3VudCA9IHRoaXMuY291bnRHYW1lcyhcInJhcGlkXCIpO1xuICAgICAgICBjb25zdCBsaXZlX2NvdW50ID0gdGhpcy5jb3VudEdhbWVzKFwibGl2ZVwiKTtcbiAgICAgICAgY29uc3QgY29ycl9jb3VudCA9IHRoaXMuY291bnRHYW1lcyhcImNvcnJlc3BvbmRlbmNlXCIpO1xuXG4gICAgICAgIHRyYWNlLmluZm8oXG4gICAgICAgICAgICBgU3RhdHVzOiBwbGF5aW5nICR7YmxpdHpfY291bnR9IGJsaXR6LCAke3JhcGlkX2NvdW50fSByYXBpZCwgJHtsaXZlX2NvdW50fSBsaXZlLCAke2NvcnJfY291bnR9IGNvcnJlc3BvbmRlbmNlIGdhbWVzYCxcbiAgICAgICAgKTtcblxuICAgICAgICBsZXQgc3RyID0gXCJCb3Qgc3RhdHVzOiBcIjtcbiAgICAgICAgZm9yIChjb25zdCBuIG9mIFtcIm1haW5cIiwgXCJlbmRpbmdcIiwgXCJvcGVuaW5nXCJdKSB7XG4gICAgICAgICAgICBjb25zdCBwb29sID0gYm90X3Bvb2xzW25dO1xuICAgICAgICAgICAgaWYgKCFwb29sKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHN0ciArPSBwb29sLnN0YXRlU3RyaW5nKCkgKyBcIiBcIjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyYWNlLmluZm8oc3RyKTtcbiAgICB9XG5cbiAgICAvKiogU2VuZCB0aGUgc2VydmVyIG91ciBjdXJyZW50IHN0YXR1cyAqL1xuICAgIHByaXZhdGUgc2VuZFN0YXR1c1VwZGF0ZSgpIHtcbiAgICAgICAgY29uc3QgdXBkYXRlID0ge1xuICAgICAgICAgICAgb25nb2luZ19ibGl0el9jb3VudDogdGhpcy5jb3VudEdhbWVzKFwiYmxpdHpcIiksXG4gICAgICAgICAgICBvbmdvaW5nX3JhcGlkX2NvdW50OiB0aGlzLmNvdW50R2FtZXMoXCJyYXBpZFwiKSxcbiAgICAgICAgICAgIG9uZ29pbmdfbGl2ZV9jb3VudDogdGhpcy5jb3VudEdhbWVzKFwibGl2ZVwiKSxcbiAgICAgICAgICAgIG9uZ29pbmdfY29ycmVzcG9uZGVuY2VfY291bnQ6IHRoaXMuY291bnRHYW1lcyhcImNvcnJlc3BvbmRlbmNlXCIpLFxuICAgICAgICB9O1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHVwZGF0ZVtcIm9uZ29pbmdfYmxpdHpfY291bnRcIl0gIT09IHRoaXMubGFzdF9zdGF0dXNfdXBkYXRlW1wib25nb2luZ19ibGl0el9jb3VudFwiXSB8fFxuICAgICAgICAgICAgdXBkYXRlW1wib25nb2luZ19yYXBpZF9jb3VudFwiXSAhPT0gdGhpcy5sYXN0X3N0YXR1c191cGRhdGVbXCJvbmdvaW5nX3JhcGlkX2NvdW50XCJdIHx8XG4gICAgICAgICAgICB1cGRhdGVbXCJvbmdvaW5nX2xpdmVfY291bnRcIl0gIT09IHRoaXMubGFzdF9zdGF0dXNfdXBkYXRlW1wib25nb2luZ19saXZlX2NvdW50XCJdIHx8XG4gICAgICAgICAgICB1cGRhdGVbXCJvbmdvaW5nX2NvcnJlc3BvbmRlbmNlX2NvdW50XCJdICE9PVxuICAgICAgICAgICAgICAgIHRoaXMubGFzdF9zdGF0dXNfdXBkYXRlW1wib25nb2luZ19jb3JyZXNwb25kZW5jZV9jb3VudFwiXVxuICAgICAgICApIHtcbiAgICAgICAgICAgIHNvY2tldC5zZW5kKFwiYm90L3N0YXR1c1wiLCB1cGRhdGUpO1xuICAgICAgICAgICAgdGhpcy5sYXN0X3N0YXR1c191cGRhdGUgPSB1cGRhdGU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjb3VudEdhbWVzKHNwZWVkOiBTcGVlZCkge1xuICAgICAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyh0aGlzLmNvbm5lY3RlZF9nYW1lcykuZmlsdGVyKFxuICAgICAgICAgICAgKGcpID0+IGc/LnN0YXRlPy50aW1lX2NvbnRyb2w/LnNwZWVkID09PSBzcGVlZCxcbiAgICAgICAgKS5sZW5ndGg7XG4gICAgfVxuXG4gICAgZGVsZXRlTm90aWZpY2F0aW9uKG5vdGlmaWNhdGlvbikge1xuICAgICAgICBzb2NrZXQuc2VuZChcIm5vdGlmaWNhdGlvbi9kZWxldGVcIiwgeyBub3RpZmljYXRpb25faWQ6IG5vdGlmaWNhdGlvbi5pZCB9LCAoKSA9PiB7XG4gICAgICAgICAgICB0cmFjZS50cmFjZShcIkRlbGV0ZWQgbm90aWZpY2F0aW9uIFwiLCBub3RpZmljYXRpb24uaWQpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBoYW5kbGVOb3RpZmljYXRpb24obm90aWZpY2F0aW9uKTogdm9pZCB7XG4gICAgICAgIHN3aXRjaCAobm90aWZpY2F0aW9uLnR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgXCJmcmllbmRSZXF1ZXN0XCI6XG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0cmFjZS5sb2coXCJGcmllbmQgcmVxdWVzdCBmcm9tIFwiLCBub3RpZmljYXRpb24udXNlci51c2VybmFtZSk7XG4gICAgICAgICAgICAgICAgICAgIHBvc3QoYXBpMShcIm1lL2ZyaWVuZHMvaW52aXRhdGlvbnNcIiksIHsgZnJvbV91c2VyOiBub3RpZmljYXRpb24udXNlci5pZCB9KVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRoZW4oKG9iaikgPT4gdHJhY2UuaW5mbyhvYmouYm9keSkpXG4gICAgICAgICAgICAgICAgICAgICAgICAuY2F0Y2godHJhY2UuaW5mbyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlIFwiY2hhbGxlbmdlXCI6XG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBsZXQgcmVqZWN0OiBSZWplY3Rpb25EZXRhaWxzIHwgdW5kZWZpbmVkID1cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2tCbGFja2xpc3Qobm90aWZpY2F0aW9uLnVzZXIpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNoZWNrVGltZUNvbnRyb2wobm90aWZpY2F0aW9uLnRpbWVfY29udHJvbCkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2tDb25jdXJyZW50R2FtZXMobm90aWZpY2F0aW9uLnRpbWVfY29udHJvbC5zcGVlZCkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2tCb2FyZFNpemUobm90aWZpY2F0aW9uLndpZHRoLCBub3RpZmljYXRpb24uaGVpZ2h0KSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jaGVja0hhbmRpY2FwKG5vdGlmaWNhdGlvbi5yYW5rZWQsIG5vdGlmaWNhdGlvbi5oYW5kaWNhcCkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2tSYW5rZWQobm90aWZpY2F0aW9uLnJhbmtlZCkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2tBbGxvd2VkUmFuayhub3RpZmljYXRpb24ucmFua2VkLCBub3RpZmljYXRpb24ubWluX3JhbmtpbmcpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNoZWNrRGVjbGluZUNoYWxsZW5nZXMoKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jaGVja0dhbWVzUGVyUGxheWVyKG5vdGlmaWNhdGlvbi51c2VyPy5pZCkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2hlY2tLb21pKG5vdGlmaWNhdGlvbi5rb21pKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgdW5kZWZpbmVkO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmNoZWNrV2hpdGVsaXN0KG5vdGlmaWNhdGlvbi51c2VyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFyZWplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBvc3QoYXBpMShgbWUvY2hhbGxlbmdlcy8ke25vdGlmaWNhdGlvbi5jaGFsbGVuZ2VfaWR9L2FjY2VwdGApLCB7fSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAudGhlbihpZ25vcmUpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLmNhdGNoKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2UuaW5mbyhcIkVycm9yIGFjY2VwdGluZyBjaGFsbGVuZ2UsIGRlY2xpbmluZyBpdFwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zdChhcGkxKGBtZS9jaGFsbGVuZ2VzLyR7bm90aWZpY2F0aW9uLmNoYWxsZW5nZV9pZH1gKSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIkVycm9yIGFjY2VwdGluZyBnYW1lIGNoYWxsZW5nZSwgY2hhbGxlbmdlIGhhcyBiZWVuIHJlbW92ZWQuXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAudGhlbihpZ25vcmUpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuY2F0Y2godHJhY2UuaW5mbyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZGVsZXRlTm90aWZpY2F0aW9uKG5vdGlmaWNhdGlvbik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFjZS5pbmZvKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBSZWplY3RpbmcgY2hhbGxlbmdlIGZyb20gJHtub3RpZmljYXRpb24udXNlci51c2VybmFtZX0gaHR0cHM6Ly9vbmxpbmUtZ28uY29tL3BsYXllci8ke25vdGlmaWNhdGlvbi51c2VyLmlkfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0LFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBvc3QoYXBpMShgbWUvY2hhbGxlbmdlcy8ke25vdGlmaWNhdGlvbi5jaGFsbGVuZ2VfaWR9YCksIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxldGU6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogcmVqZWN0Lm1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0aW9uX2RldGFpbHM6IHJlamVjdCxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLnRoZW4oaWdub3JlKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5jYXRjaCh0cmFjZS5pbmZvKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBcImxhdGVDaGF0UmVjZWl2ZWRJbkdhbWVcIjpcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZGVsZXRlTm90aWZpY2F0aW9uKG5vdGlmaWNhdGlvbik7XG4gICAgICAgICAgICAgICAgICAgIGlmICghY29uZmlnLmxvZ19nYW1lX2NoYXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGdhbWVfaWQgPSBub3RpZmljYXRpb24uZ2FtZV9pZDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGdhbWVfaWQgaW4gdGhpcy5jb25uZWN0ZWRfZmluaXNoZWRfZ2FtZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFscmVhZHkgY29ubmVjdGVkIHRvIHRoZSBmaW5pc2hlZCBnYW1lLlxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICB0cmFjZS5kZWJ1ZyhgQ29ubmVjdGluZyB0byAke2dhbWVfaWR9IHRvIHJlY2VpdmUgbGF0ZSBjaGF0c2ApO1xuICAgICAgICAgICAgICAgICAgICBzb2NrZXQuc2VuZChcImNoYXQvam9pblwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjaGFubmVsOiBgZ2FtZS0ke2dhbWVfaWR9YCxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG9uX2NoYXQgPSAoY2hhdCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaGFuZGxlQ2hhdExpbmUoZ2FtZV9pZCwgY2hhdC5saW5lLCBub3RpZmljYXRpb24udGltZXN0YW1wIC0gMSk7XG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIHNvY2tldC5vbihgZ2FtZS8ke2dhbWVfaWR9L2NoYXRgLCBvbl9jaGF0KTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBDb25uZWN0aW5nIHRvIGEgZ2FtZSBmcm9tIG91dHNpZGUgR2FtZSBkZXNlcnZlcyBhIGxpdHRsZVxuICAgICAgICAgICAgICAgICAgICAvLyBiaXQgb2YgY2FyZSwgYnV0IEkgdGhpbmsgaXQgc2hvdWxkIGJlIE9LLCBiZWNhdXNlXG4gICAgICAgICAgICAgICAgICAgIC8vIGxhdGVDaGF0UmVjZWl2ZWRJbkdhbWUgaW1wbGllcyB0aGUgZ2FtZSBpcyBvdmVyLCBzbyB3ZVxuICAgICAgICAgICAgICAgICAgICAvLyBzaG91bGQgbm90IGJlIGdldHRpbmcgaW4gdGhlIHdheSBvZiBhbnl0aGluZyBoZXJlLlxuICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAvLyBXZSBjb3VsZCBjb25uZWN0IHRvIHRoZSBnYW1lIGFzIHdlIHVzdWFsbHkgZG8sIGJ1dCB0aGlzXG4gICAgICAgICAgICAgICAgICAgIC8vIHdvdWxkIGNvbmZ1c2UgdGhlIGxvZ2ljIHRoZXJlIHRoYXQgZXhwZWN0cyB0byBoYW5kbGUgYW5cbiAgICAgICAgICAgICAgICAgICAgLy8gdW5maW5pc2hlZCBnYW1lLlxuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3RlZF9maW5pc2hlZF9nYW1lc1tnYW1lX2lkXSA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNvY2tldC5zZW5kKFwiZ2FtZS9jb25uZWN0XCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdhbWVfaWQ6IGdhbWVfaWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBjaGF0OiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFjZS5kZWJ1ZyhgRGlzY29ubmVjdGluZyBmcm9tICR7Z2FtZV9pZH0gKGNoYXRzKWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuY29ubmVjdGVkX2ZpbmlzaGVkX2dhbWVzW2dhbWVfaWRdO1xuICAgICAgICAgICAgICAgICAgICAgICAgc29ja2V0LnNlbmQoXCJnYW1lL2Rpc2Nvbm5lY3RcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdhbWVfaWQ6IGdhbWVfaWQsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNvY2tldC5vZmYoYGdhbWUvJHtnYW1lX2lkfS9jaGF0YCwgb25fY2hhdCk7XG4gICAgICAgICAgICAgICAgICAgIH0sIDUwMDApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghKG5vdGlmaWNhdGlvbi50eXBlIGluIGlnbm9yYWJsZV9ub3RpZmljYXRpb25zKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdHJhY2UubG9nKFwiVW5oYW5kbGVkIG5vdGlmaWNhdGlvbiB0eXBlOiBcIiwgbm90aWZpY2F0aW9uLnR5cGUsIG5vdGlmaWNhdGlvbik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKG5vdGlmaWNhdGlvbi50eXBlICE9PSBcImRlbGV0ZVwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmRlbGV0ZU5vdGlmaWNhdGlvbihub3RpZmljYXRpb24pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgY2hlY2tCbGFja2xpc3QodXNlcjogeyBpZDogbnVtYmVyOyB1c2VybmFtZTogc3RyaW5nIH0pOiBSZWplY3Rpb25EZXRhaWxzIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgaWYgKCFjb25maWcuYmxhY2tsaXN0KSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjb25maWcuYmxhY2tsaXN0LmluY2x1ZGVzKHVzZXIuaWQpIHx8IGNvbmZpZy5ibGFja2xpc3QuaW5jbHVkZXModXNlci51c2VybmFtZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFRoZSBvcGVyYXRvciBvZiB0aGlzIGJvdCB3aWxsIG5vdCBsZXQgeW91IHBsYXkgYWdhaW5zdCBpdC5gLFxuICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcImJsYWNrbGlzdGVkXCIsXG4gICAgICAgICAgICAgICAgZGV0YWlsczoge30sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGNoZWNrV2hpdGVsaXN0KHVzZXI6IHsgaWQ6IG51bWJlcjsgdXNlcm5hbWU6IHN0cmluZyB9KTogYm9vbGVhbiB7XG4gICAgICAgIGlmICghY29uZmlnLndoaXRlbGlzdCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjb25maWcud2hpdGVsaXN0LmluY2x1ZGVzKHVzZXIuaWQpIHx8IGNvbmZpZy53aGl0ZWxpc3QuaW5jbHVkZXModXNlci51c2VybmFtZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY2hlY2tCb2FyZFNpemUod2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpOiBSZWplY3Rpb25EZXRhaWxzIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgLy8gaGFuZGxlIGV4cGxpY2l0IGJvYXJkIHNpemUgcmFuZ2VzXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHR5cGVvZiBjb25maWcuYWxsb3dlZF9ib2FyZF9zaXplcyA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgICAgICAgXCJ3aWR0aF9yYW5nZVwiIGluIGNvbmZpZy5hbGxvd2VkX2JvYXJkX3NpemVzICYmXG4gICAgICAgICAgICBcImhlaWdodF9yYW5nZVwiIGluIGNvbmZpZy5hbGxvd2VkX2JvYXJkX3NpemVzXG4gICAgICAgICkge1xuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgIHdpZHRoIDwgY29uZmlnLmFsbG93ZWRfYm9hcmRfc2l6ZXMud2lkdGhfcmFuZ2VbMF0gfHxcbiAgICAgICAgICAgICAgICB3aWR0aCA+IGNvbmZpZy5hbGxvd2VkX2JvYXJkX3NpemVzLndpZHRoX3JhbmdlWzFdIHx8XG4gICAgICAgICAgICAgICAgaGVpZ2h0IDwgY29uZmlnLmFsbG93ZWRfYm9hcmRfc2l6ZXMuaGVpZ2h0X3JhbmdlWzBdIHx8XG4gICAgICAgICAgICAgICAgaGVpZ2h0ID4gY29uZmlnLmFsbG93ZWRfYm9hcmRfc2l6ZXMuaGVpZ2h0X3JhbmdlWzFdXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOlxuICAgICAgICAgICAgICAgICAgICAgICAgYFRoaXMgYm90IG9ubHkgc3VwcG9ydHMgYm9hcmQgc2l6ZXMgYmV0d2VlbiBgICtcbiAgICAgICAgICAgICAgICAgICAgICAgIGAke2NvbmZpZy5hbGxvd2VkX2JvYXJkX3NpemVzLndpZHRoX3JhbmdlWzBdfXgke2NvbmZpZy5hbGxvd2VkX2JvYXJkX3NpemVzLmhlaWdodF9yYW5nZVswXX0gYCArXG4gICAgICAgICAgICAgICAgICAgICAgICBgYW5kICR7Y29uZmlnLmFsbG93ZWRfYm9hcmRfc2l6ZXMud2lkdGhfcmFuZ2VbMV19eCR7Y29uZmlnLmFsbG93ZWRfYm9hcmRfc2l6ZXMuaGVpZ2h0X3JhbmdlWzFdfS5gLFxuICAgICAgICAgICAgICAgICAgICByZWplY3Rpb25fY29kZTogXCJib2FyZF9zaXplX25vdF9hbGxvd2VkXCIsXG4gICAgICAgICAgICAgICAgICAgIGRldGFpbHM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGhfcmFuZ2U6IGNvbmZpZy5hbGxvd2VkX2JvYXJkX3NpemVzLndpZHRoX3JhbmdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0X3JhbmdlOiBjb25maWcuYWxsb3dlZF9ib2FyZF9zaXplcy5oZWlnaHRfcmFuZ2UsXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEhhbmRsZSBub3JtYWwgc2l6ZXMgb3Igc3BlY2lhbCBcImFsbFwiIHwgXCJzcXVhcmVcIiBjYXNlc1xuICAgICAgICBjb25zdCBhbGxvd2VkID0gQXJyYXkuaXNBcnJheShjb25maWcuYWxsb3dlZF9ib2FyZF9zaXplcylcbiAgICAgICAgICAgID8gY29uZmlnLmFsbG93ZWRfYm9hcmRfc2l6ZXNcbiAgICAgICAgICAgIDogW2NvbmZpZy5hbGxvd2VkX2JvYXJkX3NpemVzXTtcblxuICAgICAgICBpZiAoYWxsb3dlZC5pbmNsdWRlcyhcImFsbFwiKSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChhbGxvd2VkLmluY2x1ZGVzKFwic3F1YXJlXCIpICYmIHdpZHRoID09PSBoZWlnaHQpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAod2lkdGggIT09IGhlaWdodCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3Qgb25seSBwbGF5cyBzcXVhcmUgYm9hcmRzLmAsXG4gICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwiYm9hcmRfc2l6ZV9ub3Rfc3F1YXJlXCIsXG4gICAgICAgICAgICAgICAgZGV0YWlsczogeyB3aWR0aCwgaGVpZ2h0IH0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFhbGxvd2VkLmluY2x1ZGVzKHdpZHRoKSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3Qgb25seSBwbGF5cyBvbiB0aGVzZSBib2FyZCBzaXplczogJHthbGxvd2VkXG4gICAgICAgICAgICAgICAgICAgIC5tYXAoKHgpID0+IGAke3h9eCR7eH1gKVxuICAgICAgICAgICAgICAgICAgICAuam9pbihcIiwgXCIpfS5gLFxuICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcImJvYXJkX3NpemVfbm90X2FsbG93ZWRcIixcbiAgICAgICAgICAgICAgICBkZXRhaWxzOiB7IHdpZHRoLCBoZWlnaHQgfSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBjaGVja0hhbmRpY2FwKHJhbmtlZDogbnVtYmVyLCBoYW5kaWNhcDogbnVtYmVyKTogUmVqZWN0aW9uRGV0YWlscyB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgICEocmFua2VkID8gY29uZmlnLmFsbG93X3JhbmtlZF9oYW5kaWNhcCA6IGNvbmZpZy5hbGxvd191bnJhbmtlZF9oYW5kaWNhcCkgJiZcbiAgICAgICAgICAgIGhhbmRpY2FwICE9PSAwXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3Qgb25seSBwbGF5cyBnYW1lcyB3aXRoIG5vIGhhbmRpY2FwLmAsXG4gICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwiaGFuZGljYXBfbm90X2FsbG93ZWRcIixcbiAgICAgICAgICAgICAgICBkZXRhaWxzOiB7IGhhbmRpY2FwIH0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGNoZWNrUmFua2VkKHJhbmtlZDogYm9vbGVhbik6IFJlamVjdGlvbkRldGFpbHMgfCB1bmRlZmluZWQge1xuICAgICAgICBpZiAoIXJhbmtlZCAmJiAhY29uZmlnLmFsbG93X3VucmFua2VkKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBUaGlzIGJvdCBvbmx5IHBsYXlzIHJhbmtlZCBnYW1lcy5gLFxuICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcInVucmFua2VkX25vdF9hbGxvd2VkXCIsXG4gICAgICAgICAgICAgICAgZGV0YWlsczogeyByYW5rZWQgfSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocmFua2VkICYmICFjb25maWcuYWxsb3dfcmFua2VkKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBUaGlzIGJvdCBvbmx5IHBsYXlzIHVucmFua2VkIGdhbWVzLmAsXG4gICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwicmFua2VkX25vdF9hbGxvd2VkXCIsXG4gICAgICAgICAgICAgICAgZGV0YWlsczogeyByYW5rZWQgfSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBjaGVja0NvbmN1cnJlbnRHYW1lcyhzcGVlZDogU3BlZWQpOiBSZWplY3Rpb25EZXRhaWxzIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgY29uc3QgY291bnQgPSB0aGlzLmNvdW50R2FtZXMoc3BlZWQpO1xuICAgICAgICBzd2l0Y2ggKHNwZWVkKSB7XG4gICAgICAgICAgICBjYXNlIFwiYmxpdHpcIjpcbiAgICAgICAgICAgICAgICBpZiAoIWNvbmZpZy5hbGxvd2VkX2JsaXR6X3NldHRpbmdzPy5jb25jdXJyZW50X2dhbWVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3QgZG9lcyBub3QgcGxheSBibGl0eiBnYW1lcy5gLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwiYmxpdHpfbm90X2FsbG93ZWRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGRldGFpbHM6IHt9LFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoY291bnQgPj0gKGNvbmZpZy5hbGxvd2VkX2JsaXR6X3NldHRpbmdzPy5jb25jdXJyZW50X2dhbWVzIHx8IDApKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3QgaXMgYWxyZWFkeSBwbGF5aW5nICR7Y291bnR9IG9mICR7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnLmFsbG93ZWRfYmxpdHpfc2V0dGluZ3M/LmNvbmN1cnJlbnRfZ2FtZXMgfHwgMFxuICAgICAgICAgICAgICAgICAgICAgICAgfSBhbGxvd2VkIGJsaXR6IGdhbWVzLmAsXG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3Rpb25fY29kZTogXCJ0b29fbWFueV9ibGl0el9nYW1lc1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGV0YWlsczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbG93ZWQ6IGNvbmZpZy5hbGxvd2VkX2JsaXR6X3NldHRpbmdzPy5jb25jdXJyZW50X2dhbWVzIHx8IDAsXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBcInJhcGlkXCI6XG4gICAgICAgICAgICAgICAgaWYgKCFjb25maWcuYWxsb3dlZF9yYXBpZF9zZXR0aW5ncz8uY29uY3VycmVudF9nYW1lcykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogYFRoaXMgYm90IGRvZXMgbm90IHBsYXkgcmFwaWQgZ2FtZXMuYCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcInJhcGlkX25vdF9hbGxvd2VkXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBkZXRhaWxzOiB7fSxcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGNvdW50ID49IChjb25maWcuYWxsb3dlZF9yYXBpZF9zZXR0aW5ncz8uY29uY3VycmVudF9nYW1lcyB8fCAwKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogYFRoaXMgYm90IGlzIGFscmVhZHkgcGxheWluZyAke2NvdW50fSBvZiAke1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5hbGxvd2VkX3JhcGlkX3NldHRpbmdzPy5jb25jdXJyZW50X2dhbWVzIHx8IDBcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gYWxsb3dlZCByYXBpZCBnYW1lcy5gLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwidG9vX21hbnlfcmFwaWRfZ2FtZXNcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGRldGFpbHM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGxvd2VkOiBjb25maWcuYWxsb3dlZF9yYXBpZF9zZXR0aW5ncz8uY29uY3VycmVudF9nYW1lcyB8fCAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgXCJsaXZlXCI6XG4gICAgICAgICAgICAgICAgaWYgKCFjb25maWcuYWxsb3dlZF9saXZlX3NldHRpbmdzPy5jb25jdXJyZW50X2dhbWVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3QgZG9lcyBub3QgcGxheSBsaXZlIGdhbWVzLmAsXG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3Rpb25fY29kZTogXCJsaXZlX25vdF9hbGxvd2VkXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBkZXRhaWxzOiB7fSxcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGNvdW50ID49IChjb25maWcuYWxsb3dlZF9saXZlX3NldHRpbmdzPy5jb25jdXJyZW50X2dhbWVzIHx8IDApKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3QgaXMgYWxyZWFkeSBwbGF5aW5nICR7Y291bnR9IG9mICR7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnLmFsbG93ZWRfbGl2ZV9zZXR0aW5ncz8uY29uY3VycmVudF9nYW1lcyB8fCAwXG4gICAgICAgICAgICAgICAgICAgICAgICB9IGFsbG93ZWQgbGl2ZSBnYW1lcy5gLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwidG9vX21hbnlfbGl2ZV9nYW1lc1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGV0YWlsczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbG93ZWQ6IGNvbmZpZy5hbGxvd2VkX2xpdmVfc2V0dGluZ3M/LmNvbmN1cnJlbnRfZ2FtZXMgfHwgMCxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlIFwiY29ycmVzcG9uZGVuY2VcIjpcbiAgICAgICAgICAgICAgICBpZiAoIWNvbmZpZy5hbGxvd2VkX2NvcnJlc3BvbmRlbmNlX3NldHRpbmdzPy5jb25jdXJyZW50X2dhbWVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3QgZG9lcyBub3QgcGxheSBjb3JyZXNwb25kZW5jZSBnYW1lcy5gLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwiY29ycmVzcG9uZGVuY2Vfbm90X2FsbG93ZWRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGRldGFpbHM6IHt9LFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoY291bnQgPj0gKGNvbmZpZy5hbGxvd2VkX2NvcnJlc3BvbmRlbmNlX3NldHRpbmdzPy5jb25jdXJyZW50X2dhbWVzIHx8IDApKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3QgaXMgYWxyZWFkeSBwbGF5aW5nICR7Y291bnR9IG9mICR7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlnLmFsbG93ZWRfY29ycmVzcG9uZGVuY2Vfc2V0dGluZ3M/LmNvbmN1cnJlbnRfZ2FtZXMgfHwgMFxuICAgICAgICAgICAgICAgICAgICAgICAgfSBhbGxvd2VkIGNvcnJlc3BvbmRlbmNlIGdhbWVzLmAsXG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3Rpb25fY29kZTogXCJ0b29fbWFueV9jb3JyZXNwb25kZW5jZV9nYW1lc1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGV0YWlsczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbG93ZWQ6IGNvbmZpZy5hbGxvd2VkX2NvcnJlc3BvbmRlbmNlX3NldHRpbmdzPy5jb25jdXJyZW50X2dhbWVzIHx8IDAsXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBjaGVja1RpbWVDb250cm9sKHRpbWVfY29udHJvbDogSkdPRlRpbWVDb250cm9sKTogUmVqZWN0aW9uRGV0YWlscyB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGlmICghY29uZmlnLmFsbG93ZWRfdGltZV9jb250cm9sX3N5c3RlbXMuaW5jbHVkZXModGltZV9jb250cm9sLnN5c3RlbSBhcyBhbnkpKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBUaGlzIGJvdCBvbmx5IHBsYXlzIGdhbWVzIHdpdGggdGltZSBjb250cm9sIHN5c3RlbSAke2NvbmZpZy5hbGxvd2VkX3RpbWVfY29udHJvbF9zeXN0ZW1zLmpvaW4oXG4gICAgICAgICAgICAgICAgICAgIFwiLCBcIixcbiAgICAgICAgICAgICAgICApfS5gLFxuICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcInRpbWVfY29udHJvbF9zeXN0ZW1fbm90X2FsbG93ZWRcIixcbiAgICAgICAgICAgICAgICBkZXRhaWxzOiB7IHRpbWVfY29udHJvbF9zeXN0ZW06IHRpbWVfY29udHJvbC5zeXN0ZW0gfSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgc2V0dGluZ3M6IFRpbWVDb250cm9sUmFuZ2VzIHwgdW5kZWZpbmVkO1xuICAgICAgICBzd2l0Y2ggKHRpbWVfY29udHJvbC5zcGVlZCkge1xuICAgICAgICAgICAgY2FzZSBcImJsaXR6XCI6XG4gICAgICAgICAgICAgICAgaWYgKCFjb25maWcuYWxsb3dlZF9ibGl0el9zZXR0aW5ncykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogYFRoaXMgYm90IGRvZXMgbm90IHBsYXkgYmxpdHogZ2FtZXMuYCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcImJsaXR6X25vdF9hbGxvd2VkXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBkZXRhaWxzOiB7fSxcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgc2V0dGluZ3MgPSBjb25maWcuYWxsb3dlZF9ibGl0el9zZXR0aW5ncztcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBcInJhcGlkXCI6XG4gICAgICAgICAgICAgICAgaWYgKCFjb25maWcuYWxsb3dlZF9yYXBpZF9zZXR0aW5ncykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogYFRoaXMgYm90IGRvZXMgbm90IHBsYXkgcmFwaWQgZ2FtZXMuYCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcInJhcGlkX25vdF9hbGxvd2VkXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBkZXRhaWxzOiB7fSxcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgc2V0dGluZ3MgPSBjb25maWcuYWxsb3dlZF9yYXBpZF9zZXR0aW5ncztcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSBcImxpdmVcIjpcbiAgICAgICAgICAgICAgICBpZiAoIWNvbmZpZy5hbGxvd2VkX2xpdmVfc2V0dGluZ3MpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBUaGlzIGJvdCBkb2VzIG5vdCBwbGF5IGxpdmUgZ2FtZXMuYCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcImxpdmVfbm90X2FsbG93ZWRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGRldGFpbHM6IHt9LFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBzZXR0aW5ncyA9IGNvbmZpZy5hbGxvd2VkX2xpdmVfc2V0dGluZ3M7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiY29ycmVzcG9uZGVuY2VcIjpcbiAgICAgICAgICAgICAgICBpZiAoIWNvbmZpZy5hbGxvd2VkX2NvcnJlc3BvbmRlbmNlX3NldHRpbmdzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3QgZG9lcyBub3QgcGxheSBjb3JyZXNwb25kZW5jZSBnYW1lcy5gLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwiY29ycmVzcG9uZGVuY2Vfbm90X2FsbG93ZWRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGRldGFpbHM6IHt9LFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBzZXR0aW5ncyA9IGNvbmZpZy5hbGxvd2VkX2NvcnJlc3BvbmRlbmNlX3NldHRpbmdzO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHNldHRpbmdzKSB7XG4gICAgICAgICAgICBzd2l0Y2ggKHRpbWVfY29udHJvbC5zeXN0ZW0pIHtcbiAgICAgICAgICAgICAgICBjYXNlIFwiZmlzY2hlclwiOlxuICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lX2NvbnRyb2wubWF4X3RpbWUgPCBzZXR0aW5ncy5maXNjaGVyLm1heF90aW1lX3JhbmdlWzBdIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lX2NvbnRyb2wubWF4X3RpbWUgPiBzZXR0aW5ncy5maXNjaGVyLm1heF90aW1lX3JhbmdlWzFdXG4gICAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGltZSBpbmNyZW1lbnQgaXMgb3V0IG9mIGFjY2VwdGFibGUgcmFuZ2VgLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcIm1heF90aW1lX291dF9vZl9yYW5nZVwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRldGFpbHM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9pbmNyZW1lbnQ6IHRpbWVfY29udHJvbC50aW1lX2luY3JlbWVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2U6IHNldHRpbmdzLmZpc2NoZXIudGltZV9pbmNyZW1lbnRfcmFuZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9jb250cm9sLnRpbWVfaW5jcmVtZW50IDwgc2V0dGluZ3MuZmlzY2hlci50aW1lX2luY3JlbWVudF9yYW5nZVswXSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9jb250cm9sLnRpbWVfaW5jcmVtZW50ID4gc2V0dGluZ3MuZmlzY2hlci50aW1lX2luY3JlbWVudF9yYW5nZVsxXVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogYFRpbWUgaW5jcmVtZW50IGlzIG91dCBvZiBhY2NlcHRhYmxlIHJhbmdlYCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWplY3Rpb25fY29kZTogXCJ0aW1lX2luY3JlbWVudF9vdXRfb2ZfcmFuZ2VcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXRhaWxzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVfaW5jcmVtZW50OiB0aW1lX2NvbnRyb2wudGltZV9pbmNyZW1lbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlOiBzZXR0aW5ncy5maXNjaGVyLnRpbWVfaW5jcmVtZW50X3JhbmdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgY2FzZSBcImJ5b3lvbWlcIjpcbiAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9jb250cm9sLnBlcmlvZF90aW1lIDwgc2V0dGluZ3MuYnlveW9taS5wZXJpb2RfdGltZV9yYW5nZVswXSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9jb250cm9sLnBlcmlvZF90aW1lID4gc2V0dGluZ3MuYnlveW9taS5wZXJpb2RfdGltZV9yYW5nZVsxXVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogYFBlcmlvZCB0aW1lIGlzIG91dCBvZiBhY2NlcHRhYmxlIHJhbmdlYCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWplY3Rpb25fY29kZTogXCJwZXJpb2RfdGltZV9vdXRfb2ZfcmFuZ2VcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXRhaWxzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcmlvZF90aW1lOiB0aW1lX2NvbnRyb2wucGVyaW9kX3RpbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlOiBzZXR0aW5ncy5ieW95b21pLnBlcmlvZF90aW1lX3JhbmdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVfY29udHJvbC5wZXJpb2RzIDwgc2V0dGluZ3MuYnlveW9taS5wZXJpb2RzX3JhbmdlWzBdIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lX2NvbnRyb2wucGVyaW9kcyA+IHNldHRpbmdzLmJ5b3lvbWkucGVyaW9kc19yYW5nZVsxXVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogYFBlcmlvZHMgaXMgb3V0IG9mIGFjY2VwdGFibGUgcmFuZ2VgLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcInBlcmlvZHNfb3V0X29mX3JhbmdlXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGV0YWlsczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJpb2RzOiB0aW1lX2NvbnRyb2wucGVyaW9kcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2U6IHNldHRpbmdzLmJ5b3lvbWkucGVyaW9kc19yYW5nZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lX2NvbnRyb2wubWFpbl90aW1lIDwgc2V0dGluZ3MuYnlveW9taS5tYWluX3RpbWVfcmFuZ2VbMF0gfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVfY29udHJvbC5tYWluX3RpbWUgPiBzZXR0aW5ncy5ieW95b21pLm1haW5fdGltZV9yYW5nZVsxXVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogYE1haW4gdGltZSBpcyBvdXQgb2YgYWNjZXB0YWJsZSByYW5nZWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwibWFpbl90aW1lX291dF9vZl9yYW5nZVwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRldGFpbHM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFpbl90aW1lOiB0aW1lX2NvbnRyb2wubWFpbl90aW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5nZTogc2V0dGluZ3MuYnlveW9taS5tYWluX3RpbWVfcmFuZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgICAgICBjYXNlIFwic2ltcGxlXCI6XG4gICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVfY29udHJvbC5wZXJfbW92ZSA8IHNldHRpbmdzLnNpbXBsZS5wZXJfbW92ZV90aW1lX3JhbmdlWzBdIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lX2NvbnRyb2wucGVyX21vdmUgPiBzZXR0aW5ncy5zaW1wbGUucGVyX21vdmVfdGltZV9yYW5nZVsxXVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogYFBlciBtb3ZlIHRpbWUgaXMgb3V0IG9mIGFjY2VwdGFibGUgcmFuZ2VgLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdGlvbl9jb2RlOiBcInBlcl9tb3ZlX3RpbWVfb3V0X29mX3JhbmdlXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGV0YWlsczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJfbW92ZV90aW1lOiB0aW1lX2NvbnRyb2wucGVyX21vdmUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlOiBzZXR0aW5ncy5zaW1wbGUucGVyX21vdmVfdGltZV9yYW5nZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgVGhpcyBib3QgZG9lcyBub3QgcGxheSBnYW1lcyB3aXRoIHRpbWUgY29udHJvbCBzeXN0ZW0gJHt0aW1lX2NvbnRyb2wuc3lzdGVtfS5gLFxuICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwidGltZV9jb250cm9sX3N5c3RlbV9ub3RfYWxsb3dlZFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGV0YWlsczogeyB0aW1lX2NvbnRyb2xfc3lzdGVtOiB0aW1lX2NvbnRyb2wuc3lzdGVtIH0sXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBjaGVja0FsbG93ZWRSYW5rKGdhbWVfaXNfcmFua2VkOiBib29sZWFuLCBwbGF5ZXJfcmFuazogbnVtYmVyKTogUmVqZWN0aW9uRGV0YWlscyB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGNvbnN0IG1pbl9yYW5rID0gcmFua3N0cl90b19udW1iZXIoY29uZmlnLmFsbG93ZWRfcmFua19yYW5nZVswXSk7XG4gICAgICAgIGNvbnN0IG1heF9yYW5rID0gcmFua3N0cl90b19udW1iZXIoY29uZmlnLmFsbG93ZWRfcmFua19yYW5nZVsxXSk7XG5cbiAgICAgICAgaWYgKCFnYW1lX2lzX3JhbmtlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwbGF5ZXJfcmFuayA8IG1pbl9yYW5rIHx8IHBsYXllcl9yYW5rID4gbWF4X3JhbmspIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwicGxheWVyX3Jhbmtfb3V0X29mX3JhbmdlXCIsXG4gICAgICAgICAgICAgICAgZGV0YWlsczoge1xuICAgICAgICAgICAgICAgICAgICBhbGxvd2VkX3JhbmtfcmFuZ2U6IGNvbmZpZy5hbGxvd2VkX3JhbmtfcmFuZ2UsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOlxuICAgICAgICAgICAgICAgICAgICBwbGF5ZXJfcmFuayA8IG1pbl9yYW5rXG4gICAgICAgICAgICAgICAgICAgICAgICA/IGBZb3VyIHJhbmsgaXMgdG9vIGxvdyB0byBwbGF5IGFnYWluc3QgdGhpcyBib3QuYFxuICAgICAgICAgICAgICAgICAgICAgICAgOiBgWW91ciByYW5rIGlzIHRvbyBoaWdoIHRvIHBsYXkgYWdhaW5zdCB0aGlzIGJvdC5gLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBjaGVja0RlY2xpbmVDaGFsbGVuZ2VzKCk6IFJlamVjdGlvbkRldGFpbHMgfCB1bmRlZmluZWQge1xuICAgICAgICBpZiAoY29uZmlnLmRlY2xpbmVfbmV3X2NoYWxsZW5nZXMpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwibm90X2FjY2VwdGluZ19uZXdfY2hhbGxlbmdlc1wiLFxuICAgICAgICAgICAgICAgIGRldGFpbHM6IHt9LFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IFwiVGhpcyBib3QgaXMgbm90IGFjY2VwdGluZyBuZXcgY2hhbGxlbmdlcyBhdCB0aGlzIHRpbWUuXCIsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfVxuICAgIGNoZWNrR2FtZXNQZXJQbGF5ZXIocGxheWVyX2lkOiBudW1iZXIpOiBSZWplY3Rpb25EZXRhaWxzIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgdHJhY2UubG9nKFwiTWF4IGdhbWVzIHBlciBwbGF5ZXI6IFwiLCBjb25maWcubWF4X2dhbWVzX3Blcl9wbGF5ZXIpO1xuICAgICAgICAvL2NvbmZpZztcbiAgICAgICAgaWYgKGNvbmZpZy5tYXhfZ2FtZXNfcGVyX3BsYXllcikge1xuICAgICAgICAgICAgY29uc3QgZ2FtZV9jb3VudCA9IE9iamVjdC5rZXlzKHRoaXMuY29ubmVjdGVkX2dhbWVzKS5maWx0ZXIoKGdhbWVfaWQpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBzdGF0ZSA9IHRoaXMuY29ubmVjdGVkX2dhbWVzW2dhbWVfaWRdPy5zdGF0ZTtcbiAgICAgICAgICAgICAgICBpZiAoc3RhdGU/LnBsYXllcl9wb29sICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuICEhc3RhdGUucGxheWVyX3Bvb2xbcGxheWVyX2lkXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0YXRlPy53aGl0ZV9wbGF5ZXJfaWQgPT09IHBsYXllcl9pZCB8fCBzdGF0ZT8uYmxhY2tfcGxheWVyX2lkID09PSBwbGF5ZXJfaWQ7XG4gICAgICAgICAgICB9KS5sZW5ndGg7XG4gICAgICAgICAgICB0cmFjZS5sb2coXCJHYW1lIGNvdW50OiBcIiwgZ2FtZV9jb3VudCwgXCIgZm9yIFwiLCBwbGF5ZXJfaWQpO1xuICAgICAgICAgICAgaWYgKGdhbWVfY291bnQgPj0gY29uZmlnLm1heF9nYW1lc19wZXJfcGxheWVyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwidG9vX21hbnlfZ2FtZXNfZm9yX3BsYXllclwiLFxuICAgICAgICAgICAgICAgICAgICBkZXRhaWxzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBnYW1lc19iZWluZ19wbGF5ZWQ6IGdhbWVfY291bnQsXG4gICAgICAgICAgICAgICAgICAgICAgICBtYXhfZ2FtZXNfcGVyX3BsYXllcjogY29uZmlnLm1heF9nYW1lc19wZXJfcGxheWVyLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgWW91IGFscmVhZHkgaGF2ZSAke2dhbWVfY291bnR9IGdhbWVzIGFnYWluc3QgdGhpcyBib3QuIFRoaXMgYm90IG9ubHkgYWxsb3dzICR7Y29uZmlnLm1heF9nYW1lc19wZXJfcGxheWVyfSBnYW1lcyBwZXIgcGxheWVyLCBwbGVhc2UgZW5kIHlvdXIgb3RoZXIgZ2FtZXMgYmVmb3JlIHN0YXJ0aW5nIGEgbmV3IG9uZS5gLFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgY2hlY2tLb21pKGtvbWk6IG51bWJlcik6IFJlamVjdGlvbkRldGFpbHMgfCB1bmRlZmluZWQge1xuICAgICAgICBpZiAoa29taSA8IGNvbmZpZy5hbGxvd2VkX2tvbWlfcmFuZ2VbMF0gfHwga29taSA+IGNvbmZpZy5hbGxvd2VkX2tvbWlfcmFuZ2VbMV0pIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgcmVqZWN0aW9uX2NvZGU6IFwia29taV9vdXRfb2ZfcmFuZ2VcIixcbiAgICAgICAgICAgICAgICBkZXRhaWxzOiB7XG4gICAgICAgICAgICAgICAgICAgIGFsbG93ZWRfa29taV9yYW5nZTogY29uZmlnLmFsbG93ZWRfa29taV9yYW5nZSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBLb21pIGlzIG91dCBvZiBhY2NlcHRhYmxlIHJhbmdlYCxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0ZXJtaW5hdGUoKSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aGlzLmNvbm5lY3RfdGltZW91dCk7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5waW5nX2ludGVydmFsKTtcbiAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLm5vdGlmaWNhdGlvbl9jb25uZWN0X2ludGVydmFsKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGlnbm9yZSgpIHtcbiAgICAvLyBkbyBub3RoaW5nXG59XG5cbmZ1bmN0aW9uIHJhbmtzdHJfdG9fbnVtYmVyKHJhbms6IHN0cmluZyk6IG51bWJlciB7XG4gICAgY29uc3QgYmFzZSA9IHBhcnNlSW50KHJhbmspO1xuICAgIGNvbnN0IHN1ZmZpeCA9IHJhbmtbcmFuay5sZW5ndGggLSAxXS50b0xvd2VyQ2FzZSgpO1xuXG4gICAgc3dpdGNoIChzdWZmaXgpIHtcbiAgICAgICAgY2FzZSBcInBcIjpcbiAgICAgICAgICAgIHJldHVybiA5OTk7XG4gICAgICAgIGNhc2UgXCJrXCI6XG4gICAgICAgICAgICByZXR1cm4gMzAgLSBiYXNlO1xuICAgICAgICBjYXNlIFwiZFwiOlxuICAgICAgICAgICAgcmV0dXJuIDI5ICsgYmFzZTtcbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgcmFuayBzdHJpbmc6ICR7cmFua31gKTtcbn1cblxubmV3IE1haW4oKTtcbiIsImltcG9ydCB7IEJvdCB9IGZyb20gXCIuL0JvdFwiO1xuaW1wb3J0IHsgY29uZmlnLCBCb3RDb25maWcgfSBmcm9tIFwiLi9jb25maWdcIjtcbmltcG9ydCB7IEV2ZW50RW1pdHRlciB9IGZyb20gXCJldmVudGVtaXR0ZXIzXCI7XG5pbXBvcnQgeyBTcGVlZCB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyB0cmFjZSB9IGZyb20gXCIuL3RyYWNlXCI7XG5cbmdsb2JhbC5wZXJmb3JtYW5jZSA9IGdsb2JhbC5wZXJmb3JtYW5jZSB8fCAoRGF0ZSBhcyBhbnkpO1xuXG5pbnRlcmZhY2UgRXZlbnRzIHtcbiAgICBzdGFydDogKGNvbW1hbmQ6IHN0cmluZywgcGlkOiBudW1iZXIpID0+IHZvaWQ7XG59XG5cbmludGVyZmFjZSBCb3RNYW5hZ2VySW50ZXJmYWNlIHtcbiAgICByZWFkeTogUHJvbWlzZTxzdHJpbmdbXT47XG4gICAgYm90X2NvbmZpZzogQm90Q29uZmlnO1xuXG4gICAgYWNxdWlyZShzcGVlZDogU3BlZWQsIHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyLCBnYW1lX2lkOiBudW1iZXIpOiBQcm9taXNlPEJvdD47XG4gICAgY291bnRBdmFpbGFibGUoKTogbnVtYmVyO1xuICAgIHJlbGVhc2UoYm90OiBCb3QpOiB2b2lkO1xuICAgIGNsZWFyTGFzdEdhbWVJZChnYW1lX2lkOiBudW1iZXIpOiB2b2lkO1xuICAgIHN0YXRlU3RyaW5nKCk6IHN0cmluZztcbn1cblxuLyoqIFRoaXMgY2xhc3MgbWFuYWdlcyBhIHBvb2wgb2YgQm90cyAqL1xuZXhwb3J0IGNsYXNzIEJvdFBvb2xNYW5hZ2VyIGV4dGVuZHMgRXZlbnRFbWl0dGVyPEV2ZW50cz4gaW1wbGVtZW50cyBCb3RNYW5hZ2VySW50ZXJmYWNlIHtcbiAgICBwb29sX25hbWU6IHN0cmluZztcbiAgICBib3RfY29uZmlnOiBCb3RDb25maWc7XG4gICAgaW5zdGFuY2VzOiBCb3RbXSA9IFtdO1xuICAgIHF1ZXVlOiBbU3BlZWQsIG51bWJlciwgbnVtYmVyLCAoYm90OiBCb3QpID0+IHZvaWRdW10gPSBbXTtcbiAgICByZWFkeTogUHJvbWlzZTxzdHJpbmdbXT47XG4gICAgbG9nOiAoLi4uYXJyOiBhbnlbXSkgPT4gYW55O1xuICAgIHZlcmJvc2U6ICguLi5hcnI6IGFueVtdKSA9PiBhbnk7XG4gICAgZXJyb3I6ICguLi5hcnI6IGFueVtdKSA9PiBhbnk7XG4gICAgd2FybjogKC4uLmFycjogYW55W10pID0+IGFueTtcblxuICAgIGNvbnN0cnVjdG9yKHBvb2xfbmFtZTogc3RyaW5nLCBib3RfY29uZmlnOiBCb3RDb25maWcpIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICB0aGlzLmxvZyA9IHRyYWNlLmxvZy5iaW5kKG51bGwsIGBbJHtwb29sX25hbWV9IHBvb2xdYCk7XG4gICAgICAgIHRoaXMudmVyYm9zZSA9IHRyYWNlLmRlYnVnLmJpbmQobnVsbCwgYFske3Bvb2xfbmFtZX0gcG9vbF1gKTtcbiAgICAgICAgdGhpcy53YXJuID0gdHJhY2Uud2Fybi5iaW5kKG51bGwsIGBbJHtwb29sX25hbWV9IHBvb2xdYCk7XG4gICAgICAgIHRoaXMuZXJyb3IgPSB0cmFjZS5lcnJvci5iaW5kKG51bGwsIGBbJHtwb29sX25hbWV9IHBvb2xdYCk7XG5cbiAgICAgICAgdGhpcy5ib3RfY29uZmlnID0gYm90X2NvbmZpZztcbiAgICAgICAgdGhpcy5wb29sX25hbWUgPSBwb29sX25hbWU7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBib3RfY29uZmlnLmluc3RhbmNlczsgaSsrKSB7XG4gICAgICAgICAgICB0aGlzLmFkZEluc3RhbmNlKGJvdF9jb25maWcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZWFkeSA9IFByb21pc2UuYWxsKHRoaXMuaW5zdGFuY2VzLm1hcCgoYm90KSA9PiBib3QucmVhZHkpKTtcblxuICAgICAgICB0aGlzLnJlYWR5XG4gICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgdHJhY2UuaW5mbyhgJHt0aGlzLnBvb2xfbmFtZX0gYm90IHBvb2w6ICR7dGhpcy5pbnN0YW5jZXMubGVuZ3RofSBib3RzIHJlYWR5YCk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICAgICAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhZGRJbnN0YW5jZShib3RfY29uZmlnOiBCb3RDb25maWcpIHtcbiAgICAgICAgY29uc3Qgc3RhcnRfdGltZSA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgICAgICBjb25zdCBib3QgPSBuZXcgQm90KGJvdF9jb25maWcsIHRoaXMucG9vbF9uYW1lID09PSBcIkVuZGluZ1wiKTtcbiAgICAgICAgdGhpcy5pbnN0YW5jZXMucHVzaChib3QpO1xuXG4gICAgICAgIGJvdC5vbihcInRlcm1pbmF0ZWRcIiwgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5pbnN0YW5jZXMuc3BsaWNlKHRoaXMuaW5zdGFuY2VzLmluZGV4T2YoYm90KSwgMSk7XG4gICAgICAgICAgICBpZiAocGVyZm9ybWFuY2Uubm93KCkgLSBzdGFydF90aW1lIDwgMTAwMCkge1xuICAgICAgICAgICAgICAgIHRyYWNlLmVycm9yKGBCb3QgXCIke2JvdF9jb25maWcuY29tbWFuZC5qb2luKFwiIFwiKX1cIiB0ZXJtaW5hdGVkIHRvbyBxdWlja2x5YCk7XG4gICAgICAgICAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5hZGRJbnN0YW5jZShib3RfY29uZmlnKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGJvdC5vbihcInJlYWR5XCIsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZW1pdChcInN0YXJ0XCIsIGJvdF9jb25maWcuY29tbWFuZC5qb2luKFwiIFwiKSwgYm90LnBpZCk7XG4gICAgICAgICAgICB0cmFjZS5pbmZvKFxuICAgICAgICAgICAgICAgIGBCb3QgXCIke2JvdF9jb25maWcuY29tbWFuZC5qb2luKFwiIFwiKX1cIiBzdGFydGVkIHdpdGggUElEICR7XG4gICAgICAgICAgICAgICAgICAgIGJvdC5waWRcbiAgICAgICAgICAgICAgICB9LiBSZWFkeSBpbiAke01hdGgucm91bmQocGVyZm9ybWFuY2Uubm93KCkgLSBzdGFydF90aW1lKX1tcy5gLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgYXN5bmMgYWNxdWlyZShzcGVlZDogU3BlZWQsIHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyLCBnYW1lX2lkOiBudW1iZXIpOiBQcm9taXNlPEJvdD4ge1xuICAgICAgICB0cmFjZS5pbmZvKGBBY3F1aXJpbmcgYm90IGZvciAke3NwZWVkfSBnYW1lYCk7XG4gICAgICAgIGF3YWl0IHRoaXMucmVhZHk7XG4gICAgICAgIGZvciAoY29uc3QgcGFzcyBvZiBbXCJnYW1lX2lkXCIsIFwiYm9hcmRfc2l6ZVwiLCBcImFueVwiXSkge1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmluc3RhbmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGJvdCA9IHRoaXMuaW5zdGFuY2VzW2ldO1xuXG4gICAgICAgICAgICAgICAgLyogV2UgcHJpb3JpdGl6ZSBpbnN0YW5jZXMgdGhhdCBoYXZlIGJlZW4gcGxheWluZyB0aGlzIGdhbWUsIGFyZSBhbHJlYWR5XG4gICAgICAgICAgICAgICAgICogc2V0dXAgdG8gcGxheSBvbiB0aGlzIGJvYXJkIHNpemUsIG9yIGZpbmFsbHkgYW55IHRoYXQgYXJlIGF2YWlsYWJsZS5cbiAgICAgICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICAgICBjb25zdCBwYXNzX2NoZWNrID1cbiAgICAgICAgICAgICAgICAgICAgKHBhc3MgPT09IFwiZ2FtZV9pZFwiICYmIGJvdC5sYXN0X2dhbWVfaWQgPT09IGdhbWVfaWQpIHx8XG4gICAgICAgICAgICAgICAgICAgIChwYXNzID09PSBcImJvYXJkX3NpemVcIiAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgYm90Lmxhc3Rfd2lkdGggPT09IHdpZHRoICYmXG4gICAgICAgICAgICAgICAgICAgICAgICBib3QubGFzdF9oZWlnaHQgPT09IGhlaWdodCkgfHxcbiAgICAgICAgICAgICAgICAgICAgcGFzcyA9PT0gXCJhbnlcIjtcblxuICAgICAgICAgICAgICAgIGlmIChib3QuYXZhaWxhYmxlICYmIHBhc3NfY2hlY2spIHtcbiAgICAgICAgICAgICAgICAgICAgYm90LmF2YWlsYWJsZSA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB0cmFjZS5pbmZvKFwiUGlja2VkIGJvdCBpbiBcIiArIHBhc3MgKyBcIiBwYXNzXCIpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYm90O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgICAgIHRoaXMucXVldWUucHVzaChbc3BlZWQsIHdpZHRoLCBoZWlnaHQsIHJlc29sdmVdKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGNvdW50QXZhaWxhYmxlKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLmluc3RhbmNlcy5maWx0ZXIoKGJvdCkgPT4gYm90LmF2YWlsYWJsZSkubGVuZ3RoO1xuICAgIH1cblxuICAgIHB1YmxpYyByZWxlYXNlKGJvdDogQm90KTogdm9pZCB7XG4gICAgICAgIGJvdC5zZXRHYW1lKG51bGwpO1xuICAgICAgICBpZiAodGhpcy5xdWV1ZS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHBhc3Mgb2YgW1wiYm9hcmRfc2l6ZVwiLCBcImFueVwiXSkge1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgdGFyZ2V0X3NwZWVkIG9mIFtcImJsaXR6XCIsIFwicmFwaWRcIiwgXCJsaXZlXCIsIFwiY29ycmVzcG9uZGVuY2VcIl0pIHtcbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnF1ZXVlLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBbc3BlZWQsIHdpZHRoLCBoZWlnaHQsIHJlc29sdmVdID0gdGhpcy5xdWV1ZVtpXTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcGFzc19jaGVjayA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhc3MgPT09IFwiYm9hcmRfc2l6ZVwiICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdC5sYXN0X3dpZHRoID09PSB3aWR0aCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3QubGFzdF9oZWlnaHQgPT09IGhlaWdodCkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXNzID09PSBcImFueVwiO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc3BlZWQgPT09IHRhcmdldF9zcGVlZCAmJiBwYXNzX2NoZWNrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBSZWxlYXNpbmcgYm90IGJhY2sgdG8gdGhlICR7c3BlZWR9IHBvb2wsIHF1ZXVlIGxlbmd0aDogJHt0aGlzLnF1ZXVlLmxlbmd0aH1gLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5xdWV1ZS5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShib3QpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGJvdC5hdmFpbGFibGUgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHB1YmxpYyBjbGVhckxhc3RHYW1lSWQoZ2FtZV9pZDogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIGZvciAoY29uc3QgYm90IG9mIHRoaXMuaW5zdGFuY2VzKSB7XG4gICAgICAgICAgICBpZiAoYm90Lmxhc3RfZ2FtZV9pZCA9PT0gZ2FtZV9pZCkge1xuICAgICAgICAgICAgICAgIGJvdC5sYXN0X2dhbWVfaWQgPSAtMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0ZVN0cmluZygpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gYCR7dGhpcy5wb29sX25hbWV9OiAke3RoaXMuY291bnRBdmFpbGFibGUoKX0vJHt0aGlzLmluc3RhbmNlcy5sZW5ndGh9IGF2YWlsYWJsZWA7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgUGVyc2lzdGVudEJvdE1hbmFnZXIgZXh0ZW5kcyBFdmVudEVtaXR0ZXI8RXZlbnRzPiBpbXBsZW1lbnRzIEJvdE1hbmFnZXJJbnRlcmZhY2Uge1xuICAgIHBvb2xfbmFtZTogc3RyaW5nO1xuICAgIGJvdF9jb25maWc6IEJvdENvbmZpZztcbiAgICBpbnN0YW5jZXM6IEJvdFtdID0gW107XG4gICAgcXVldWU6IFtTcGVlZCwgbnVtYmVyLCBudW1iZXIsIChib3Q6IEJvdCkgPT4gdm9pZF1bXSA9IFtdO1xuICAgIHJlYWR5OiBQcm9taXNlPHN0cmluZ1tdPjtcbiAgICBsb2c6ICguLi5hcnI6IGFueVtdKSA9PiBhbnk7XG4gICAgdmVyYm9zZTogKC4uLmFycjogYW55W10pID0+IGFueTtcbiAgICBlcnJvcjogKC4uLmFycjogYW55W10pID0+IGFueTtcbiAgICB3YXJuOiAoLi4uYXJyOiBhbnlbXSkgPT4gYW55O1xuXG4gICAgY29uc3RydWN0b3IocG9vbF9uYW1lOiBzdHJpbmcsIGJvdF9jb25maWc6IEJvdENvbmZpZykge1xuICAgICAgICBzdXBlcigpO1xuXG4gICAgICAgIHRoaXMubG9nID0gdHJhY2UubG9nLmJpbmQobnVsbCwgYFske3Bvb2xfbmFtZX0gYm90c11gKTtcbiAgICAgICAgdGhpcy52ZXJib3NlID0gdHJhY2UuZGVidWcuYmluZChudWxsLCBgWyR7cG9vbF9uYW1lfSBib3RzXWApO1xuICAgICAgICB0aGlzLndhcm4gPSB0cmFjZS53YXJuLmJpbmQobnVsbCwgYFske3Bvb2xfbmFtZX0gYm90c11gKTtcbiAgICAgICAgdGhpcy5lcnJvciA9IHRyYWNlLmVycm9yLmJpbmQobnVsbCwgYFske3Bvb2xfbmFtZX0gYm90c11gKTtcblxuICAgICAgICB0aGlzLmJvdF9jb25maWcgPSBib3RfY29uZmlnO1xuICAgICAgICB0aGlzLnBvb2xfbmFtZSA9IHBvb2xfbmFtZTtcblxuICAgICAgICB0aGlzLnJlYWR5ID0gUHJvbWlzZS5yZXNvbHZlKFtdKTtcbiAgICAgICAgdHJhY2UuaW5mbyhgJHt0aGlzLnBvb2xfbmFtZX0gcGVyc2lzdGVudCBib3RzIHJlYWR5YCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhZGRJbnN0YW5jZShib3RfY29uZmlnOiBCb3RDb25maWcsIGdhbWVfaWQ6IG51bWJlcik6IEJvdCB7XG4gICAgICAgIGNvbnN0IHN0YXJ0X3RpbWUgPSBwZXJmb3JtYW5jZS5ub3coKTtcbiAgICAgICAgY29uc3QgYm90ID0gbmV3IEJvdChib3RfY29uZmlnLCB0aGlzLnBvb2xfbmFtZSA9PT0gXCJFbmRpbmdcIik7XG4gICAgICAgIGJvdC5sYXN0X2dhbWVfaWQgPSBnYW1lX2lkO1xuICAgICAgICB0aGlzLmluc3RhbmNlcy5wdXNoKGJvdCk7XG5cbiAgICAgICAgYm90Lm9uKFwidGVybWluYXRlZFwiLCAoKSA9PiB7XG4gICAgICAgICAgICBpZiAoYm90LnBlcnNpc3RlbnRfaWRsZV90aW1lb3V0KSB7XG4gICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KGJvdC5wZXJzaXN0ZW50X2lkbGVfdGltZW91dCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmluc3RhbmNlcy5zcGxpY2UodGhpcy5pbnN0YW5jZXMuaW5kZXhPZihib3QpLCAxKTtcbiAgICAgICAgICAgIGlmIChwZXJmb3JtYW5jZS5ub3coKSAtIHN0YXJ0X3RpbWUgPCAxMDAwKSB7XG4gICAgICAgICAgICAgICAgdHJhY2UuZXJyb3IoYEJvdCBcIiR7Ym90X2NvbmZpZy5jb21tYW5kLmpvaW4oXCIgXCIpfVwiIHRlcm1pbmF0ZWQgdG9vIHF1aWNrbHlgKTtcbiAgICAgICAgICAgICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoYm90Lmxhc3RfZ2FtZV9pZCAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmFkZEluc3RhbmNlKGJvdF9jb25maWcsIGdhbWVfaWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgYm90Lm9uKFwicmVhZHlcIiwgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5lbWl0KFwic3RhcnRcIiwgYm90X2NvbmZpZy5jb21tYW5kLmpvaW4oXCIgXCIpLCBib3QucGlkKTtcbiAgICAgICAgICAgIHRyYWNlLmluZm8oXG4gICAgICAgICAgICAgICAgYEJvdCBcIiR7Ym90X2NvbmZpZy5jb21tYW5kLmpvaW4oXCIgXCIpfVwiIHN0YXJ0ZWQgd2l0aCBQSUQgJHtcbiAgICAgICAgICAgICAgICAgICAgYm90LnBpZFxuICAgICAgICAgICAgICAgIH0uIFJlYWR5IGluICR7TWF0aC5yb3VuZChwZXJmb3JtYW5jZS5ub3coKSAtIHN0YXJ0X3RpbWUpfW1zLmAsXG4gICAgICAgICAgICApO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gYm90O1xuICAgIH1cblxuICAgIGFzeW5jIGFjcXVpcmUoX3NwZWVkOiBTcGVlZCwgX3dpZHRoOiBudW1iZXIsIF9oZWlnaHQ6IG51bWJlciwgZ2FtZV9pZDogbnVtYmVyKTogUHJvbWlzZTxCb3Q+IHtcbiAgICAgICAgY29uc3QgYm90ID1cbiAgICAgICAgICAgIHRoaXMuaW5zdGFuY2VzLmZpbmQoKGJvdCkgPT4gYm90Lmxhc3RfZ2FtZV9pZCA9PT0gZ2FtZV9pZCkgfHxcbiAgICAgICAgICAgIHRoaXMuYWRkSW5zdGFuY2UodGhpcy5ib3RfY29uZmlnLCBnYW1lX2lkKTtcblxuICAgICAgICBpZiAoYm90LnBlcnNpc3RlbnRfaWRsZV90aW1lb3V0KSB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQoYm90LnBlcnNpc3RlbnRfaWRsZV90aW1lb3V0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBib3Q7XG4gICAgfVxuXG4gICAgcHVibGljIGNvdW50QXZhaWxhYmxlKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiAxO1xuICAgIH1cblxuICAgIHJlbGVhc2UoYm90OiBCb3QpOiB2b2lkIHtcbiAgICAgICAgdHJhY2UuaW5mbyhcIltwZXJzaXN0ZW50XSBSZWxlYXNpbmcgYm90LCBxdWV1ZSBsZW5ndGg6IFwiICsgdGhpcy5xdWV1ZS5sZW5ndGgpO1xuXG4gICAgICAgIGlmIChib3QucGVyc2lzdGVudF9pZGxlX3RpbWVvdXQpIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dChib3QucGVyc2lzdGVudF9pZGxlX3RpbWVvdXQpO1xuICAgICAgICB9XG4gICAgICAgIGJvdC5wZXJzaXN0ZW50X2lkbGVfdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgICAgICAgYEJvdCBoYXMgYmVlbiBpZGxlIGZvciAke3RoaXMuYm90X2NvbmZpZy5wZXJzaXN0ZW50X2lkbGVfdGltZW91dH1tcywgdGVybWluYXRpbmdgLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGJvdC5wZXJzaXN0ZW50X2lkbGVfdGltZW91dCA9IG51bGw7XG4gICAgICAgICAgICBib3QubGFzdF9nYW1lX2lkID0gLTE7XG4gICAgICAgICAgICBib3Qua2lsbCgpO1xuICAgICAgICB9LCB0aGlzLmJvdF9jb25maWcucGVyc2lzdGVudF9pZGxlX3RpbWVvdXQpO1xuICAgIH1cbiAgICBwdWJsaWMgY2xlYXJMYXN0R2FtZUlkKGdhbWVfaWQ6IG51bWJlcik6IHZvaWQge1xuICAgICAgICBmb3IgKGNvbnN0IGJvdCBvZiB0aGlzLmluc3RhbmNlcykge1xuICAgICAgICAgICAgaWYgKGJvdC5sYXN0X2dhbWVfaWQgPT09IGdhbWVfaWQpIHtcbiAgICAgICAgICAgICAgICBib3QubGFzdF9nYW1lX2lkID0gLTE7XG4gICAgICAgICAgICAgICAgYm90LmtpbGwoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0ZVN0cmluZygpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gYCR7dGhpcy5wb29sX25hbWV9OiAke3RoaXMuaW5zdGFuY2VzLmxlbmd0aH0gYm90c2A7XG4gICAgfVxufVxuXG5leHBvcnQgY29uc3QgYm90X3Bvb2xzOiB7XG4gICAgbWFpbjogQm90TWFuYWdlckludGVyZmFjZTtcbiAgICBlbmRpbmc6IEJvdE1hbmFnZXJJbnRlcmZhY2UgfCBudWxsO1xuICAgIG9wZW5pbmc6IEJvdE1hbmFnZXJJbnRlcmZhY2UgfCBudWxsO1xufSA9IHtcbiAgICBtYWluOlxuICAgICAgICBjb25maWcuYm90Lm1hbmFnZXIgPT09IFwicG9vbFwiXG4gICAgICAgICAgICA/IG5ldyBCb3RQb29sTWFuYWdlcihcIk1haW5cIiwgY29uZmlnLmJvdClcbiAgICAgICAgICAgIDogbmV3IFBlcnNpc3RlbnRCb3RNYW5hZ2VyKFwiTWFpblwiLCBjb25maWcuYm90KSxcbiAgICBlbmRpbmc6XG4gICAgICAgIGNvbmZpZy5lbmRpbmdfYm90Py5tYW5hZ2VyID09PSBcInBvb2xcIlxuICAgICAgICAgICAgPyBuZXcgQm90UG9vbE1hbmFnZXIoXCJFbmRpbmdcIiwgY29uZmlnLmVuZGluZ19ib3QpXG4gICAgICAgICAgICA6IGNvbmZpZy5lbmRpbmdfYm90Py5tYW5hZ2VyID09PSBcInBlcnNpc3RlbnRcIlxuICAgICAgICAgICAgICA/IG5ldyBQZXJzaXN0ZW50Qm90TWFuYWdlcihcIkVuZGluZ1wiLCBjb25maWcuZW5kaW5nX2JvdClcbiAgICAgICAgICAgICAgOiBudWxsLFxuICAgIG9wZW5pbmc6XG4gICAgICAgIGNvbmZpZy5vcGVuaW5nX2JvdD8ubWFuYWdlciA9PT0gXCJwb29sXCJcbiAgICAgICAgICAgID8gbmV3IEJvdFBvb2xNYW5hZ2VyKFwiT3BlbmluZ1wiLCBjb25maWcub3BlbmluZ19ib3QpXG4gICAgICAgICAgICA6IGNvbmZpZy5vcGVuaW5nX2JvdD8ubWFuYWdlciA9PT0gXCJwZXJzaXN0ZW50XCJcbiAgICAgICAgICAgICAgPyBuZXcgUGVyc2lzdGVudEJvdE1hbmFnZXIoXCJPcGVuaW5nXCIsIGNvbmZpZy5vcGVuaW5nX2JvdClcbiAgICAgICAgICAgICAgOiBudWxsLFxufTtcbiIsImltcG9ydCB7IGNvbmZpZyB9IGZyb20gXCIuL2NvbmZpZ1wiO1xuaW1wb3J0IHsgR29iYW5Tb2NrZXQgfSBmcm9tIFwiZ29iYW4tZW5naW5lXCI7XG5pbXBvcnQgeyB0cmFjZSB9IGZyb20gXCIuL3RyYWNlXCI7XG5cbmdsb2JhbC5wZXJmb3JtYW5jZSA9IGdsb2JhbC5wZXJmb3JtYW5jZSB8fCAoRGF0ZSBhcyBhbnkpO1xuXG5jb25zdCBNSU5fQ09OTkVDVF9USU1FID0gMTAwMDtcblxuZXhwb3J0IGNvbnN0IHNvY2tldCA9IG5ldyBHb2JhblNvY2tldChjb25maWcuc2VydmVyKTtcblxuc29ja2V0Lm9uKFwiRVJST1JcIiwgKG1lc3NhZ2UpID0+IHtcbiAgICB0cmFjZS5lcnJvcihtZXNzYWdlKTtcbn0pO1xuXG5sZXQgY29ubmVjdF90aW1lID0gcGVyZm9ybWFuY2Uubm93KCk7XG5zb2NrZXQub24oXCJjb25uZWN0XCIsICgpID0+IHtcbiAgICBjb25uZWN0X3RpbWUgPSBwZXJmb3JtYW5jZS5ub3coKSAtIGNvbm5lY3RfdGltZTtcbiAgICB0cmFjZS5pbmZvKGBDb25uZWN0ZWQgdG8gJHtjb25maWcuc2VydmVyfSBpbiAke2Nvbm5lY3RfdGltZS50b0ZpeGVkKDApfW1zYCk7XG59KTtcbnNvY2tldC5vbihcImRpc2Nvbm5lY3RcIiwgKCkgPT4ge1xuICAgIGlmIChwZXJmb3JtYW5jZS5ub3coKSAtIGNvbm5lY3RfdGltZSA8IE1JTl9DT05ORUNUX1RJTUUpIHtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cbn0pO1xuIiwiaW1wb3J0ICogYXMgZnMgZnJvbSBcImZzXCI7XG5pbXBvcnQgKiBhcyB0cmFjZXIgZnJvbSBcInRyYWNlclwiO1xuaW1wb3J0IHsgY29uZmlnIH0gZnJvbSBcIi4vY29uZmlnXCI7XG5cbmNvbnN0IGNvbnNvbGVfZm10ID1cbiAgICBcInt7dGltZXN0YW1wfX0ge3t0aXRsZX19IFwiICtcbiAgICAoY29uZmlnLnZlcmJvc2l0eSA+IDAgPyBcInt7ZmlsZX19Ont7bGluZX19e3tzcGFjZX19IFwiIDogXCJcIikgK1xuICAgIFwie3ttZXNzYWdlfX1cIjtcblxuY29uc3QgY29uc29sZV9jb25maWcgPSB7XG4gICAgZm9ybWF0OiBjb25zb2xlX2ZtdCxcbiAgICBkYXRlZm9ybWF0OiBcIm1tbSBkZCBISDpNTTpzc1wiLFxuICAgIHByZXByb2Nlc3M6IChkYXRhKSA9PiB7XG4gICAgICAgIHN3aXRjaCAoZGF0YS50aXRsZSkge1xuICAgICAgICAgICAgY2FzZSBcInRyYWNlXCI6XG4gICAgICAgICAgICAgICAgZGF0YS50aXRsZSA9IFwiIFwiO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcImRlYnVnXCI6XG4gICAgICAgICAgICAgICAgZGF0YS50aXRsZSA9IFwiIFwiO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcImxvZ1wiOlxuICAgICAgICAgICAgICAgIGRhdGEudGl0bGUgPSBcIiBcIjtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJpbmZvXCI6XG4gICAgICAgICAgICAgICAgZGF0YS50aXRsZSA9IFwiIFwiO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcIndhcm5cIjpcbiAgICAgICAgICAgICAgICBkYXRhLnRpdGxlID0gXCIgXCI7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiZXJyb3JcIjpcbiAgICAgICAgICAgICAgICBkYXRhLnRpdGxlID0gXCIhXCI7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNvbmZpZy52ZXJib3NpdHkgPiAwKSB7XG4gICAgICAgICAgICBkYXRhLnNwYWNlID0gXCIgXCIucmVwZWF0KE1hdGgubWF4KDAsIDIwIC0gYCR7ZGF0YS5maWxlfToke2RhdGEubGluZX1gLmxlbmd0aCkpO1xuICAgICAgICB9XG4gICAgfSxcbn07XG5cbmNvbnN0IG9yaWdfY29uc29sZSA9IGNvbnNvbGU7XG4oY29uc29sZV9jb25maWcgYXMgYW55KS50cmFuc3BvcnQgPSAoZGF0YTogYW55KSA9PiB7XG4gICAgb3JpZ19jb25zb2xlLmxvZyhkYXRhLm91dHB1dCk7XG4gICAgaWYgKGNvbmZpZy5sb2dmaWxlKSB7XG4gICAgICAgIGZzLm9wZW4oY29uZmlnLmxvZ2ZpbGUsIFwiYVwiLCBwYXJzZUludChcIjA2NDRcIiwgOCksIChfZSwgaWQpID0+IHtcbiAgICAgICAgICAgIC8vIHN0cmlwIGNvbG9yIGNvbnRyb2xzIGNoYXJhY3RlcnNcbiAgICAgICAgICAgIGNvbnN0IHN0cmlwcGVkID0gZGF0YS5vdXRwdXQucmVwbGFjZShcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29udHJvbC1yZWdleFxuICAgICAgICAgICAgICAgIC9bXFx1MDAxYlxcdTAwOWJdW1soKSM7P10qKD86WzAtOV17MSw0fSg/OjtbMC05XXswLDR9KSopP1swLTlBLU9SWmNmLW5xcnk9PjxdL2csXG4gICAgICAgICAgICAgICAgXCJcIixcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBmcy53cml0ZShpZCwgc3RyaXBwZWQgKyBcIlxcblwiLCBudWxsLCBcInV0ZjhcIiwgKCkgPT4ge1xuICAgICAgICAgICAgICAgIGZzLmNsb3NlKGlkLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIC8vIG5vb3BcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG59O1xuXG5leHBvcnQgY29uc3QgdHJhY2UgPSB0cmFjZXIuY29sb3JDb25zb2xlKGNvbnNvbGVfY29uZmlnKTtcblxuKGdsb2JhbCBhcyBhbnkpLmNvbnNvbGUgPSB0cmFjZTtcblxuaWYgKGNvbmZpZy52ZXJib3NpdHkgPD0gMSkge1xuICAgIHRyYWNlLnRyYWNlID0gKC4uLl9hcmdzOiBhbnlbXSkgPT4ge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9O1xufVxuaWYgKGNvbmZpZy52ZXJib3NpdHkgPD0gMCkge1xuICAgIHRyYWNlLmRlYnVnID0gKC4uLl9hcmdzOiBhbnlbXSkgPT4ge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9O1xuICAgIHRyYWNlLnZlcmJvc2UgPSAoLi4uX2FyZ3M6IGFueVtdKSA9PiB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH07XG59XG4iLCJpbXBvcnQgKiBhcyBodHRwIGZyb20gXCJodHRwXCI7XG5pbXBvcnQgKiBhcyBodHRwcyBmcm9tIFwiaHR0cHNcIjtcbmltcG9ydCAqIGFzIHF1ZXJ5c3RyaW5nIGZyb20gXCJxdWVyeXN0cmluZ1wiO1xuaW1wb3J0IHsgY29uZmlnIH0gZnJvbSBcIi4vY29uZmlnXCI7XG5pbXBvcnQgeyB0cmFjZSB9IGZyb20gXCIuL3RyYWNlXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBndHBjaGFyMm51bShjaDogc3RyaW5nKTogbnVtYmVyIHtcbiAgICBpZiAoY2ggPT09IFwiLlwiIHx8ICFjaCkge1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgfVxuICAgIHJldHVybiBcImFiY2RlZmdoamtsbW5vcHFyc3R1dnd4eXpcIi5pbmRleE9mKGNoLnRvTG93ZXJDYXNlKCkpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbW92ZTJndHB2ZXJ0ZXgobW92ZSwgd2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpOiBzdHJpbmcge1xuICAgIGlmIChtb3ZlLnggPCAwKSB7XG4gICAgICAgIHJldHVybiBcInBhc3NcIjtcbiAgICB9XG4gICAgcmV0dXJuIG51bTJndHBjaGFyKG1vdmVbXCJ4XCJdKSArIChoZWlnaHQgLSBtb3ZlW1wieVwiXSk7XG59XG5cbmZ1bmN0aW9uIG51bTJndHBjaGFyKG51bTogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBpZiAobnVtID09PSAtMSkge1xuICAgICAgICByZXR1cm4gXCIuXCI7XG4gICAgfVxuICAgIHJldHVybiBcImFiY2RlZmdoamtsbW5vcHFyc3R1dnd4eXpcIltudW1dO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVxdWVzdChtZXRob2QsIHBhdGgsIGRhdGEpIHtcbiAgICBjb25zdCB1cmwgPSBjb25maWcuc2VydmVyO1xuICAgIGNvbnN0IGhvc3QgPSB1cmwucmVwbGFjZSgvXmh0dHBzPzpcXC9cXC8vLCBcIlwiKS5yZXBsYWNlKC9cXC8uKiQvLCBcIlwiKTtcbiAgICBjb25zdCBtID0gdXJsLm1hdGNoKC86KFxcZCspJC8pO1xuICAgIGNvbnN0IHBvcnQgPSBtID8gbVsxXSA6IHVybC5tYXRjaCgvXmh0dHBzLykgPyA0NDMgOiA4MDtcbiAgICBjb25zdCBpbnNlY3VyZSA9IHVybC5pbmRleE9mKFwiaHR0cHNcIikgIT09IDA7XG5cbiAgICB0cmFjZS5kZWJ1ZyhgJHttZXRob2R9ICR7cGF0aH0gJHtKU09OLnN0cmluZ2lmeShkYXRhKX1gKTtcbiAgICBkYXRhLmFwaWtleSA9IGNvbmZpZy5hcGlrZXk7XG4gICAgZGF0YS5ib3RfaWQgPSBjb25maWcuYm90X2lkO1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgbGV0IGVuY19kYXRhX3R5cGUgPSBcImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZFwiO1xuICAgICAgICBmb3IgKGNvbnN0IGsgaW4gZGF0YSkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBkYXRhW2tdID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgZW5jX2RhdGFfdHlwZSA9IFwiYXBwbGljYXRpb24vanNvblwiO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGhlYWRlcnMgPSBudWxsO1xuICAgICAgICBpZiAoZGF0YS5faGVhZGVycykge1xuICAgICAgICAgICAgZGF0YSA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoZGF0YSkpO1xuICAgICAgICAgICAgaGVhZGVycyA9IGRhdGEuX2hlYWRlcnM7XG4gICAgICAgICAgICBkZWxldGUgZGF0YS5faGVhZGVycztcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBlbmNfZGF0YSA9IG51bGw7XG4gICAgICAgIGlmIChlbmNfZGF0YV90eXBlID09PSBcImFwcGxpY2F0aW9uL2pzb25cIikge1xuICAgICAgICAgICAgZW5jX2RhdGEgPSBKU09OLnN0cmluZ2lmeShkYXRhKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGVuY19kYXRhID0gcXVlcnlzdHJpbmcuc3RyaW5naWZ5KGRhdGEpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgb3B0aW9ucyA9IHtcbiAgICAgICAgICAgIGhvc3Q6IGhvc3QsXG4gICAgICAgICAgICBwb3J0OiBwb3J0LFxuICAgICAgICAgICAgcGF0aDogcGF0aCxcbiAgICAgICAgICAgIG1ldGhvZDogbWV0aG9kLFxuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIFwiQ29udGVudC1UeXBlXCI6IGVuY19kYXRhX3R5cGUsXG4gICAgICAgICAgICAgICAgXCJDb250ZW50LUxlbmd0aFwiOiBlbmNfZGF0YS5sZW5ndGgsXG4gICAgICAgICAgICB9LFxuICAgICAgICB9O1xuICAgICAgICBpZiAoaGVhZGVycykge1xuICAgICAgICAgICAgZm9yIChjb25zdCBrIGluIGhlYWRlcnMpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmhlYWRlcnNba10gPSBoZWFkZXJzW2tdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcmVxID0gKGluc2VjdXJlID8gaHR0cCA6IGh0dHBzKS5yZXF1ZXN0KG9wdGlvbnMsIChyZXMpID0+IHtcbiAgICAgICAgICAgIC8vdGVzdFxuICAgICAgICAgICAgcmVzLnNldEVuY29kaW5nKFwidXRmOFwiKTtcbiAgICAgICAgICAgIGxldCBib2R5ID0gXCJcIjtcbiAgICAgICAgICAgIHJlcy5vbihcImRhdGFcIiwgKGNodW5rKSA9PiB7XG4gICAgICAgICAgICAgICAgYm9keSArPSBjaHVuaztcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmVzLm9uKFwiZW5kXCIsICgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAocmVzLnN0YXR1c0NvZGUgPCAyMDAgfHwgcmVzLnN0YXR1c0NvZGUgPiAyOTkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KHsgZXJyb3I6IGAke3Jlcy5zdGF0dXNDb2RlfSAtICR7Ym9keX1gLCByZXNwb25zZTogcmVzLCBib2R5OiBib2R5IH0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJlc29sdmUoeyByZXNwb25zZTogcmVzLCBib2R5OiBib2R5IH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXEub24oXCJlcnJvclwiLCAoZSkgPT4ge1xuICAgICAgICAgICAgcmVqZWN0KHsgZXJyb3I6IGUubWVzc2FnZSB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmVxLndyaXRlKGVuY19kYXRhKTtcbiAgICAgICAgcmVxLmVuZCgpO1xuICAgIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcG9zdChwYXRoLCBkYXRhKTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gcmVxdWVzdChcIlBPU1RcIiwgcGF0aCwgZGF0YSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhcGkxKHN0cikge1xuICAgIHJldHVybiBgL2FwaS92MS8ke3N0cn1gO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaWdub3JlX3Byb21pc2UocHJvbWlzZTogUHJvbWlzZTxhbnk+KTogdm9pZCB7XG4gICAgcHJvbWlzZS5jYXRjaCgoZSkgPT4ge1xuICAgICAgICB0cmFjZS5lcnJvcihlKTtcbiAgICB9KTtcbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZShcImV2ZW50ZW1pdHRlcjNcIik7IiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwiZ29iYW4tZW5naW5lXCIpOyIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZShcImpzb241XCIpOyIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZShcImpzb25zY2hlbWFcIik7IiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwic3BsaXQyXCIpOyIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZShcInRyYWNlclwiKTsiLCJtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoXCJ3c1wiKTsiLCJtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoXCJ5YXJnc1wiKTsiLCJtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoXCJjaGlsZF9wcm9jZXNzXCIpOyIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZShcImZzXCIpOyIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZShcImh0dHBcIik7IiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwiaHR0cHNcIik7IiwibW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKFwicXVlcnlzdHJpbmdcIik7IiwiLy8gVGhlIG1vZHVsZSBjYWNoZVxudmFyIF9fd2VicGFja19tb2R1bGVfY2FjaGVfXyA9IHt9O1xuXG4vLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcblx0dmFyIGNhY2hlZE1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF07XG5cdGlmIChjYWNoZWRNb2R1bGUgIT09IHVuZGVmaW5lZCkge1xuXHRcdHJldHVybiBjYWNoZWRNb2R1bGUuZXhwb3J0cztcblx0fVxuXHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuXHR2YXIgbW9kdWxlID0gX193ZWJwYWNrX21vZHVsZV9jYWNoZV9fW21vZHVsZUlkXSA9IHtcblx0XHQvLyBubyBtb2R1bGUuaWQgbmVlZGVkXG5cdFx0Ly8gbm8gbW9kdWxlLmxvYWRlZCBuZWVkZWRcblx0XHRleHBvcnRzOiB7fVxuXHR9O1xuXG5cdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuXHRfX3dlYnBhY2tfbW9kdWxlc19fW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuXHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuXHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG59XG5cbiIsIiIsIi8vIHN0YXJ0dXBcbi8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuLy8gVGhpcyBlbnRyeSBtb2R1bGUgaXMgcmVmZXJlbmNlZCBieSBvdGhlciBtb2R1bGVzIHNvIGl0IGNhbid0IGJlIGlubGluZWRcbnZhciBfX3dlYnBhY2tfZXhwb3J0c19fID0gX193ZWJwYWNrX3JlcXVpcmVfXyhcIi4vc3JjL21haW4udHNcIik7XG4iLCIiXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=