@magic-xpa/utils
Version:
magic utils package
573 lines (572 loc) • 49.5 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';
var Logger = /** @class */ (function () {
function Logger() {
this.LogLevel = 0;
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>
/**
* @param {?} logLevel
* @param {?} internalLogSync
* @param {?} shouldBeep
* @return {?}
*/
Logger.prototype.Initialize = /**
* @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>
/**
* @param {?} msg
* @param {?} openIfNecessary
* @param {?=} logType
* @return {?}
*/
Logger.prototype.WriteToLog = /**
* @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), 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 {?}
*/
Logger.prototype.WriteServerToLog = /**
* @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>
/**
* @param {?} msg
* @return {?}
*/
Logger.prototype.WriteServerMessagesToLog = /**
* @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>
/**
* @param {?} msg
* @param {?} skipLine
* @return {?}
*/
Logger.prototype.WriteSupportToLog = /**
* @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>
/**
* @param {?} msg
* @return {?}
*/
Logger.prototype.WriteGuiToLog = /**
* @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>
/**
* @param {?} msg
* @return {?}
*/
Logger.prototype.WriteDevToLog = /**
* @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>
/**
* @param {?} messageDirection
* @param {?} contextID
* @param {?} sessionCounter
* @param {?} clientID
* @param {?} serverID
* @param {?} responseTime
* @param {?} statusCode
* @param {?} httpHeaders
* @param {?} contentLength
* @return {?}
*/
Logger.prototype.WriteBasicToLog = /**
* @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>
/**
* @param {?} contextID
* @param {?} sessionCounter
* @param {?} clientID
* @param {?} serverID
* @param {?} ex
* @return {?}
*/
Logger.prototype.WriteBasicErrorToLog = /**
* @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>
/**
* @param {?} msg
* @return {?}
*/
Logger.prototype.WriteErrorToLog = /**
* @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 || msgOrEx instanceof Exception)) {
this.WriteWarningToLog_1(msgOrEx);
return;
}
if (arguments.length === 1 && (msgOrEx !== null || msgOrEx instanceof Error)) {
this.WriteWarningToLog_2(msgOrEx);
}
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>
/**
* @return {?}
*/
Logger.prototype.Flush = /**
* @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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9nZ2VyLmpzIiwic291cmNlUm9vdCI6Im5nOi8vQG1hZ2ljLXhwYS91dGlscy8iLCJzb3VyY2VzIjpbInNyYy9Mb2dnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBQyxnQkFBZ0IsRUFBRSx1QkFBdUIsRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUNsRSxPQUFPLEVBQUMsUUFBUSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFjLGFBQWEsRUFBRSxNQUFNLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQUM1RyxPQUFPLEVBQUMsYUFBYSxFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDOUMsT0FBTyxFQUFDLGFBQWEsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUU1QyxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxNQUFNLENBQUM7OztJQUlyQyxPQUFRO0lBQ1IsVUFBTztJQUNQLFFBQUs7OztnQkFGTCxJQUFJO2dCQUNKLE9BQU87Z0JBQ1AsS0FBSzs7SUErVUw7d0JBclU2QixDQUFDOzBCQUtSLEtBQUs7S0FpVTFCO0lBL1RELHNCQUFXLGtCQUFROzs7O1FBSW5CO1lBQ0UsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVEsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUM3QixNQUFNLENBQUMsUUFBUSxHQUFHLElBQUksTUFBTSxFQUFFLENBQUM7YUFDaEM7WUFDRCxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQztTQUN4Qjs7Ozs7UUFURCxVQUFvQixLQUFhO1lBQy9CLE1BQU0sQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFDO1NBQ3pCOzs7T0FBQTtJQVNILGFBQWE7SUFDWCxxQkFBcUI7SUFDckIsY0FBYztJQUNkLG1DQUFtQztJQUNuQywwQ0FBMEM7Ozs7Ozs7SUFDMUMsMkJBQVU7Ozs7OztJQUFWLFVBQVcsUUFBMEIsRUFB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LENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7O1lBQ3BELElBQUksVUFBVSxHQUFpQixLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDeEMsYUFBYSxHQUFHLGFBQWEsR0FBRyxDQUFDLENBQUM7WUFFbEMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztZQUU1QyxFQUFFLENBQUMsQ0FBQyxhQUFhLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDeEIsYUFBYSxDQUFDLE1BQU0sQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO2dCQUN0RCxLQUFLLENBQUM7YUFDUDtTQUNGO1FBQ0QsSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsUUFBUSxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7S0FDakQ7SUFFRCxhQUFhO0lBQ2IseUJBQXlCO0lBQ3pCLGNBQWM7Ozs7SUFDZCxzQkFBSzs7O0lBQUw7S0FFQztzQkFwVXlCLElBQUk7aUJBckJoQzs7U0FvQmEsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7TG9nZ2VyX0xvZ0xldmVscywgTG9nZ2VyX01lc3NhZ2VEaXJlY3Rpb259IGZyb20gXCIuL2VudW1zXCI7XHJcbmltcG9ydCB7RGF0ZVRpbWUsIERlYnVnLCBFeGNlcHRpb24sIE5TdHJpbmcsIFN0YWNrVHJhY2UsIFN0cmluZ0J1aWxkZXIsIFRocmVhZH0gZnJvbSBcIkBtYWdpYy14cGEvbXNjb3JlbGliXCI7XHJcbmltcG9ydCB7T1NFbnZpcm9ubWVudH0gZnJvbSBcIi4vUGxhdGZvcm1VdGlsc1wiO1xyXG5pbXBvcnQge0RhdGVUaW1lVXRpbHN9IGZyb20gXCIuL0RhdGVUaW1lVXRpbHNcIjtcclxuaW1wb3J0IHtYTUxDb25zdGFudHN9IGZyb20gXCIuL1hNTENvbnN0YW50c1wiO1xyXG5pbXBvcnQgKiBhcyBKU1N0YWNrVHJhY2UgZnJvbSAnc3RhY2t0cmFjZS1qcyc7XHJcbmltcG9ydCB7aXNOdWxsT3JVbmRlZmluZWR9IGZyb20gXCJ1dGlsXCI7XHJcbmltcG9ydCBKU1N0YWNrRnJhbWUgPSBKU1N0YWNrVHJhY2UuU3RhY2tGcmFtZTtcclxuXHJcbmV4cG9ydCBlbnVtIExvZ1R5cGUge1xyXG4gIGluZm8gPSAxLFxyXG4gIHdhcm5pbmcsXHJcbiAgZXJyb3JcclxufVxyXG5cclxuXHJcbi8vLyA8c3VtbWFyeT5cclxuLy8vIExvZ2dlciBjbGFzcyB3aWxsIHRha2UgY2FyZSBvZiBjbGllbnQgc2lkZSBsb2dnaW5nIC4gSXQgd2lsbCBjaGVjayBmb3IgdmFyaW91cyBsb2cgbGV2ZWxzIGFuZCBhY2NvcmRpbmdseSB3aWxsIHdyaXRlIG1lc3NhZ2VzIGluIGxvZyBmaWxlLlxyXG4vLy8gPC9zdW1tYXJ5PlxyXG4vL0BkeW5hbWljXHJcbmV4cG9ydCBjbGFzcyBMb2dnZXIge1xyXG4gIHN0YXRpYyBpbnN0YW5jZTogTG9nZ2VyID0gbnVsbDtcclxuICBMb2dMZXZlbDogTG9nZ2VyX0xvZ0xldmVscyA9IDA7IC8vIEludGVybmFsTG9nTGV2ZWxcclxuXHJcbiAgLy8vIDxzdW1tYXJ5PlxyXG4gIC8vLyBXaGlsZSB3cml0aW5nIHRoZSBlcnJvciBtZXNzYWdlcyBpbiB0aGUgZmlsZSBwbGF5IHRoZSBiZWVwLlxyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgU2hvdWxkQmVlcDogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICBzdGF0aWMgc2V0IEluc3RhbmNlKHZhbHVlOiBMb2dnZXIpIHtcclxuICAgIExvZ2dlci5pbnN0YW5jZSA9IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgc3RhdGljIGdldCBJbnN0YW5jZSgpOiBMb2dnZXIge1xyXG4gICAgaWYgKExvZ2dlci5pbnN0YW5jZSA9PT0gbnVsbCkge1xyXG4gICAgICBMb2dnZXIuaW5zdGFuY2UgPSBuZXcgTG9nZ2VyKCk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gTG9nZ2VyLmluc3RhbmNlO1xyXG4gIH1cclxuXHJcbi8vLyA8c3VtbWFyeT5cclxuICAvLy8gSW5pdGlhbGl6ZSBsb2dnZXJcclxuICAvLy8gPC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cImxvZ0xldmVsXCI+PC9wYXJhbT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJpbnRlcm5hbExvZ1N5bmNcIj48L3BhcmFtPlxyXG4gIEluaXRpYWxpemUobG9nTGV2ZWw6IExvZ2dlcl9Mb2dMZXZlbHMsIGludGVybmFsTG9nU3luYzogc3RyaW5nLCBzaG91bGRCZWVwOiBib29sZWFuKTogdm9pZCB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBsZXQgbG9nU3luYzogTG9nU3luY01vZGUgID0gTG9nU3luY01vZGUuU2Vzc2lvbjtcclxuICAgICAgdGhpcy5Mb2dMZXZlbCA9IGxvZ0xldmVsO1xyXG4gICAgICB0aGlzLlNob3VsZEJlZXAgPSBzaG91bGRCZWVwO1xyXG5cclxuICAgICAgLy8gVE9ETzogaW1wbGVtZW50XHJcbi8vICAgU3RyaW5nIHN0ckxvZ1N5bmMgPSBpbnRlcm5hbExvZ1N5bmM7XHJcbi8vICAgaWYgKCFzdHJpbmcuSXNOdWxsT3JFbXB0eShzdHJMb2dTeW5jKSlcclxuLy8ge1xyXG4vLyAgIGlmIChzdHJMb2dTeW5jLlN0YXJ0c1dpdGgoXCJNXCIsIFN0cmluZ0NvbXBhcmlzb24uQ3VycmVudEN1bHR1cmVJZ25vcmVDYXNlKSlcclxuLy8gICBsb2dTeW5jID0gTG9nU3luY01vZGUuTWVzc2FnZTtcclxuLy8gICBlbHNlIGlmIChzdHJMb2dTeW5jLlN0YXJ0c1dpdGgoXCJGXCIsIFN0cmluZ0NvbXBhcmlzb24uQ3VycmVudEN1bHR1cmVJZ25vcmVDYXNlKSlcclxuLy8gICBsb2dTeW5jID0gTG9nU3luY01vZGUuRmx1c2g7XHJcbi8vIH1cclxuLy9cclxuICAgIH1cclxuICAgIGNhdGNoIChlKSB7XHJcbiAgICAgIHRoaXMuV3JpdGVEZXZUb0xvZyhcIkNsaWVudE1hbmFnZXIuaW5pdCgpOiBcIiArIGUuTWVzc2FnZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+PC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cImxvZ0xldmVsXCI+PC9wYXJhbT5cclxuICAvLy8gPHJldHVybnM+PC9yZXR1cm5zPlxyXG5cclxuICBTaG91bGRMb2cobG9nTGV2ZWw6IExvZ2dlcl9Mb2dMZXZlbHMpOiBib29sZWFuO1xyXG4gIFNob3VsZExvZygpOiBib29sZWFuO1xyXG4gIFNob3VsZExvZyhsb2dMZXZlbD86IExvZ2dlcl9Mb2dMZXZlbHMpOiBib29sZWFuIHtcclxuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAxKVxyXG4gICAgICByZXR1cm4gdGhpcy5TaG91bGRMb2dfMChsb2dMZXZlbCk7XHJcbiAgICBlbHNlXHJcbiAgICAgIHJldHVybiB0aGlzLlNob3VsZExvZ18xKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIFNob3VsZExvZ18wKGxvZ0xldmVsOiBMb2dnZXJfTG9nTGV2ZWxzKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5Mb2dMZXZlbCA9PT0gbG9nTGV2ZWw7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIFNob3VsZExvZ18xKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuTG9nTGV2ZWwgPiBMb2dnZXJfTG9nTGV2ZWxzLk5vbmU7XHJcbiAgfVxyXG5cclxuICBTaG91bGRMb2dTZXJ2ZXJSZWxhdGVkTWVzc2FnZXMoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gKHRoaXMuU2hvdWxkTG9nRXh0ZW5kZWRTZXJ2ZXJSZWxhdGVkTWVzc2FnZXMoKSB8fCBMb2dnZXIuSW5zdGFuY2UuU2hvdWxkTG9nKExvZ2dlcl9Mb2dMZXZlbHMuU2VydmVyKSkgJiYgdGhpcy5Mb2dMZXZlbCAhPT0gTG9nZ2VyX0xvZ0xldmVscy5CYXNpYztcclxuICB9XHJcblxyXG4gIFNob3VsZExvZ0V4dGVuZGVkU2VydmVyUmVsYXRlZE1lc3NhZ2VzKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIChMb2dnZXIuSW5zdGFuY2UuU2hvdWxkTG9nKExvZ2dlcl9Mb2dMZXZlbHMuU2VydmVyTWVzc2FnZXMpIHx8IExvZ2dlci5JbnN0YW5jZS5TaG91bGRMb2coTG9nZ2VyX0xvZ0xldmVscy5TdXBwb3J0KSB8fCBMb2dnZXIuSW5zdGFuY2UuU2hvdWxkTG9nKExvZ2dlcl9Mb2dMZXZlbHMuRGV2ZWxvcG1lbnQpKSAmJiB0aGlzLkxvZ0xldmVsICE9PSBMb2dnZXJfTG9nTGV2ZWxzLkJhc2ljO1xyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5Pjwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJtc2dcIj48L3BhcmFtPlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cIm9wZW5JZk5lY2Vzc2FyeVwiPm9wZW4gdGhlIGxvZyBmaWxlIGlmIG5vdCBvcGVuZWQgeWV0PC9wYXJhbT5cclxuXHJcbiAgV3JpdGVUb0xvZyhtc2c6IHN0cmluZywgb3BlbklmTmVjZXNzYXJ5OiBib29sZWFuLCBsb2dUeXBlOiBMb2dUeXBlID0gTG9nVHlwZS5pbmZvKTogdm9pZCB7XHJcblxyXG4gICAgaWYgKHRoaXMuTG9nTGV2ZWwgPiBMb2dnZXJfTG9nTGV2ZWxzLk5vbmUgfHwgb3BlbklmTmVjZXNzYXJ5KSB7XHJcbiAgICAgIG1zZyA9IE5TdHJpbmcuRm9ybWF0KFwiezB9IHsxfVwiLCAodGhpcy5Mb2dMZXZlbCA9PT0gTG9nZ2VyX0xvZ0xldmVscy5CYXNpYykgPyBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkgOiBEYXRlVGltZVV0aWxzLlRvU3RyaW5nKERhdGVUaW1lLk5vdywgWE1MQ29uc3RhbnRzLkVSUk9SX0xPR19USU1FX0ZPUk1BVCksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1zZyk7XHJcblxyXG4gICAgICBzd2l0Y2ggKGxvZ1R5cGUpIHtcclxuICAgICAgICBjYXNlIExvZ1R5cGUuZXJyb3I6XHJcbiAgICAgICAgICBjb25zb2xlLmVycm9yKG1zZyk7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICBjYXNlIExvZ1R5cGUud2FybmluZzpcclxuICAgICAgICAgIGNvbnNvbGUud2Fybihtc2cpO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgIGNvbnNvbGUubG9nKG1zZyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT5cclxuICAvLy8gd3JpdGUgYSBzZXJ2ZXIgYWNjZXNzIHRvIHRoZSBsb2dcclxuICAvLy8gPC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cIm1zZ1wiPnRoZSBtZXNzYWdlIHRvIHdyaXRlIHRvIHRoZSBsb2c8L3BhcmFtPlxyXG4gIFdyaXRlU2VydmVyVG9Mb2cobXNnOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLlNob3VsZExvZ1NlcnZlclJlbGF0ZWRNZXNzYWdlcygpKSB7XHJcbiAgICAgIHRoaXMuV3JpdGVUb0xvZyhOU3RyaW5nLkZvcm1hdChcIlNlcnZlciwgVGhyZWFkPXswfTogXCIsIFRocmVhZC5DdXJyZW50VGhyZWFkLk1hbmFnZWRUaHJlYWRJZCkgKyBtc2csIGZhbHNlLCBMb2dUeXBlLmluZm8pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5PlxyXG4gIC8vLyB3cml0ZSBhIHNlcnZlciBhY2Nlc3MgdG8gdGhlIGxvZywgaW5jbHVkaW5nIHRoZSBjb250ZW50XHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJtc2dcIj50aGUgbWVzc2FnZSB0byB3cml0ZSB0byB0aGUgbG9nPC9wYXJhbT5cclxuICBXcml0ZVNlcnZlck1lc3NhZ2VzVG9Mb2cobXNnOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLlNob3VsZExvZ0V4dGVuZGVkU2VydmVyUmVsYXRlZE1lc3NhZ2VzKCkpIHtcclxuICAgICAgdGhpcy5Xcml0ZVRvTG9nKFwiU2VydmVyIzogXCIgKyBtc2csIGZhbHNlLCBMb2dUeXBlLmluZm8pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5PldyaXRlIGEgUUMgbWVzc2FnZSB0byB0aGUgbG9nPC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cIm1zZ1wiPnRoZSBtZXNzYWdlIHRvIHdyaXRlIHRvIHRoZSBsb2c8L3BhcmFtPlxyXG4gIFdyaXRlU3VwcG9ydFRvTG9nKG1zZzogc3RyaW5nLCBza2lwTGluZTogYm9vbGVhbik6IHZvaWQge1xyXG5cclxuICAgIGlmICh0aGlzLkxvZ0xldmVsID49IExvZ2dlcl9Mb2dMZXZlbHMuU3VwcG9ydCAmJiB0aGlzLkxvZ0xldmVsICE9PSBMb2dnZXJfTG9nTGV2ZWxzLkJhc2ljKSB7XHJcbiAgICAgIGlmIChza2lwTGluZSkge1xyXG4gICAgICAgIHRoaXMuV3JpdGVUb0xvZyhcIlNVUFBPUlQ6IFwiICsgbXNnLCBmYWxzZSwgTG9nVHlwZS5pbmZvKTtcclxuICAgICAgfVxyXG4gICAgICBlbHNlIHtcclxuICAgICAgICB0aGlzLldyaXRlVG9Mb2coXCJTVVBQT1JUOiBcIiArIG1zZyArIE9TRW52aXJvbm1lbnQuRW9sU2VxICsgXCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiLCBmYWxzZSwgTG9nVHlwZS5pbmZvKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5PlxyXG4gIC8vLyB3cml0ZSBhIHBlcmZvcm1hbmNlIG1lc3NhZ2UgdG8gdGhlIGxvZ1xyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibXNnXCI+dGhlIG1lc3NhZ2UgdG8gd3JpdGUgdG8gdGhlIGxvZzwvcGFyYW0+XHJcbiAgV3JpdGVHdWlUb0xvZyhtc2c6IHN0cmluZyk6IHZvaWQge1xyXG5cclxuICAgIGlmICh0aGlzLkxvZ0xldmVsID49IExvZ2dlcl9Mb2dMZXZlbHMuR3VpICYmIHRoaXMuTG9nTGV2ZWwgIT09IExvZ2dlcl9Mb2dMZXZlbHMuQmFzaWMpIHtcclxuICAgICAgdGhpcy5Xcml0ZVRvTG9nKG1zZywgZmFsc2UsIExvZ1R5cGUuaW5mbyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+XHJcbiAgLy8vIHdyaXRlIGEgZGV2ZWxvcGVyIG1lc3NhZ2UgdG8gdGhlIGxvZ1xyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibXNnXCI+dGhlIG1lc3NhZ2UgdG8gd3JpdGUgdG8gdGhlIGxvZzwvcGFyYW0+XHJcbiAgV3JpdGVEZXZUb0xvZyhtc2c6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuTG9nTGV2ZWwgPj0gTG9nZ2VyX0xvZ0xldmVscy5EZXZlbG9wbWVudCAmJiB0aGlzLkxvZ0xldmVsICE9PSBMb2dnZXJfTG9nTGV2ZWxzLkJhc2ljKSB7XHJcbiAgICAgIHRoaXMuV3JpdGVUb0xvZyhcIkRFVjogXCIgKyBtc2csIGZhbHNlLCBMb2dUeXBlLmluZm8pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5PlxyXG4gIC8vLyBXcml0ZXMgYSBiYXNpYyBsZXZlbCBlbnRyeSB0byBsb2dcclxuICAvLy8gPC9zdW1tYXJ5PlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cIm1lc3NhZ2VEaXJlY3Rpb25cIj5tZXNzYWdlIGRpcmVjdGlvbiByZWxhdGl2ZSB0byB0aGUgY3VycmVudCBtb2R1bGUgKFJJQSBjbGllbnQpLiBDYW4gYmUgZWl0aGVyIE1lc3NhZ2VFbnRlcmluZyBvciBNZXNzYWdlTGVhdmluZzwvcGFyYW0+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwic3RhdHVzQ29kZVwiPkhUVFAgc3RhdHVzIGNvZGU8L3BhcmFtPlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cImNvbnRlbnRMZW5ndGhcIj5sZW5ndGggb2YgdGhlIGh0dHAgbWVzc2FnZTwvcGFyYW0+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwiaHR0cEhlYWRlcnNcIj5IVFRQIGhlYWRlcnM8L3BhcmFtPlxyXG4gIFdyaXRlQmFzaWNUb0xvZyhtZXNzYWdlRGlyZWN0aW9uOiBMb2dnZXJfTWVzc2FnZURpcmVjdGlvbiwgY29udGV4dElEOiBzdHJpbmcsIHNlc3Npb25Db3VudGVyOiBudW1iZXIsIGNsaWVudElEOiBzdHJpbmcsIHNlcnZlcklEOiBzdHJpbmcsIHJlc3BvbnNlVGltZTogbnVtYmVyLCBzdGF0dXNDb2RlOiBzdHJpbmcsIGh0dHBIZWFkZXJzOiBzdHJpbmcsIGNvbnRlbnRMZW5ndGg6IG51bWJlcik6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuTG9nTGV2ZWwgPT09IExvZ2dlcl9Mb2dMZXZlbHMuQmFzaWMpIHtcclxuICAgICAgbGV0IHRleHQ6IHN0cmluZyA9IGh0dHBIZWFkZXJzO1xyXG4gICAgICB0ZXh0ID0gdGV4dC50cmltKCk7XHJcbiAgICAgIHRleHQgPSBOU3RyaW5nLlJlcGxhY2UodGV4dCwgXCJcXHJcXG5cIiwgXCJ8XCIpO1xyXG4gICAgICBsZXQgYXJnX0U0XzA6IHN0cmluZyA9IFwiUklBLHswfV97MX0sezJ9LHszfSx7NH0sezV9LC0sezZ9LHs3fSx7OH0sezl9LHsxMH0sezExfVwiO1xyXG4gICAgICBsZXQgZXhwcl8zRTogYW55W10gPSBuZXcgQXJyYXk8YW55PigxMik7XHJcblxyXG4gICAgICAvLyBUT0RPIDogbmVlZCB0byBjaGVjayBIb3cgdG8gaGFuZGxlIFByb2Nlc3MgY2xhc3MuXHJcbiAgICAgIC8vIGV4cHJfM0VbMF0gPSBQcm9jZXNzLkdldEN1cnJlbnRQcm9jZXNzKCkuSWQ7XHJcbiAgICAgIGV4cHJfM0VbMV0gPSBUaHJlYWQuQ3VycmVudFRocmVhZC5NYW5hZ2VkVGhyZWFkSWQ7XHJcbiAgICAgIGV4cHJfM0VbMl0gPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XHJcbiAgICAgIGV4cHJfM0VbM10gPSAoKG1lc3NhZ2VEaXJlY3Rpb24gPT09IExvZ2dlcl9NZXNzYWdlRGlyZWN0aW9uLk1lc3NhZ2VMZWF2aW5nKSA/IFwiTVNHTFwiIDogXCJNU0dFXCIpO1xyXG4gICAgICBleHByXzNFWzRdID0gY29udGV4dElEO1xyXG4gICAgICBleHByXzNFWzVdID0gc2Vzc2lvbkNvdW50ZXI7XHJcbiAgICAgIGV4cHJfM0VbNl0gPSBjbGllbnRJRDtcclxuICAgICAgZXhwcl8zRVs3XSA9IHNlcnZlcklEO1xyXG4gICAgICBleHByXzNFWzhdID0gKChyZXNwb25zZVRpbWUgIT09IDApID8gcmVzcG9uc2VUaW1lLnRvU3RyaW5nKCkgOiBcIi1cIik7XHJcbiAgICAgIGxldCBhcmdfRDNfMTogbnVtYmVyID0gOTtcclxuICAgICAgbGV0IGFyZ19EM18yOiBhbnk7XHJcbiAgICAgIGFyZ19EM18yID0gc3RhdHVzQ29kZTtcclxuICAgICAgZXhwcl8zRVthcmdfRDNfMV0gPSBhcmdfRDNfMjtcclxuICAgICAgZXhwcl8zRVsxMF0gPSB0ZXh0O1xyXG4gICAgICBleHByXzNFWzExXSA9IGNvbnRlbnRMZW5ndGg7XHJcbiAgICAgIGxldCB2YWx1ZTogc3RyaW5nID0gTlN0cmluZy5Gb3JtYXQoYXJnX0U0XzAsIGV4cHJfM0UpO1xyXG4gICAgICBjb25zb2xlLmxvZyh2YWx1ZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLy8gPHN1bW1hcnk+XHJcbiAgLy8vIFdyaXRlcyBhIHJlcXVlc3QgZXhjZXB0aW9uIGJhc2ljIGxldmVsIGVudHJ5IHRvIGxvZ1xyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwiY29udGV4dElEXCI+PC9wYXJhbT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJzZXNzaW9uQ291bnRlclwiPjwvcGFyYW0+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwiY2xpZW50SURcIj48L3BhcmFtPlxyXG4gIC8vLyA8cGFyYW0gbmFtZT1cInNlcnZlcklEXCI+PC9wYXJhbT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJleFwiPnRoZSBsb2dnZWQgZXhjZXB0aW9uPC9wYXJhbT5cclxuICBXcml0ZUJhc2ljRXJyb3JUb0xvZyhjb250ZXh0SUQ6IHN0cmluZywgc2Vzc2lvbkNvdW50ZXI6IG51bWJlciwgY2xpZW50SUQ6IHN0cmluZywgc2VydmVySUQ6IHN0cmluZywgZXg6IEV4Y2VwdGlvbik6IHZvaWQge1xyXG4gICAgRGVidWcuQXNzZXJ0KHRoaXMuTG9nTGV2ZWwgPT09IExvZ2dlcl9Mb2dMZXZlbHMuQmFzaWMpO1xyXG5cclxuICAgIC8vIFRPRE8gOiBOZWVkIHRvIGNoZWNrIGhvdyB0byBoYW5kbGUgUHJvY2Vzc1xyXG4gICAgLy8gbGV0IHZhbHVlOiBzdHJpbmcgPSBOU3RyaW5nLkZvcm1hdChcIlJJQSx7MH1fezF9LHsyfSx7M30sezR9LHs1fSwtLHs2fSx7N30sLSwtLC0sezh9IHs5fVwiLCBbXHJcbiAgICAvLyBQcm9jZXNzLkdldEN1cnJlbnRQcm9jZXNzKCkuSWQsIFRocmVhZC5DdXJyZW50VGhyZWFkLk1hbmFnZWRUaHJlYWRJZCwgRGF0ZVRpbWUuVXRjTm93LlRvU3RyaW5nKFwieXl5eS1NTS1kZFRISDptbTpzcy5mZmZmZmZmWlwiKSwgXCJSRVNcIiwgY29udGV4dElELCBzZXNzaW9uQ291bnRlciwgY2xpZW50SUQsIHNlcnZlcklELCBleC5HZXRUeXBlKCksIGV4Lk1lc3NhZ2VcclxuICAgIC8vIF0pO1xyXG4gICAgLy8gTkNvbnNvbGUuV3JpdGVMaW5lKHZhbHVlKTtcclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT5cclxuICAvLy8gV3JpdGUgYW4gZXJyb3IgdG8gdGhlIGxvZ1xyXG4gIC8vLyA8L3N1bW1hcnk+XHJcbiAgLy8vIDxwYXJhbSBuYW1lPVwibXNnXCI+dGhlIG1lc3NhZ2UgdG8gd3JpdGUgdG8gdGhlIGxvZzwvcGFyYW0+XHJcbiAgV3JpdGVFcnJvclRvTG9nKG1zZzogc3RyaW5nKTogdm9pZCB7XHJcbiAgICB0aGlzLldyaXRlVG9Mb2coXCJFUlJPUjogXCIgKyBtc2csIHRydWUsIExvZ1R5cGUuZXJyb3IpO1xyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5PlxyXG4gIC8vLyBXcml0ZSBhbiBpbnRlcm5hbCBlcnJvciB0byB0aGUgbG9nLiBBbHNvIHByaW50cyBzdGFjayB0cmFjZSBhbG9uZyB3aXRoIHRoZSBtZXNzYWdlXHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJtc2dcIj50aGUgbWVzc2FnZSB0byB3cml0ZSB0byB0aGUgbG9nPC9wYXJhbT5cclxuICBXcml0ZUV4Y2VwdGlvblRvTG9nKGV4OiBFeGNlcHRpb24pOiB2b2lkO1xyXG4gIFdyaXRlRXhjZXB0aW9uVG9Mb2coZXg6IEVycm9yKTogdm9pZDtcclxuICBXcml0ZUV4Y2VwdGlvblRvTG9nKGV4OiBFeGNlcHRpb24sIG1zZzogc3RyaW5nKTogdm9pZDtcclxuICBXcml0ZUV4Y2VwdGlvblRvTG9nKG1zZ09yRXg6IGFueSwgbXNnPzogc3RyaW5nKTogdm9pZCB7XHJcbiAgICBpZiAobXNnT3JFeCBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgIHRoaXMuV3JpdGVFeGNlcHRpb25Ub0xvZ18yKG1zZ09yRXgsIG1zZyk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAxICYmIChtc2dPckV4ICE9PSBudWxsIHx8IG1zZ09yRXggaW5zdGFuY2VvZiBFeGNlcHRpb24pKSB7XHJcbiAgICAgIHRoaXMuV3JpdGVFeGNlcHRpb25Ub0xvZ18xKG1zZ09yRXgpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5Xcml0ZUV4Y2VwdGlvblRvTG9nXzMobXNnT3JFeCwgbXNnKTtcclxuICB9XHJcblxyXG4gIFdyaXRlRXhjZXB0aW9uVG9Mb2dXaXRoTXNnKG1zZzogc3RyaW5nKTogdm9pZCB7XHJcbiAgICB0aGlzLldyaXRlVG9Mb2coXCJFUlJPUjogXCIgKyBtc2csIHRydWUsIExvZ1R5cGUuZXJyb3IpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBXcml0ZUV4Y2VwdGlvblRvTG9nXzEoZXg6IEV4Y2VwdGlvbik6IHZvaWQge1xyXG4gICAgdGhpcy5Xcml0ZUV4Y2VwdGlvblRvTG9nV2l0aE1zZyhOU3RyaW5nLkZvcm1hdChcInswfSA6IHsxfXsyfXszfXs0fVwiLCBbXHJcbiAgICAgIGV4LkdldFR5cGUoKSwgT1NFbnZpcm9ubWVudC5Fb2xTZXEsIGV4LlN0YWNrVHJhY2UsIE9TRW52aXJvbm1lbnQuRW9sU2VxLCBleC5NZXNzYWdlXHJcbiAgICBdKSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIFdyaXRlRXhjZXB0aW9uVG9Mb2dfMihleDogRXJyb3IsIG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKGlzTnVsbE9yVW5kZWZpbmVkKG1lc3NhZ2UpKVxyXG4gICAgICB0aGlzLldyaXRlRXhjZXB0aW9uVG9Mb2dXaXRoTXNnKE5TdHJpbmcuRm9ybWF0KFwiezB9ezF9ezJ9XCIsIFtleC5zdGFjaywgT1NFbnZpcm9ubWVudC5Fb2xTZXEsIGV4Lm1lc3NhZ2VdKSk7XHJcbiAgICBlbHNlXHJcbiAgICAgIHRoaXMuV3JpdGVFeGNlcHRpb25Ub0xvZ1dpdGhNc2coTlN0cmluZy5Gb3JtYXQoXCJ7MH17MX17Mn17NH17NX1cIiwgW21lc3NhZ2UsIE9TRW52aXJvbm1lbnQuRW9sU2VxLCBleC5zdGFjaywgT1NFbnZpcm9ubWVudC5Fb2xTZXEsIGV4Lm1lc3NhZ2VdKSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIFdyaXRlRXhjZXB0aW9uVG9Mb2dfMyhleDogRXhjZXB0aW9uLCBtc2c6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5Xcml0ZUV4Y2VwdGlvblRvTG9nV2l0aE1zZyhOU3RyaW5nLkZvcm1hdChcInswfSwgezF9IDogezJ9ezN9ezR9ezV9XCIsIFtcclxuICAgICAgZXguR2V0VHlwZSgpLCBtc2csIE9TRW52aXJvbm1lbnQuRW9sU2VxLCBleC5TdGFja1RyYWNlLCBPU0Vudmlyb25tZW50LkVvbFNlcSwgZXguTWVzc2FnZVxyXG4gICAgXSkpO1xyXG4gIH1cclxuXHJcbiAgLy8vIDxzdW1tYXJ5PiB3cml0ZSBhIHdhcm5pbmcgdG8gdGhlIGxvZzwvc3VtbWFyeT5cclxuICAvLy8gPHBhcmFtIG5hbWU9XCJtc2dcIj50aGUgbWVzc2FnZSB0byB3cml0ZSB0byB0aGUgbG9nPC9wYXJhbT5cclxuICBXcml0ZVdhcm5pbmdUb0xvZyhleDogRXhjZXB0aW9uKTogdm9pZDtcclxuICBXcml0ZVdhcm5pbmdUb0xvZyhleDogRXhjZXB0aW9uLCBtc2c6IHN0cmluZyk6IHZvaWQ7XHJcbiAgV3JpdGVXYXJuaW5nVG9Mb2coZXg6IEVycm9yKTogdm9pZDtcclxuICBXcml0ZVdhcm5pbmdUb0xvZyhtc2dPckV4OiBhbnksIG1zZz86IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDEgJiYgKG1zZ09yRXggIT09IG51bGwgfHwgbXNnT3JFeCBpbnN0YW5jZW9mIEV4Y2VwdGlvbikpIHtcclxuICAgICAgdGhpcy5Xcml0ZVdhcm5pbmdUb0xvZ18xKG1zZ09yRXgpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSAmJiAobXNnT3JFeCAhPT0gbnVsbCB8fCBtc2dPckV4IGluc3RhbmNlb2YgRXJyb3IpKSB7XHJcbiAgICAgIHRoaXMuV3JpdGVXYXJuaW5nVG9Mb2dfMihtc2dPckV4KTtcclxuICAgIH1cclxuICAgIHRoaXMuV3JpdGVXYXJuaW5nVG9Mb2dfMyhtc2dPckV4LCBtc2cpO1xyXG4gIH1cclxuXHJcbiAgV3JpdGVXYXJuaW5nVG9Mb2dXaXRoTXNnKG1zZzogc3RyaW5nKTogdm9pZCB7XHJcblxyXG4gICAgaWYgKHRoaXMuTG9nTGV2ZWwgIT09IExvZ2dlcl9Mb2dMZXZlbHMuQmFzaWMpIHtcclxuICAgICAgdGhpcy5Xcml0ZVRvTG9nKFwiV0FSTklORzogXCIgKyBtc2csIHRydWUsIExvZ1R5cGUud2FybmluZyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIFdyaXRlV2FybmluZ1RvTG9nXzEoZXg6IEV4Y2VwdGlvbik6IHZvaWQge1xyXG4gICAgdGhpcy5Xcml0ZVdhcm5pbmdUb0xvZ1dpdGhNc2coZXguR2V0VHlwZSgpICsgXCIgOiBcIiArIE9TRW52aXJvbm1lbnQuRW9sU2VxICsgZXguU3RhY2tUcmFjZSArIE9TRW52aXJvbm1lbnQuRW9sU2VxICsgZXguTWVzc2FnZSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIFdyaXRlV2FybmluZ1RvTG9nXzIoZXg6IEVycm9yKTogdm9pZCB7XHJcbiAgICB0aGlzLldyaXRlV2FybmluZ1RvTG9nV2l0aE1zZyhOU3RyaW5nLkZvcm1hdChcInswfXsxfXsyfVwiLCBbXHJcbiAgICAgIGV4LnN0YWNrLCBPU0Vudmlyb25tZW50LkVvbFNlcSwgZXgubWVzc2FnZVxyXG4gICAgXSkpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBXcml0ZVdhcm5pbmdUb0xvZ18zKGV4OiBFeGNlcHRpb24sIG1zZzogc3RyaW5nKTogdm9pZCB7XHJcbiAgICB0aGlzLldyaXRlV2FybmluZ1RvTG9nV2l0aE1zZyhOU3RyaW5nLkZvcm1hdChcInswfSwgezF9IDogezJ9ezN9ezR9ezV9XCIsIFtcclxuICAgICAgZXguR2V0VHlwZSgpLCBtc2csIE9TRW52aXJvbm1lbnQuRW9sU2VxLCBleC5TdGFja1RyYWNlLCBPU0Vudmlyb25tZW50LkVvbFNlcSwgZXguTWVzc2FnZVxyXG4gICAgXSkpO1xyXG4gIH1cclxuXHJcbiAgV3JpdGVTdGFja1RyYWNlKHN0YWNrVHJhY2U6IFN0YWNrVHJhY2UsIGZyYW1lc1RvUHJpbnQ6IG51bWJlciwgdHJhY2VUaXRsZTogc3RyaW5nKTogdm9pZCB7XHJcblxyXG4gICAgaWYgKHRyYWNlVGl0bGUgPT09IG51bGwpIHtcclxuICAgICAgdHJhY2VUaXRsZSA9IFwiU3RhY2sgdHJhY2U6XCI7XHJcbiAgICB9XHJcbiAgICBsZXQgc3RyaW5nQnVpbGRlcjogU3RyaW5nQnVpbGRlciA9IG5ldyBTdHJpbmdCdWlsZGVyKHRyYWNlVGl0bGUgKyBPU0Vudmlyb25tZW50LkVvbFNlcSk7XHJcbiAgICBsZXQgZnJhbWVzOiBKU1N0YWNrRnJhbWVbXSA9IHN0YWNrVHJhY2UuR2V0RnJhbWVzKCk7XHJcbiAgICBsZXQgYXJyYXk6IEpTU3RhY2tGcmFtZVtdID0gZnJhbWVzO1xyXG4gICAgZm9yIChsZXQgaTogbnVtYmVyID0gMDsgaSA8IGFycmF5Lmxlbmd0aDsgaSA9IGkgKyAxKSB7XHJcbiAgICAgIGxldCBzdGFja0ZyYW1lOiBKU1N0YWNrRnJhbWUgPSBhcnJheVtpXTtcclxuICAgICAgZnJhbWVzVG9QcmludCA9IGZyYW1lc1RvUHJpbnQgLSAxO1xyXG5cclxuICAgICAgc3RyaW5nQnVpbGRlci5BcHBlbmQoc3RhY2tGcmFtZS50b1N0cmluZygpKTtcclxuXHJcbiAgICAgIGlmIChmcmFtZXNUb1ByaW50ID09PSAwKSB7XHJcbiAgICAgICAgc3RyaW5nQnVpbGRlci5BcHBlbmQoXCJcXHQuLi4gbW9yZSBzdGFjayBmcmFtZXMgLi4uXFxuXCIpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICB0aGlzLldyaXRlVG9Mb2coc3RyaW5nQnVpbGRlci5Ub1N0cmluZygpLCB0cnVlKTtcclxuICB9XHJcblxyXG4gIC8vLyA8c3VtbWFyeT5cclxuICAvLy8gRmx1c2ggdGhlIGxvZyB3cml0ZXIuXHJcbiAgLy8vIDwvc3VtbWFyeT5cclxuICBGbHVzaCgpOiB2b2lkIHtcclxuXHJcbiAgfVxyXG5cclxuICBjb25zdHJ1Y3RvcigpIHtcclxuICB9XHJcbn1cclxuIl19