@magic-xpa/utils
Version:
magic utils package
686 lines • 54.7 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} */
var 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
var Logger = /** @class */ (function () {
function Logger() {
this.LogLevel = 0; // InternalLogLevel
/// <summary>
/// While writing the error messages in the file play the beep.
/// </summary>
this.ShouldBeep = false;
}
Object.defineProperty(Logger, "Instance", {
get: /**
* @return {?}
*/
function () {
if (Logger.instance === null) {
Logger.instance = new Logger();
}
return Logger.instance;
},
set: /**
* @param {?} value
* @return {?}
*/
function (value) {
Logger.instance = value;
},
enumerable: true,
configurable: true
});
/// <summary>
/// Initialize logger
/// </summary>
/// <param name="logLevel"></param>
/// <param name="internalLogSync"></param>
/// <summary>
/// Initialize logger
/// </summary>
/// <param name="logLevel"></param>
/// <param name="internalLogSync"></param>
/**
* @param {?} logLevel
* @param {?} internalLogSync
* @param {?} shouldBeep
* @return {?}
*/
Logger.prototype.Initialize =
/// <summary>
/// Initialize logger
/// </summary>
/// <param name="logLevel"></param>
/// <param name="internalLogSync"></param>
/**
* @param {?} logLevel
* @param {?} internalLogSync
* @param {?} shouldBeep
* @return {?}
*/
function (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 {?}
*/
Logger.prototype.ShouldLog = /**
* @param {?=} logLevel
* @return {?}
*/
function (logLevel) {
if (arguments.length === 1)
return this.ShouldLog_0(logLevel);
else
return this.ShouldLog_1();
};
/**
* @param {?} logLevel
* @return {?}
*/
Logger.prototype.ShouldLog_0 = /**
* @param {?} logLevel
* @return {?}
*/
function (logLevel) {
return this.LogLevel === logLevel;
};
/**
* @return {?}
*/
Logger.prototype.ShouldLog_1 = /**
* @return {?}
*/
function () {
return this.LogLevel > Logger_LogLevels.None;
};
/**
* @return {?}
*/
Logger.prototype.ShouldLogServerRelatedMessages = /**
* @return {?}
*/
function () {
return (this.ShouldLogExtendedServerRelatedMessages() || Logger.Instance.ShouldLog(Logger_LogLevels.Server)) && this.LogLevel !== Logger_LogLevels.Basic;
};
/**
* @return {?}
*/
Logger.prototype.ShouldLogExtendedServerRelatedMessages = /**
* @return {?}
*/
function () {
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>
/// <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 {?}
*/
Logger.prototype.WriteToLog =
/// <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 {?}
*/
function (msg, openIfNecessary, logType) {
if (logType === void 0) { 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>
/// <summary>
/// write a server access to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
Logger.prototype.WriteServerToLog =
/// <summary>
/// write a server access to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
function (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>
/// <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 {?}
*/
Logger.prototype.WriteServerMessagesToLog =
/// <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 {?}
*/
function (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>
/// <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 {?}
*/
Logger.prototype.WriteSupportToLog =
/// <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 {?}
*/
function (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>
/// <summary>
/// write a performance message to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
Logger.prototype.WriteGuiToLog =
/// <summary>
/// write a performance message to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
function (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>
/// <summary>
/// write a developer message to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
Logger.prototype.WriteDevToLog =
/// <summary>
/// write a developer message to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
function (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>
/// <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 {?}
*/
Logger.prototype.WriteBasicToLog =
/// <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 {?}
*/
function (messageDirection, contextID, sessionCounter, clientID, serverID, responseTime, statusCode, httpHeaders, contentLength) {
if (this.LogLevel === Logger_LogLevels.Basic) {
/** @type {?} */
var text = httpHeaders;
text = text.trim();
text = NString.Replace(text, "\r\n", "|");
/** @type {?} */
var arg_E4_0 = "RIA,{0}_{1},{2},{3},{4},{5},-,{6},{7},{8},{9},{10},{11}";
/** @type {?} */
var 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 {?} */
var arg_D3_1 = 9;
/** @type {?} */
var arg_D3_2 = void 0;
arg_D3_2 = statusCode;
expr_3E[arg_D3_1] = arg_D3_2;
expr_3E[10] = text;
expr_3E[11] = contentLength;
/** @type {?} */
var 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>
/// <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 {?}
*/
Logger.prototype.WriteBasicErrorToLog =
/// <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 {?}
*/
function (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>
/// <summary>
/// Write an error to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
Logger.prototype.WriteErrorToLog =
/// <summary>
/// Write an error to the log
/// </summary>
/// <param name="msg">the message to write to the log</param>
/**
* @param {?} msg
* @return {?}
*/
function (msg) {
this.WriteToLog("ERROR: " + msg, true, LogType.error);
};
/**
* @param {?} msgOrEx
* @param {?=} msg
* @return {?}
*/
Logger.prototype.WriteExceptionToLog = /**
* @param {?} msgOrEx
* @param {?=} msg
* @return {?}
*/
function (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 {?}
*/
Logger.prototype.WriteExceptionToLogWithMsg = /**
* @param {?} msg
* @return {?}
*/
function (msg) {
this.WriteToLog("ERROR: " + msg, true, LogType.error);
};
/**
* @param {?} ex
* @return {?}
*/
Logger.prototype.WriteExceptionToLog_1 = /**
* @param {?} ex
* @return {?}
*/
function (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 {?}
*/
Logger.prototype.WriteExceptionToLog_2 = /**
* @param {?} ex
* @param {?} message
* @return {?}
*/
function (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 {?}
*/
Logger.prototype.WriteExceptionToLog_3 = /**
* @param {?} ex
* @param {?} msg
* @return {?}
*/
function (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 {?}
*/
Logger.prototype.WriteWarningToLog = /**
* @param {?} msgOrEx
* @param {?=} msg
* @return {?}
*/
function (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 {?}
*/
Logger.prototype.WriteWarningToLogWithMsg = /**
* @param {?} msg
* @return {?}
*/
function (msg) {
if (this.LogLevel !== Logger_LogLevels.Basic) {
this.WriteToLog("WARNING: " + msg, true, LogType.warning);
}
};
/**
* @param {?} ex
* @return {?}
*/
Logger.prototype.WriteWarningToLog_1 = /**
* @param {?} ex
* @return {?}
*/
function (ex) {
this.WriteWarningToLogWithMsg(ex.GetType() + " : " + OSEnvironment.EolSeq + ex.StackTrace + OSEnvironment.EolSeq + ex.Message);
};
/**
* @param {?} ex
* @return {?}
*/
Logger.prototype.WriteWarningToLog_2 = /**
* @param {?} ex
* @return {?}
*/
function (ex) {
this.WriteWarningToLogWithMsg(NString.Format("{0}{1}{2}", [
ex.stack, OSEnvironment.EolSeq, ex.message
]));
};
/**
* @param {?} ex
* @param {?} msg
* @return {?}
*/
Logger.prototype.WriteWarningToLog_3 = /**
* @param {?} ex
* @param {?} msg
* @return {?}
*/
function (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 {?}
*/
Logger.prototype.WriteStackTrace = /**
* @param {?} stackTrace
* @param {?} framesToPrint
* @param {?} traceTitle
* @return {?}
*/
function (stackTrace, framesToPrint, traceTitle) {
if (traceTitle === null) {
traceTitle = "Stack trace:";
}
/** @type {?} */
var stringBuilder = new StringBuilder(traceTitle + OSEnvironment.EolSeq);
/** @type {?} */
var frames = stackTrace.GetFrames();
/** @type {?} */
var array = frames;
for (var i = 0; i < array.length; i = i + 1) {
/** @type {?} */
var 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>
/// <summary>
/// Flush the log writer.
/// </summary>
/**
* @return {?}
*/
Logger.prototype.Flush =
/// <summary>
/// Flush the log writer.
/// </summary>
/**
* @return {?}
*/
function () {
};
Logger.instance = null;
return Logger;
}());
export { Logger };
if (false) {
/** @type {?} */
Logger.instance;
/** @type {?} */
Logger.prototype.LogLevel;
/** @type {?} */
Logger.prototype.ShouldBeep;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9nZ2VyLmpzIiwic291cmNlUm9vdCI6Im5nOi8vQG1hZ2ljLXhwYS91dGlscy8iLCJzb3VyY2VzIjpbInNyYy9Mb2dnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBQyxnQkFBZ0IsRUFBRSx1QkFBdUIsRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUNsRSxPQUFPLEVBQUMsUUFBUSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFjLGFBQWEsRUFBRSxNQUFNLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUM1RyxPQUFPLEVBQUMsYUFBYSxFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDOUMsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUU1QyxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxNQUFNLENBQUM7OztJQUlyQyxPQUFRO0lBQ1IsVUFBTztJQUNQLFFBQUs7Ozs7Ozs7Ozs7QUFRUDtJQXVVRTtRQXJVQSxhQUFRLEdBQXFCLENBQUMsQ0FBQyxDQUFDLG1CQUFtQjtRQUVuRCxhQUFhO1FBQ2IsK0RBQStEO1FBQy9ELGNBQWM7UUFDZCxlQUFVLEdBQVksS0FBSyxDQUFDO0lBaVU1QixDQUFDO0lBL1RELHNCQUFXLGtCQUFROzs7O1FBSW5CO1lBQ0UsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUM3QixNQUFNLENBQUMsUUFBUSxHQUFHLElBQUksTUFBTSxFQUFFLENBQUM7WUFDakMsQ0FBQztZQUNELE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDO1FBQ3pCLENBQUM7Ozs7O1FBVEQsVUFBb0IsS0FBYTtZQUMvQixNQUFNLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQztRQUMxQixDQUFDOzs7T0FBQTtJQVNILGFBQWE7SUFDWCxxQkFBcUI7SUFDckIs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QUFDLGFBQWEsQ0FBQyxRQUFRLEVBQUUsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBRUQsYUFBYTtJQUNiLHlCQUF5QjtJQUN6QixjQUFjOzs7Ozs7O0lBQ2Qsc0JBQUs7Ozs7Ozs7SUFBTDtJQUVBLENBQUM7SUFwVU0sZUFBUSxHQUFXLElBQUksQ0FBQztJQXdVakMsYUFBQztDQUFBLEFBelVELElBeVVDO1NBelVZLE1BQU07OztJQUNqQixnQkFBK0I7O0lBQy9CLDBCQUErQjs7SUFLL0IsNEJBQTRCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtMb2dnZXJfTG9nTGV2ZWxzLCBMb2dnZXJfTWVzc2FnZURpcmVjdGlvbn0gZnJvbSBcIi4vZW51bXNcIjtcclxuaW1wb3J0IHtEYXRlVGltZSwgRGVidWcsIEV4Y2VwdGlvbiwgTlN0cmluZywgU3RhY2tUcmFjZSwgU3RyaW5nQnVpbGRlciwgVGhyZWFkfSBmcm9tIFwiQG1hZ2ljLXhwYS9tc2NvcmVsaWJcIjtcclxuaW1wb3J0IHtPU0Vudmlyb25tZW50fSBmcm9tIFwiLi9QbGF0Zm9ybVV0aWxzXCI7XHJcbmltcG9ydCB7RGF0ZVRpbWVVdGlsc30gZnJvbSBcIi4vRGF0ZVRpbWVVdGlsc1wiO1xyXG5pbXBvcnQge1hNTENvbnN0YW50c30gZnJvbSBcIi4vWE1MQ29uc3RhbnRzXCI7XHJcbmltcG9ydCAqIGFzIEpTU3RhY2tUcmFjZSBmcm9tICdzdGFja3RyYWNlLWpzJztcclxuaW1wb3J0IHtpc051bGxPclVuZGVmaW5lZH0gZnJvbSBcInV0aWxcIjtcclxuaW1wb3J0IEpTU3RhY2tGcmFtZSA9IEpTU3RhY2tUcmFjZS5TdGFja0ZyYW1lO1xyXG5cclxuZXhwb3J0IGVudW0gTG9nVHlwZSB7XHJcbiAgaW5mbyA9IDEsXHJcbiAgd2FybmluZyxcclxuICBlcnJvclxyXG59XHJcblxyXG5cclxuLy8vIDxzdW1tYXJ5PlxyXG4vLy8gTG9nZ2VyIGNsYXNzIHdpbGwgdGFrZSBjYXJlIG9mIGNsaWVudCBzaWRlIGxvZ2dpbmcgLiBJdCB3aWxsIGNoZWNrIGZvciB2YXJpb3VzIGxvZyBsZXZlbHMgYW5kIGFjY29yZGluZ2x5IHdpbGwgd3JpdGUgbWVzc2FnZXMgaW4gbG9nIGZpbGUuXHJcbi8vLyA8L3N1bW1hcnk+XHJcbi8vQGR5bmFtaWNcclxuZXhwb3J0IGNsYXNzIExvZ2dlciB7XHJcbiAgc3RhdGljIGluc3RhbmNlOiBMb2dnZXIgPSBudWxsO1xyXG4gIExvZ0xldmVsOiBMb2dnZXJfTG9nTGV2ZWxzID0gMDsgLy8gSW50ZXJuYWxMb2dMZXZlbFxyXG5cclxuICAvLy8gPHN1bW1hcnk+XHJcbiAgLy8vIFdoaWxlIHdyaXRpbmcgdGhlIGVycm9yIG1lc3NhZ2VzIGluIHRoZSBmaWxlIHBsYXkgdGhlIGJlZXAuXHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICBTaG91bGRCZWVwOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIHN0YXRpYyBzZXQgSW5zdGFuY2UodmFsdWU6IExvZ2dlcikge1xyXG4gICAgTG9nZ2VyLmluc3RhbmNlID0gdmFsdWU7XHJcbiAgfVxyXG5cclxuICBzdGF0aWMgZ2V0IEluc3RhbmNlKCk6IExvZ2dlciB7XHJcbiAgICBpZiAoTG9nZ2VyLmluc3RhbmNlID09PSBudWxsKSB7XHJcbiAgICAgIExvZ2dlci5pbnN0YW5jZSA9IG5ldyBMb2dnZXIoKTtcclxuICAgIH1cclxuICAgIHJldHVybiBMb2dnZXIuaW5zdGFuY2U7XHJcbiAgfVxyXG5cclxuLy8vIDxzdW1tYXJ5PlxyXG4gIC8vLyBJbml0aWFsaXplIGxvZ2dlclxyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibG9nTGV2ZWxcIj48L3BhcmFtPlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cImludGVybmFsTG9nU3luY1wiPjwvcGFyYW0+XHJcbiAgSW5pdGlhbGl6ZShsb2dMZXZlbDogTG9nZ2VyX0xvZ0xldmVscywgaW50ZXJuYWxMb2dTeW5jOiBzdHJpbmcsIHNob3VsZEJlZXA6IGJvb2xlYW4pOiB2b2lkIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIGxldCBsb2dTeW5jOiBMb2dTeW5jTW9kZSAgPSBMb2dTeW5jTW9kZS5TZXNzaW9uO1xyXG4gICAgICB0aGlzLkxvZ0xldmVsID0gbG9nTGV2ZWw7XHJcbiAgICAgIHRoaXMuU2hvdWxkQmVlcCA9IHNob3VsZEJlZXA7XHJcblxyXG4gICAgICAvLyBUT0RPOiBpbXBsZW1lbnRcclxuLy8gICBTdHJpbmcgc3RyTG9nU3luYyA9IGludGVybmFsTG9nU3luYztcclxuLy8gICBpZiAoIXN0cmluZy5Jc051bGxPckVtcHR5KHN0ckxvZ1N5bmMpKVxyXG4vLyB7XHJcbi8vICAgaWYgKHN0ckxvZ1N5bmMuU3RhcnRzV2l0aChcIk1cIiwgU3RyaW5nQ29tcGFyaXNvbi5DdXJyZW50Q3VsdHVyZUlnbm9yZUNhc2UpKVxyXG4vLyAgIGxvZ1N5bmMgPSBMb2dTeW5jTW9kZS5NZXNzYWdlO1xyXG4vLyAgIGVsc2UgaWYgKHN0ckxvZ1N5bmMuU3RhcnRzV2l0aChcIkZcIiwgU3RyaW5nQ29tcGFyaXNvbi5DdXJyZW50Q3VsdHVyZUlnbm9yZUNhc2UpKVxyXG4vLyAgIGxvZ1N5bmMgPSBMb2dTeW5jTW9kZS5GbHVzaDtcclxuLy8gfVxyXG4vL1xyXG4gICAgfVxyXG4gICAgY2F0Y2ggKGUpIHtcclxuICAgICAgdGhpcy5Xcml0ZURldlRvTG9nKFwiQ2xpZW50TWFuYWdlci5pbml0KCk6IFwiICsgZS5NZXNzYWdlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT48L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibG9nTGV2ZWxcIj48L3BhcmFtPlxyXG4gIC8vLyA8cmV0dXJucz48L3JldHVybnM+XHJcblxyXG4gIFNob3VsZExvZyhsb2dMZXZlbDogTG9nZ2VyX0xvZ0xldmVscyk6IGJvb2xlYW47XHJcbiAgU2hvdWxkTG9nKCk6IGJvb2xlYW47XHJcbiAgU2hvdWxkTG9nKGxvZ0xldmVsPzogTG9nZ2VyX0xvZ0xldmVscyk6IGJvb2xlYW4ge1xyXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDEpXHJcbiAgICAgIHJldHVybiB0aGlzLlNob3VsZExvZ18wKGxvZ0xldmVsKTtcclxuICAgIGVsc2VcclxuICAgICAgcmV0dXJuIHRoaXMuU2hvdWxkTG9nXzEoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgU2hvdWxkTG9nXzAobG9nTGV2ZWw6IExvZ2dlcl9Mb2dMZXZlbHMpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLkxvZ0xldmVsID09PSBsb2dMZXZlbDtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgU2hvdWxkTG9nXzEoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5Mb2dMZXZlbCA+IExvZ2dlcl9Mb2dMZXZlbHMuTm9uZTtcclxuICB9XHJcblxyXG4gIFNob3VsZExvZ1NlcnZlclJlbGF0ZWRNZXNzYWdlcygpOiBib29sZWFuIHtcclxuICAgIHJldHVybiAodGhpcy5TaG91bGRMb2dFeHRlbmRlZFNlcnZlclJlbGF0ZWRNZXNzYWdlcygpIHx8IExvZ2dlci5JbnN0YW5jZS5TaG91bGRMb2coTG9nZ2VyX0xvZ0xldmVscy5TZXJ2ZXIpKSAmJiB0aGlzLkxvZ0xldmVsICE9PSBMb2dnZXJfTG9nTGV2ZWxzLkJhc2ljO1xyXG4gIH1cclxuXHJcbiAgU2hvdWxkTG9nRXh0ZW5kZWRTZXJ2ZXJSZWxhdGVkTWVzc2FnZXMoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gKExvZ2dlci5JbnN0YW5jZS5TaG91bGRMb2coTG9nZ2VyX0xvZ0xldmVscy5TZXJ2ZXJNZXNzYWdlcykgfHwgTG9nZ2VyLkluc3RhbmNlLlNob3VsZExvZyhMb2dnZXJfTG9nTGV2ZWxzLlN1cHBvcnQpIHx8IExvZ2dlci5JbnN0YW5jZS5TaG91bGRMb2coTG9nZ2VyX0xvZ0xldmVscy5EZXZlbG9wbWVudCkpICYmIHRoaXMuTG9nTGV2ZWwgIT09IExvZ2dlcl9Mb2dMZXZlbHMuQmFzaWM7XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+PC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cIm1zZ1wiPjwvcGFyYW0+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwib3BlbklmTmVjZXNzYXJ5XCI+b3BlbiB0aGUgbG9nIGZpbGUgaWYgbm90IG9wZW5lZCB5ZXQ8L3BhcmFtPlxyXG5cclxuICBXcml0ZVRvTG9nKG1zZzogc3RyaW5nLCBvcGVuSWZOZWNlc3Nhcnk6IGJvb2xlYW4sIGxvZ1R5cGU6IExvZ1R5cGUgPSBMb2dUeXBlLmluZm8pOiB2b2lkIHtcclxuXHJcbiAgICBpZiAodGhpcy5Mb2dMZXZlbCA+IExvZ2dlcl9Mb2dMZXZlbHMuTm9uZSB8fCBvcGVuSWZOZWNlc3NhcnkpIHtcclxuICAgICAgbXNnID0gTlN0cmluZy5Gb3JtYXQoXCJ7MH0gezF9XCIsICh0aGlzLkxvZ0xldmVsID09PSBMb2dnZXJfTG9nTGV2ZWxzLkJhc2ljKSA/IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSA6IERhdGVUaW1lVXRpbHMuVG9TdHJpbmcoRGF0ZVRpbWUuTm93LCBYTUxDb25zdGFudHMuRVJST1JfTE9HX1RJTUVfRk9STUFULCB0aGlzKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgbXNnKTtcclxuXHJcbiAgICAgIHN3aXRjaCAobG9nVHlwZSkge1xyXG4gICAgICAgIGNhc2UgTG9nVHlwZS5lcnJvcjpcclxuICAgICAgICAgIGNvbnNvbGUuZXJyb3IobXNnKTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIGNhc2UgTG9nVHlwZS53YXJuaW5nOlxyXG4gICAgICAgICAgY29uc29sZS53YXJuKG1zZyk7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgY29uc29sZS5sb2cobXNnKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5PlxyXG4gIC8vLyB3cml0ZSBhIHNlcnZlciBhY2Nlc3MgdG8gdGhlIGxvZ1xyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibXNnXCI+dGhlIG1lc3NhZ2UgdG8gd3JpdGUgdG8gdGhlIGxvZzwvcGFyYW0+XHJcbiAgV3JpdGVTZXJ2ZXJUb0xvZyhtc2c6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuU2hvdWxkTG9nU2VydmVyUmVsYXRlZE1lc3NhZ2VzKCkpIHtcclxuICAgICAgdGhpcy5Xcml0ZVRvTG9nKE5TdHJpbmcuRm9ybWF0KFwiU2VydmVyLCBUaHJlYWQ9ezB9OiBcIiwgVGhyZWFkLkN1cnJlbnRUaHJlYWQuTWFuYWdlZFRocmVhZElkKSArIG1zZywgZmFsc2UsIExvZ1R5cGUuaW5mbyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+XHJcbiAgLy8vIHdyaXRlIGEgc2VydmVyIGFjY2VzcyB0byB0aGUgbG9nLCBpbmNsdWRpbmcgdGhlIGNvbnRlbnRcclxuICAvLy8gPC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cIm1zZ1wiPnRoZSBtZXNzYWdlIHRvIHdyaXRlIHRvIHRoZSBsb2c8L3BhcmFtPlxyXG4gIFdyaXRlU2VydmVyTWVzc2FnZXNUb0xvZyhtc2c6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuU2hvdWxkTG9nRXh0ZW5kZWRTZXJ2ZXJSZWxhdGVkTWVzc2FnZXMoKSkge1xyXG4gICAgICB0aGlzLldyaXRlVG9Mb2coXCJTZXJ2ZXIjOiBcIiArIG1zZywgZmFsc2UsIExvZ1R5cGUuaW5mbyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+V3JpdGUgYSBRQyBtZXNzYWdlIHRvIHRoZSBsb2c8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibXNnXCI+dGhlIG1lc3NhZ2UgdG8gd3JpdGUgdG8gdGhlIGxvZzwvcGFyYW0+XHJcbiAgV3JpdGVTdXBwb3J0VG9Mb2cobXNnOiBzdHJpbmcsIHNraXBMaW5lOiBib29sZWFuKTogdm9pZCB7XHJcblxyXG4gICAgaWYgKHRoaXMuTG9nTGV2ZWwgPj0gTG9nZ2VyX0xvZ0xldmVscy5TdXBwb3J0ICYmIHRoaXMuTG9nTGV2ZWwgIT09IExvZ2dlcl9Mb2dMZXZlbHMuQmFzaWMpIHtcclxuICAgICAgaWYgKHNraXBMaW5lKSB7XHJcbiAgICAgICAgdGhpcy5Xcml0ZVRvTG9nKFwiU1VQUE9SVDogXCIgKyBtc2csIGZhbHNlLCBMb2dUeXBlLmluZm8pO1xyXG4gICAgICB9XHJcbiAgICAgIGVsc2Uge1xyXG4gICAgICAgIHRoaXMuV3JpdGVUb0xvZyhcIlNVUFBPUlQ6IFwiICsgbXNnICsgT1NFbnZpcm9ubWVudC5Fb2xTZXEgKyBcIi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXCIsIGZhbHNlLCBMb2dUeXBlLmluZm8pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+XHJcbiAgLy8vIHdyaXRlIGEgcGVyZm9ybWFuY2UgbWVzc2FnZSB0byB0aGUgbG9nXHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJtc2dcIj50aGUgbWVzc2FnZSB0byB3cml0ZSB0byB0aGUgbG9nPC9wYXJhbT5cclxuICBXcml0ZUd1aVRvTG9nKG1zZzogc3RyaW5nKTogdm9pZCB7XHJcblxyXG4gICAgaWYgKHRoaXMuTG9nTGV2ZWwgPj0gTG9nZ2VyX0xvZ0xldmVscy5HdWkgJiYgdGhpcy5Mb2dMZXZlbCAhPT0gTG9nZ2VyX0xvZ0xldmVscy5CYXNpYykge1xyXG4gICAgICB0aGlzLldyaXRlVG9Mb2cobXNnLCBmYWxzZSwgTG9nVHlwZS5pbmZvKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT5cclxuICAvLy8gd3JpdGUgYSBkZXZlbG9wZXIgbWVzc2FnZSB0byB0aGUgbG9nXHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJtc2dcIj50aGUgbWVzc2FnZSB0byB3cml0ZSB0byB0aGUgbG9nPC9wYXJhbT5cclxuICBXcml0ZURldlRvTG9nKG1zZzogc3RyaW5nKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5Mb2dMZXZlbCA+PSBMb2dnZXJfTG9nTGV2ZWxzLkRldmVsb3BtZW50ICYmIHRoaXMuTG9nTGV2ZWwgIT09IExvZ2dlcl9Mb2dMZXZlbHMuQmFzaWMpIHtcclxuICAgICAgdGhpcy5Xcml0ZVRvTG9nKFwiREVWOiBcIiArIG1zZywgZmFsc2UsIExvZ1R5cGUuaW5mbyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+XHJcbiAgLy8vIFdyaXRlcyBhIGJhc2ljIGxldmVsIGVudHJ5IHRvIGxvZ1xyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibWVzc2FnZURpcmVjdGlvblwiPm1lc3NhZ2UgZGlyZWN0aW9uIHJlbGF0aXZlIHRvIHRoZSBjdXJyZW50IG1vZHVsZSAoUklBIGNsaWVudCkuIENhbiBiZSBlaXRoZXIgTWVzc2FnZUVudGVyaW5nIG9yIE1lc3NhZ2VMZWF2aW5nPC9wYXJhbT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJzdGF0dXNDb2RlXCI+SFRUUCBzdGF0dXMgY29kZTwvcGFyYW0+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwiY29udGVudExlbmd0aFwiPmxlbmd0aCBvZiB0aGUgaHR0cCBtZXNzYWdlPC9wYXJhbT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJodHRwSGVhZGVyc1wiPkhUVFAgaGVhZGVyczwvcGFyYW0+XHJcbiAgV3JpdGVCYXNpY1RvTG9nKG1lc3NhZ2VEaXJlY3Rpb246IExvZ2dlcl9NZXNzYWdlRGlyZWN0aW9uLCBjb250ZXh0SUQ6IHN0cmluZywgc2Vzc2lvbkNvdW50ZXI6IG51bWJlciwgY2xpZW50SUQ6IHN0cmluZywgc2VydmVySUQ6IHN0cmluZywgcmVzcG9uc2VUaW1lOiBudW1iZXIsIHN0YXR1c0NvZGU6IHN0cmluZywgaHR0cEhlYWRlcnM6IHN0cmluZywgY29udGVudExlbmd0aDogbnVtYmVyKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5Mb2dMZXZlbCA9PT0gTG9nZ2VyX0xvZ0xldmVscy5CYXNpYykge1xyXG4gICAgICBsZXQgdGV4dDogc3RyaW5nID0gaHR0cEhlYWRlcnM7XHJcbiAgICAgIHRleHQgPSB0ZXh0LnRyaW0oKTtcclxuICAgICAgdGV4dCA9IE5TdHJpbmcuUmVwbGFjZSh0ZXh0LCBcIlxcclxcblwiLCBcInxcIik7XHJcbiAgICAgIGxldCBhcmdfRTRfMDogc3RyaW5nID0gXCJSSUEsezB9X3sxfSx7Mn0sezN9LHs0fSx7NX0sLSx7Nn0sezd9LHs4fSx7OX0sezEwfSx7MTF9XCI7XHJcbiAgICAgIGxldCBleHByXzNFOiBhbnlbXSA9IG5ldyBBcnJheTxhbnk+KDEyKTtcclxuXHJcbiAgICAgIC8vIFRPRE8gOiBuZWVkIHRvIGNoZWNrIEhvdyB0byBoYW5kbGUgUHJvY2VzcyBjbGFzcy5cclxuICAgICAgLy8gZXhwcl8zRVswXSA9IFByb2Nlc3MuR2V0Q3VycmVudFByb2Nlc3MoKS5JZDtcclxuICAgICAgZXhwcl8zRVsxXSA9IFRocmVhZC5DdXJyZW50VGhyZWFkLk1hbmFnZWRUaHJlYWRJZDtcclxuICAgICAgZXhwcl8zRVsyXSA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcclxuICAgICAgZXhwcl8zRVszXSA9ICgobWVzc2FnZURpcmVjdGlvbiA9PT0gTG9nZ2VyX01lc3NhZ2VEaXJlY3Rpb24uTWVzc2FnZUxlYXZpbmcpID8gXCJNU0dMXCIgOiBcIk1TR0VcIik7XHJcbiAgICAgIGV4cHJfM0VbNF0gPSBjb250ZXh0SUQ7XHJcbiAgICAgIGV4cHJfM0VbNV0gPSBzZXNzaW9uQ291bnRlcjtcclxuICAgICAgZXhwcl8zRVs2XSA9IGNsaWVudElEO1xyXG4gICAgICBleHByXzNFWzddID0gc2VydmVySUQ7XHJcbiAgICAgIGV4cHJfM0VbOF0gPSAoKHJlc3BvbnNlVGltZSAhPT0gMCkgPyByZXNwb25zZVRpbWUudG9TdHJpbmcoKSA6IFwiLVwiKTtcclxuICAgICAgbGV0IGFyZ19EM18xOiBudW1iZXIgPSA5O1xyXG4gICAgICBsZXQgYXJnX0QzXzI6IGFueTtcclxuICAgICAgYXJnX0QzXzIgPSBzdGF0dXNDb2RlO1xyXG4gICAgICBleHByXzNFW2FyZ19EM18xXSA9IGFyZ19EM18yO1xyXG4gICAgICBleHByXzNFWzEwXSA9IHRleHQ7XHJcbiAgICAgIGV4cHJfM0VbMTFdID0gY29udGVudExlbmd0aDtcclxuICAgICAgbGV0IHZhbHVlOiBzdHJpbmcgPSBOU3RyaW5nLkZvcm1hdChhcmdfRTRfMCwgZXhwcl8zRSk7XHJcbiAgICAgIGNvbnNvbGUubG9nKHZhbHVlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT5cclxuICAvLy8gV3JpdGVzIGEgcmVxdWVzdCBleGNlcHRpb24gYmFzaWMgbGV2ZWwgZW50cnkgdG8gbG9nXHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJjb250ZXh0SURcIj48L3BhcmFtPlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cInNlc3Npb25Db3VudGVyXCI+PC9wYXJhbT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJjbGllbnRJRFwiPjwvcGFyYW0+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwic2VydmVySURcIj48L3BhcmFtPlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cImV4XCI+dGhlIGxvZ2dlZCBleGNlcHRpb248L3BhcmFtPlxyXG4gIFdyaXRlQmFzaWNFcnJvclRvTG9nKGNvbnRleHRJRDogc3RyaW5nLCBzZXNzaW9uQ291bnRlcjogbnVtYmVyLCBjbGllbnRJRDogc3RyaW5nLCBzZXJ2ZXJJRDogc3RyaW5nLCBleDogRXhjZXB0aW9uKTogdm9pZCB7XHJcbiAgICBEZWJ1Zy5Bc3NlcnQodGhpcy5Mb2dMZXZlbCA9PT0gTG9nZ2VyX0xvZ0xldmVscy5CYXNpYyk7XHJcblxyXG4gICAgLy8gVE9ETyA6IE5lZWQgdG8gY2hlY2sgaG93IHRvIGhhbmRsZSBQcm9jZXNzXHJcbiAgICAvLyBsZXQgdmFsdWU6IHN0cmluZyA9IE5TdHJpbmcuRm9ybWF0KFwiUklBLHswfV97MX0sezJ9LHszfSx7NH0sezV9LC0sezZ9LHs3fSwtLC0sLSx7OH0gezl9XCIsIFtcclxuICAgIC8vIFByb2Nlc3MuR2V0Q3VycmVudFByb2Nlc3MoKS5JZCwgVGhyZWFkLkN1cnJlbnRUaHJlYWQuTWFuYWdlZFRocmVhZElkLCBEYXRlVGltZS5VdGNOb3cuVG9TdHJpbmcoXCJ5eXl5LU1NLWRkVEhIOm1tOnNzLmZmZmZmZmZaXCIpLCBcIlJFU1wiLCBjb250ZXh0SUQsIHNlc3Npb25Db3VudGVyLCBjbGllbnRJRCwgc2VydmVySUQsIGV4LkdldFR5cGUoKSwgZXguTWVzc2FnZVxyXG4gICAgLy8gXSk7XHJcbiAgICAvLyBOQ29uc29sZS5Xcml0ZUxpbmUodmFsdWUpO1xyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5PlxyXG4gIC8vLyBXcml0ZSBhbiBlcnJvciB0byB0aGUgbG9nXHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJtc2dcIj50aGUgbWVzc2FnZSB0byB3cml0ZSB0byB0aGUgbG9nPC9wYXJhbT5cclxuICBXcml0ZUVycm9yVG9Mb2cobXNnOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIHRoaXMuV3JpdGVUb0xvZyhcIkVSUk9SOiBcIiArIG1zZywgdHJ1ZSwgTG9nVHlwZS5lcnJvcik7XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+XHJcbiAgLy8vIFdyaXRlIGFuIGludGVybmFsIGVycm9yIHRvIHRoZSBsb2cuIEFsc28gcHJpbnRzIHN0YWNrIHRyYWNlIGFsb25nIHdpdGggdGhlIG1lc3NhZ2VcclxuICAvLy8gPC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cIm1zZ1wiPnRoZSBtZXNzYWdlIHRvIHdyaXRlIHRvIHRoZSBsb2c8L3BhcmFtPlxyXG4gIFdyaXRlRXhjZXB0aW9uVG9Mb2coZXg6IEV4Y2VwdGlvbik6IHZvaWQ7XHJcbiAgV3JpdGVFeGNlcHRpb25Ub0xvZyhleDogRXJyb3IpOiB2b2lkO1xyXG4gIFdyaXRlRXhjZXB0aW9uVG9Mb2coZXg6IEV4Y2VwdGlvbiwgbXNnOiBzdHJpbmcpOiB2b2lkO1xyXG4gIFdyaXRlRXhjZXB0aW9uVG9Mb2cobXNnT3JFeDogYW55LCBtc2c/OiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmIChtc2dPckV4IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgdGhpcy5Xcml0ZUV4Y2VwdGlvblRvTG9nXzIobXNnT3JFeCwgbXNnKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDEgJiYgKG1zZ09yRXggIT09IG51bGwgfHwgbXNnT3JFeCBpbnN0YW5jZW9mIEV4Y2VwdGlvbikpIHtcclxuICAgICAgdGhpcy5Xcml0ZUV4Y2VwdGlvblRvTG9nXzEobXNnT3JFeCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLldyaXRlRXhjZXB0aW9uVG9Mb2dfMyhtc2dPckV4LCBtc2cpO1xyXG4gIH1cclxuXHJcbiAgV3Jpd