@magic-xpa/utils
Version:
magic utils package
444 lines • 45.9 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
import { Logger_LogLevels, Logger_MessageDirection } from "./enums";
import { DateTime, Debug, Exception, NString, StringBuilder, Thread } from "@magic-xpa/mscorelib";
import { OSEnvironment } from "./PlatformUtils";
import { DateTimeUtils } from "./DateTimeUtils";
import { XMLConstants } from "./XMLConstants";
import { isNullOrUndefined } from "util";
/** @enum {number} */
const LogType = {
info: 1,
warning: 2,
error: 3,
};
export { LogType };
LogType[LogType.info] = 'info';
LogType[LogType.warning] = 'warning';
LogType[LogType.error] = 'error';
/// <summary>
/// Logger class will take care of client side logging . It will check for various log levels and accordingly will write messages in log file.
/// </summary>
//@dynamic
export class Logger {
constructor() {
this.LogLevel = 0; // InternalLogLevel
/// <summary>
/// While writing the error messages in the file play the beep.
/// </summary>
this.ShouldBeep = false;
}
/**
* @param {?} value
* @return {?}
*/
static set Instance(value) {
Logger.instance = value;
}
/**
* @return {?}
*/
static get Instance() {
if (Logger.instance === null) {
Logger.instance = new Logger();
}
return Logger.instance;
}
/// <summary>
/// Initialize logger
/// </summary>
/// <param name="logLevel"></param>
/// <param name="internalLogSync"></param>
/**
* @param {?} logLevel
* @param {?} internalLogSync
* @param {?} shouldBeep
* @return {?}
*/
Initialize(logLevel, internalLogSync, shouldBeep) {
try {
// let logSync: LogSyncMode = LogSyncMode.Session;
this.LogLevel = logLevel;
this.ShouldBeep = shouldBeep;
// TODO: implement
// String strLogSync = internalLogSync;
// if (!string.IsNullOrEmpty(strLogSync))
// {
// if (strLogSync.StartsWith("M", StringComparison.CurrentCultureIgnoreCase))
// logSync = LogSyncMode.Message;
// else if (strLogSync.StartsWith("F", StringComparison.CurrentCultureIgnoreCase))
// logSync = LogSyncMode.Flush;
// }
//
}
catch (e) {
this.WriteDevToLog("ClientManager.init(): " + e.Message);
}
}
/**
* @param {?=} logLevel
* @return {?}
*/
ShouldLog(logLevel) {
if (arguments.length === 1)
return this.ShouldLog_0(logLevel);
else
return this.ShouldLog_1();
}
/**
* @param {?} logLevel
* @return {?}
*/
ShouldLog_0(logLevel) {
return this.LogLevel === logLevel;
}
/**
* @return {?}
*/
ShouldLog_1() {
return this.LogLevel > Logger_LogLevels.None;
}
/**
* @return {?}
*/
ShouldLogServerRelatedMessages() {
return (this.ShouldLogExtendedServerRelatedMessages() || Logger.Instance.ShouldLog(Logger_LogLevels.Server)) && this.LogLevel !== Logger_LogLevels.Basic;
}
/**
* @return {?}
*/
ShouldLogExtendedServerRelatedMessages() {
return (Logger.Instance.ShouldLog(Logger_LogLevels.ServerMessages) || Logger.Instance.ShouldLog(Logger_LogLevels.Support) || Logger.Instance.ShouldLog(Logger_LogLevels.Development)) && this.LogLevel !== Logger_LogLevels.Basic;
}
/// <summary></summary>
/// <param name="msg"></param>
/// <param name="openIfNecessary">open the log file if not opened yet</param>
/**
* @param {?} msg
* @param {?} openIfNecessary
* @param {?=} logType
* @return {?}
*/
WriteToLog(msg, openIfNecessary, logType = LogType.info) {
if (this.LogLevel > Logger_LogLevels.None || openIfNecessary) {
msg = NString.Format("{0} {1}", (this.LogLevel === Logger_LogLevels.Basic) ? new Date().toISOString() : DateTimeUtils.ToString(DateTime.Now, XMLConstants.ERROR_LOG_TIME_FORMAT, this), msg);
switch (logType) {
case LogType.error:
console.error(msg);
break;
case LogType.warning:
console.warn(msg);
break;
default:
console.log(msg);
}
}
}
/// <summary>
/// write a server access to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
WriteServerToLog(msg) {
if (this.ShouldLogServerRelatedMessages()) {
this.WriteToLog(NString.Format("Server, Thread={0}: ", Thread.CurrentThread.ManagedThreadId) + msg, false, LogType.info);
}
}
/// <summary>
/// write a server access to the log, including the content
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
WriteServerMessagesToLog(msg) {
if (this.ShouldLogExtendedServerRelatedMessages()) {
this.WriteToLog("Server#: " + msg, false, LogType.info);
}
}
/// <summary>Write a QC message to the log</summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @param {?} skipLine
* @return {?}
*/
WriteSupportToLog(msg, skipLine) {
if (this.LogLevel >= Logger_LogLevels.Support && this.LogLevel !== Logger_LogLevels.Basic) {
if (skipLine) {
this.WriteToLog("SUPPORT: " + msg, false, LogType.info);
}
else {
this.WriteToLog("SUPPORT: " + msg + OSEnvironment.EolSeq + "-----------------------------------------------------------------------------------------------------------", false, LogType.info);
}
}
}
/// <summary>
/// write a performance message to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
WriteGuiToLog(msg) {
if (this.LogLevel >= Logger_LogLevels.Gui && this.LogLevel !== Logger_LogLevels.Basic) {
this.WriteToLog(msg, false, LogType.info);
}
}
/// <summary>
/// write a developer message to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
WriteDevToLog(msg) {
if (this.LogLevel >= Logger_LogLevels.Development && this.LogLevel !== Logger_LogLevels.Basic) {
this.WriteToLog("DEV: " + msg, false, LogType.info);
}
}
/// <summary>
/// Writes a basic level entry to log
/// </summary>
/// <param name="messageDirection">message direction relative to the current module (RIA client). Can be either MessageEntering or MessageLeaving</param>
/// <param name="statusCode">HTTP status code</param>
/// <param name="contentLength">length of the http message</param>
/// <param name="httpHeaders">HTTP headers</param>
/**
* @param {?} messageDirection
* @param {?} contextID
* @param {?} sessionCounter
* @param {?} clientID
* @param {?} serverID
* @param {?} responseTime
* @param {?} statusCode
* @param {?} httpHeaders
* @param {?} contentLength
* @return {?}
*/
WriteBasicToLog(messageDirection, contextID, sessionCounter, clientID, serverID, responseTime, statusCode, httpHeaders, contentLength) {
if (this.LogLevel === Logger_LogLevels.Basic) {
/** @type {?} */
let text = httpHeaders;
text = text.trim();
text = NString.Replace(text, "\r\n", "|");
/** @type {?} */
let arg_E4_0 = "RIA,{0}_{1},{2},{3},{4},{5},-,{6},{7},{8},{9},{10},{11}";
/** @type {?} */
let expr_3E = new Array(12);
// TODO : need to check How to handle Process class.
// expr_3E[0] = Process.GetCurrentProcess().Id;
expr_3E[1] = Thread.CurrentThread.ManagedThreadId;
expr_3E[2] = new Date().toISOString();
expr_3E[3] = ((messageDirection === Logger_MessageDirection.MessageLeaving) ? "MSGL" : "MSGE");
expr_3E[4] = contextID;
expr_3E[5] = sessionCounter;
expr_3E[6] = clientID;
expr_3E[7] = serverID;
expr_3E[8] = ((responseTime !== 0) ? responseTime.toString() : "-");
/** @type {?} */
let arg_D3_1 = 9;
/** @type {?} */
let arg_D3_2;
arg_D3_2 = statusCode;
expr_3E[arg_D3_1] = arg_D3_2;
expr_3E[10] = text;
expr_3E[11] = contentLength;
/** @type {?} */
let value = NString.Format(arg_E4_0, expr_3E);
console.log(value);
}
}
/// <summary>
/// Writes a request exception basic level entry to log
/// </summary>
/// <param name="contextID"></param>
/// <param name="sessionCounter"></param>
/// <param name="clientID"></param>
/// <param name="serverID"></param>
/// <param name="ex">the logged exception</param>
/**
* @param {?} contextID
* @param {?} sessionCounter
* @param {?} clientID
* @param {?} serverID
* @param {?} ex
* @return {?}
*/
WriteBasicErrorToLog(contextID, sessionCounter, clientID, serverID, ex) {
Debug.Assert(this.LogLevel === Logger_LogLevels.Basic);
// TODO : Need to check how to handle Process
// let value: string = NString.Format("RIA,{0}_{1},{2},{3},{4},{5},-,{6},{7},-,-,-,{8} {9}", [
// Process.GetCurrentProcess().Id, Thread.CurrentThread.ManagedThreadId, DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ"), "RES", contextID, sessionCounter, clientID, serverID, ex.GetType(), ex.Message
// ]);
// NConsole.WriteLine(value);
}
/// <summary>
/// Write an error to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
WriteErrorToLog(msg) {
this.WriteToLog("ERROR: " + msg, true, LogType.error);
}
/**
* @param {?} msgOrEx
* @param {?=} msg
* @return {?}
*/
WriteExceptionToLog(msgOrEx, msg) {
if (msgOrEx instanceof Error) {
this.WriteExceptionToLog_2(msgOrEx, msg);
return;
}
if (arguments.length === 1 && (msgOrEx !== null || msgOrEx instanceof Exception)) {
this.WriteExceptionToLog_1(msgOrEx);
return;
}
this.WriteExceptionToLog_3(msgOrEx, msg);
}
/**
* @param {?} msg
* @return {?}
*/
WriteExceptionToLogWithMsg(msg) {
this.WriteToLog("ERROR: " + msg, true, LogType.error);
}
/**
* @param {?} ex
* @return {?}
*/
WriteExceptionToLog_1(ex) {
this.WriteExceptionToLogWithMsg(NString.Format("{0} : {1}{2}{3}{4}", [
ex.GetType(), OSEnvironment.EolSeq, ex.StackTrace, OSEnvironment.EolSeq, ex.Message
]));
}
/**
* @param {?} ex
* @param {?} message
* @return {?}
*/
WriteExceptionToLog_2(ex, message) {
if (isNullOrUndefined(message))
this.WriteExceptionToLogWithMsg(NString.Format("{0}{1}{2}", [ex.stack, OSEnvironment.EolSeq, ex.message]));
else
this.WriteExceptionToLogWithMsg(NString.Format("{0}{1}{2}{4}{5}", [message, OSEnvironment.EolSeq, ex.stack, OSEnvironment.EolSeq, ex.message]));
}
/**
* @param {?} ex
* @param {?} msg
* @return {?}
*/
WriteExceptionToLog_3(ex, msg) {
this.WriteExceptionToLogWithMsg(NString.Format("{0}, {1} : {2}{3}{4}{5}", [
ex.GetType(), msg, OSEnvironment.EolSeq, ex.StackTrace, OSEnvironment.EolSeq, ex.Message
]));
}
/**
* @param {?} msgOrEx
* @param {?=} msg
* @return {?}
*/
WriteWarningToLog(msgOrEx, msg) {
if (arguments.length === 1 && msgOrEx !== null) {
if (msgOrEx instanceof Exception)
this.WriteWarningToLog_1(msgOrEx);
else if (msgOrEx instanceof Error)
this.WriteWarningToLog_2(msgOrEx);
}
else
this.WriteWarningToLog_3(msgOrEx, msg);
}
/**
* @param {?} msg
* @return {?}
*/
WriteWarningToLogWithMsg(msg) {
if (this.LogLevel !== Logger_LogLevels.Basic) {
this.WriteToLog("WARNING: " + msg, true, LogType.warning);
}
}
/**
* @param {?} ex
* @return {?}
*/
WriteWarningToLog_1(ex) {
this.WriteWarningToLogWithMsg(ex.GetType() + " : " + OSEnvironment.EolSeq + ex.StackTrace + OSEnvironment.EolSeq + ex.Message);
}
/**
* @param {?} ex
* @return {?}
*/
WriteWarningToLog_2(ex) {
this.WriteWarningToLogWithMsg(NString.Format("{0}{1}{2}", [
ex.stack, OSEnvironment.EolSeq, ex.message
]));
}
/**
* @param {?} ex
* @param {?} msg
* @return {?}
*/
WriteWarningToLog_3(ex, msg) {
this.WriteWarningToLogWithMsg(NString.Format("{0}, {1} : {2}{3}{4}{5}", [
ex.GetType(), msg, OSEnvironment.EolSeq, ex.StackTrace, OSEnvironment.EolSeq, ex.Message
]));
}
/**
* @param {?} stackTrace
* @param {?} framesToPrint
* @param {?} traceTitle
* @return {?}
*/
WriteStackTrace(stackTrace, framesToPrint, traceTitle) {
if (traceTitle === null) {
traceTitle = "Stack trace:";
}
/** @type {?} */
let stringBuilder = new StringBuilder(traceTitle + OSEnvironment.EolSeq);
/** @type {?} */
let frames = stackTrace.GetFrames();
/** @type {?} */
let array = frames;
for (let i = 0; i < array.length; i = i + 1) {
/** @type {?} */
let stackFrame = array[i];
framesToPrint = framesToPrint - 1;
stringBuilder.Append(stackFrame.toString());
if (framesToPrint === 0) {
stringBuilder.Append("\t... more stack frames ...\n");
break;
}
}
this.WriteToLog(stringBuilder.ToString(), true);
}
/// <summary>
/// Flush the log writer.
/// </summary>
/**
* @return {?}
*/
Flush() {
}
}
Logger.instance = null;
if (false) {
/** @type {?} */
Logger.instance;
/** @type {?} */
Logger.prototype.LogLevel;
/** @type {?} */
Logger.prototype.ShouldBeep;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9nZ2VyLmpzIiwic291cmNlUm9vdCI6Im5nOi8vQG1hZ2ljLXhwYS91dGlscy8iLCJzb3VyY2VzIjpbInNyYy9Mb2dnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBQyxnQkFBZ0IsRUFBRSx1QkFBdUIsRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUNsRSxPQUFPLEVBQUMsUUFBUSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFjLGFBQWEsRUFBRSxNQUFNLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUM1RyxPQUFPLEVBQUMsYUFBYSxFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDOUMsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUU1QyxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxNQUFNLENBQUM7OztJQUlyQyxPQUFRO0lBQ1IsVUFBTztJQUNQLFFBQUs7Ozs7Ozs7Ozs7QUFRUCxNQUFNO0lBdVVKO1FBclVBLGFBQVEsR0FBcUIsQ0FBQyxDQUFDLENBQUMsbUJBQW1CO1FBRW5ELGFBQWE7UUFDYiwrREFBK0Q7UUFDL0QsY0FBYztRQUNkLGVBQVUsR0FBWSxLQUFLLENBQUM7SUFpVTVCLENBQUM7Ozs7O0lBL1RELE1BQU0sS0FBSyxRQUFRLENBQUMsS0FBYTtRQUMvQixNQUFNLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUMxQixDQUFDOzs7O0lBRUQsTUFBTSxLQUFLLFFBQVE7UUFDakIsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQzdCLE1BQU0sQ0FBQyxRQUFRLEdBQUcsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUNqQyxDQUFDO1FBQ0QsTUFBTSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUM7SUFDekIsQ0FBQzs7Ozs7Ozs7Ozs7O0lBT0QsVUFB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LElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ2xELENBQUM7Ozs7Ozs7SUFLRCxLQUFLO0lBRUwsQ0FBQzs7QUFwVU0sZUFBUSxHQUFXLElBQUksQ0FBQzs7O0lBQS9CLGdCQUErQjs7SUFDL0IsMEJBQStCOztJQUsvQiw0QkFBNEIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0xvZ2dlcl9Mb2dMZXZlbHMsIExvZ2dlcl9NZXNzYWdlRGlyZWN0aW9ufSBmcm9tIFwiLi9lbnVtc1wiO1xyXG5pbXBvcnQge0RhdGVUaW1lLCBEZWJ1ZywgRXhjZXB0aW9uLCBOU3RyaW5nLCBTdGFja1RyYWNlLCBTdHJpbmdCdWlsZGVyLCBUaHJlYWR9IGZyb20gXCJAbWFnaWMteHBhL21zY29yZWxpYlwiO1xyXG5pbXBvcnQge09TRW52aXJvbm1lbnR9IGZyb20gXCIuL1BsYXRmb3JtVXRpbHNcIjtcclxuaW1wb3J0IHtEYXRlVGltZVV0aWxzfSBmcm9tIFwiLi9EYXRlVGltZVV0aWxzXCI7XHJcbmltcG9ydCB7WE1MQ29uc3RhbnRzfSBmcm9tIFwiLi9YTUxDb25zdGFudHNcIjtcclxuaW1wb3J0ICogYXMgSlNTdGFja1RyYWNlIGZyb20gJ3N0YWNrdHJhY2UtanMnO1xyXG5pbXBvcnQge2lzTnVsbE9yVW5kZWZpbmVkfSBmcm9tIFwidXRpbFwiO1xyXG5pbXBvcnQgSlNTdGFja0ZyYW1lID0gSlNTdGFja1RyYWNlLlN0YWNrRnJhbWU7XHJcblxyXG5leHBvcnQgZW51bSBMb2dUeXBlIHtcclxuICBpbmZvID0gMSxcclxuICB3YXJuaW5nLFxyXG4gIGVycm9yXHJcbn1cclxuXHJcblxyXG4vLy8gPHN1bW1hcnk+XHJcbi8vLyBMb2dnZXIgY2xhc3Mgd2lsbCB0YWtlIGNhcmUgb2YgY2xpZW50IHNpZGUgbG9nZ2luZyAuIEl0IHdpbGwgY2hlY2sgZm9yIHZhcmlvdXMgbG9nIGxldmVscyBhbmQgYWNjb3JkaW5nbHkgd2lsbCB3cml0ZSBtZXNzYWdlcyBpbiBsb2cgZmlsZS5cclxuLy8vIDwvc3VtbWFyeT5cclxuLy9AZHluYW1pY1xyXG5leHBvcnQgY2xhc3MgTG9nZ2VyIHtcclxuICBzdGF0aWMgaW5zdGFuY2U6IExvZ2dlciA9IG51bGw7XHJcbiAgTG9nTGV2ZWw6IExvZ2dlcl9Mb2dMZXZlbHMgPSAwOyAvLyBJbnRlcm5hbExvZ0xldmVsXHJcblxyXG4gIC8vLyA8c3VtbWFyeT5cclxuICAvLy8gV2hpbGUgd3JpdGluZyB0aGUgZXJyb3IgbWVzc2FnZXMgaW4gdGhlIGZpbGUgcGxheSB0aGUgYmVlcC5cclxuICAvLy8gPC9zdW1tYXJ5PlxyXG4gIFNob3VsZEJlZXA6IGJvb2xlYW4gPSBmYWxzZTtcclxuXHJcbiAgc3RhdGljIHNldCBJbnN0YW5jZSh2YWx1ZTogTG9nZ2VyKSB7XHJcbiAgICBMb2dnZXIuaW5zdGFuY2UgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIHN0YXRpYyBnZXQgSW5zdGFuY2UoKTogTG9nZ2VyIHtcclxuICAgIGlmIChMb2dnZXIuaW5zdGFuY2UgPT09IG51bGwpIHtcclxuICAgICAgTG9nZ2VyLmluc3RhbmNlID0gbmV3IExvZ2dlcigpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIExvZ2dlci5pbnN0YW5jZTtcclxuICB9XHJcblxyXG4vLy8gPHN1bW1hcnk+XHJcbiAgLy8vIEluaXRpYWxpemUgbG9nZ2VyXHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJsb2dMZXZlbFwiPjwvcGFyYW0+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwiaW50ZXJuYWxMb2dTeW5jXCI+PC9wYXJhbT5cclxuICBJbml0aWFsaXplKGxvZ0xldmVsOiBMb2dnZXJfTG9nTGV2ZWxzLCBpbnRlcm5hbExvZ1N5bmM6IHN0cmluZywgc2hvdWxkQmVlcDogYm9vbGVhbik6IHZvaWQge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gbGV0IGxvZ1N5bmM6IExvZ1N5bmNNb2RlICA9IExvZ1N5bmNNb2RlLlNlc3Npb247XHJcbiAgICAgIHRoaXMuTG9nTGV2ZWwgPSBsb2dMZXZlbDtcclxuICAgICAgdGhpcy5TaG91bGRCZWVwID0gc2hvdWxkQmVlcDtcclxuXHJcbiAgICAgIC8vIFRPRE86IGltcGxlbWVudFxyXG4vLyAgIFN0cmluZyBzdHJMb2dTeW5jID0gaW50ZXJuYWxMb2dTeW5jO1xyXG4vLyAgIGlmICghc3RyaW5nLklzTnVsbE9yRW1wdHkoc3RyTG9nU3luYykpXHJcbi8vIHtcclxuLy8gICBpZiAoc3RyTG9nU3luYy5TdGFydHNXaXRoKFwiTVwiLCBTdHJpbmdDb21wYXJpc29uLkN1cnJlbnRDdWx0dXJlSWdub3JlQ2FzZSkpXHJcbi8vICAgbG9nU3luYyA9IExvZ1N5bmNNb2RlLk1lc3NhZ2U7XHJcbi8vICAgZWxzZSBpZiAoc3RyTG9nU3luYy5TdGFydHNXaXRoKFwiRlwiLCBTdHJpbmdDb21wYXJpc29uLkN1cnJlbnRDdWx0dXJlSWdub3JlQ2FzZSkpXHJcbi8vICAgbG9nU3luYyA9IExvZ1N5bmNNb2RlLkZsdXNoO1xyXG4vLyB9XHJcbi8vXHJcbiAgICB9XHJcbiAgICBjYXRjaCAoZSkge1xyXG4gICAgICB0aGlzLldyaXRlRGV2VG9Mb2coXCJDbGllbnRNYW5hZ2VyLmluaXQoKTogXCIgKyBlLk1lc3NhZ2UpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5Pjwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJsb2dMZXZlbFwiPjwvcGFyYW0+XHJcbiAgLy8vIDxyZXR1cm5zPjwvcmV0dXJucz5cclxuXHJcbiAgU2hvdWxkTG9nKGxvZ0xldmVsOiBMb2dnZXJfTG9nTGV2ZWxzKTogYm9vbGVhbjtcclxuICBTaG91bGRMb2coKTogYm9vbGVhbjtcclxuICBTaG91bGRMb2cobG9nTGV2ZWw/OiBMb2dnZXJfTG9nTGV2ZWxzKTogYm9vbGVhbiB7XHJcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSlcclxuICAgICAgcmV0dXJuIHRoaXMuU2hvdWxkTG9nXzAobG9nTGV2ZWwpO1xyXG4gICAgZWxzZVxyXG4gICAgICByZXR1cm4gdGhpcy5TaG91bGRMb2dfMSgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBTaG91bGRMb2dfMChsb2dMZXZlbDogTG9nZ2VyX0xvZ0xldmVscyk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuTG9nTGV2ZWwgPT09IGxvZ0xldmVsO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBTaG91bGRMb2dfMSgpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLkxvZ0xldmVsID4gTG9nZ2VyX0xvZ0xldmVscy5Ob25lO1xyXG4gIH1cclxuXHJcbiAgU2hvdWxkTG9nU2VydmVyUmVsYXRlZE1lc3NhZ2VzKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuICh0aGlzLlNob3VsZExvZ0V4dGVuZGVkU2VydmVyUmVsYXRlZE1lc3NhZ2VzKCkgfHwgTG9nZ2VyLkluc3RhbmNlLlNob3VsZExvZyhMb2dnZXJfTG9nTGV2ZWxzLlNlcnZlcikpICYmIHRoaXMuTG9nTGV2ZWwgIT09IExvZ2dlcl9Mb2dMZXZlbHMuQmFzaWM7XHJcbiAgfVxyXG5cclxuICBTaG91bGRMb2dFeHRlbmRlZFNlcnZlclJlbGF0ZWRNZXNzYWdlcygpOiBib29sZWFuIHtcclxuICAgIHJldHVybiAoTG9nZ2VyLkluc3RhbmNlLlNob3VsZExvZyhMb2dnZXJfTG9nTGV2ZWxzLlNlcnZlck1lc3NhZ2VzKSB8fCBMb2dnZXIuSW5zdGFuY2UuU2hvdWxkTG9nKExvZ2dlcl9Mb2dMZXZlbHMuU3VwcG9ydCkgfHwgTG9nZ2VyLkluc3RhbmNlLlNob3VsZExvZyhMb2dnZXJfTG9nTGV2ZWxzLkRldmVsb3BtZW50KSkgJiYgdGhpcy5Mb2dMZXZlbCAhPT0gTG9nZ2VyX0xvZ0xldmVscy5CYXNpYztcclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT48L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibXNnXCI+PC9wYXJhbT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJvcGVuSWZOZWNlc3NhcnlcIj5vcGVuIHRoZSBsb2cgZmlsZSBpZiBub3Qgb3BlbmVkIHlldDwvcGFyYW0+XHJcblxyXG4gIFdyaXRlVG9Mb2cobXNnOiBzdHJpbmcsIG9wZW5JZk5lY2Vzc2FyeTogYm9vbGVhbiwgbG9nVHlwZTogTG9nVHlwZSA9IExvZ1R5cGUuaW5mbyk6IHZvaWQge1xyXG5cclxuICAgIGlmICh0aGlzLkxvZ0xldmVsID4gTG9nZ2VyX0xvZ0xldmVscy5Ob25lIHx8IG9wZW5JZk5lY2Vzc2FyeSkge1xyXG4gICAgICBtc2cgPSBOU3RyaW5nLkZvcm1hdChcInswfSB7MX1cIiwgKHRoaXMuTG9nTGV2ZWwgPT09IExvZ2dlcl9Mb2dMZXZlbHMuQmFzaWMpID8gbmV3IERhdGUoKS50b0lTT1N0cmluZygpIDogRGF0ZVRpbWVVdGlscy5Ub1N0cmluZyhEYXRlVGltZS5Ob3csIFhNTENvbnN0YW50cy5FUlJPUl9MT0dfVElNRV9GT1JNQVQsIHRoaXMpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICBtc2cpO1xyXG5cclxuICAgICAgc3dpdGNoIChsb2dUeXBlKSB7XHJcbiAgICAgICAgY2FzZSBMb2dUeXBlLmVycm9yOlxyXG4gICAgICAgICAgY29uc29sZS5lcnJvcihtc2cpO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgY2FzZSBMb2dUeXBlLndhcm5pbmc6XHJcbiAgICAgICAgICBjb25zb2xlLndhcm4obXNnKTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhtc2cpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+XHJcbiAgLy8vIHdyaXRlIGEgc2VydmVyIGFjY2VzcyB0byB0aGUgbG9nXHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJtc2dcIj50aGUgbWVzc2FnZSB0byB3cml0ZSB0byB0aGUgbG9nPC9wYXJhbT5cclxuICBXcml0ZVNlcnZlclRvTG9nKG1zZzogc3RyaW5nKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5TaG91bGRMb2dTZXJ2ZXJSZWxhdGVkTWVzc2FnZXMoKSkge1xyXG4gICAgICB0aGlzLldyaXRlVG9Mb2coTlN0cmluZy5Gb3JtYXQoXCJTZXJ2ZXIsIFRocmVhZD17MH06IFwiLCBUaHJlYWQuQ3VycmVudFRocmVhZC5NYW5hZ2VkVGhyZWFkSWQpICsgbXNnLCBmYWxzZSwgTG9nVHlwZS5pbmZvKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT5cclxuICAvLy8gd3JpdGUgYSBzZXJ2ZXIgYWNjZXNzIHRvIHRoZSBsb2csIGluY2x1ZGluZyB0aGUgY29udGVudFxyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibXNnXCI+dGhlIG1lc3NhZ2UgdG8gd3JpdGUgdG8gdGhlIGxvZzwvcGFyYW0+XHJcbiAgV3JpdGVTZXJ2ZXJNZXNzYWdlc1RvTG9nKG1zZzogc3RyaW5nKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5TaG91bGRMb2dFeHRlbmRlZFNlcnZlclJlbGF0ZWRNZXNzYWdlcygpKSB7XHJcbiAgICAgIHRoaXMuV3JpdGVUb0xvZyhcIlNlcnZlciM6IFwiICsgbXNnLCBmYWxzZSwgTG9nVHlwZS5pbmZvKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT5Xcml0ZSBhIFFDIG1lc3NhZ2UgdG8gdGhlIGxvZzwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJtc2dcIj50aGUgbWVzc2FnZSB0byB3cml0ZSB0byB0aGUgbG9nPC9wYXJhbT5cclxuICBXcml0ZVN1cHBvcnRUb0xvZyhtc2c6IHN0cmluZywgc2tpcExpbmU6IGJvb2xlYW4pOiB2b2lkIHtcclxuXHJcbiAgICBpZiAodGhpcy5Mb2dMZXZlbCA+PSBMb2dnZXJfTG9nTGV2ZWxzLlN1cHBvcnQgJiYgdGhpcy5Mb2dMZXZlbCAhPT0gTG9nZ2VyX0xvZ0xldmVscy5CYXNpYykge1xyXG4gICAgICBpZiAoc2tpcExpbmUpIHtcclxuICAgICAgICB0aGlzLldyaXRlVG9Mb2coXCJTVVBQT1JUOiBcIiArIG1zZywgZmFsc2UsIExvZ1R5cGUuaW5mbyk7XHJcbiAgICAgIH1cclxuICAgICAgZWxzZSB7XHJcbiAgICAgICAgdGhpcy5Xcml0ZVRvTG9nKFwiU1VQUE9SVDogXCIgKyBtc2cgKyBPU0Vudmlyb25tZW50LkVvbFNlcSArIFwiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cIiwgZmFsc2UsIExvZ1R5cGUuaW5mbyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT5cclxuICAvLy8gd3JpdGUgYSBwZXJmb3JtYW5jZSBtZXNzYWdlIHRvIHRoZSBsb2dcclxuICAvLy8gPC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cIm1zZ1wiPnRoZSBtZXNzYWdlIHRvIHdyaXRlIHRvIHRoZSBsb2c8L3BhcmFtPlxyXG4gIFdyaXRlR3VpVG9Mb2cobXNnOiBzdHJpbmcpOiB2b2lkIHtcclxuXHJcbiAgICBpZiAodGhpcy5Mb2dMZXZlbCA+PSBMb2dnZXJfTG9nTGV2ZWxzLkd1aSAmJiB0aGlzLkxvZ0xldmVsICE9PSBMb2dnZXJfTG9nTGV2ZWxzLkJhc2ljKSB7XHJcbiAgICAgIHRoaXMuV3JpdGVUb0xvZyhtc2csIGZhbHNlLCBMb2dUeXBlLmluZm8pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5PlxyXG4gIC8vLyB3cml0ZSBhIGRldmVsb3BlciBtZXNzYWdlIHRvIHRoZSBsb2dcclxuICAvLy8gPC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cIm1zZ1wiPnRoZSBtZXNzYWdlIHRvIHdyaXRlIHRvIHRoZSBsb2c8L3BhcmFtPlxyXG4gIFdyaXRlRGV2VG9Mb2cobXNnOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLkxvZ0xldmVsID49IExvZ2dlcl9Mb2dMZXZlbHMuRGV2ZWxvcG1lbnQgJiYgdGhpcy5Mb2dMZXZlbCAhPT0gTG9nZ2VyX0xvZ0xldmVscy5CYXNpYykge1xyXG4gICAgICB0aGlzLldyaXRlVG9Mb2coXCJERVY6IFwiICsgbXNnLCBmYWxzZSwgTG9nVHlwZS5pbmZvKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT5cclxuICAvLy8gV3JpdGVzIGEgYmFzaWMgbGV2ZWwgZW50cnkgdG8gbG9nXHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJtZXNzYWdlRGlyZWN0aW9uXCI+bWVzc2FnZSBkaXJlY3Rpb24gcmVsYXRpdmUgdG8gdGhlIGN1cnJlbnQgbW9kdWxlIChSSUEgY2xpZW50KS4gQ2FuIGJlIGVpdGhlciBNZXNzYWdlRW50ZXJpbmcgb3IgTWVzc2FnZUxlYXZpbmc8L3BhcmFtPlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cInN0YXR1c0NvZGVcIj5IVFRQIHN0YXR1cyBjb2RlPC9wYXJhbT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJjb250ZW50TGVuZ3RoXCI+bGVuZ3RoIG9mIHRoZSBodHRwIG1lc3NhZ2U8L3BhcmFtPlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cImh0dHBIZWFkZXJzXCI+SFRUUCBoZWFkZXJzPC9wYXJhbT5cclxuICBXcml0ZUJhc2ljVG9Mb2cobWVzc2FnZURpcmVjdGlvbjogTG9nZ2VyX01lc3NhZ2VEaXJlY3Rpb24sIGNvbnRleHRJRDogc3RyaW5nLCBzZXNzaW9uQ291bnRlcjogbnVtYmVyLCBjbGllbnRJRDogc3RyaW5nLCBzZXJ2ZXJJRDogc3RyaW5nLCByZXNwb25zZVRpbWU6IG51bWJlciwgc3RhdHVzQ29kZTogc3RyaW5nLCBodHRwSGVhZGVyczogc3RyaW5nLCBjb250ZW50TGVuZ3RoOiBudW1iZXIpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLkxvZ0xldmVsID09PSBMb2dnZXJfTG9nTGV2ZWxzLkJhc2ljKSB7XHJcbiAgICAgIGxldCB0ZXh0OiBzdHJpbmcgPSBodHRwSGVhZGVycztcclxuICAgICAgdGV4dCA9IHRleHQudHJpbSgpO1xyXG4gICAgICB0ZXh0ID0gTlN0cmluZy5SZXBsYWNlKHRleHQsIFwiXFxyXFxuXCIsIFwifFwiKTtcclxuICAgICAgbGV0IGFyZ19FNF8wOiBzdHJpbmcgPSBcIlJJQSx7MH1fezF9LHsyfSx7M30sezR9LHs1fSwtLHs2fSx7N30sezh9LHs5fSx7MTB9LHsxMX1cIjtcclxuICAgICAgbGV0IGV4cHJfM0U6IGFueVtdID0gbmV3IEFycmF5PGFueT4oMTIpO1xyXG5cclxuICAgICAgLy8gVE9ETyA6IG5lZWQgdG8gY2hlY2sgSG93IHRvIGhhbmRsZSBQcm9jZXNzIGNsYXNzLlxyXG4gICAgICAvLyBleHByXzNFWzBdID0gUHJvY2Vzcy5HZXRDdXJyZW50UHJvY2VzcygpLklkO1xyXG4gICAgICBleHByXzNFWzFdID0gVGhyZWFkLkN1cnJlbnRUaHJlYWQuTWFuYWdlZFRocmVhZElkO1xyXG4gICAgICBleHByXzNFWzJdID0gbmV3IERhdGUoKS50b0lTT1N0cmluZygpO1xyXG4gICAgICBleHByXzNFWzNdID0gKChtZXNzYWdlRGlyZWN0aW9uID09PSBMb2dnZXJfTWVzc2FnZURpcmVjdGlvbi5NZXNzYWdlTGVhdmluZykgPyBcIk1TR0xcIiA6IFwiTVNHRVwiKTtcclxuICAgICAgZXhwcl8zRVs0XSA9IGNvbnRleHRJRDtcclxuICAgICAgZXhwcl8zRVs1XSA9IHNlc3Npb25Db3VudGVyO1xyXG4gICAgICBleHByXzNFWzZdID0gY2xpZW50SUQ7XHJcbiAgICAgIGV4cHJfM0VbN10gPSBzZXJ2ZXJJRDtcclxuICAgICAgZXhwcl8zRVs4XSA9ICgocmVzcG9uc2VUaW1lICE9PSAwKSA/IHJlc3BvbnNlVGltZS50b1N0cmluZygpIDogXCItXCIpO1xyXG4gICAgICBsZXQgYXJnX0QzXzE6IG51bWJlciA9IDk7XHJcbiAgICAgIGxldCBhcmdfRDNfMjogYW55O1xyXG4gICAgICBhcmdfRDNfMiA9IHN0YXR1c0NvZGU7XHJcbiAgICAgIGV4cHJfM0VbYXJnX0QzXzFdID0gYXJnX0QzXzI7XHJcbiAgICAgIGV4cHJfM0VbMTBdID0gdGV4dDtcclxuICAgICAgZXhwcl8zRVsxMV0gPSBjb250ZW50TGVuZ3RoO1xyXG4gICAgICBsZXQgdmFsdWU6IHN0cmluZyA9IE5TdHJpbmcuRm9ybWF0KGFyZ19FNF8wLCBleHByXzNFKTtcclxuICAgICAgY29uc29sZS5sb2codmFsdWUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5PlxyXG4gIC8vLyBXcml0ZXMgYSByZXF1ZXN0IGV4Y2VwdGlvbiBiYXNpYyBsZXZlbCBlbnRyeSB0byBsb2dcclxuICAvLy8gPC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cImNvbnRleHRJRFwiPjwvcGFyYW0+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwic2Vzc2lvbkNvdW50ZXJcIj48L3BhcmFtPlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cImNsaWVudElEXCI+PC9wYXJhbT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJzZXJ2ZXJJRFwiPjwvcGFyYW0+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwiZXhcIj50aGUgbG9nZ2VkIGV4Y2VwdGlvbjwvcGFyYW0+XHJcbiAgV3JpdGVCYXNpY0Vycm9yVG9Mb2coY29udGV4dElEOiBzdHJpbmcsIHNlc3Npb25Db3VudGVyOiBudW1iZXIsIGNsaWVudElEOiBzdHJpbmcsIHNlcnZlcklEOiBzdHJpbmcsIGV4OiBFeGNlcHRpb24pOiB2b2lkIHtcclxuICAgIERlYnVnLkFzc2VydCh0aGlzLkxvZ0xldmVsID09PSBMb2dnZXJfTG9nTGV2ZWxzLkJhc2ljKTtcclxuXHJcbiAgICAvLyBUT0RPIDogTmVlZCB0byBjaGVjayBob3cgdG8gaGFuZGxlIFByb2Nlc3NcclxuICAgIC8vIGxldCB2YWx1ZTogc3RyaW5nID0gTlN0cmluZy5Gb3JtYXQoXCJSSUEsezB9X3sxfSx7Mn0sezN9LHs0fSx7NX0sLSx7Nn0sezd9LC0sLSwtLHs4fSB7OX1cIiwgW1xyXG4gICAgLy8gUHJvY2Vzcy5HZXRDdXJyZW50UHJvY2VzcygpLklkLCBUaHJlYWQuQ3VycmVudFRocmVhZC5NYW5hZ2VkVGhyZWFkSWQsIERhdGVUaW1lLlV0Y05vdy5Ub1N0cmluZyhcInl5eXktTU0tZGRUSEg6bW06c3MuZmZmZmZmZlpcIiksIFwiUkVTXCIsIGNvbnRleHRJRCwgc2Vzc2lvbkNvdW50ZXIsIGNsaWVudElELCBzZXJ2ZXJJRCwgZXguR2V0VHlwZSgpLCBleC5NZXNzYWdlXHJcbiAgICAvLyBdKTtcclxuICAgIC8vIE5Db25zb2xlLldyaXRlTGluZSh2YWx1ZSk7XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+XHJcbiAgLy8vIFdyaXRlIGFuIGVycm9yIHRvIHRoZSBsb2dcclxuICAvLy8gPC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cIm1zZ1wiPnRoZSBtZXNzYWdlIHRvIHdyaXRlIHRvIHRoZSBsb2c8L3BhcmFtPlxyXG4gIFdyaXRlRXJyb3JUb0xvZyhtc2c6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5Xcml0ZVRvTG9nKFwiRVJST1I6IFwiICsgbXNnLCB0cnVlLCBMb2dUeXBlLmVycm9yKTtcclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT5cclxuICAvLy8gV3JpdGUgYW4gaW50ZXJuYWwgZXJyb3IgdG8gdGhlIGxvZy4gQWxzbyBwcmludHMgc3RhY2sgdHJhY2UgYWxvbmcgd2l0aCB0aGUgbWVzc2FnZVxyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibXNnXCI+dGhlIG1lc3NhZ2UgdG8gd3JpdGUgdG8gdGhlIGxvZzwvcGFyYW0+XHJcbiAgV3JpdGVFeGNlcHRpb25Ub0xvZyhleDogRXhjZXB0aW9uKTogdm9pZDtcclxuICBXcml0ZUV4Y2VwdGlvblRvTG9nKGV4OiBFcnJvcik6IHZvaWQ7XHJcbiAgV3JpdGVFeGNlcHRpb25Ub0xvZyhleDogRXhjZXB0aW9uLCBtc2c6IHN0cmluZyk6IHZvaWQ7XHJcbiAgV3JpdGVFeGNlcHRpb25Ub0xvZyhtc2dPckV4OiBhbnksIG1zZz86IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKG1zZ09yRXggaW5zdGFuY2VvZiBFcnJvcikge1xyXG4gICAgICB0aGlzLldyaXRlRXhjZXB0aW9uVG9Mb2dfMihtc2dPckV4LCBtc2cpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSAmJiAobXNnT3JFeCAhPT0gbnVsbCB8fCBtc2dPckV4IGluc3RhbmNlb2YgRXhjZXB0aW9uKSkge1xyXG4gICAgICB0aGlzLldyaXRlRXhjZXB0aW9uVG9Mb2dfMShtc2dPckV4KTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuV3JpdGVFeGNlcHRpb25Ub0xvZ18zKG1zZ09yRXgsIG1zZyk7XHJcbiAgfVxyXG5cclxuICBXcml0ZUV4Y2VwdGlvblRvTG9nV2l0aE1zZyhtc2c6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5Xcml0ZVRvTG9nKFwiRVJST1I6IFwiICsgbXNnLCB0cnVlLCBMb2dUeXBlLmVycm9yKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgV3JpdGVFeGNlcHRpb25Ub0xvZ18xKGV4OiBFeGNlcHRpb24pOiB2b2lkIHtcclxuICAgIHRoaXMuV3JpdGVFeGNlcHRpb25Ub0xvZ1dpdGhNc2coTlN0cmluZy5Gb3JtYXQoXCJ7MH0gOiB7MX17Mn17M317NH1cIiwgW1xyXG4gICAgICBleC5HZXRUeXBlKCksIE9TRW52aXJvbm1lbnQuRW9sU2VxLCBleC5TdGFja1RyYWNlLCBPU0Vudmlyb25tZW50LkVvbFNlcSwgZXguTWVzc2FnZVxyXG4gICAgXSkpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBXcml0ZUV4Y2VwdGlvblRvTG9nXzIoZXg6IEVycm9yLCBtZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmIChpc051bGxPclVuZGVmaW5lZChtZXNzYWdlKSlcclxuICAgICAgdGhpcy5Xcml0ZUV4Y2VwdGlvblRvTG9nV2l0aE1zZyhOU3RyaW5nLkZvcm1hdChcInswfXsxfXsyfVwiLCBbZXguc3RhY2ssIE9TRW52aXJvbm1lbnQuRW9sU2VxLCBleC5tZXNzYWdlXSkpO1xyXG4gICAgZWxzZVxyXG4gICAgICB0aGlzLldyaXRlRXhjZXB0aW9uVG9Mb2dXaXRoTXNnKE5TdHJpbmcuRm9ybWF0KFwiezB9ezF9ezJ9ezR9ezV9XCIsIFttZXNzYWdlLCBPU0Vudmlyb25tZW50LkVvbFNlcSwgZXguc3RhY2ssIE9TRW52aXJvbm1lbnQuRW9sU2VxLCBleC5tZXNzYWdlXSkpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBXcml0ZUV4Y2VwdGlvblRvTG9nXzMoZXg6IEV4Y2VwdGlvbiwgbXNnOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIHRoaXMuV3JpdGVFeGNlcHRpb25Ub0xvZ1dpdGhNc2coTlN0cmluZy5Gb3JtYXQoXCJ7MH0sIHsxfSA6IHsyfXszfXs0fXs1fVwiLCBbXHJcbiAgICAgIGV4LkdldFR5cGUoKSwgbXNnLCBPU0Vudmlyb25tZW50LkVvbFNlcSwgZXguU3RhY2tUcmFjZSwgT1NFbnZpcm9ubWVudC5Fb2xTZXEsIGV4Lk1lc3NhZ2VcclxuICAgIF0pKTtcclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT4gd3JpdGUgYSB3YXJuaW5nIHRvIHRoZSBsb2c8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibXNnXCI+dGhlIG1lc3NhZ2UgdG8gd3JpdGUgdG8gdGhlIGxvZzwvcGFyYW0+XHJcbiAgV3JpdGVXYXJuaW5nVG9Mb2coZXg6IEV4Y2VwdGlvbik6IHZvaWQ7XHJcbiAgV3JpdGVXYXJuaW5nVG9Mb2coZXg6IEV4Y2VwdGlvbiwgbXNnOiBzdHJpbmcpOiB2b2lkO1xyXG4gIFdyaXRlV2FybmluZ1RvTG9nKGV4OiBFcnJvcik6IHZvaWQ7XHJcbiAgV3JpdGVXYXJuaW5nVG9Mb2cobXNnT3JFeDogYW55LCBtc2c/OiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAxICYmIG1zZ09yRXggIT09IG51bGwpIHtcclxuICAgICAgaWYgKG1zZ09yRXggaW5zdGFuY2VvZiBFeGNlcHRpb24pXHJcbiAgICAgICAgdGhpcy5Xcml0ZVdhcm5pbmdUb0xvZ18xKG1zZ09yRXgpO1xyXG4gICAgICBlbHNlIGlmIChtc2dPckV4IGluc3RhbmNlb2YgRXJyb3IpXHJcbiAgICAgICAgdGhpcy5Xcml0ZVdhcm5pbmdUb0xvZ18yKG1zZ09yRXgpO1xyXG4gICAgfVxyXG4gICAgZWxzZVxyXG4gICAgICB0aGlzLldyaXRlV2FybmluZ1RvTG9nXzMobXNnT3JFeCwgbXNnKTtcclxuICB9XHJcblxyXG4gIFdyaXRlV2FybmluZ1RvTG9nV2l0aE1zZyhtc2c6IHN0cmluZyk6IHZvaWQge1xyXG5cclxuICAgIGlmICh0aGlzLkxvZ0xldmVsICE9PSBMb2dnZXJfTG9nTGV2ZWxzLkJhc2ljKSB7XHJcbiAgICAgIHRoaXMuV3JpdGVUb0xvZyhcIldBUk5JTkc6IFwiICsgbXNnLCB0cnVlLCBMb2dUeXBlLndhcm5pbmcpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBXcml0ZVdhcm5pbmdUb0xvZ18xKGV4OiBFeGNlcHRpb24pOiB2b2lkIHtcclxuICAgIHRoaXMuV3JpdGVXYXJuaW5nVG9Mb2dXaXRoTXNnKGV4LkdldFR5cGUoKSArIFwiIDogXCIgKyBPU0Vudmlyb25tZW50LkVvbFNlcSArIGV4LlN0YWNrVHJhY2UgKyBPU0Vudmlyb25tZW50LkVvbFNlcSArIGV4Lk1lc3NhZ2UpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBXcml0ZVdhcm5pbmdUb0xvZ18yKGV4OiBFcnJvcik6IHZvaWQge1xyXG4gICAgdGhpcy5Xcml0ZVdhcm5pbmdUb0xvZ1dpdGhNc2coTlN0cmluZy5Gb3JtYXQoXCJ7MH17MX17Mn1cIiwgW1xyXG4gICAgICBleC5zdGFjaywgT1NFbnZpcm9ubWVudC5Fb2xTZXEsIGV4Lm1lc3NhZ2VcclxuICAgIF0pKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgV3JpdGVXYXJuaW5nVG9Mb2dfMyhleDogRXhjZXB0aW9uLCBtc2c6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5Xcml0ZVdhcm5pbmdUb0xvZ1dpdGhNc2coTlN0cmluZy5Gb3JtYXQoXCJ7MH0sIHsxfSA6IHsyfXszfXs0fXs1fVwiLCBbXHJcbiAgICAgIGV4LkdldFR5cGUoKSwgbXNnLCBPU0Vudmlyb25tZW50LkVvbFNlcSwgZXguU3RhY2tUcmFjZSwgT1NFbnZpcm9ubWVudC5Fb2xTZXEsIGV4Lk1lc3NhZ2VcclxuICAgIF0pKTtcclxuICB9XHJcblxyXG4gIFdyaXRlU3RhY2tUcmFjZShzdGFja1RyYWNlOiBTdGFja1RyYWNlLCBmcmFtZXNUb1ByaW50OiBudW1iZXIsIHRyYWNlVGl0bGU6IHN0cmluZyk6IHZvaWQge1xyXG5cclxuICAgIGlmICh0cmFjZVRpdGxlID09PSBudWxsKSB7XHJcbiAgICAgIHRyYWNlVGl0bGUgPSBcIlN0YWNrIHRyYWNlOlwiO1xyXG4gICAgfVxyXG4gICAgbGV0IHN0cmluZ0J1aWxkZXI6IFN0cmluZ0J1aWxkZXIgPSBuZXcgU3RyaW5nQnVpbGRlcih0cmFjZVRpdGxlICsgT1NFbnZpcm9ubWVudC5Fb2xTZXEpO1xyXG4gICAgbGV0IGZyYW1lczogSlNTdGFja0ZyYW1lW10gPSBzdGFja1RyYWNlLkdldEZyYW1lcygpO1xyXG4gICAgbGV0IGFycmF5OiBKU1N0YWNrRnJhbWVbXSA9IGZyYW1lcztcclxuICAgIGZvciAobGV0IGk6IG51bWJlciA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkgPSBpICsgMSkge1xyXG4gICAgICBsZXQgc3RhY2tGcmFtZTogSlNTdGFja0ZyYW1lID0gYXJyYXlbaV07XHJcbiAgICAgIGZyYW1lc1RvUHJpbnQgPSBmcmFtZXNUb1ByaW50IC0gMTtcclxuXHJcbiAgICAgIHN0cmluZ0J1aWxkZXIuQXBwZW5kKHN0YWNrRnJhbWUudG9TdHJpbmcoKSk7XHJcblxyXG4gICAgICBpZiAoZnJhbWVzVG9QcmludCA9PT0gMCkge1xyXG4gICAgICAgIHN0cmluZ0J1aWxkZXIuQXBwZW5kKFwiXFx0Li4uIG1vcmUgc3RhY2sgZnJhbWVzIC4uLlxcblwiKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgdGhpcy5Xcml0ZVRvTG9nKHN0cmluZ0J1aWxkZXIuVG9TdHJpbmcoKSwgdHJ1ZSk7XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+XHJcbiAgLy8vIEZsdXNoIHRoZSBsb2cgd3JpdGVyLlxyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgRmx1c2goKTogdm9pZCB7XHJcblxyXG4gIH1cclxuXHJcbiAgY29uc3RydWN0b3IoKSB7XHJcbiAgfVxyXG59XHJcbiJdfQ==