performance-monitor-logger
Version:
## Instalação
1,439 lines • 214 kB
JavaScript
/**
* 📊 SISTEMA DE LOGS DE PERFORMANCE
*
* Sistema completo de monitoramento de performance para aplicações Angular
* com feedback visual através de emojis e relatórios automáticos.
*
* Características:
* - 📈 Monitoramento em Tempo Real
* - 🟢🟡🔴 Classificação Visual por Performance
* - ⏰ Relatórios Automáticos após Inatividade
* - 📊 Análise Detalhada com Recomendações
* - 🛠️ API Pública para Controle Manual
*
* @author Pedro Henrique dos Santos Leuchs
* @version 1.0.23
* @since 2025-07-11
*/
import { __awaiter } from "tslib";
export class LogsPerformatico {
constructor(serviceName = 'Service') {
this.monitoramentoAtivo = true; // Começa ativo na primeira vez
// 📊 Propriedades do Sistema
this.performanceTimers = new Map();
this.performanceSummary = new Map();
this.httpRequests = new Map();
// 🆕 Stack para contexto de função monitorada
this.functionContextStack = [];
this.eventContextStack = [];
this.timerStack = [];
// 🆕 Estado de atividade para fechamento inteligente de contexto de UI
this.lastTimerActivityAt = null;
this.firstTimerInEventAt = null;
this.currentEventBeginAt = null;
// 🔒 Controle de funções já instrumentadas
this.instrumentedFns = new WeakMap();
this.serviceName = serviceName;
}
/**
* Registra requisição HTTP associando à função monitorada ativa (se houver)
* @param payload Dados da requisição
*/
registerHttpRequest(authReq, tempo, error = false) {
var _a, _b;
// Nome robusto da operação HTTP
let nome = '(desconhecido)';
try {
const byBodyName = (_a = authReq === null || authReq === void 0 ? void 0 : authReq.body) === null || _a === void 0 ? void 0 : _a.name;
const bySql = this.extrairNomeDeSQL((_b = authReq === null || authReq === void 0 ? void 0 : authReq.body) === null || _b === void 0 ? void 0 : _b.sqlInstruction);
const method = (authReq === null || authReq === void 0 ? void 0 : authReq.method) || 'HTTP';
const url = authReq === null || authReq === void 0 ? void 0 : authReq.url;
// Usa nome planejado (body/sql), senão fallback para método + último segmento da URL
if (byBodyName) {
nome = byBodyName;
}
else if (bySql) {
nome = bySql;
}
else if (url) {
const cleanUrl = String(url).split('?')[0];
const segs = cleanUrl.split('/').filter(Boolean);
const tail = segs[segs.length - 1] || cleanUrl;
nome = `${method} ${tail}`;
}
else {
nome = method;
}
}
catch (_c) { }
const currentEvent = this.eventContextStack.length
? this.eventContextStack[this.eventContextStack.length - 1]
: undefined;
const key = currentEvent ? `${currentEvent} | ${nome}` : nome;
const atual = this.httpRequests.get(key) || {
tempoTotal: 0,
execucoes: 0,
errors: 0,
};
atual.tempoTotal += Number.isFinite(tempo) ? tempo : 0;
atual.execucoes += 1;
if (error)
atual.errors += 1;
this.httpRequests.set(key, atual);
}
// Função auxiliar para extrair nome da função de um SQL, ex: PACK_PARMGEN.CONSULTA_PARAMETRO(...)
extrairNomeDeSQL(sql) {
if (!sql)
return null;
const match = sql.match(/([A-Z0-9_]+\.[A-Z0-9_]+)/i);
return match ? match[1] : null;
}
/**
* 🚀 Mensagem de boas-vindas do sistema
*/
showWelcomeMessage() {
console.log(`%cSISTEMA DE MONITORAMENTO DE PERFORMANCE`, 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;');
}
/**
* ⏱️ Inicia cronômetro para uma operação
* @param operationName Nome da operação a ser monitorada
*/
startTimer(operationName) {
if (!this.monitoramentoAtivo)
return;
// Se for a primeira operação, abre borda visual
if (this.performanceTimers.size === 0 &&
this.performanceSummary.size === 0) {
const border = '═'.repeat(56);
console.log(`%cINÍCIO DO MONITORAMENTO DE PERFORMANCE`, 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;');
}
this.performanceTimers.set(operationName, Date.now());
// Empilha contexto de função monitorada
this.functionContextStack.push(operationName);
// Adiciona contexto ao stack para medir tempo exclusivo
const currentEvent = this.eventContextStack.length
? this.eventContextStack[0] // usa rótulo raiz do fluxo do usuário
: undefined;
// Se a operação vier como pack.metodo, usamos pack como evento e metodo como nome
const parts = String(operationName).split('.');
let displayEvent;
let displayName;
if (parts.length >= 2) {
displayEvent = parts[0];
displayName = parts[parts.length - 1];
}
else {
// Sem prefixo (pack) no nome — exibe apenas o método
displayEvent = undefined;
displayName = operationName;
}
const fullName = displayEvent
? `${displayEvent} | ${displayName}`
: displayName;
// Registra atividade de timer para controle de janela do evento
const nowStart = Date.now();
if (currentEvent && this.firstTimerInEventAt === null) {
this.firstTimerInEventAt = nowStart;
}
this.lastTimerActivityAt = nowStart;
this.timerStack.push({
name: operationName,
start: nowStart,
childElapsed: 0,
event: currentEvent,
fullName,
});
console.log(`║ [INÍCIO] ${fullName} - ${new Date().toLocaleTimeString()}`);
}
/**
* 🏁 Finaliza cronômetro e exibe resultado com emoji
* @param operationName Nome da operação
* @param customMessage Mensagem customizada opcional (ex: para erros)
* @param customThresholds Thresholds customizados para esta operação específica
*/
endTimer(operationName, customMessage, customThresholds) {
var _a, _b, _c, _d, _e, _f;
if (!this.monitoramentoAtivo)
return;
// Usa pilha de contexto para calcular tempo exclusivo (exclui filhos)
const now = Date.now();
let ctx = this.timerStack.length
? this.timerStack[this.timerStack.length - 1]
: undefined;
if (!ctx || ctx.name !== operationName) {
// Busca robusta caso encerramento fora de ordem
let foundIndex = -1;
for (let i = this.timerStack.length - 1; i >= 0; i--) {
if (this.timerStack[i].name === operationName) {
foundIndex = i;
break;
}
}
if (foundIndex === -1) {
console.warn(`⚠️ Timer não encontrado para: ${operationName}`);
return;
}
ctx = this.timerStack[foundIndex];
this.timerStack.splice(foundIndex, 1);
}
else {
this.timerStack.pop();
}
// Atualiza atividade de timers (para lógica de fechamento por silêncio)
this.lastTimerActivityAt = now;
const inclusiveElapsed = now - ctx.start;
const exclusiveElapsed = Math.max(0, inclusiveElapsed - ctx.childElapsed);
// Propaga tempo do filho para o pai (para excluir na contagem do pai)
const parent = this.timerStack[this.timerStack.length - 1];
if (parent) {
parent.childElapsed += inclusiveElapsed;
}
// Remove referência antiga baseada em Map (mantida para compatibilidade)
this.performanceTimers.delete(operationName);
// Desempilha contexto de função monitorada (somente se topo)
if (this.functionContextStack[this.functionContextStack.length - 1] ===
operationName) {
this.functionContextStack.pop();
}
// Determina status baseado no tempo exclusivo
const { emoji, status, color } = this.getPerformanceStatus(exclusiveElapsed, customThresholds, (_a = ctx.fullName) !== null && _a !== void 0 ? _a : (ctx.event ? `${ctx.event} | ${operationName}` : operationName));
// Log com emoji e cor (com mensagem customizada se fornecida)
const message = customMessage
? `${(_b = ctx.fullName) !== null && _b !== void 0 ? _b : (ctx.event ? `${ctx.event} | ${operationName}` : operationName)} - ${customMessage}`
: `${(_c = ctx.fullName) !== null && _c !== void 0 ? _c : (ctx.event ? `${ctx.event} | ${operationName}` : operationName)}`;
const fixedStatus = `[${status}]`.padEnd(5);
const fixedMessage = message.padEnd(10);
const fixedTime = exclusiveElapsed.toString().padStart(5);
console.log(`║ %c${emoji} ${fixedStatus} ${fixedMessage} - ${fixedTime}ms `, color);
// Mostra thresholds customizados se estiverem sendo usados
if (customThresholds &&
(customThresholds.ok ||
customThresholds.lento ||
customThresholds.critico)) {
console.log(`⚙️ Thresholds customizados: OK<${(_d = customThresholds.ok) !== null && _d !== void 0 ? _d : 500}ms, LENTO<${(_e = customThresholds.lento) !== null && _e !== void 0 ? _e : 2000}ms`);
}
// Atualiza sumário com tempo exclusivo
this.updatePerformanceSummary((_f = ctx.fullName) !== null && _f !== void 0 ? _f : (ctx.event ? `${ctx.event} | ${operationName}` : operationName), exclusiveElapsed, customThresholds);
}
/**
* 🎨 Determina status de performance baseado no tempo
* @param elapsedTime Tempo decorrido em milissegundos
* @param customThresholds Thresholds customizados para esta operação específica
* @param operationName Nome da operação (para calcular thresholds dinâmicos)
* @returns Objeto com emoji, status e cor
*/
getPerformanceStatus(elapsedTime, customThresholds, operationName) {
var _a, _b, _c;
let okThreshold;
let lentoThreshold;
let criticoThreshold;
if (customThresholds &&
(customThresholds.ok ||
customThresholds.lento ||
customThresholds.critico)) {
// Usa thresholds customizados se fornecidos
okThreshold = (_a = customThresholds.ok) !== null && _a !== void 0 ? _a : 500;
lentoThreshold = (_b = customThresholds.lento) !== null && _b !== void 0 ? _b : 2000;
criticoThreshold = (_c = customThresholds.critico) !== null && _c !== void 0 ? _c : Number.MAX_SAFE_INTEGER;
}
else if (operationName) {
// Calcula thresholds dinâmicos baseados na quantidade de execuções
const stats = this.performanceSummary.get(operationName);
// Corrige: soma +1 para considerar a execução atual
const executionCount = stats ? stats.count + 1 : 1;
const dynamicThresholds = this.calculateDynamicThresholds(executionCount);
okThreshold = dynamicThresholds.ok;
lentoThreshold = dynamicThresholds.lento;
criticoThreshold = dynamicThresholds.critico;
}
else {
// Usa thresholds padrões
okThreshold = 500;
lentoThreshold = 2000;
criticoThreshold = Number.MAX_SAFE_INTEGER;
}
if (elapsedTime < okThreshold) {
return {
emoji: '🟢',
status: 'OK',
color: 'color: green; font-weight: bold;',
};
}
else if (elapsedTime < lentoThreshold) {
return {
emoji: '🟡',
status: 'LENTO',
color: 'color: orange; font-weight: bold;',
};
}
else {
return {
emoji: '🔴',
status: 'CRÍTICO',
color: 'color: red; font-weight: bold;',
};
}
}
/**
* 📈 Atualiza estatísticas de performance para o sumário
* @param operationName Nome da operação
* @param elapsedTime Tempo decorrido em milissegundos
* @param customThresholds Thresholds customizados para armazenar (opcional)
*/
updatePerformanceSummary(operationName, elapsedTime, customThresholds) {
const existing = this.performanceSummary.get(operationName);
if (existing) {
existing.count++;
existing.totalTime += elapsedTime;
existing.minTime = Math.min(existing.minTime, elapsedTime);
existing.maxTime = Math.max(existing.maxTime, elapsedTime);
// Atualiza thresholds customizados se fornecidos
if (customThresholds &&
(customThresholds.ok ||
customThresholds.lento ||
customThresholds.critico)) {
existing.customThresholds = customThresholds;
}
}
else {
this.performanceSummary.set(operationName, {
count: 1,
totalTime: elapsedTime,
minTime: elapsedTime,
maxTime: elapsedTime,
customThresholds: customThresholds,
});
}
// Não faz mais nada aqui, relatório só manual
}
/**
* 📊 Exibe relatório resumido de todas as operações (compactado)
*/
showPerformanceSummary(showFullDetails = false) {
// Fecha borda do monitoramento ao gerar relatório
console.log('%c RELATÓRIO DE PERFORMANCE', 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;');
if (this.performanceSummary.size === 0) {
console.log('%c Nenhuma operação monitorada ainda.', 'color: gray; font-style: italic;');
return;
}
const sortedEntries = Array.from(this.performanceSummary.entries()).sort((a, b) => b[1].maxTime - a[1].maxTime);
const table = Object.fromEntries(sortedEntries.map(([operation, stats]) => {
const avgTime = Math.round(stats.totalTime / stats.count);
const { emoji, status } = this.getPerformanceStatus(avgTime, stats.customThresholds, operation);
return [
operation,
{
Execuções: stats.count,
'Média(ms)': `${avgTime}ms (${status}) ${emoji}`.trim(),
'Mínimo(ms)': stats.minTime,
'Máximo(ms)': stats.maxTime,
'Total(ms)': stats.totalTime,
},
];
}));
console.table(table);
// Removido: agora a análise detalhada é chamada apenas pelo botão
}
/**
* 📑 Exibe relatório detalhado de requisições HTTP agrupadas por função
*/
showHttpRequestsReport() {
console.log(`%cRELATÓRIO DETALHADO DE REQUISIÇÕES HTTP`, 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;');
if (this.httpRequests.size === 0) {
console.log('Nenhuma requisição HTTP registrada.');
return;
}
const tabela = Object.fromEntries(Array.from(this.httpRequests.entries())
.sort((a, b) => b[1].tempoTotal - a[1].tempoTotal)
.map(([nome, dados]) => [
nome,
{
Execuções: dados.execucoes,
Média: `${Math.round(dados.tempoTotal / dados.execucoes)}ms`,
'Tempo Total': `${Math.round(dados.tempoTotal)}ms`,
Erros: dados.errors,
},
]));
console.table(tabela);
}
/**
* 🔍 Gera análise detalhada de performance
*/
generateDetailedAnalysis() {
// Título discreto
console.log('%cANÁLISE DETALHADA DE PERFORMANCE', 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;');
console.log('');
if (this.performanceSummary.size === 0) {
console.log('%cNenhuma operação registrada para análise.', 'color: #bbb; font-style: italic; font-size: 14px; padding: 4px 0 4px 10px;');
return;
}
const { criticalOperations, slowOperations, fastOperations } = this.categorizeOperations();
// Helper para bloco discreto com texto claro
const printBlock = (color, emoji, operation, avg, extra) => {
const style = `border-left: 4px solid ${color}; padding: 2px 0 2px 10px; margin: 2px 0 2px 0; font-size: 14px; color: #fff; background: none; font-weight: normal;`;
console.log(`%c${emoji} ${operation} - ${avg}ms (média) ${extra}`.trim(), style);
};
if (criticalOperations.length > 0) {
console.log('%c🔴 CRÍTICAS ( > 2000ms)', 'color: #fff; font-size: 14px; font-weight: bold; margin-top: 10px;');
criticalOperations.forEach(([operation, stats]) => {
const avg = Math.round(stats.totalTime / stats.count);
const { emoji } = this.getPerformanceStatus(avg, stats.customThresholds, operation);
printBlock('#c53030', emoji, operation, avg, '| otimizar urgente');
});
}
if (slowOperations.length > 0) {
console.log('%c🟡 LENTAS (500ms - 2000ms)', 'color: #fff; font-size: 14px; font-weight: bold; margin-top: 10px;');
slowOperations.forEach(([operation, stats]) => {
const avg = Math.round(stats.totalTime / stats.count);
const { emoji } = this.getPerformanceStatus(avg, stats.customThresholds, operation);
printBlock('#b7791f', emoji, operation, avg, '| pode ser melhorada');
});
}
if (fastOperations.length > 0) {
console.log('%c🟢 RÁPIDAS ( < 500ms)', 'color: #fff; font-size: 14px; font-weight: bold; margin-top: 10px;');
fastOperations.forEach(([operation, stats]) => {
const avg = Math.round(stats.totalTime / stats.count);
const { emoji } = this.getPerformanceStatus(avg, stats.customThresholds, operation);
printBlock('#38a169', emoji, operation, avg, '| excelente');
});
}
// Recomendações
console.log('%cRecomendações:', 'color: #fff; font-size: 13px; font-weight: bold; margin-top: 14px; padding: 2px 0 2px 0;');
if (criticalOperations.length > 0) {
console.log('%c• Priorize a otimização das operações críticas.', 'color: #fff; font-size: 13px; font-weight: normal;');
console.log('%c• Considere implementar cache ou otimizar consultas SQL para essas operações.', 'color: #fff; font-size: 13px; font-weight: normal;');
}
if (slowOperations.length > 0) {
console.log('%c• Operações lentas podem se beneficiar de índices no banco de dados.', 'color: #fff; font-size: 13px; font-weight: normal;');
}
if (criticalOperations.length === 0 && slowOperations.length === 0) {
console.log('%c• Todas as operações estão com performance excelente!', 'color: #fff; font-size: 13px; font-weight: normal;');
}
// Score
const totalOperations = this.performanceSummary.size;
const fastCount = fastOperations.length;
const performanceScore = totalOperations > 0
? Math.round((fastCount / totalOperations) * 100)
: 100;
let scoreColor = performanceScore >= 80
? '#38a169'
: performanceScore >= 60
? '#f6e05e'
: '#c53030';
let scoreMsg = performanceScore >= 80
? 'Excelente! A maioria das operações está performando bem.'
: performanceScore >= 60
? 'Médio. Há espaço para melhorias de performance.'
: 'Crítico. Muitas operações precisam de otimização urgente.';
console.log(`%cScore de performance: ${performanceScore}%`, `color: #fff; background: ${scoreColor}; font-size: 14px; font-weight: bold; margin-top: 10px; padding: 2px 8px; border-radius: 3px;`);
console.log(`%c${scoreMsg}`, `color: #fff; font-size: 13px; font-weight: normal; margin-bottom: 8px;`);
console.log('');
}
/**
* 📋 Categoriza operações por performance
* @returns Objeto com arrays de operações categorizadas
*/
categorizeOperations() {
const criticalOperations = Array.from(this.performanceSummary.entries()).filter(([_, stats]) => stats.totalTime / stats.count > 2000);
const slowOperations = Array.from(this.performanceSummary.entries()).filter(([_, stats]) => {
const avg = stats.totalTime / stats.count;
return avg >= 500 && avg <= 2000;
});
const fastOperations = Array.from(this.performanceSummary.entries()).filter(([_, stats]) => stats.totalTime / stats.count < 500);
return { criticalOperations, slowOperations, fastOperations };
}
/**
* 💡 Exibe recomendações baseadas na análise
* @param criticalOperations Array de operações críticas
* @param slowOperations Array de operações lentas
*/
showRecommendations(criticalOperations, slowOperations) {
console.log('RECOMENDAÇÕES:');
if (criticalOperations.length > 0) {
console.log(' Priorize a otimização das operações críticas.');
console.log(' Considere implementar cache ou otimizar consultas SQL para essas operações.');
}
if (slowOperations.length > 0) {
console.log(' Operações lentas podem se beneficiar de índices no banco de dados.');
}
if (criticalOperations.length === 0 && slowOperations.length === 0) {
console.log(' Todas as operações estão com performance excelente!');
}
}
/**
* 📊 Exibe score de performance
* @param fastOperationsCount Número de operações rápidas
*/
showPerformanceScore(fastOperationsCount) {
const totalOperations = this.performanceSummary.size;
const performanceScore = Math.round((fastOperationsCount / totalOperations) * 100);
console.log(`SCORE DE PERFORMANCE: ${performanceScore}%`);
if (performanceScore >= 80) {
console.log('Excelente! A maioria das operações está performando bem.');
}
else if (performanceScore >= 60) {
console.log('Médio. Há espaço para melhorias de performance.');
}
else {
console.log('Crítico. Muitas operações precisam de otimização urgente.');
}
}
// ===== API PÚBLICA =====
/**
* 📊 Método público para exibir relatório de performance
* Pode ser chamado no console do navegador para análise
*/
getPerformanceReport() {
this.showPerformanceSummary();
}
/**
* 🏷️ Controla contexto de evento atual (ex.: AppInit, Click)
*/
beginEventContext(label) {
if (label) {
// Se não há contexto aberto, inicia uma nova janela raiz
if (this.eventContextStack.length === 0) {
this.currentEventBeginAt = Date.now();
this.firstTimerInEventAt = null;
this.lastTimerActivityAt = null;
}
this.eventContextStack.push(label);
}
}
endEventContext() {
if (this.eventContextStack.length > 0) {
this.eventContextStack.pop();
}
}
runInEventContext(label, fn) {
return __awaiter(this, void 0, void 0, function* () {
this.beginEventContext(label);
try {
const result = fn();
return yield Promise.resolve(result);
}
finally {
this.endEventContext();
}
});
}
/**
* 🧹 Método público para limpar dados de performance
* Útil para resetar estatísticas e começar nova análise
*/
resetPerformanceData() {
this.performanceTimers.clear();
this.performanceSummary.clear();
this.httpRequests.clear();
// Mensagem estilizada de limpeza
console.log('%c🧹 [CLEANUP] Dados de performance limpos', 'color: #fff; background: #43248bff; font-size: 13px; font-weight: bold; border-radius: 4px; padding: 4px 12px; margin: 6px 0;');
}
/**
* ⏰ Configura o delay para relatório por inatividade
* @param seconds Número de segundos de inatividade para mostrar relatório
*/
setInactivityDelay(seconds) {
// Desabilitado
console.log('⏰ Relatório por inatividade está desabilitado.');
}
/**
* 🔇 Desabilita relatório automático por inatividade
*/
disableInactivityReport() {
// Desabilitado
console.log('🔇 Relatório por inatividade já está desabilitado');
}
/**
* ⚙️ Configura o threshold para relatório automático
* @param threshold Número de operações para mostrar relatório automaticamente
*/
setAutoReportThreshold(threshold) {
// Desabilitado
console.log('⚙️ Threshold para relatório automático está desabilitado.');
}
/**
* 🔇 Desabilita relatório automático
*/
disableAutoReport() {
// Desabilitado
console.log('🔇 Relatório automático desabilitado');
}
/**
* 📈 Obtém estatísticas resumidas sem exibir no console
* @returns Objeto com estatísticas de performance
*/
getStatistics() {
const { criticalOperations, slowOperations, fastOperations } = this.categorizeOperations();
const totalOperations = this.performanceSummary.size;
let totalTime = 0;
let totalCount = 0;
this.performanceSummary.forEach((stats) => {
totalTime += stats.totalTime;
totalCount += stats.count;
});
const averageTime = totalCount > 0 ? Math.round(totalTime / totalCount) : 0;
const performanceScore = totalOperations > 0
? Math.round((fastOperations.length / totalOperations) * 100)
: 100;
return {
totalOperations,
averageTime,
fastOperations: fastOperations.length,
slowOperations: slowOperations.length,
criticalOperations: criticalOperations.length,
performanceScore,
};
}
/**
* 🎯 Obtém dados de uma operação específica
* @param operationName Nome da operação
* @returns Estatísticas da operação ou null se não encontrada
*/
getOperationStats(operationName) {
const baseStats = this.performanceSummary.get(operationName);
if (!baseStats)
return null;
// Extrai nomes das requisições HTTP como array de strings
const httpRequestEntry = this.httpRequests.get(operationName);
const httpCalls = httpRequestEntry ? [operationName] : [];
return Object.assign(Object.assign({}, baseStats), { httpCalls });
}
/**
* 📋 Lista todas as operações monitoradas
* @returns Array com nomes das operações
*/
getMonitoredOperations() {
return Array.from(this.performanceSummary.keys());
}
/**
* 🔄 Verifica se há timers ativos
* @returns true se há timers em execução
*/
hasActiveTimers() {
return this.timerStack.length > 0;
}
/**
* 🗑️ Limpa apenas os timers ativos (não as estatísticas)
*/
clearActiveTimers() {
this.performanceTimers.clear();
this.timerStack = [];
this.functionContextStack = [];
console.log('%c🗑️ [CLEANUP] Timers ativos limpos', 'color: #fff; background: #23272f; font-size: 13px; font-weight: bold; border-radius: 4px; padding: 4px 12px; margin: 6px 0;');
}
// ===== AUTO‑INSTRUMENTAÇÃO (sem decorators) =====
/**
* 🔌 Instrumenta todas as funções públicas de um objeto/instância sem alterar assinatura
* @param obj Objeto ou instância a instrumentar
* @param options Filtros e ajustes de nome
*/
instrumentObject(obj, options) {
if (!obj || typeof obj !== 'object')
return;
const opt = Object.assign({ preserveToString: true }, options);
const shouldInclude = (name) => {
const inc = opt.include;
const exc = opt.exclude;
const match = (p) => typeof p === 'string' ? name.includes(p) : p.test(name);
const okInc = !inc || inc.some(match);
const okExc = exc ? !exc.some(match) : true;
return okInc && okExc;
};
const instrumentProp = (target, key, path) => {
try {
const value = target[key];
if (typeof value !== 'function')
return;
const original = value;
if (original.__pm_instrumented)
return;
if (!shouldInclude(key))
return;
const opBase = key;
const opName = opt.nameTransform
? opt.nameTransform(opBase, path)
: opBase;
const wrapped = this.createWrapper(original, opName, opt.preserveToString);
// Sombra no objeto (não altera prototype global)
Object.defineProperty(target, key, {
value: wrapped,
writable: true,
configurable: true,
});
}
catch (_a) { }
};
// Instrumenta próprias propriedades
Object.getOwnPropertyNames(obj).forEach((k) => instrumentProp(obj, k, [k]));
// Instrumenta métodos do prototype (sobrescrevendo no instance)
const proto = Object.getPrototypeOf(obj);
if (proto && proto !== Object.prototype) {
Object.getOwnPropertyNames(proto)
.filter((k) => k !== 'constructor')
.forEach((k) => instrumentProp(obj, k, [k]));
}
}
/**
* 🌐 Instrumenta funções em um namespace (ex.: window) com filtros e profundidade
* @param root Objeto raiz (ex.: window)
* @param options include/exclude, nameTransform, preserveToString, maxDepth
*/
instrumentNamespace(root, options) {
if (!root || typeof root !== 'object')
return;
const opt = Object.assign({ preserveToString: true, maxDepth: 2 }, options);
const shouldInclude = (name) => {
const inc = opt.include;
const exc = opt.exclude;
const match = (p) => typeof p === 'string' ? name.includes(p) : p.test(name);
const okInc = !inc || inc.some(match);
const okExc = exc ? !exc.some(match) : true;
return okInc && okExc;
};
const visited = new WeakSet();
const walk = (node, depth, path) => {
if (!node || typeof node !== 'object')
return;
if (visited.has(node))
return;
visited.add(node);
if (depth > (opt.maxDepth || 2))
return;
const keys = [];
try {
keys.push(...Object.getOwnPropertyNames(node));
}
catch (_a) { }
for (const key of keys) {
let value;
try {
value = node[key];
}
catch (_b) {
continue;
}
if (typeof value === 'function') {
const original = value;
if (original.__pm_instrumented)
continue;
if (!shouldInclude(key))
continue;
const opBase = key;
const opName = opt.nameTransform
? opt.nameTransform(opBase, path.concat(key))
: opBase;
const wrapped = this.createWrapper(original, opName, opt.preserveToString);
// Tenta sobrescrever função no namespace
try {
Object.defineProperty(node, key, {
value: wrapped,
writable: true,
configurable: true,
});
}
catch (_c) { }
}
else if (typeof value === 'object' && value) {
// Recurse
walk(value, depth + 1, path.concat(key));
}
}
};
walk(root, 0, []);
}
/**
* 🪝 Envolve a função setService(target.setService) para instrumentar o serviço passado
* @param target Objeto que possui setService(service)
* @param label Rótulo usado no nome das operações (ex.: "packTela")
* @param options Opções de instrumentação (nameTransform, exclude, etc.)
*/
hookSetService(target, label, options) {
var _a;
if (!target || typeof target !== 'object')
return;
const fn = target.setService;
if (typeof fn !== 'function')
return;
const alreadyHooked = fn.__pm_setservice_hooked;
if (alreadyHooked)
return;
const opt = Object.assign({ preserveToString: true, exclude: ['constructor'] }, options);
const labelFinal = label ||
(((_a = target === null || target === void 0 ? void 0 : target.constructor) === null || _a === void 0 ? void 0 : _a.name) ? String(target.constructor.name) : 'service');
// Garante que o label (pack) entre na path[0] quando houver nameTransform customizado
const nameTransform = opt.nameTransform
? (n, path) => opt.nameTransform(n, [labelFinal].concat(path || []))
: (n) => `${labelFinal}.${n}`;
const original = fn;
const logger = this;
const wrapped = function (serviceInstance, ...rest) {
try {
// Instrumenta o próprio objeto alvo (pack), pois são seus métodos que queremos medir
const packObj = this || target;
if (packObj && typeof packObj === 'object') {
const alreadyInstrumentedPack = packObj
.__pm_pack_instrumented;
if (!alreadyInstrumentedPack) {
logger.instrumentObject(packObj, Object.assign(Object.assign({}, opt), { nameTransform }));
try {
Object.defineProperty(packObj, '__pm_pack_instrumented', {
value: true,
configurable: true,
enumerable: false,
writable: false,
});
}
catch (_a) { }
}
}
}
catch (_b) { }
return original.apply(this, [serviceInstance, ...rest]);
};
// marca como hookado para evitar duplicação
wrapped.__pm_setservice_hooked = true;
try {
Object.defineProperty(target, 'setService', {
value: wrapped,
writable: true,
configurable: true,
});
}
catch (_b) { }
// Instrumenta imediatamente o pack (cobre casos onde setService já foi chamado antes do hook)
try {
const packObj = target;
const alreadyInstrumentedPack = packObj.__pm_pack_instrumented;
if (!alreadyInstrumentedPack) {
this.instrumentObject(packObj, Object.assign(Object.assign({}, opt), { nameTransform }));
Object.defineProperty(packObj, '__pm_pack_instrumented', {
value: true,
configurable: true,
enumerable: false,
writable: false,
});
}
}
catch (_c) { }
}
/**
* 🪝 Hook de setService para vários alvos em uma única chamada
* @param targets Mapa de label -> objeto que contém setService
* @param options Opções de instrumentação
*/
hookSetServiceBulk(targets, options) {
if (!targets || typeof targets !== 'object')
return;
for (const [label, obj] of Object.entries(targets)) {
const hasSetService = !!(obj && typeof obj.setService === 'function');
if (hasSetService) {
this.hookSetService(obj, label, options);
}
else if (obj && typeof obj === 'object') {
// Instrumenta objetos sem setService usando o label como prefixo
const opt = Object.assign({}, options);
const nameTransform = opt.nameTransform
? (n, path) => opt.nameTransform(n, [String(label)].concat(path || []))
: (n) => `${String(label)}.${n}`;
this.instrumentObject(obj, Object.assign(Object.assign({}, opt), { nameTransform, exclude: ['constructor', ...(opt.exclude || [])] }));
}
}
}
/**
* 🌐 Varre um namespace e aplica hook em qualquer função setService encontrada
* @param root Objeto raiz (ex.: window, module scope wrapper, etc.)
* @param options Filtros e regras de nomeação
*/
hookSetServiceNamespace(root, options) {
if (!root || typeof root !== 'object')
return;
const opt = Object.assign({ preserveToString: true, exclude: ['constructor'], maxWalkDepth: 2 }, options);
const shouldIncludeObj = (pathStr) => {
const inc = opt.includeObjects;
const exc = opt.excludeObjects;
const match = (p) => typeof p === 'string' ? pathStr.includes(p) : p.test(pathStr);
const okInc = !inc || inc.some(match);
const okExc = exc ? !exc.some(match) : true;
return okInc && okExc;
};
const visited = new WeakSet();
const walk = (node, depth, path) => {
if (!node || typeof node !== 'object')
return;
if (visited.has(node))
return;
visited.add(node);
if (depth > (opt.maxWalkDepth || 2))
return;
const keys = [];
try {
keys.push(...Object.getOwnPropertyNames(node));
}
catch (_a) { }
for (const key of keys) {
let value;
try {
value = node[key];
}
catch (_b) {
continue;
}
const pathNow = path.concat(key);
const pathStr = pathNow.join('.');
if (value && typeof value === 'object') {
// Se o objeto tiver setService, aplica hook
const fn = value.setService;
if (typeof fn === 'function' && shouldIncludeObj(pathStr)) {
const labelFromPath = opt.labelFromPath || ((p) => p.join('.'));
this.hookSetService(value, labelFromPath(pathNow), opt);
}
// Continua a varredura
walk(value, depth + 1, pathNow);
}
}
};
walk(root, 0, []);
}
// ===== Helpers =====
/**
* Cria wrapper que inicia/encerra timer preservando contexto e toString()
*/
createWrapper(original, opName, preserveToString) {
// Idempotência: reutiliza wrapper se já existir
const existing = this.instrumentedFns.get(original);
if (existing)
return existing;
const logger = this;
const wrapped = function (...args) {
// Determina nome final com fallback ao nome do arquivo (pack) via stacktrace
let finalName = opName;
try {
const parts = String(opName).split('.');
const methodName = parts[parts.length - 1];
const prefix = parts.length > 1 ? parts[0] : undefined;
if (!prefix || prefix.toLowerCase() === methodName.toLowerCase()) {
const fileLabel = logger.guessFileLabelFromStack();
if (fileLabel) {
finalName = `${fileLabel}.${methodName}`;
}
}
}
catch (_a) { }
// Herda label do evento ativo (já garantido pelo logger)
logger.startTimer(finalName);
try {
const result = original.apply(this, args);
if (result && typeof result.then === 'function') {
// Promises/async
return result.finally(() => {
logger.endTimer(finalName);
});
}
else {
logger.endTimer(finalName);
return result;
}
}
catch (e) {
logger.endTimer(finalName, 'erro');
throw e;
}
};
// Marca instrumentado
original.__pm_instrumented = true;
wrapped.__pm_instrumented = true;
// Preserva toString() para compatibilidade com regex
if (preserveToString) {
try {
Object.defineProperty(wrapped, 'toString', {
value: function () {
return original.toString();
},
writable: false,
configurable: true,
});
}
catch (_a) { }
}
// Tenta igualar o nome (nem sempre é possível)
try {
Object.defineProperty(wrapped, 'name', {
value: original.name || opName,
configurable: true,
});
}
catch (_b) { }
this.instrumentedFns.set(original, wrapped);
return wrapped;
}
/**
* 🔎 Tenta inferir o nome do arquivo (pack) a partir do stacktrace
* Preferência por nomes que começam com "pack"
*/
guessFileLabelFromStack() {
try {
const err = new Error();
const stack = String(err.stack || '');
const lines = stack.split('\n');
const candidates = [];
for (const line of lines) {
const m = line.match(/[\\\/]([A-Za-z0-9_-]+)\.(?:ts|js)(?::\d+:\d+|\?|$)/);
if (m && m[1]) {
const base = m[1];
if (/^pack/i.test(base)) {
return base;
}
candidates.push(base);
}
}
return candidates[0];
}
catch (_a) {
return undefined;
}
}
/**
* 💾 Exporta dados de performance para JSON
* @returns String JSON com todos os dados
*/
exportData() {
const data = {
timestamp: new Date().toISOString(),
serviceName: this.serviceName,
statistics: this.getStatistics(),
operations: Array.from(this.performanceSummary.entries()).map(([name, stats]) => (Object.assign(Object.assign({ name }, stats), { averageTime: Math.round(stats.totalTime / stats.count) }))),
};
return JSON.stringify(data, null, 2);
}
/**
* 🎯 Calcula thresholds dinâmicos baseados na quantidade de execuções
* @param executionCount Número de execuções da operação
* @returns Objeto com thresholds calculados dinamicamente
*/
calculateDynamicThresholds(executionCount) {
if (executionCount === 1) {
// Primeira execução - expectativas mais relaxadas
return {
ok: 1000,
lento: 2000,
critico: 2000,
};
}
else if (executionCount <= 5) {
// Até 5 execuções - sistema ainda aquecendo
return {
ok: 500,
lento: 1000,
critico: 1000,
};
}
else if (executionCount <= 10) {
// Até 10 execuções - sistema otimizado
return {
ok: 100,
lento: 250,
critico: 250,
};
}
else {
// Acima de 10 execuções - expectativas altas
return {
ok: 20,
lento: 60,
critico: 60,
};
}
}
injectMonitorButton() {
if (document.getElementById('btn-monitorar-performance'))
return;
// ====== ESTILO MODERNO E BOTÃO DE OLHO ======
const BUTTON_COLOR = '#23272f'; // cinza escuro elegante
const BUTTON_TEXT_COLOR = '#f3f4f6';
const BUTTON_RADIUS = '8px';
const BUTTON_FONT_SIZE = '13px';
const BUTTON_PADDING = '10px 5px';
const BUTTON_WIDTH = '210px';
const BUTTON_HEIGHT = '44px';
const BUTTON_BOX_SHADOW = '0 2px 12px #0002';
const BUTTON_BORDER = '1px solid #353a40';
// Container para animação
const container = document.createElement('div');
container.id = 'performance-monitor-container';
Object.assign(container.style, {
position: 'fixed',
bottom: '5px',
left: '50px',
zIndex: '9999',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-end',
transition: 'transform 0.5s cubic-bezier(.4,2,.6,1)',
gap: '10px',
});
// Função para criar botões padronizados
const criarBotao = (id, texto) => {
const btn = document.createElement('button');
btn.id = id;
btn.innerText = texto;
Object.assign(btn.style, {
width: BUTTON_WIDTH,
height: BUTTON_HEIGHT,
background: BUTTON_COLOR,
color: BUTTON_TEXT_COLOR,
borderRadius: BUTTON_RADIUS,
border: BUTTON_BORDER,
padding: BUTTON_PADDING,
fontSize: BUTTON_FONT_SIZE,
fontWeight: '600',
cursor: 'pointer',
boxShadow: BUTTON_BOX_SHADOW,
letterSpacing: '0.01em',
textAlign: 'center',
transition: 'background 0.2s, color 0.2s, transform 0.5s cubic-bezier(.4,2,.6,1)',
});
btn.onmouseenter = () => {
btn.style.background = '#353a40';
btn.style.color = '#fff';
};
btn.onmouseleave = () => {
btn.style.background = BUTTON_COLOR;
btn.style.color = BUTTON_TEXT_COLOR;
};
return btn;
};
// Botões principais
const btnMain = criarBotao('btn-monitorar-performance', 'Parar monitoramento');
const btnFinalizar = criarBotao('btn-finalizar-monitoramento', 'Finalizar monitoramento');
const btnRequisicoesDetalhadas = criarBotao('btn-req-detalhadas-performance', 'Requisições detalhadas');
const btnAnaliseDetalhada = criarBotao('btn-analise-detalhada-performance', 'Análise detalhada');
const btnRelatorioEvento = criarBotao('btn-relatorio-evento-performance', 'Relatório separado');
// Inicialmente escondidos
btnRequisicoesDetalhadas.style.display = 'none';
btnAnaliseDetalhada.style.display = 'none';
btnFinalizar.style.display = 'none';
btnRelatorioEvento.style.display = 'none';
// Botão de esconder/mostrar com ícone de olho (fora do container)
const btnToggle = document.createElement('button');
btnToggle.id = 'btn-toggle-performance';
btnToggle.innerHTML = `
<img
src="https://cdn-icons-png.flaticon.com/512/565/565655.png"
alt="esconder"
style="width:15px; height:15px; vertical-align:middle; filter: invert(1);"
/>
`;
Object.assign(btnToggle.style, {
width: '38px',
height: '38px',
background: '#23272f',
color: '#f3f4f6',
borderRadius: '50%',
border: BUTTON_BORDER,
fontSize: '20px',
fontWeight: 'bold',
cursor: 'pointer',
boxShadow: BUTTON_BOX_SHADOW,
position: 'fixed',
left: '5px',
bottom: '5px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: '10000',
});
btnToggle.onmouseenter = () => {
btnToggle.style.background = '#353a40';
btnToggle.style.color = '#fff';
};
btnToggle.onmouseleave = () => {
btnToggle.style.background = '#23272f';
btnToggle.style.color = '#f3f4f6';
};
let hidden = false;
btnToggle.onclick = () => {
hidden = !hidden;
if (hidden) {
container.style.display = 'none';
btnToggle.innerHTML = `
<img
src="https://cdn-icons-png.flaticon.com/512/159/159604.png"
alt="mostrar"
style="width:15px; height:15px; vertical-align:middle; filter: invert(1);"
/>
`;
}
else {
container.style.display = 'flex';
btnToggle.innerHTML = `
<img
src="https://cdn-icons-png.flaticon.com/512/565/565655.png"
alt="esconder"
style="width:15px; height:15px; vertical-align:middle; filter: invert(1);"
/>
`;
}
};
// Estado dos botões
let estado = 'monitorando';
const atualizarBotoes = (novoEstado) => {
estado = novoEstado;
switch (estado) {
case 'inativo':
btnMain.innerText = 'Iniciar monitoramento';
this.monitoramentoAtivo = false;
btnFinalizar.style.display = 'none';
btnRequisicoesDetalhadas.style.display = 'none';
btnAnaliseDetalhada.style.display = 'none';
btnRelatorioEvento.style.display = 'none';
break;
case 'monitorando':
btnMain.innerText = 'Parar monitoramento';
this.monitoramentoAtivo = true;
btnFinalizar.style.display = 'none';
btnRequisicoesDetalhadas.style.display = 'none';
btnAnaliseDetalhada.style.display = 'none';
btnRelatorioEvento.style.display = 'none';
break;
case 'relatorio':
btnMain.innerText = 'Gerar relatório';
this.monitoramentoAtivo = false;
btnFinalizar.style.display = 'none';
btnRequisicoesDetalhadas.style.display = 'block';
btnAnaliseDetalhada.style.display = 'block';
btnRelatorioEvento.style.display = 'block';
break;
case 'relatorio_gerado':
btnMain.innerText = 'Gerar relatório';
this.monitoramentoAtivo = false;
btnFinalizar.style.display = 'block';
btnRequisicoesDetalhadas.style.display = 'block';
btnAnaliseDetalhada.style.display = 'block';
btnRelatorioEvento.style.display = 'block';
break;
}
};
// Ações dos botões
btnMain.onclick = () => {
if (estado === 'inativo') {
this.resetPerformanceData();
this.showWelcomeMessage();
atualizarBotoes('monitorando');
}
else if (estado === 'monitorando') {
atualizarBotoes('relatorio');
}
else if (estado === 'relatorio' || estado === 'relatorio_gerado') {
this.showPerformanceSummary(false);
atualizarBotoes('relatorio_gerado');
}
};
btnFinalizar.onclick = () => {
this.resetPerformanceData();
atualizarBotoes('inativo');
};
// Apêndice
this.showWelcomeMessage();
container.appendChild(btnMain);
container.appendChild(btnRequisicoesDetalhadas);
container.appendChild(btnRelatorioEvento);
container.appendChild(btnAnaliseDetalhada);
container.appendChild(btnFinalizar);
document.body.appendChild(container);
document.body.appendChild(btnToggle);
// Ação do botão de requisições detalhadas
btnRequisicoesDetalhadas.onclick = () => {
this.showHttpRequestsReport();
};
// Ação do botão de análise detalhada
btnAnaliseDetalhada.onclick = () => {
this.generateDetailedAnalysis();
};
// Ação do relatório por evento
btnRelatorioEvento.onclick = () => {
this.showEventReport(true);
};
// ====== Captura automática de eventos de UI para separar por evento ======
try {
// Evita adicionar múltiplos listeners
const anyWindow = window;
if (!anyWindow.__pm_auto_ui_listeners_added) {
anyWindow.__pm_auto_ui_listeners_added = true;
const describeTarget = (el, ev) => {
try {
const isKeyboard = typeof KeyboardEvent !== 'undefined' &&
ev instanceof KeyboardEvent;
const keyPart = isKeyboard && ev.key
? `[${ev.key}]`
: '';
if (!el || typeof el !== 'object')
return `ui${keyPart}`;
const tag = (el.tagName || el.nodeName || '').toString().toLowerCase() ||
'element';
const id = el.id ? `#${el.id}` : '';
const rawClass = typeof el.className === 'string'
? el.className
: el.classList &&
typeof el.classList === 'object' &&
typeof el.classList.toString === 'function'
? el.classList.toString()
: '';
const filtered = rawClass
.split(' ')
.filter((c) => c && !c.startsWith('ng-') && !c.startsWith('cdk-'))
.slice(0, 2)
.join('.');
const cls = filtered ? `.${filtered}` : '';
const includeText = tag === 'button' || tag === 'a';
const txt = includeText && typeof el.innerText === 'string'
? el.innerText.trim().slice(0, 30)
: '';
return `${tag}${id}${cls}${keyPart}${txt ? `:"${txt}"` : ''}`;
}
catch (_a) {
return 'ui';
}
};
let uiEventEndTimer = null;
let uiEventEndInterval = null;
const startUiEventContext = (label) => {
if (uiEventEndTimer) {
clearTimeout(uiEventEndTimer);
uiEventEndTimer = null;
}
if (uiEventEndInterval) {
clearInterval(uiEventEndInterval);
uiEventEndInterval = null;
}
this.beginEventContext(label);
// Se já há um contexto aberto, não cria nova janela de encerramento (evento aninhado)
if (this.eventContextStack.length > 1) {
return;
}
// Janela inteligente: espera primeiro timer e fecha após período de silêncio
const MAX_WINDOW_MS = 60000;
const GRACE_MS = 2000; // tempo para permitir timers que começam depois
const QUIET_MS = 600; // tempo sem atividade para considerar fluxo encerrado
uiEventEndInterval = setInterval(() => {
var _a, _b;
const now = Date.now();
const active = this.hasActiveTimers();
const beginAt = (_a = this.currentEventBeginAt) !== null && _a !== void 0 ? _a : now;
const hasStarted = this.firstTimerInEventAt !== null;
const graceExceeded = now - beginAt > GRACE_MS;
const lastActivity = (_b = this.lastTimerActivityAt) !== null && _b !== void 0 ? _b : beginAt;
const quietEnough = hasStarted && !active && now - lastActivity > QUIET_MS;
const exceededMax = now - beginAt > MAX_WINDOW_MS;
if (quietEnough || (!hasStarted && graceExceeded) || exceededMax) {
this.endEventContext();
clearInterval(uiEventEndInterval);
uiEventEndInterval = null;
}
}, 250);
// Fallback: fecha no máximo após MAX_WINDOW_MS
uiEventEndTimer = setTimeout(() => {
if (uiEventEndInterval) {
clearInterval(uiEventEndInterval);
uiEventEndInterval = null;
}
this.endEventContext();
uiEventEndTimer = null;
}, MAX_WINDOW_MS);
};
['click', 'submit', 'change', 'keydown'].forEach((type) => {
document.addEventListener(type, (ev) => {
const target = ev.target;
const label = `UserInput:${type} ${describeTarget(target, ev)}`;
startUiEventContext(label);
}, true // captura cedo na fase de captura
);
});
// Contexto inicial para operações de inicialização da tela
this.beginEventContext('AppInit');
setTimeout(() => this.endEventContext(), 3000);
}
}
catch (e) {
// Evita quebrar caso ambiente não permita acesso ao document
console.warn('[PerformanceMonitor] Falha ao ativar captura automática de UI:', e);
}
}
showEventReport(includeHttp = true) {
console.log('%cRELATÓRIO POR EVENTO', 'color: #bbc7c8ff; font-size: 18px; font-weight: bold; text-shadow: 1px 1px #000; background-color: #43248bff; border-radius: 5px; padding: 10px 20px;');
if (this.performanceSummary.size === 0) {
console.log('Nenhuma operação monitorada ainda.');
return;
}
const events = new Map();
this.performanceSummary.forEach((stats, fullName) => {
const parts = fullName.split(' | ');
const event = parts.length > 1 ? parts[0] : 'SemEvento';
const opName = parts.length > 1 ? parts.slice(1).join(' | ') : fullName;
if (!events.has(event)) {
events.set(event, { totalTime: 0, totalExec: 0, operations: [] });
}
const group = events.get(event);
group.totalTime += stats.totalTime;
group.totalExec += stats.count;
group.operations.push({ name: opName, stats });
});
let overallTime = 0;
let overallExec = 0;
Array.from(events.entries())
.sort((a, b) => b[1].totalTime - a[1].totalTime)
.forEach(([event, group]) => {
overallTime += group.totalTime;
overallExec += group.totalExec;
console.log(`%cEVENTO: ${event} | Tempo: ${Math.round(group.totalTime)}ms | Execuções: ${group.totalExec}`, 'color: #fff; background: #28647b; font-size: 13px; font-weight: bold; border-radius: 4px; padding: 3px 8px;');
const table = Object.fromEntries(group.operations
.sort((a, b) => b.stats.totalTime - a.stats.totalTime)
.map(({ name, stats }) => {
const avgTime = Math.round(stats.totalTime / stats.count);
const { emoji, status } = this.getPerformanceStatus(avgTime, stats.customThresholds, name);
return [
name,
{
Execuções: stats.count,
'Média(ms)': `${avgTime}ms (${status}) ${emoji}`.trim(),
'Mínimo(ms)': stats.minTime,
'Máximo(ms)': stats.maxTime,
'Total(ms)': Math.round(stats.totalTime),
},
];
}));
console.table(table);
if (includeHttp) {
const httpTable = {};
this.httpRequests.forEach((dados, key) => {
const parts = key.split(' | ');
const httpEvent = parts.length > 1 ? parts[0] : 'SemEvento';
const httpName = parts.length > 1 ? parts.slice(1).join(' | ') : key;
if (httpEvent === event) {
httpTable[httpName] = {
Execuções: dados.execucoes,
Média: `${Math.round(dados.tempoTotal / Math.max(dados.execucoes, 1))}ms`,
'Tempo Total': `${Math.round(dados.tempoTotal)}ms`,
Erros: dados.errors,
};
}
});
const hasHttpRows = Object.keys(httpTable).length > 0;
if (hasHttpRows) {
console.log(`%cHTTP (${event})`, 'color: #fff; background: #28336b; font-size: 12px; font-weight: bold; border-radius: 4px; padding: 2px 8px;');
console.table(httpTable);
}
}
});
console.log(`%cTOTAL GERAL: ${Math.round(overallTime)}ms | Execuções: ${overallExec}`, 'color: #fff; background: #43248bff; font-size: 14px; font-weight: bold; border-radius: 4px; padding: 4px 12px; margin-top: 8px;');
}
}
/**
* 🏭 Factory function para criar instância do LogsPerformatico
* @param serviceName Nome do serviço (para logs personalizados)
* @returns Nova instância de LogsPerformatico
*/
export function createPerformanceLogger(serviceName = 'Service') {
return new LogsPerformatico(serviceName);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nLXBlcmZvcm1hdGljby5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3BlcmZvcm1hbmNlLW1vbml0b3ItbG9nZ2VyL3NyYy9saWIvbG9nLXBlcmZvcm1hdGljby50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRzs7QUFpQ0gsTUFBTSxPQUFPLGdCQUFnQjtJQTRCM0IsWUFBWSxjQUFzQixTQUFTO1FBM0JuQyx1QkFBa0IsR0FBWSxJQUFJLENBQUMsQ0FBQywrQkFBK0I7UUFDM0UsNkJBQTZCO1FBQ3JCLHNCQUFpQixHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO1FBQzlDLHVCQUFrQixHQUFHLElBQUksR0FBRyxFQUE0QixDQUFDO1FBRXpELGlCQUFZLEdBR2hCLElBQUksR0FBRyxFQUFFLENBQUM7UUFFZCw4Q0FBOEM7UUFDdEMseUJBQW9CLEdBQWEsRUFBRSxDQUFDO1FBQ3BDLHNCQUFpQixHQUFhLEVBQUUsQ0FBQztRQUNqQyxlQUFVLEdBTVosRUFBRSxDQUFDO1FBQ1QsdUVBQXVFO1FBQy9ELHdCQUFtQixHQUFrQixJQUFJLENBQUM7UUFDMUMsd0JBQW1CLEdBQWtCLElBQUksQ0FBQztRQUMxQyx3QkFBbUIsR0FBa0IsSUFBSSxDQUFDO1FBQ2xELDJDQUEyQztRQUNuQyxvQkFBZSxHQUFHLElBQUksT0FBTyxFQUFzQixDQUFDO1FBRzFELElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7O09BR0c7SUFDSCxtQkFBbUIsQ0FDakIsT0FBWSxFQUNaLEtBQWEsRUFDYixRQUFpQixLQUFLOztRQUV0QixnQ0FBZ0M7UUFDaEMsSUFBSSxJQUFJLEdBQVcsZ0JBQWdCLENBQUM7UUFDcEMsSUFBSTtZQUNGLE1BQU0sVUFBVSxHQUFHLE1BQUEsT0FBTyxhQUFQLE9BQU8sdUJBQVAsT0FBTyxDQUFFLElBQUksMENBQUUsSUFBMEIsQ0FB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c291cmNlc0NvbnRlbnQiOlsiLyoqXHJcbiAqIPCfk4ogU0lTVEVNQSBERSBMT0dTIERFIFBFUkZPUk1BTkNFXHJcbiAqXHJcbiAqIFNpc3RlbWEgY29tcGxldG8gZGUgbW9uaXRvcmFtZW50byBkZSBwZXJmb3JtYW5jZSBwYXJhIGFwbGljYcOnw7VlcyBBbmd1bGFyXHJcbiAqIGNvbSBmZWVkYmFjayB2aXN1YWwgYXRyYXbDqXMgZGUgZW1vamlzIGUgcmVsYXTDs3Jpb3MgYXV0b23DoXRpY29zLlxyXG4gKlxyXG4gKiBDYXJhY3RlcsOtc3RpY2FzOlxyXG4gKiAtIPCfk4ggTW9uaXRvcmFtZW50byBlbSBUZW1wbyBSZWFsXHJcbiAqIC0g8J+fovCfn6Hwn5S0IENsYXNzaWZpY2HDp8OjbyBWaXN1YWwgcG9yIFBlcmZvcm1hbmNlXHJcbiAqIC0g4o+wIFJlbGF0w7NyaW9zIEF1dG9tw6F0aWNvcyBhcMOzcyBJbmF0aXZpZGFkZVxyXG4gKiAtIPCfk4ogQW7DoWxpc2UgRGV0YWxoYWRhIGNvbSBSZWNvbWVuZGHDp8O1ZXNcclxuICogLSDwn5ug77iPIEFQSSBQw7pibGljYSBwYXJhIENvbnRyb2xlIE1hbnVhbFxyXG4gKlxyXG4gKiBAYXV0aG9yIFBlZHJvIEhlbnJpcXVlIGRvcyBTYW50b3MgTGV1Y2hzXHJcbiAqIEB2ZXJzaW9uIDEuMC4yM1xyXG4gKiBAc2luY2UgMjAyNS0wNy0xMVxyXG4gKi9cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgUGVyZm9ybWFuY2VTdGF0cyB7XHJcbiAgY291bnQ6IG51bWJlcjtcclxuICB0b3RhbFRpbWU6IG51bWJlcjtcclxuICBtaW5UaW1lOiBudW1iZXI7XHJcbiAgbWF4VGltZTogbnVtYmVyO1xyXG4gIGN1c3RvbVRocmVzaG9sZHM/OiB7IG9rPzogbnVtYmVyOyBsZW50bz86IG51bWJlcjsgY3JpdGljbz86IG51bWJlciB9OyAvLyDwn4aVIEFybWF6ZW5hIHRocmVzaG9sZHMgY3VzdG9taXphZG9zXHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgRHluYW1pY1RocmVzaG9sZHMge1xyXG4gIG9rOiBudW1iZXI7XHJcbiAgbGVudG86IG51bWJlcjtcclxuICBjcml0aWNvOiBudW1iZXI7XHJcbn1cclxuXHJcbi8vIPCfjpvvuI8gT3DDp8O1ZXMgcGFyYSBhdXRv4oCRaW5zdHJ1bWVudGHDp8OjbyBzZW0gZGVjb3JhdG9yc1xyXG5leHBvcnQgaW50ZXJmYWNlIEluc3RydW1lbnRPcHRpb25zIHtcclxuICBpbmNsdWRlPzogQXJyYXk8c3RyaW5nIHwgUmVnRXhwPjtcclxuICBleGNsdWRlPzogQXJyYXk8c3RyaW5nIHwgUmVnRXhwPjtcclxuICBuYW1lVHJhbnNmb3JtPzogKG5hbWU6IHN0cmluZywgcGF0aD86IHN0cmluZ1tdKSA9PiBzdHJpbmc7XHJcbiAgcHJlc2VydmVUb1N0cmluZz86IGJvb2xlYW47IC8vIG1hbnTDqW0gZm4udG9TdHJpbmcoKSBvcmlnaW5hbCBwYXJhIGNvbXBhdGliaWxpZGFkZSBjb20gcmVnZXhcclxuICBtYXhEZXB0aD86IG51bWJlcjsgLy8gdXNhZG8gbm8gaW5zdHJ1bWVudE5hbWVzcGFjZVxyXG59XHJcblxyXG4vLyDwn5SnIE9ww6fDtWVzIHBhcmEgYXV0b+KAkWluc3RydW1lbnRhw6fDo28gYmFzZWFkYSBlbSBjaGFtYWRhcyBzZXRTZXJ2aWNlKC4uLilcclxuZXhwb3J0IGludGVyZmFjZSBIb29rU2V0U2VydmljZU9wdGlvbnMgZXh0ZW5kcyBJbnN0cnVtZW50T3B0aW9ucyB7XHJcbiAgaW5jbHVkZU9iamVjdHM/OiBBcnJheTxzdHJpbmcgfCBSZWdFeHA+OyAvLyBmaWx0cm8gZGUgb2JqZXRvcyAocG9yIGNhbWluaG8vbm9tZSlcclxuICBleGNsdWRlT2JqZWN0cz86IEFycmF5PHN0cmluZyB8IFJlZ0V4cD47XHJcbiAgbWF4V2Fsa0RlcHRoPzogbnVtYmVyOyAvLyBwcm9mdW5kaWRhZGUgbcOheGltYSBhbyB2YXJyZXIgbmFtZXNwYWNlc1xyXG4gIGxhYmVsRnJvbVBhdGg/OiAocGF0aDogc3RyaW5nW10pID0+IHN0cmluZzsgLy8gY29tbyBub21lYXIgc2VydmnDp29zXHJcbn1cclxuXHJcbmV4cG9ydCBjbGFzcyBMb2dzUGVyZm9ybWF0aWNvIHtcclxuICBwcml2YXRlIG1vbml0b3JhbWVudG9BdGl2bzogYm9vbGVhbiA9IHRydWU7IC8vIENvbWXDp2EgYXRpdm8gbmEgcHJpbWVpcmEgdmV6XHJcbiAgLy8g8J+TiiBQcm9wcmllZGFkZXMgZG8gU2lzdGVtYVxyXG4gIHByaXZhdGUgcGVyZm9ybWFuY2VUaW1lcnMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xyXG4gIHByaXZhdGUgcGVyZm9ybWFuY2VTdW1tYXJ5ID0gbmV3IE1hcDxzdHJpbmcsIFBlcmZvcm1hbmNlU3RhdHM+KCk7XHJcbiAgcHJpdmF0ZSBzZXJ2aWNlTmFtZTogc3RyaW5nO1xyXG4gIHByaXZhdGUgaHR0cFJlcXVlc3RzOiBNYXA8XHJcbiAgICBzdHJpbmcsXHJcbiAgICB7IHRlbXBvVG90YWw6IG51bWJlcjsgZXhlY3Vjb2VzOiBudW1iZXI7IGVycm9yczogbnVtYmVyIH1cclxuICA+ID0gbmV3IE1hcCgpO1xyXG5cclxuICAvLyDwn4aVIFN0YWNrIHBhcmEgY29udGV4dG8gZGUgZnVuw6fDo28gbW9uaXRvcmFkYVxyXG4gIHByaXZhdGUgZnVuY3Rpb25Db250ZXh0U3RhY2s6IHN0cmluZ1tdID0gW107XHJcbiAgcHJpdmF0ZSBldmVudENvbnRleHRTdGFjazogc3RyaW5nW10gPSBbXTtcclxuICBwcml2YXRlIHRpbWVyU3RhY2s6IHtcclxuICAgIG5hbWU6IHN0cmluZztcclxuICAgIHN0YXJ0OiBudW1iZXI7XHJcbiAgICBjaGlsZEVsYXBzZWQ6IG51bWJlcjtcclxuICAgIGV2ZW50Pzogc3RyaW5nO1xyXG4gICAgZnVsbE5hbWU/OiBzdHJpbmc7XHJcbiAgfVtdID0gW107XHJcbiAgLy8g8J+GlSBFc3RhZG8gZGUgYXRpdmlkYWRlIHBhcmEgZmVjaGFtZW50byBpbnRlbGlnZW50ZSBkZSBjb250ZXh0byBkZSBVSVxyXG4gIHByaXZhdGUgbGFzdFRpbWVyQWN0aXZpdHlBdDogbnVtYmVyIHwgbnVsbCA9IG51bGw7XHJcbiAgcHJpdmF0ZSBmaXJzdFRpbWVySW5FdmVudEF0OiBudW1iZXIgfCBudWxsID0gbnVsbDtcclxuICBwcml2YXRlIGN1cnJlbnRFdmVudEJlZ2luQXQ6IG51bWJlciB8IG51bGwgPSBudWxsO1xyXG4gIC8vIPCflJIgQ29udHJvbGUgZGUgZnVuw6fDtWVzIGrDoSBpbnN0cnVtZW50YWRhc1xyXG4gIHByaXZhdGUgaW5zdHJ1bWVudGVkRm5zID0gbmV3IFdlYWtNYXA8RnVuY3Rpb24sIEZ1bmN0aW9uPigpO1xyXG5cclxuICBjb25zdHJ1Y3RvcihzZXJ2aWNlTmFtZTogc3RyaW5nID0gJ1NlcnZpY2UnKSB7XHJcbiAgICB0aGlzLnNlcnZpY2VOYW1lID0gc2VydmljZU5hbWU7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSZWdpc3RyYSByZXF1aXNpw6fDo28gSFRUUCBhc3NvY2lhbmRvIMOgIGZ1bsOnw6NvIG1vbml0b3JhZGEgYXRpdmEgKHNlIGhvdXZlcilcclxuICAgKiBAcGFyYW0gcGF5bG9hZCBEYWRvcyBkYSByZXF1aXNpw6fDo29cclxuICAgKi9cclxuICByZWdpc3Rlckh0dHBSZXF1ZXN0KFxyXG4gICAgYXV0aFJlcTogYW55LFxyXG4gICAgdGVtcG86IG51bWJlcixcclxuICAgIGVycm9yOiBib29sZWFuID0gZmFsc2VcclxuICApOiB2b2lkIHtcclxuICAgIC8vIE5vbWUgcm9idXN0byBkYSBvcGVyYcOnw6NvIEhUVFBcclxuICAgIGxldCBub21lOiBzdHJpbmcgPSAnKGRlc2NvbmhlY2lkbyknO1xyXG4gICAgdHJ5IHtcclxuICAgICAgY29uc3QgYnlCb2R5TmFtZSA9IGF1dGhSZXE/LmJvZHk/Lm5hbWUgYXMgc3RyaW5nIHwgdW5kZWZpbmVkO1xyXG4gICAgICBjb25zdCBieVNxbCA9IHRoaXMuZXh0cmFpck5vbWVEZVNRTChcclxuICAgICAgICBhdXRoUmVxPy5ib2R5Py5zcWxJbnN0cnVjdGlvbiBhcyBzdHJpbmcgfCB1bmRlZmluZWRcclxuICAgICAgKTtcclxuICAgICAgY29uc3QgbWV0aG9kID0gKGF1dGhSZXE/Lm1ldGhvZCBhcyBzdHJpbmcgfCB1bmRlZmluZWQpIHx8ICdIVFRQJztcclxuICAgICAgY29uc3QgdXJsOiBzdHJpbmcgfCB1bmRlZmluZWQgPSBhdXRoUmVxPy51cmwgYXMgc3RyaW5nIHwgdW5kZWZpbmVkO1xyXG5cclxuICAgICAgLy8gVXNhIG5vbWUgcGxhbmVqYWRvIChib2R5L3NxbCksIHNlbsOjbyBmYWxsYmFjayBwYXJhIG3DqXRvZG8gKyDDumx0aW1vIHNlZ21lbnRvIGRhIFVSTFxyXG4gICAgICBpZiAoYnlCb2R5TmFtZSkge1xyXG4gICAgICAgIG5vbWUgPSBieUJvZHlOYW1lO1xyXG4gICAgICB9IGVsc2UgaWYgKGJ5U3FsKSB7XHJcbiAgICAgICAgbm9tZSA9IGJ5U3FsO1xyXG4gICAgICB9IGVsc2UgaWYgKHVybCkge1xyXG4gICAgICAgIGNvbnN0IGNsZWFuVXJsID0gU3RyaW5nKHVybCkuc3BsaXQoJz8nKVswXTtcclxuICAgICAgICBjb25zdCBzZWdzID0gY2xlYW5Vcmwuc3BsaXQoJy8nKS5maWx0ZXIoQm9vbGVhbik7XHJcbiAgICAgICAgY29uc3QgdGFpbCA9IHNlZ3Nbc2Vncy5sZW5ndGggLSAxXSB8fCBjbGVhblVybDtcclxuICAgICAgICBub21lID0gYCR7bWV0aG9kfSAke3RhaWx9YDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBub21lID0gbWV0aG9kO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIHt9XHJcblxyXG4gICAgY29uc3QgY3VycmVudEV2ZW50ID0gdGhpcy5ldmVudENvbnRleHRTdGFjay5sZW5ndGhcclxuICAgICAgPyB0aGlzLmV2ZW50Q29udGV4dFN0YWNrW3RoaXMuZXZlbnRDb250ZXh0U3RhY2subGVuZ3RoIC0gMV1cclxuICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICBjb25zdCBrZXkgPSBjdXJyZW50RXZlbnQgPyBgJHtjdXJyZW50RXZlbnR9IHwgJHtub21lfWAgOiBub21lO1xyXG5cclxuICAgIGNvbnN0IGF0dWFsID0gdGhpcy5odHRwUmVxdWVzdHMuZ2V0KGtleSkgfHwge1xyXG4gICAgICB0ZW1wb1RvdGFsOiAwLFxyXG4gICAgICBleGVjdWNvZXM6IDAsXHJcbiAgICAgIGVycm9yczogMCxcclxuICAgIH07XHJcblxyXG4gICAgYXR1YWwudGVtcG9Ub3RhbCArPSBOdW1iZXIuaXNGaW5pdGUodGVtcG8pID8gdGVtcG8gOiAwO1xyXG4gICAgYXR1YWwuZXhlY3Vjb2VzICs9IDE7XHJcbiAgICBpZiAoZXJyb3IpIGF0dWFsLmVycm9ycyArPSAxO1xyXG5cclxuICAgIHRoaXMuaHR0cFJlcXVlc3RzLnNldChrZXksIGF0dWFsKTtcclxuICB9XHJcblxyXG4gIC8vIEZ1bsOnw6NvIGF1eGlsaWFyIHBhcmEgZXh0cmFpciBub21lIGRhIGZ1bsOnw6NvIGRlIHVtIFNRTCwgZXg6IFBBQ0tfUEFSTUdFTi5DT05TVUxUQV9QQVJBTUVUUk8oLi4uKVxyXG4gIHByaXZhdGUgZXh0cmFpck5vbWVEZVNRTChzcWw6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xyXG4gICAgaWYgKCFzcWwpIHJldHVybiBudWxsO1xyXG4gICAgY29uc3QgbWF0Y2ggPSBzcWwubWF0Y2goLyhbQS1aMC05X10rXFwuW0EtWjAtOV9dKykvaSk7XHJcbiAgICByZXR1cm4gbWF0Y2ggPyBtYXRjaFsxXSA6IG51bGw7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn5qAIE1lbnNhZ2VtIGRlIGJvYXMtdmluZGFzIGRvIHNpc3RlbWFcclxuICAgKi9cclxuICBwdWJsaWMgc2hvd1dlbGNvbWVNZXNzYWdlKCk6IHZvaWQge1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIGAlY1NJU1RFTUEgREUgTU9OSVRPUkFNRU5UTyBERSBQRVJGT1JNQU5DRWAsXHJcbiAgICAgICdjb2xvcjogI2JiYzdjOGZmOyBmb250LXNpemU6IDE4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyB0ZXh0LXNoYWRvdzogMXB4IDFweCAjMDAwOyBiYWNrZ3JvdW5kLWNvbG9yOiAjNDMyNDhiZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMTBweCAyMHB4OydcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDij7HvuI8gSW5pY2lhIGNyb27DtG1ldHJvIHBhcmEgdW1hIG9wZXJhw6fDo29cclxuICAgKiBAcGFyYW0gb3BlcmF0aW9uTmFtZSBOb21lIGRhIG9wZXJhw6fDo28gYSBzZXIgbW9uaXRvcmFkYVxyXG4gICAqL1xyXG4gIHB1YmxpYyBzdGFydFRpbWVyKG9wZXJhdGlvbk5hbWU6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLm1vbml0b3JhbWVudG9BdGl2bykgcmV0dXJuO1xyXG4gICAgLy8gU2UgZm9yIGEgcHJpbWVpcmEgb3BlcmHDp8OjbywgYWJyZSBib3JkYSB2aXN1YWxcclxuICAgIGlmIChcclxuICAgICAgdGhpcy5wZXJmb3JtYW5jZVRpbWVycy5zaXplID09PSAwICYmXHJcbiAgICAgIHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LnNpemUgPT09IDBcclxuICAgICkge1xyXG4gICAgICBjb25zdCBib3JkZXIgPSAn4pWQJy5yZXBlYXQoNTYpO1xyXG5cclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgYCVjSU7DjUNJTyBETyBNT05JVE9SQU1FTlRPIERFIFBFUkZPUk1BTkNFYCxcclxuICAgICAgICAnY29sb3I6ICNiYmM3YzhmZjsgZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsgdGV4dC1zaGFkb3c6IDFweCAxcHggIzAwMDsgYmFja2dyb3VuZC1jb2xvcjogIzQzMjQ4YmZmOyBib3JkZXItcmFkaXVzOiA1cHg7IHBhZGRpbmc6IDEwcHggMjBweDsnXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICB0aGlzLnBlcmZvcm1hbmNlVGltZXJzLnNldChvcGVyYXRpb25OYW1lLCBEYXRlLm5vdygpKTtcclxuICAgIC8vIEVtcGlsaGEgY29udGV4dG8gZGUgZnVuw6fDo28gbW9uaXRvcmFkYVxyXG4gICAgdGhpcy5mdW5jdGlvbkNvbnRleHRTdGFjay5wdXNoKG9wZXJhdGlvbk5hbWUpO1xyXG4gICAgLy8gQWRpY2lvbmEgY29udGV4dG8gYW8gc3RhY2sgcGFyYSBtZWRpciB0ZW1wbyBleGNsdXNpdm9cclxuICAgIGNvbnN0IGN1cnJlbnRFdmVudCA9IHRoaXMuZXZlbnRDb250ZXh0U3RhY2subGVuZ3RoXHJcbiAgICAgID8gdGhpcy5ldmVudENvbnRleHRTdGFja1swXSAvLyB1c2EgcsOzdHVsbyByYWl6IGRvIGZsdXhvIGRvIHVzdcOhcmlvXHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG4gICAgLy8gU2UgYSBvcGVyYcOnw6NvIHZpZXIgY29tbyBwYWNrLm1ldG9kbywgdXNhbW9zIHBhY2sgY29tbyBldmVudG8gZSBtZXRvZG8gY29tbyBub21lXHJcbiAgICBjb25zdCBwYXJ0cyA9IFN0cmluZyhvcGVyYXRpb25OYW1lKS5zcGxpdCgnLicpO1xyXG4gICAgbGV0IGRpc3BsYXlFdmVudDogc3RyaW5nIHwgdW5kZWZpbmVkO1xyXG4gICAgbGV0IGRpc3BsYXlOYW1lOiBzdHJpbmc7XHJcbiAgICBpZiAocGFydHMubGVuZ3RoID49IDIpIHtcclxuICAgICAgZGlzcGxheUV2ZW50ID0gcGFydHNbMF07XHJcbiAgICAgIGRpc3BsYXlOYW1lID0gcGFydHNbcGFydHMubGVuZ3RoIC0gMV07XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBTZW0gcHJlZml4byAocGFjaykgbm8gbm9tZSDigJQgZXhpYmUgYXBlbmFzIG8gbcOpdG9kb1xyXG4gICAgICBkaXNwbGF5RXZlbnQgPSB1bmRlZmluZWQ7XHJcbiAgICAgIGRpc3BsYXlOYW1lID0gb3BlcmF0aW9uTmFtZTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBmdWxsTmFtZSA9IGRpc3BsYXlFdmVudFxyXG4gICAgICA/IGAke2Rpc3BsYXlFdmVudH0gfCAke2Rpc3BsYXlOYW1lfWBcclxuICAgICAgOiBkaXNwbGF5TmFtZTtcclxuXHJcbiAgICAvLyBSZWdpc3RyYSBhdGl2aWRhZGUgZGUgdGltZXIgcGFyYSBjb250cm9sZSBkZSBqYW5lbGEgZG8gZXZlbnRvXHJcbiAgICBjb25zdCBub3dTdGFydCA9IERhdGUubm93KCk7XHJcbiAgICBpZiAoY3VycmVudEV2ZW50ICYmIHRoaXMuZmlyc3RUaW1lckluRXZlbnRBdCA9PT0gbnVsbCkge1xyXG4gICAgICB0aGlzLmZpcnN0VGltZXJJbkV2ZW50QXQgPSBub3dTdGFydDtcclxuICAgIH1cclxuICAgIHRoaXMubGFzdFRpbWVyQWN0aXZpdHlBdCA9IG5vd1N0YXJ0O1xyXG5cclxuICAgIHRoaXMudGltZXJTdGFjay5wdXNoKHtcclxuICAgICAgbmFtZTogb3BlcmF0aW9uTmFtZSxcclxuICAgICAgc3RhcnQ6IG5vd1N0YXJ0LFxyXG4gICAgICBjaGlsZEVsYXBzZWQ6IDAsXHJcbiAgICAgIGV2ZW50OiBjdXJyZW50RXZlbnQsXHJcbiAgICAgIGZ1bGxOYW1lLFxyXG4gICAgfSk7XHJcbiAgICBjb25zb2xlLmxvZyhg4pWRIFtJTsONQ0lPXSAke2Z1bGxOYW1lfSAtICR7bmV3IERhdGUoKS50b0xvY2FsZVRpbWVTdHJpbmcoKX1gKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfj4EgRmluYWxpemEgY3JvbsO0bWV0cm8gZSBleGliZSByZXN1bHRhZG8gY29tIGVtb2ppXHJcbiAgICogQHBhcmFtIG9wZXJhdGlvbk5hbWUgTm9tZSBkYSBvcGVyYcOnw6NvXHJcbiAgICogQHBhcmFtIGN1c3RvbU1lc3NhZ2UgTWVuc2FnZW0gY3VzdG9taXphZGEgb3BjaW9uYWwgKGV4OiBwYXJhIGVycm9zKVxyXG4gICAqIEBwYXJhbSBjdXN0b21UaHJlc2hvbGRzIFRocmVzaG9sZHMgY3VzdG9taXphZG9zIHBhcmEgZXN0YSBvcGVyYcOnw6NvIGVzcGVjw61maWNhXHJcbiAgICovXHJcbiAgcHVibGljIGVuZFRpbWVyKFxyXG4gICAgb3BlcmF0aW9uTmFtZTogc3RyaW5nLFxyXG4gICAgY3VzdG9tTWVzc2FnZT86IHN0cmluZyxcclxuICAgIGN1c3RvbVRocmVzaG9sZHM/OiB7IG9rPzogbnVtYmVyOyBsZW50bz86IG51bWJlcjsgY3JpdGljbz86IG51bWJlciB9XHJcbiAgKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMubW9uaXRvcmFtZW50b0F0aXZvKSByZXR1cm47XHJcblxyXG4gICAgLy8gVXNhIHBpbGhhIGRlIGNvbnRleHRvIHBhcmEgY2FsY3VsYXIgdGVtcG8gZXhjbHVzaXZvIChleGNsdWkgZmlsaG9zKVxyXG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcclxuICAgIGxldCBjdHggPSB0aGlzLnRpbWVyU3RhY2subGVuZ3RoXHJcbiAgICAgID8gdGhpcy50aW1lclN0YWNrW3RoaXMudGltZXJTdGFjay5sZW5ndGggLSAxXVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgICBpZiAoIWN0eCB8fCBjdHgubmFtZSAhPT0gb3BlcmF0aW9uTmFtZSkge1xyXG4gICAgICAvLyBCdXNjYSByb2J1c3RhIGNhc28gZW5jZXJyYW1lbnRvIGZvcmEgZGUgb3JkZW1cclxuICAgICAgbGV0IGZvdW5kSW5kZXggPSAtMTtcclxuICAgICAgZm9yIChsZXQgaSA9IHRoaXMudGltZXJTdGFjay5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xyXG4gICAgICAgIGlmICh0aGlzLnRpbWVyU3RhY2tbaV0ubmFtZSA9PT0gb3BlcmF0aW9uTmFtZSkge1xyXG4gICAgICAgICAgZm91bmRJbmRleCA9IGk7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgaWYgKGZvdW5kSW5kZXggPT09IC0xKSB7XHJcbiAgICAgICAgY29uc29sZS53YXJuKGDimqDvuI8gVGltZXIgbsOjbyBlbmNvbnRyYWRvIHBhcmE6ICR7b3BlcmF0aW9uTmFtZX1gKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuICAgICAgY3R4ID0gdGhpcy50aW1lclN0YWNrW2ZvdW5kSW5kZXhdO1xyXG4gICAgICB0aGlzLnRpbWVyU3RhY2suc3BsaWNlKGZvdW5kSW5kZXgsIDEpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy50aW1lclN0YWNrLnBvcCgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEF0dWFsaXphIGF0aXZpZGFkZSBkZSB0aW1lcnMgKHBhcmEgbMOzZ2ljYSBkZSBmZWNoYW1lbnRvIHBvciBzaWzDqm5jaW8pXHJcbiAgICB0aGlzLmxhc3RUaW1lckFjdGl2aXR5QXQgPSBub3c7XHJcblxyXG4gICAgY29uc3QgaW5jbHVzaXZlRWxhcHNlZCA9IG5vdyAtIGN0eC5zdGFydDtcclxuICAgIGNvbnN0IGV4Y2x1c2l2ZUVsYXBzZWQgPSBNYXRoLm1heCgwLCBpbmNsdXNpdmVFbGFwc2VkIC0gY3R4LmNoaWxkRWxhcHNlZCk7XHJcblxyXG4gICAgLy8gUHJvcGFnYSB0ZW1wbyBkbyBmaWxobyBwYXJhIG8gcGFpIChwYXJhIGV4Y2x1aXIgbmEgY29udGFnZW0gZG8gcGFpKVxyXG4gICAgY29uc3QgcGFyZW50ID0gdGhpcy50aW1lclN0YWNrW3RoaXMudGltZXJTdGFjay5sZW5ndGggLSAxXTtcclxuICAgIGlmIChwYXJlbnQpIHtcclxuICAgICAgcGFyZW50LmNoaWxkRWxhcHNlZCArPSBpbmNsdXNpdmVFbGFwc2VkO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbW92ZSByZWZlcsOqbmNpYSBhbnRpZ2EgYmFzZWFkYSBlbSBNYXAgKG1hbnRpZGEgcGFyYSBjb21wYXRpYmlsaWRhZGUpXHJcbiAgICB0aGlzLnBlcmZvcm1hbmNlVGltZXJzLmRlbGV0ZShvcGVyYXRpb25OYW1lKTtcclxuXHJcbiAgICAvLyBEZXNlbXBpbGhhIGNvbnRleHRvIGRlIGZ1bsOnw6NvIG1vbml0b3JhZGEgKHNvbWVudGUgc2UgdG9wbylcclxuICAgIGlmIChcclxuICAgICAgdGhpcy5mdW5jdGlvbkNvbnRleHRTdGFja1t0aGlzLmZ1bmN0aW9uQ29udGV4dFN0YWNrLmxlbmd0aCAtIDFdID09PVxyXG4gICAgICBvcGVyYXRpb25OYW1lXHJcbiAgICApIHtcclxuICAgICAgdGhpcy5mdW5jdGlvbkNvbnRleHRTdGFjay5wb3AoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXRlcm1pbmEgc3RhdHVzIGJhc2VhZG8gbm8gdGVtcG8gZXhjbHVzaXZvXHJcbiAgICBjb25zdCB7IGVtb2ppLCBzdGF0dXMsIGNvbG9yIH0gPSB0aGlzLmdldFBlcmZvcm1hbmNlU3RhdHVzKFxyXG4gICAgICBleGNsdXNpdmVFbGFwc2VkLFxyXG4gICAgICBjdXN0b21UaHJlc2hvbGRzLFxyXG4gICAgICBjdHguZnVsbE5hbWUgPz9cclxuICAgICAgICAoY3R4LmV2ZW50ID8gYCR7Y3R4LmV2ZW50fSB8ICR7b3BlcmF0aW9uTmFtZX1gIDogb3BlcmF0aW9uTmFtZSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gTG9nIGNvbSBlbW9qaSBlIGNvciAoY29tIG1lbnNhZ2VtIGN1c3RvbWl6YWRhIHNlIGZvcm5lY2lkYSlcclxuICAgIGNvbnN0IG1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlXHJcbiAgICAgID8gYCR7XHJcbiAgICAgICAgICBjdHguZnVsbE5hbWUgPz9cclxuICAgICAgICAgIChjdHguZXZlbnQgPyBgJHtjdHguZXZlbnR9IHwgJHtvcGVyYXRpb25OYW1lfWAgOiBvcGVyYXRpb25OYW1lKVxyXG4gICAgICAgIH0gLSAke2N1c3RvbU1lc3NhZ2V9YFxyXG4gICAgICA6IGAke1xyXG4gICAgICAgICAgY3R4LmZ1bGxOYW1lID8/XHJcbiAgICAgICAgICAoY3R4LmV2ZW50ID8gYCR7Y3R4LmV2ZW50fSB8ICR7b3BlcmF0aW9uTmFtZX1gIDogb3BlcmF0aW9uTmFtZSlcclxuICAgICAgICB9YDtcclxuICAgIGNvbnN0IGZpeGVkU3RhdHVzID0gYFske3N0YXR1c31dYC5wYWRFbmQoNSk7XHJcbiAgICBjb25zdCBmaXhlZE1lc3NhZ2UgPSBtZXNzYWdlLnBhZEVuZCgxMCk7XHJcbiAgICBjb25zdCBmaXhlZFRpbWUgPSBleGNsdXNpdmVFbGFwc2VkLnRvU3RyaW5nKCkucGFkU3RhcnQoNSk7XHJcblxyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIGDilZEgJWMke2Vtb2ppfSAke2ZpeGVkU3RhdHVzfSAke2ZpeGVkTWVzc2FnZX0gLSAke2ZpeGVkVGltZX1tcyBgLFxyXG4gICAgICBjb2xvclxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBNb3N0cmEgdGhyZXNob2xkcyBjdXN0b21pemFkb3Mgc2UgZXN0aXZlcmVtIHNlbmRvIHVzYWRvc1xyXG4gICAgaWYgKFxyXG4gICAgICBjdXN0b21UaHJlc2hvbGRzICYmXHJcbiAgICAgIChjdXN0b21UaHJlc2hvbGRzLm9rIHx8XHJcbiAgICAgICAgY3VzdG9tVGhyZXNob2xkcy5sZW50byB8fFxyXG4gICAgICAgIGN1c3RvbVRocmVzaG9sZHMuY3JpdGljbylcclxuICAgICkge1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICBg4pqZ77iPIFRocmVzaG9sZHMgY3VzdG9taXphZG9zOiBPSzwke1xyXG4gICAgICAgICAgY3VzdG9tVGhyZXNob2xkcy5vayA/PyA1MDBcclxuICAgICAgICB9bXMsIExFTlRPPCR7Y3VzdG9tVGhyZXNob2xkcy5sZW50byA/PyAyMDAwfW1zYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEF0dWFsaXphIHN1bcOhcmlvIGNvbSB0ZW1wbyBleGNsdXNpdm9cclxuICAgIHRoaXMudXBkYXRlUGVyZm9ybWFuY2VTdW1tYXJ5KFxyXG4gICAgICBjdHguZnVsbE5hbWUgPz9cclxuICAgICAgICAoY3R4LmV2ZW50ID8gYCR7Y3R4LmV2ZW50fSB8ICR7b3BlcmF0aW9uTmFtZX1gIDogb3BlcmF0aW9uTmFtZSksXHJcbiAgICAgIGV4Y2x1c2l2ZUVsYXBzZWQsXHJcbiAgICAgIGN1c3RvbVRocmVzaG9sZHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn46oIERldGVybWluYSBzdGF0dXMgZGUgcGVyZm9ybWFuY2UgYmFzZWFkbyBubyB0ZW1wb1xyXG4gICAqIEBwYXJhbSBlbGFwc2VkVGltZSBUZW1wbyBkZWNvcnJpZG8gZW0gbWlsaXNzZWd1bmRvc1xyXG4gICAqIEBwYXJhbSBjdXN0b21UaHJlc2hvbGRzIFRocmVzaG9sZHMgY3VzdG9taXphZG9zIHBhcmEgZXN0YSBvcGVyYcOnw6NvIGVzcGVjw61maWNhXHJcbiAgICogQHBhcmFtIG9wZXJhdGlvbk5hbWUgTm9tZSBkYSBvcGVyYcOnw6NvIChwYXJhIGNhbGN1bGFyIHRocmVzaG9sZHMgZGluw6JtaWNvcylcclxuICAgKiBAcmV0dXJucyBPYmpldG8gY29tIGVtb2ppLCBzdGF0dXMgZSBjb3JcclxuICAgKi9cclxuICBwcml2YXRlIGdldFBlcmZvcm1hbmNlU3RhdHVzKFxyXG4gICAgZWxhcHNlZFRpbWU6IG51bWJlcixcclxuICAgIGN1c3RvbVRocmVzaG9sZHM/OiB7IG9rPzogbnVtYmVyOyBsZW50bz86IG51bWJlcjsgY3JpdGljbz86IG51bWJlciB9LFxyXG4gICAgb3BlcmF0aW9uTmFtZT86IHN0cmluZ1xyXG4gICk6IHsgZW1vamk6IHN0cmluZzsgc3RhdHVzOiBzdHJpbmc7IGNvbG9yOiBzdHJpbmcgfSB7XHJcbiAgICBsZXQgb2tUaHJlc2hvbGQ6IG51bWJlcjtcclxuICAgIGxldCBsZW50b1RocmVzaG9sZDogbnVtYmVyO1xyXG4gICAgbGV0IGNyaXRpY29UaHJlc2hvbGQ6IG51bWJlcjtcclxuXHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbVRocmVzaG9sZHMgJiZcclxuICAgICAgKGN1c3RvbVRocmVzaG9sZHMub2sgfHxcclxuICAgICAgICBjdXN0b21UaHJlc2hvbGRzLmxlbnRvIHx8XHJcbiAgICAgICAgY3VzdG9tVGhyZXNob2xkcy5jcml0aWNvKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFVzYSB0aHJlc2hvbGRzIGN1c3RvbWl6YWRvcyBzZSBmb3JuZWNpZG9zXHJcbiAgICAgIG9rVGhyZXNob2xkID0gY3VzdG9tVGhyZXNob2xkcy5vayA/PyA1MDA7XHJcbiAgICAgIGxlbnRvVGhyZXNob2xkID0gY3VzdG9tVGhyZXNob2xkcy5sZW50byA/PyAyMDAwO1xyXG4gICAgICBjcml0aWNvVGhyZXNob2xkID0gY3VzdG9tVGhyZXNob2xkcy5jcml0aWNvID8/IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSO1xyXG4gICAgfSBlbHNlIGlmIChvcGVyYXRpb25OYW1lKSB7XHJcbiAgICAgIC8vIENhbGN1bGEgdGhyZXNob2xkcyBkaW7Dom1pY29zIGJhc2VhZG9zIG5hIHF1YW50aWRhZGUgZGUgZXhlY3XDp8O1ZXNcclxuICAgICAgY29uc3Qgc3RhdHMgPSB0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5nZXQob3BlcmF0aW9uTmFtZSk7XHJcbiAgICAgIC8vIENvcnJpZ2U6IHNvbWEgKzEgcGFyYSBjb25zaWRlcmFyIGEgZXhlY3XDp8OjbyBhdHVhbFxyXG4gICAgICBjb25zdCBleGVjdXRpb25Db3VudCA9IHN0YXRzID8gc3RhdHMuY291bnQgKyAxIDogMTtcclxuICAgICAgY29uc3QgZHluYW1pY1RocmVzaG9sZHMgPSB0aGlzLmNhbGN1bGF0ZUR5bmFtaWNUaHJlc2hvbGRzKGV4ZWN1dGlvbkNvdW50KTtcclxuXHJcbiAgICAgIG9rVGhyZXNob2xkID0gZHluYW1pY1RocmVzaG9sZHMub2s7XHJcbiAgICAgIGxlbnRvVGhyZXNob2xkID0gZHluYW1pY1RocmVzaG9sZHMubGVudG87XHJcbiAgICAgIGNyaXRpY29UaHJlc2hvbGQgPSBkeW5hbWljVGhyZXNob2xkcy5jcml0aWNvO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gVXNhIHRocmVzaG9sZHMgcGFkcsO1ZXNcclxuICAgICAgb2tUaHJlc2hvbGQgPSA1MDA7XHJcbiAgICAgIGxlbnRvVGhyZXNob2xkID0gMjAwMDtcclxuICAgICAgY3JpdGljb1RocmVzaG9sZCA9IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChlbGFwc2VkVGltZSA8IG9rVGhyZXNob2xkKSB7XHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgZW1vamk6ICfwn5+iJyxcclxuICAgICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgICAgY29sb3I6ICdjb2xvcjogZ3JlZW47IGZvbnQtd2VpZ2h0OiBib2xkOycsXHJcbiAgICAgIH07XHJcbiAgICB9IGVsc2UgaWYgKGVsYXBzZWRUaW1lIDwgbGVudG9UaHJlc2hvbGQpIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBlbW9qaTogJ/Cfn6EnLFxyXG4gICAgICAgIHN0YXR1czogJ0xFTlRPJyxcclxuICAgICAgICBjb2xvcjogJ2NvbG9yOiBvcmFuZ2U7IGZvbnQtd2VpZ2h0OiBib2xkOycsXHJcbiAgICAgIH07XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIGVtb2ppOiAn8J+UtCcsXHJcbiAgICAgICAgc3RhdHVzOiAnQ1LDjVRJQ08nLFxyXG4gICAgICAgIGNvbG9yOiAnY29sb3I6IHJlZDsgZm9udC13ZWlnaHQ6IGJvbGQ7JyxcclxuICAgICAgfTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfk4ggQXR1YWxpemEgZXN0YXTDrXN0aWNhcyBkZSBwZXJmb3JtYW5jZSBwYXJhIG8gc3Vtw6FyaW9cclxuICAgKiBAcGFyYW0gb3BlcmF0aW9uTmFtZSBOb21lIGRhIG9wZXJhw6fDo29cclxuICAgKiBAcGFyYW0gZWxhcHNlZFRpbWUgVGVtcG8gZGVjb3JyaWRvIGVtIG1pbGlzc2VndW5kb3NcclxuICAgKiBAcGFyYW0gY3VzdG9tVGhyZXNob2xkcyBUaHJlc2hvbGRzIGN1c3RvbWl6YWRvcyBwYXJhIGFybWF6ZW5hciAob3BjaW9uYWwpXHJcbiAgICovXHJcbiAgcHJpdmF0ZSB1cGRhdGVQZXJmb3JtYW5jZVN1bW1hcnkoXHJcbiAgICBvcGVyYXRpb25OYW1lOiBzdHJpbmcsXHJcbiAgICBlbGFwc2VkVGltZTogbnVtYmVyLFxyXG4gICAgY3VzdG9tVGhyZXNob2xkcz86IHsgb2s/OiBudW1iZXI7IGxlbnRvPzogbnVtYmVyOyBjcml0aWNvPzogbnVtYmVyIH1cclxuICApOiB2b2lkIHtcclxuICAgIGNvbnN0IGV4aXN0aW5nID0gdGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuZ2V0KG9wZXJhdGlvbk5hbWUpO1xyXG5cclxuICAgIGlmIChleGlzdGluZykge1xyXG4gICAgICBleGlzdGluZy5jb3VudCsrO1xyXG4gICAgICBleGlzdGluZy50b3RhbFRpbWUgKz0gZWxhcHNlZFRpbWU7XHJcbiAgICAgIGV4aXN0aW5nLm1pblRpbWUgPSBNYXRoLm1pbihleGlzdGluZy5taW5UaW1lLCBlbGFwc2VkVGltZSk7XHJcbiAgICAgIGV4aXN0aW5nLm1heFRpbWUgPSBNYXRoLm1heChleGlzdGluZy5tYXhUaW1lLCBlbGFwc2VkVGltZSk7XHJcblxyXG4gICAgICAvLyBBdHVhbGl6YSB0aHJlc2hvbGRzIGN1c3RvbWl6YWRvcyBzZSBmb3JuZWNpZG9zXHJcbiAgICAgIGlmIChcclxuICAgICAgICBjdXN0b21UaHJlc2hvbGRzICYmXHJcbiAgICAgICAgKGN1c3RvbVRocmVzaG9sZHMub2sgfHxcclxuICAgICAgICAgIGN1c3RvbVRocmVzaG9sZHMubGVudG8gfHxcclxuICAgICAgICAgIGN1c3RvbVRocmVzaG9sZHMuY3JpdGljbylcclxuICAgICAgKSB7XHJcbiAgICAgICAgZXhpc3RpbmcuY3VzdG9tVGhyZXNob2xkcyA9IGN1c3RvbVRocmVzaG9sZHM7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LnNldChvcGVyYXRpb25OYW1lLCB7XHJcbiAgICAgICAgY291bnQ6IDEsXHJcbiAgICAgICAgdG90YWxUaW1lOiBlbGFwc2VkVGltZSxcclxuICAgICAgICBtaW5UaW1lOiBlbGFwc2VkVGltZSxcclxuICAgICAgICBtYXhUaW1lOiBlbGFwc2VkVGltZSxcclxuICAgICAgICBjdXN0b21UaHJlc2hvbGRzOiBjdXN0b21UaHJlc2hvbGRzLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBOw6NvIGZheiBtYWlzIG5hZGEgYXF1aSwgcmVsYXTDs3JpbyBzw7MgbWFudWFsXHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn5OKIEV4aWJlIHJlbGF0w7NyaW8gcmVzdW1pZG8gZGUgdG9kYXMgYXMgb3BlcmHDp8O1ZXMgKGNvbXBhY3RhZG8pXHJcbiAgICovXHJcbiAgcHVibGljIHNob3dQZXJmb3JtYW5jZVN1bW1hcnkoc2hvd0Z1bGxEZXRhaWxzID0gZmFsc2UpOiB2b2lkIHtcclxuICAgIC8vIEZlY2hhIGJvcmRhIGRvIG1vbml0b3JhbWVudG8gYW8gZ2VyYXIgcmVsYXTDs3Jpb1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgICclYyBSRUxBVMOTUklPIERFIFBFUkZPUk1BTkNFJyxcclxuICAgICAgJ2NvbG9yOiAjYmJjN2M4ZmY7IGZvbnQtc2l6ZTogMThweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IHRleHQtc2hhZG93OiAxcHggMXB4ICMwMDA7IGJhY2tncm91bmQtY29sb3I6ICM0MzI0OGJmZjsgYm9yZGVyLXJhZGl1czogNXB4OyBwYWRkaW5nOiAxMHB4IDIwcHg7J1xyXG4gICAgKTtcclxuXHJcbiAgICBpZiAodGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuc2l6ZSA9PT0gMCkge1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAnJWMgTmVuaHVtYSBvcGVyYcOnw6NvIG1vbml0b3JhZGEgYWluZGEuJyxcclxuICAgICAgICAnY29sb3I6IGdyYXk7IGZvbnQtc3R5bGU6IGl0YWxpYzsnXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBzb3J0ZWRFbnRyaWVzID0gQXJyYXkuZnJvbSh0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5lbnRyaWVzKCkpLnNvcnQoXHJcbiAgICAgIChhLCBiKSA9PiBiWzFdLm1heFRpbWUgLSBhWzFdLm1heFRpbWVcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgdGFibGUgPSBPYmplY3QuZnJvbUVudHJpZXMoXHJcbiAgICAgIHNvcnRlZEVudHJpZXMubWFwKChbb3BlcmF0aW9uLCBzdGF0c10pID0+IHtcclxuICAgICAgICBjb25zdCBhdmdUaW1lID0gTWF0aC5yb3VuZChzdGF0cy50b3RhbFRpbWUgLyBzdGF0cy5jb3VudCk7XHJcbiAgICAgICAgY29uc3QgeyBlbW9qaSwgc3RhdHVzIH0gPSB0aGlzLmdldFBlcmZvcm1hbmNlU3RhdHVzKFxyXG4gICAgICAgICAgYXZnVGltZSxcclxuICAgICAgICAgIHN0YXRzLmN1c3RvbVRocmVzaG9sZHMsXHJcbiAgICAgICAgICBvcGVyYXRpb25cclxuICAgICAgICApO1xyXG5cclxuICAgICAgICByZXR1cm4gW1xyXG4gICAgICAgICAgb3BlcmF0aW9uLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBFeGVjdcOnw7Vlczogc3RhdHMuY291bnQsXHJcbiAgICAgICAgICAgICdNw6lkaWEobXMpJzogYCR7YXZnVGltZX1tcyAoJHtzdGF0dXN9KSAke2Vtb2ppfWAudHJpbSgpLFxyXG4gICAgICAgICAgICAnTcOtbmltbyhtcyknOiBzdGF0cy5taW5UaW1lLFxyXG4gICAgICAgICAgICAnTcOheGltbyhtcyknOiBzdGF0cy5tYXhUaW1lLFxyXG4gICAgICAgICAgICAnVG90YWwobXMpJzogc3RhdHMudG90YWxUaW1lLFxyXG4gICAgICAgICAgfSxcclxuICAgICAgICBdO1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICBjb25zb2xlLnRhYmxlKHRhYmxlKTtcclxuXHJcbiAgICAvLyBSZW1vdmlkbzogYWdvcmEgYSBhbsOhbGlzZSBkZXRhbGhhZGEgw6kgY2hhbWFkYSBhcGVuYXMgcGVsbyBib3TDo29cclxuICB9XHJcbiAgLyoqXHJcbiAgICog8J+TkSBFeGliZSByZWxhdMOzcmlvIGRldGFsaGFkbyBkZSByZXF1aXNpw6fDtWVzIEhUVFAgYWdydXBhZGFzIHBvciBmdW7Dp8Ojb1xyXG4gICAqL1xyXG4gIHB1YmxpYyBzaG93SHR0cFJlcXVlc3RzUmVwb3J0KCk6IHZvaWQge1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIGAlY1JFTEFUw5NSSU8gREVUQUxIQURPIERFIFJFUVVJU0nDh8OVRVMgSFRUUGAsXHJcbiAgICAgICdjb2xvcjogI2JiYzdjOGZmOyBmb250LXNpemU6IDE4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyB0ZXh0LXNoYWRvdzogMXB4IDFweCAjMDAwOyBiYWNrZ3JvdW5kLWNvbG9yOiAjNDMyNDhiZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMTBweCAyMHB4OydcclxuICAgICk7XHJcblxyXG4gICAgaWYgKHRoaXMuaHR0cFJlcXVlc3RzLnNpemUgPT09IDApIHtcclxuICAgICAgY29uc29sZS5sb2coJ05lbmh1bWEgcmVxdWlzacOnw6NvIEhUVFAgcmVnaXN0cmFkYS4nKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHRhYmVsYSA9IE9iamVjdC5mcm9tRW50cmllcyhcclxuICAgICAgQXJyYXkuZnJvbSh0aGlzLmh0dHBSZXF1ZXN0cy5lbnRyaWVzKCkpXHJcbiAgICAgICAgLnNvcnQoKGEsIGIpID0+IGJbMV0udGVtcG9Ub3RhbCAtIGFbMV0udGVtcG9Ub3RhbClcclxuICAgICAgICAubWFwKChbbm9tZSwgZGFkb3NdKSA9PiBbXHJcbiAgICAgICAgICBub21lLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICBFeGVjdcOnw7VlczogZGFkb3MuZXhlY3Vjb2VzLFxyXG4gICAgICAgICAgICBNw6lkaWE6IGAke01hdGgucm91bmQoZGFkb3MudGVtcG9Ub3RhbCAvIGRhZG9zLmV4ZWN1Y29lcyl9bXNgLFxyXG4gICAgICAgICAgICAnVGVtcG8gVG90YWwnOiBgJHtNYXRoLnJvdW5kKGRhZG9zLnRlbXBvVG90YWwpfW1zYCxcclxuICAgICAgICAgICAgRXJyb3M6IGRhZG9zLmVycm9ycyxcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgXSlcclxuICAgICk7XHJcblxyXG4gICAgY29uc29sZS50YWJsZSh0YWJlbGEpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+UjSBHZXJhIGFuw6FsaXNlIGRldGFsaGFkYSBkZSBwZXJmb3JtYW5jZVxyXG4gICAqL1xyXG4gIHB1YmxpYyBnZW5lcmF0ZURldGFpbGVkQW5hbHlzaXMoKTogdm9pZCB7XHJcbiAgICAvLyBUw610dWxvIGRpc2NyZXRvXHJcbiAgICBjb25zb2xlLmxvZyhcclxuICAgICAgJyVjQU7DgUxJU0UgREVUQUxIQURBIERFIFBFUkZPUk1BTkNFJyxcclxuICAgICAgJ2NvbG9yOiAjYmJjN2M4ZmY7IGZvbnQtc2l6ZTogMThweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IHRleHQtc2hhZG93OiAxcHggMXB4ICMwMDA7IGJhY2tncm91bmQtY29sb3I6ICM0MzI0OGJmZjsgYm9yZGVyLXJhZGl1czogNXB4OyBwYWRkaW5nOiAxMHB4IDIwcHg7J1xyXG4gICAgKTtcclxuICAgIGNvbnNvbGUubG9nKCcnKTtcclxuXHJcbiAgICBpZiAodGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuc2l6ZSA9PT0gMCkge1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAnJWNOZW5odW1hIG9wZXJhw6fDo28gcmVnaXN0cmFkYSBwYXJhIGFuw6FsaXNlLicsXHJcbiAgICAgICAgJ2NvbG9yOiAjYmJiOyBmb250LXN0eWxlOiBpdGFsaWM7IGZvbnQtc2l6ZTogMTRweDsgcGFkZGluZzogNHB4IDAgNHB4IDEwcHg7J1xyXG4gICAgICApO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgeyBjcml0aWNhbE9wZXJhdGlvbnMsIHNsb3dPcGVyYXRpb25zLCBmYXN0T3BlcmF0aW9ucyB9ID1cclxuICAgICAgdGhpcy5jYXRlZ29yaXplT3BlcmF0aW9ucygpO1xyXG5cclxuICAgIC8vIEhlbHBlciBwYXJhIGJsb2NvIGRpc2NyZXRvIGNvbSB0ZXh0byBjbGFyb1xyXG4gICAgY29uc3QgcHJpbnRCbG9jayA9IChcclxuICAgICAgY29sb3I6IHN0cmluZyxcclxuICAgICAgZW1vamk6IHN0cmluZyxcclxuICAgICAgb3BlcmF0aW9uOiBzdHJpbmcsXHJcbiAgICAgIGF2ZzogbnVtYmVyLFxyXG4gICAgICBleHRyYTogc3RyaW5nXHJcbiAgICApID0+IHtcclxuICAgICAgY29uc3Qgc3R5bGUgPSBgYm9yZGVyLWxlZnQ6IDRweCBzb2xpZCAke2NvbG9yfTsgcGFkZGluZzogMnB4IDAgMnB4IDEwcHg7IG1hcmdpbjogMnB4IDAgMnB4IDA7IGZvbnQtc2l6ZTogMTRweDsgY29sb3I6ICNmZmY7IGJhY2tncm91bmQ6IG5vbmU7IGZvbnQtd2VpZ2h0OiBub3JtYWw7YDtcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgYCVjJHtlbW9qaX0gJHtvcGVyYXRpb259ICAtICAke2F2Z31tcyAobcOpZGlhKSAgJHtleHRyYX1gLnRyaW0oKSxcclxuICAgICAgICBzdHlsZVxyXG4gICAgICApO1xyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoY3JpdGljYWxPcGVyYXRpb25zLmxlbmd0aCA+IDApIHtcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgJyVj8J+UtCBDUsONVElDQVMgKCA+IDIwMDBtcyknLFxyXG4gICAgICAgICdjb2xvcjogI2ZmZjsgZm9udC1zaXplOiAxNHB4OyBmb250LXdlaWdodDogYm9sZDsgbWFyZ2luLXRvcDogMTBweDsnXHJcbiAgICAgICk7XHJcbiAgICAgIGNyaXRpY2FsT3BlcmF0aW9ucy5mb3JFYWNoKChbb3BlcmF0aW9uLCBzdGF0c10pID0+IHtcclxuICAgICAgICBjb25zdCBhdmcgPSBNYXRoLnJvdW5kKHN0YXRzLnRvdGFsVGltZSAvIHN0YXRzLmNvdW50KTtcclxuICAgICAgICBjb25zdCB7IGVtb2ppIH0gPSB0aGlzLmdldFBlcmZvcm1hbmNlU3RhdHVzKFxyXG4gICAgICAgICAgYXZnLFxyXG4gICAgICAgICAgc3RhdHMuY3VzdG9tVGhyZXNob2xkcyxcclxuICAgICAgICAgIG9wZXJhdGlvblxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcHJpbnRCbG9jaygnI2M1MzAzMCcsIGVtb2ppLCBvcGVyYXRpb24sIGF2ZywgJ3wgb3RpbWl6YXIgdXJnZW50ZScpO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoc2xvd09wZXJhdGlvbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAnJWPwn5+hIExFTlRBUyAoNTAwbXMgLSAyMDAwbXMpJyxcclxuICAgICAgICAnY29sb3I6ICNmZmY7IGZvbnQtc2l6ZTogMTRweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IG1hcmdpbi10b3A6IDEwcHg7J1xyXG4gICAgICApO1xyXG4gICAgICBzbG93T3BlcmF0aW9ucy5mb3JFYWNoKChbb3BlcmF0aW9uLCBzdGF0c10pID0+IHtcclxuICAgICAgICBjb25zdCBhdmcgPSBNYXRoLnJvdW5kKHN0YXRzLnRvdGFsVGltZSAvIHN0YXRzLmNvdW50KTtcclxuICAgICAgICBjb25zdCB7IGVtb2ppIH0gPSB0aGlzLmdldFBlcmZvcm1hbmNlU3RhdHVzKFxyXG4gICAgICAgICAgYXZnLFxyXG4gICAgICAgICAgc3RhdHMuY3VzdG9tVGhyZXNob2xkcyxcclxuICAgICAgICAgIG9wZXJhdGlvblxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcHJpbnRCbG9jaygnI2I3NzkxZicsIGVtb2ppLCBvcGVyYXRpb24sIGF2ZywgJ3wgcG9kZSBzZXIgbWVsaG9yYWRhJyk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChmYXN0T3BlcmF0aW9ucy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICclY/Cfn6IgUsOBUElEQVMgKCA8IDUwMG1zKScsXHJcbiAgICAgICAgJ2NvbG9yOiAjZmZmOyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBtYXJnaW4tdG9wOiAxMHB4OydcclxuICAgICAgKTtcclxuICAgICAgZmFzdE9wZXJhdGlvbnMuZm9yRWFjaCgoW29wZXJhdGlvbiwgc3RhdHNdKSA9PiB7XHJcbiAgICAgICAgY29uc3QgYXZnID0gTWF0aC5yb3VuZChzdGF0cy50b3RhbFRpbWUgLyBzdGF0cy5jb3VudCk7XHJcbiAgICAgICAgY29uc3QgeyBlbW9qaSB9ID0gdGhpcy5nZXRQZXJmb3JtYW5jZVN0YXR1cyhcclxuICAgICAgICAgIGF2ZyxcclxuICAgICAgICAgIHN0YXRzLmN1c3RvbVRocmVzaG9sZHMsXHJcbiAgICAgICAgICBvcGVyYXRpb25cclxuICAgICAgICApO1xyXG4gICAgICAgIHByaW50QmxvY2soJyMzOGExNjknLCBlbW9qaSwgb3BlcmF0aW9uLCBhdmcsICd8IGV4Y2VsZW50ZScpO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWNvbWVuZGHDp8O1ZXNcclxuICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAnJWNSZWNvbWVuZGHDp8O1ZXM6JyxcclxuICAgICAgJ2NvbG9yOiAjZmZmOyBmb250LXNpemU6IDEzcHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBtYXJnaW4tdG9wOiAxNHB4OyBwYWRkaW5nOiAycHggMCAycHggMDsnXHJcbiAgICApO1xyXG4gICAgaWYgKGNyaXRpY2FsT3BlcmF0aW9ucy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICclY+KAoiBQcmlvcml6ZSBhIG90aW1pemHDp8OjbyBkYXMgb3BlcmHDp8O1ZXMgY3LDrXRpY2FzLicsXHJcbiAgICAgICAgJ2NvbG9yOiAjZmZmOyBmb250LXNpemU6IDEzcHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7J1xyXG4gICAgICApO1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAnJWPigKIgQ29uc2lkZXJlIGltcGxlbWVudGFyIGNhY2hlIG91IG90aW1pemFyIGNvbnN1bHRhcyBTUUwgcGFyYSBlc3NhcyBvcGVyYcOnw7Vlcy4nLFxyXG4gICAgICAgICdjb2xvcjogI2ZmZjsgZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogbm9ybWFsOydcclxuICAgICAgKTtcclxuICAgIH1cclxuICAgIGlmIChzbG93T3BlcmF0aW9ucy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICclY+KAoiBPcGVyYcOnw7VlcyBsZW50YXMgcG9kZW0gc2UgYmVuZWZpY2lhciBkZSDDrW5kaWNlcyBubyBiYW5jbyBkZSBkYWRvcy4nLFxyXG4gICAgICAgICdjb2xvcjogI2ZmZjsgZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogbm9ybWFsOydcclxuICAgICAgKTtcclxuICAgIH1cclxuICAgIGlmIChjcml0aWNhbE9wZXJhdGlvbnMubGVuZ3RoID09PSAwICYmIHNsb3dPcGVyYXRpb25zLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAnJWPigKIgVG9kYXMgYXMgb3BlcmHDp8O1ZXMgZXN0w6NvIGNvbSBwZXJmb3JtYW5jZSBleGNlbGVudGUhJyxcclxuICAgICAgICAnY29sb3I6ICNmZmY7IGZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsnXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2NvcmVcclxuICAgIGNvbnN0IHRvdGFsT3BlcmF0aW9ucyA9IHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LnNpemU7XHJcbiAgICBjb25zdCBmYXN0Q291bnQgPSBmYXN0T3BlcmF0aW9ucy5sZW5ndGg7XHJcbiAgICBjb25zdCBwZXJmb3JtYW5jZVNjb3JlID1cclxuICAgICAgdG90YWxPcGVyYXRpb25zID4gMFxyXG4gICAgICAgID8gTWF0aC5yb3VuZCgoZmFzdENvdW50IC8gdG90YWxPcGVyYXRpb25zKSAqIDEwMClcclxuICAgICAgICA6IDEwMDtcclxuICAgIGxldCBzY29yZUNvbG9yID1cclxuICAgICAgcGVyZm9ybWFuY2VTY29yZSA+PSA4MFxyXG4gICAgICAgID8gJyMzOGExNjknXHJcbiAgICAgICAgOiBwZXJmb3JtYW5jZVNjb3JlID49IDYwXHJcbiAgICAgICAgPyAnI2Y2ZTA1ZSdcclxuICAgICAgICA6ICcjYzUzMDMwJztcclxuICAgIGxldCBzY29yZU1zZyA9XHJcbiAgICAgIHBlcmZvcm1hbmNlU2NvcmUgPj0gODBcclxuICAgICAgICA/ICdFeGNlbGVudGUhIEEgbWFpb3JpYSBkYXMgb3BlcmHDp8O1ZXMgZXN0w6EgcGVyZm9ybWFuZG8gYmVtLidcclxuICAgICAgICA6IHBlcmZvcm1hbmNlU2NvcmUgPj0gNjBcclxuICAgICAgICA/ICdNw6lkaW8uIEjDoSBlc3Bhw6dvIHBhcmEgbWVsaG9yaWFzIGRlIHBlcmZvcm1hbmNlLidcclxuICAgICAgICA6ICdDcsOtdGljby4gTXVpdGFzIG9wZXJhw6fDtWVzIHByZWNpc2FtIGRlIG90aW1pemHDp8OjbyB1cmdlbnRlLic7XHJcbiAgICBjb25zb2xlLmxvZyhcclxuICAgICAgYCVjU2NvcmUgZGUgcGVyZm9ybWFuY2U6ICR7cGVyZm9ybWFuY2VTY29yZX0lYCxcclxuICAgICAgYGNvbG9yOiAjZmZmOyBiYWNrZ3JvdW5kOiAke3Njb3JlQ29sb3J9OyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBtYXJnaW4tdG9wOiAxMHB4OyBwYWRkaW5nOiAycHggOHB4OyBib3JkZXItcmFkaXVzOiAzcHg7YFxyXG4gICAgKTtcclxuICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICBgJWMke3Njb3JlTXNnfWAsXHJcbiAgICAgIGBjb2xvcjogI2ZmZjsgZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogbm9ybWFsOyBtYXJnaW4tYm90dG9tOiA4cHg7YFxyXG4gICAgKTtcclxuICAgIGNvbnNvbGUubG9nKCcnKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfk4sgQ2F0ZWdvcml6YSBvcGVyYcOnw7VlcyBwb3IgcGVyZm9ybWFuY2VcclxuICAgKiBAcmV0dXJucyBPYmpldG8gY29tIGFycmF5cyBkZSBvcGVyYcOnw7VlcyBjYXRlZ29yaXphZGFzXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjYXRlZ29yaXplT3BlcmF0aW9ucygpIHtcclxuICAgIGNvbnN0IGNyaXRpY2FsT3BlcmF0aW9ucyA9IEFycmF5LmZyb20oXHJcbiAgICAgIHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LmVudHJpZXMoKVxyXG4gICAgKS5maWx0ZXIoKFtfLCBzdGF0c10pID0+IHN0YXRzLnRvdGFsVGltZSAvIHN0YXRzLmNvdW50ID4gMjAwMCk7XHJcblxyXG4gICAgY29uc3Qgc2xvd09wZXJhdGlvbnMgPSBBcnJheS5mcm9tKHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LmVudHJpZXMoKSkuZmlsdGVyKFxyXG4gICAgICAoW18sIHN0YXRzXSkgPT4ge1xyXG4gICAgICAgIGNvbnN0IGF2ZyA9IHN0YXRzLnRvdGFsVGltZSAvIHN0YXRzLmNvdW50O1xyXG4gICAgICAgIHJldHVybiBhdmcgPj0gNTAwICYmIGF2ZyA8PSAyMDAwO1xyXG4gICAgICB9XHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IGZhc3RPcGVyYXRpb25zID0gQXJyYXkuZnJvbSh0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5lbnRyaWVzKCkpLmZpbHRlcihcclxuICAgICAgKFtfLCBzdGF0c10pID0+IHN0YXRzLnRvdGFsVGltZSAvIHN0YXRzLmNvdW50IDwgNTAwXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiB7IGNyaXRpY2FsT3BlcmF0aW9ucywgc2xvd09wZXJhdGlvbnMsIGZhc3RPcGVyYXRpb25zIH07XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn5KhIEV4aWJlIHJlY29tZW5kYcOnw7VlcyBiYXNlYWRhcyBuYSBhbsOhbGlzZVxyXG4gICAqIEBwYXJhbSBjcml0aWNhbE9wZXJhdGlvbnMgQXJyYXkgZGUgb3BlcmHDp8O1ZXMgY3LDrXRpY2FzXHJcbiAgICogQHBhcmFtIHNsb3dPcGVyYXRpb25zIEFycmF5IGRlIG9wZXJhw6fDtWVzIGxlbnRhc1xyXG4gICAqL1xyXG4gIHByaXZhdGUgc2hvd1JlY29tbWVuZGF0aW9ucyhcclxuICAgIGNyaXRpY2FsT3BlcmF0aW9uczogYW55W10sXHJcbiAgICBzbG93T3BlcmF0aW9uczogYW55W11cclxuICApOiB2b2lkIHtcclxuICAgIGNvbnNvbGUubG9nKCdSRUNPTUVOREHDh8OVRVM6Jyk7XHJcbiAgICBpZiAoY3JpdGljYWxPcGVyYXRpb25zLmxlbmd0aCA+IDApIHtcclxuICAgICAgY29uc29sZS5sb2coJyAgIFByaW9yaXplIGEgb3RpbWl6YcOnw6NvIGRhcyBvcGVyYcOnw7VlcyBjcsOtdGljYXMuJyk7XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICcgICBDb25zaWRlcmUgaW1wbGVtZW50YXIgY2FjaGUgb3Ugb3RpbWl6YXIgY29uc3VsdGFzIFNRTCBwYXJhIGVzc2FzIG9wZXJhw6fDtWVzLidcclxuICAgICAgKTtcclxuICAgIH1cclxuICAgIGlmIChzbG93T3BlcmF0aW9ucy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICcgICBPcGVyYcOnw7VlcyBsZW50YXMgcG9kZW0gc2UgYmVuZWZpY2lhciBkZSDDrW5kaWNlcyBubyBiYW5jbyBkZSBkYWRvcy4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBpZiAoY3JpdGljYWxPcGVyYXRpb25zLmxlbmd0aCA9PT0gMCAmJiBzbG93T3BlcmF0aW9ucy5sZW5ndGggPT09IDApIHtcclxuICAgICAgY29uc29sZS5sb2coJyAgIFRvZGFzIGFzIG9wZXJhw6fDtWVzIGVzdMOjbyBjb20gcGVyZm9ybWFuY2UgZXhjZWxlbnRlIScpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+TiiBFeGliZSBzY29yZSBkZSBwZXJmb3JtYW5jZVxyXG4gICAqIEBwYXJhbSBmYXN0T3BlcmF0aW9uc0NvdW50IE7Dum1lcm8gZGUgb3BlcmHDp8O1ZXMgcsOhcGlkYXNcclxuICAgKi9cclxuICBwcml2YXRlIHNob3dQZXJmb3JtYW5jZVNjb3JlKGZhc3RPcGVyYXRpb25zQ291bnQ6IG51bWJlcik6IHZvaWQge1xyXG4gICAgY29uc3QgdG90YWxPcGVyYXRpb25zID0gdGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuc2l6ZTtcclxuICAgIGNvbnN0IHBlcmZvcm1hbmNlU2NvcmUgPSBNYXRoLnJvdW5kKFxyXG4gICAgICAoZmFzdE9wZXJhdGlvbnNDb3VudCAvIHRvdGFsT3BlcmF0aW9ucykgKiAxMDBcclxuICAgICk7XHJcbiAgICBjb25zb2xlLmxvZyhgU0NPUkUgREUgUEVSRk9STUFOQ0U6ICR7cGVyZm9ybWFuY2VTY29yZX0lYCk7XHJcbiAgICBpZiAocGVyZm9ybWFuY2VTY29yZSA+PSA4MCkge1xyXG4gICAgICBjb25zb2xlLmxvZygnRXhjZWxlbnRlISBBIG1haW9yaWEgZGFzIG9wZXJhw6fDtWVzIGVzdMOhIHBlcmZvcm1hbmRvIGJlbS4nKTtcclxuICAgIH0gZWxzZSBpZiAocGVyZm9ybWFuY2VTY29yZSA+PSA2MCkge1xyXG4gICAgICBjb25zb2xlLmxvZygnTcOpZGlvLiBIw6EgZXNwYcOnbyBwYXJhIG1lbGhvcmlhcyBkZSBwZXJmb3JtYW5jZS4nKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKCdDcsOtdGljby4gTXVpdGFzIG9wZXJhw6fDtWVzIHByZWNpc2FtIGRlIG90aW1pemHDp8OjbyB1cmdlbnRlLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gPT09PT0gQVBJIFDDmkJMSUNBID09PT09XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfk4ogTcOpdG9kbyBww7pibGljbyBwYXJhIGV4aWJpciByZWxhdMOzcmlvIGRlIHBlcmZvcm1hbmNlXHJcbiAgICogUG9kZSBzZXIgY2hhbWFkbyBubyBjb25zb2xlIGRvIG5hdmVnYWRvciBwYXJhIGFuw6FsaXNlXHJcbiAgICovXHJcbiAgcHVibGljIGdldFBlcmZvcm1hbmNlUmVwb3J0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5zaG93UGVyZm9ybWFuY2VTdW1tYXJ5KCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn4+377iPIENvbnRyb2xhIGNvbnRleHRvIGRlIGV2ZW50byBhdHVhbCAoZXguOiBBcHBJbml0LCBDbGljaylcclxuICAgKi9cclxuICBwdWJsaWMgYmVnaW5FdmVudENvbnRleHQobGFiZWw6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKGxhYmVsKSB7XHJcbiAgICAgIC8vIFNlIG7Do28gaMOhIGNvbnRleHRvIGFiZXJ0bywgaW5pY2lhIHVtYSBub3ZhIGphbmVsYSByYWl6XHJcbiAgICAgIGlmICh0aGlzLmV2ZW50Q29udGV4dFN0YWNrLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgIHRoaXMuY3VycmVudEV2ZW50QmVnaW5BdCA9IERhdGUubm93KCk7XHJcbiAgICAgICAgdGhpcy5maXJzdFRpbWVySW5FdmVudEF0ID0gbnVsbDtcclxuICAgICAgICB0aGlzLmxhc3RUaW1lckFjdGl2aXR5QXQgPSBudWxsO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuZXZlbnRDb250ZXh0U3RhY2sucHVzaChsYWJlbCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgZW5kRXZlbnRDb250ZXh0KCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuZXZlbnRDb250ZXh0U3RhY2subGVuZ3RoID4gMCkge1xyXG4gICAgICB0aGlzLmV2ZW50Q29udGV4dFN0YWNrLnBvcCgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHVibGljIGFzeW5jIHJ1bkluRXZlbnRDb250ZXh0PFQ+KFxyXG4gICAgbGFiZWw6IHN0cmluZyxcclxuICAgIGZuOiAoKSA9PiBQcm9taXNlPFQ+IHwgVFxyXG4gICk6IFByb21pc2U8VD4ge1xyXG4gICAgdGhpcy5iZWdpbkV2ZW50Q29udGV4dChsYWJlbCk7XHJcbiAgICB0cnkge1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBmbigpO1xyXG4gICAgICByZXR1cm4gYXdhaXQgUHJvbWlzZS5yZXNvbHZlKHJlc3VsdCk7XHJcbiAgICB9IGZpbmFsbHkge1xyXG4gICAgICB0aGlzLmVuZEV2ZW50Q29udGV4dCgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+nuSBNw6l0b2RvIHDDumJsaWNvIHBhcmEgbGltcGFyIGRhZG9zIGRlIHBlcmZvcm1hbmNlXHJcbiAgICogw5p0aWwgcGFyYSByZXNldGFyIGVzdGF0w61zdGljYXMgZSBjb21lw6dhciBub3ZhIGFuw6FsaXNlXHJcbiAgICovXHJcbiAgcHVibGljIHJlc2V0UGVyZm9ybWFuY2VEYXRhKCk6IHZvaWQge1xyXG4gICAgdGhpcy5wZXJmb3JtYW5jZVRpbWVycy5jbGVhcigpO1xyXG4gICAgdGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuY2xlYXIoKTtcclxuICAgIHRoaXMuaHR0cFJlcXVlc3RzLmNsZWFyKCk7XHJcblxyXG4gICAgLy8gTWVuc2FnZW0gZXN0aWxpemFkYSBkZSBsaW1wZXphXHJcbiAgICBjb25zb2xlLmxvZyhcclxuICAgICAgJyVj8J+nuSBbQ0xFQU5VUF0gRGFkb3MgZGUgcGVyZm9ybWFuY2UgbGltcG9zJyxcclxuICAgICAgJ2NvbG9yOiAjZmZmOyBiYWNrZ3JvdW5kOiAjNDMyNDhiZmY7IGZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJvcmRlci1yYWRpdXM6IDRweDsgcGFkZGluZzogNHB4IDEycHg7IG1hcmdpbjogNnB4IDA7J1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIOKPsCBDb25maWd1cmEgbyBkZWxheSBwYXJhIHJlbGF0w7NyaW8gcG9yIGluYXRpdmlkYWRlXHJcbiAgICogQHBhcmFtIHNlY29uZHMgTsO6bWVybyBkZSBzZWd1bmRvcyBkZSBpbmF0aXZpZGFkZSBwYXJhIG1vc3RyYXIgcmVsYXTDs3Jpb1xyXG4gICAqL1xyXG4gIHB1YmxpYyBzZXRJbmFjdGl2aXR5RGVsYXkoc2Vjb25kczogbnVtYmVyKTogdm9pZCB7XHJcbiAgICAvLyBEZXNhYmlsaXRhZG9cclxuICAgIGNvbnNvbGUubG9nKCfij7AgUmVsYXTDs3JpbyBwb3IgaW5hdGl2aWRhZGUgZXN0w6EgZGVzYWJpbGl0YWRvLicpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+UhyBEZXNhYmlsaXRhIHJlbGF0w7NyaW8gYXV0b23DoXRpY28gcG9yIGluYXRpdmlkYWRlXHJcbiAgICovXHJcbiAgcHVibGljIGRpc2FibGVJbmFjdGl2aXR5UmVwb3J0KCk6IHZvaWQge1xyXG4gICAgLy8gRGVzYWJpbGl0YWRvXHJcbiAgICBjb25zb2xlLmxvZygn8J+UhyBSZWxhdMOzcmlvIHBvciBpbmF0aXZpZGFkZSBqw6EgZXN0w6EgZGVzYWJpbGl0YWRvJyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDimpnvuI8gQ29uZmlndXJhIG8gdGhyZXNob2xkIHBhcmEgcmVsYXTDs3JpbyBhdXRvbcOhdGljb1xyXG4gICAqIEBwYXJhbSB0aHJlc2hvbGQgTsO6bWVybyBkZSBvcGVyYcOnw7VlcyBwYXJhIG1vc3RyYXIgcmVsYXTDs3JpbyBhdXRvbWF0aWNhbWVudGVcclxuICAgKi9cclxuICBwdWJsaWMgc2V0QXV0b1JlcG9ydFRocmVzaG9sZCh0aHJlc2hvbGQ6IG51bWJlcik6IHZvaWQge1xyXG4gICAgLy8gRGVzYWJpbGl0YWRvXHJcbiAgICBjb25zb2xlLmxvZygn4pqZ77iPIFRocmVzaG9sZCBwYXJhIHJlbGF0w7NyaW8gYXV0b23DoXRpY28gZXN0w6EgZGVzYWJpbGl0YWRvLicpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+UhyBEZXNhYmlsaXRhIHJlbGF0w7NyaW8gYXV0b23DoXRpY29cclxuICAgKi9cclxuICBwdWJsaWMgZGlzYWJsZUF1dG9SZXBvcnQoKTogdm9pZCB7XHJcbiAgICAvLyBEZXNhYmlsaXRhZG9cclxuICAgIGNvbnNvbGUubG9nKCfwn5SHIFJlbGF0w7NyaW8gYXV0b23DoXRpY28gZGVzYWJpbGl0YWRvJyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn5OIIE9idMOpbSBlc3RhdMOtc3RpY2FzIHJlc3VtaWRhcyBzZW0gZXhpYmlyIG5vIGNvbnNvbGVcclxuICAgKiBAcmV0dXJucyBPYmpldG8gY29tIGVzdGF0w61zdGljYXMgZGUgcGVyZm9ybWFuY2VcclxuICAgKi9cclxuICBwdWJsaWMgZ2V0U3RhdGlzdGljcygpOiB7XHJcbiAgICB0b3RhbE9wZXJhdGlvbnM6IG51bWJlcjtcclxuICAgIGF2ZXJhZ2VUaW1lOiBudW1iZXI7XHJcbiAgICBmYXN0T3BlcmF0aW9uczogbnVtYmVyO1xyXG4gICAgc2xvd09wZXJhdGlvbnM6IG51bWJlcjtcclxuICAgIGNyaXRpY2FsT3BlcmF0aW9uczogbnVtYmVyO1xyXG4gICAgcGVyZm9ybWFuY2VTY29yZTogbnVtYmVyO1xyXG4gIH0ge1xyXG4gICAgY29uc3QgeyBjcml0aWNhbE9wZXJhdGlvbnMsIHNsb3dPcGVyYXRpb25zLCBmYXN0T3BlcmF0aW9ucyB9ID1cclxuICAgICAgdGhpcy5jYXRlZ29yaXplT3BlcmF0aW9ucygpO1xyXG4gICAgY29uc3QgdG90YWxPcGVyYXRpb25zID0gdGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuc2l6ZTtcclxuXHJcbiAgICBsZXQgdG90YWxUaW1lID0gMDtcclxuICAgIGxldCB0b3RhbENvdW50ID0gMDtcclxuXHJcbiAgICB0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5mb3JFYWNoKChzdGF0cykgPT4ge1xyXG4gICAgICB0b3RhbFRpbWUgKz0gc3RhdHMudG90YWxUaW1lO1xyXG4gICAgICB0b3RhbENvdW50ICs9IHN0YXRzLmNvdW50O1xyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgYXZlcmFnZVRpbWUgPSB0b3RhbENvdW50ID4gMCA/IE1hdGgucm91bmQodG90YWxUaW1lIC8gdG90YWxDb3VudCkgOiAwO1xyXG4gICAgY29uc3QgcGVyZm9ybWFuY2VTY29yZSA9XHJcbiAgICAgIHRvdGFsT3BlcmF0aW9ucyA+IDBcclxuICAgICAgICA/IE1hdGgucm91bmQoKGZhc3RPcGVyYXRpb25zLmxlbmd0aCAvIHRvdGFsT3BlcmF0aW9ucykgKiAxMDApXHJcbiAgICAgICAgOiAxMDA7XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgdG90YWxPcGVyYXRpb25zLFxyXG4gICAgICBhdmVyYWdlVGltZSxcclxuICAgICAgZmFzdE9wZXJhdGlvbnM6IGZhc3RPcGVyYXRpb25zLmxlbmd0aCxcclxuICAgICAgc2xvd09wZXJhdGlvbnM6IHNsb3dPcGVyYXRpb25zLmxlbmd0aCxcclxuICAgICAgY3JpdGljYWxPcGVyYXRpb25zOiBjcml0aWNhbE9wZXJhdGlvbnMubGVuZ3RoLFxyXG4gICAgICBwZXJmb3JtYW5jZVNjb3JlLFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfjq8gT2J0w6ltIGRhZG9zIGRlIHVtYSBvcGVyYcOnw6NvIGVzcGVjw61maWNhXHJcbiAgICogQHBhcmFtIG9wZXJhdGlvbk5hbWUgTm9tZSBkYSBvcGVyYcOnw6NvXHJcbiAgICogQHJldHVybnMgRXN0YXTDrXN0aWNhcyBkYSBvcGVyYcOnw6NvIG91IG51bGwgc2UgbsOjbyBlbmNvbnRyYWRhXHJcbiAgICovXHJcbiAgcHVibGljIGdldE9wZXJhdGlvblN0YXRzKFxyXG4gICAgb3BlcmF0aW9uTmFtZTogc3RyaW5nXHJcbiAgKTogKFBlcmZvcm1hbmNlU3RhdHMgJiB7IGh0dHBDYWxsczogc3RyaW5nW10gfSkgfCBudWxsIHtcclxuICAgIGNvbnN0IGJhc2VTdGF0cyA9IHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LmdldChvcGVyYXRpb25OYW1lKTtcclxuICAgIGlmICghYmFzZVN0YXRzKSByZXR1cm4gbnVsbDtcclxuXHJcbiAgICAvLyBFeHRyYWkgbm9tZXMgZGFzIHJlcXVpc2nDp8O1ZXMgSFRUUCBjb21vIGFycmF5IGRlIHN0cmluZ3NcclxuICAgIGNvbnN0IGh0dHBSZXF1ZXN0RW50cnkgPSB0aGlzLmh0dHBSZXF1ZXN0cy5nZXQob3BlcmF0aW9uTmFtZSk7XHJcbiAgICBjb25zdCBodHRwQ2FsbHM6IHN0cmluZ1tdID0gaHR0cFJlcXVlc3RFbnRyeSA/IFtvcGVyYXRpb25OYW1lXSA6IFtdO1xyXG4gICAgcmV0dXJuIHsgLi4uYmFzZVN0YXRzLCBodHRwQ2FsbHMgfTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfk4sgTGlzdGEgdG9kYXMgYXMgb3BlcmHDp8O1ZXMgbW9uaXRvcmFkYXNcclxuICAgKiBAcmV0dXJucyBBcnJheSBjb20gbm9tZXMgZGFzIG9wZXJhw6fDtWVzXHJcbiAgICovXHJcbiAgcHVibGljIGdldE1vbml0b3JlZE9wZXJhdGlvbnMoKTogc3RyaW5nW10ge1xyXG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkua2V5cygpKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCflIQgVmVyaWZpY2Egc2UgaMOhIHRpbWVycyBhdGl2b3NcclxuICAgKiBAcmV0dXJucyB0cnVlIHNlIGjDoSB0aW1lcnMgZW0gZXhlY3XDp8Ojb1xyXG4gICAqL1xyXG4gIHB1YmxpYyBoYXNBY3RpdmVUaW1lcnMoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy50aW1lclN0YWNrLmxlbmd0aCA+IDA7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn5eR77iPIExpbXBhIGFwZW5hcyBvcyB0aW1lcnMgYXRpdm9zIChuw6NvIGFzIGVzdGF0w61zdGljYXMpXHJcbiAgICovXHJcbiAgcHVibGljIGNsZWFyQWN0aXZlVGltZXJzKCk6IHZvaWQge1xyXG4gICAgdGhpcy5wZXJmb3JtYW5jZVRpbWVycy5jbGVhcigpO1xyXG4gICAgdGhpcy50aW1lclN0YWNrID0gW107XHJcbiAgICB0aGlzLmZ1bmN0aW9uQ29udGV4dFN0YWNrID0gW107XHJcbiAgICBjb25zb2xlLmxvZyhcclxuICAgICAgJyVj8J+Xke+4jyBbQ0xFQU5VUF0gVGltZXJzIGF0aXZvcyBsaW1wb3MnLFxyXG4gICAgICAnY29sb3I6ICNmZmY7IGJhY2tncm91bmQ6ICMyMzI3MmY7IGZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJvcmRlci1yYWRpdXM6IDRweDsgcGFkZGluZzogNHB4IDEycHg7IG1hcmdpbjogNnB4IDA7J1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vID09PT09IEFVVE/igJFJTlNUUlVNRU5UQcOHw4NPIChzZW0gZGVjb3JhdG9ycykgPT09PT1cclxuICAvKipcclxuICAgKiDwn5SMIEluc3RydW1lbnRhIHRvZGFzIGFzIGZ1bsOnw7VlcyBww7pibGljYXMgZGUgdW0gb2JqZXRvL2luc3TDom5jaWEgc2VtIGFsdGVyYXIgYXNzaW5hdHVyYVxyXG4gICAqIEBwYXJhbSBvYmogT2JqZXRvIG91IGluc3TDom5jaWEgYSBpbnN0cnVtZW50YXJcclxuICAgKiBAcGFyYW0gb3B0aW9ucyBGaWx0cm9zIGUgYWp1c3RlcyBkZSBub21lXHJcbiAgICovXHJcbiAgcHVibGljIGluc3RydW1lbnRPYmplY3Qob2JqOiBhbnksIG9wdGlvbnM/OiBJbnN0cnVtZW50T3B0aW9ucyk6IHZvaWQge1xyXG4gICAgaWYgKCFvYmogfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHJldHVybjtcclxuICAgIGNvbnN0IG9wdDogSW5zdHJ1bWVudE9wdGlvbnMgPSB7XHJcbiAgICAgIHByZXNlcnZlVG9TdHJpbmc6IHRydWUsXHJcbiAgICAgIC4uLm9wdGlvbnMsXHJcbiAgICB9O1xyXG5cclxuICAgIGNvbnN0IHNob3VsZEluY2x1ZGUgPSAobmFtZTogc3RyaW5nKSA9PiB7XHJcbiAgICAgIGNvbnN0IGluYyA9IG9wdC5pbmNsdWRlO1xyXG4gICAgICBjb25zdCBleGMgPSBvcHQuZXhjbHVkZTtcclxuICAgICAgY29uc3QgbWF0Y2ggPSAocDogc3RyaW5nIHwgUmVnRXhwKSA9PlxyXG4gICAgICAgIHR5cGVvZiBwID09PSAnc3RyaW5nJyA/IG5hbWUuaW5jbHVkZXMocCkgOiBwLnRlc3QobmFtZSk7XHJcbiAgICAgIGNvbnN0IG9rSW5jID0gIWluYyB8fCBpbmMuc29tZShtYXRjaCk7XHJcbiAgICAgIGNvbnN0IG9rRXhjID0gZXhjID8gIWV4Yy5zb21lKG1hdGNoKSA6IHRydWU7XHJcbiAgICAgIHJldHVybiBva0luYyAmJiBva0V4YztcclxuICAgIH07XHJcblxyXG4gICAgY29uc3QgaW5zdHJ1bWVudFByb3AgPSAodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBwYXRoOiBzdHJpbmdbXSkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHZhbHVlID0gdGFyZ2V0W2tleV07XHJcbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ2Z1bmN0aW9uJykgcmV0dXJuO1xyXG4gICAgICAgIGNvbnN0IG9yaWdpbmFsOiBGdW5jdGlvbiA9IHZhbHVlO1xyXG4gICAgICAgIGlmICgob3JpZ2luYWwgYXMgYW55KS5fX3BtX2luc3RydW1lbnRlZCkgcmV0dXJuO1xyXG5cclxuICAgICAgICBpZiAoIXNob3VsZEluY2x1ZGUoa2V5KSkgcmV0dXJuO1xyXG5cclxuICAgICAgICBjb25zdCBvcEJhc2UgPSBrZXk7XHJcbiAgICAgICAgY29uc3Qgb3BOYW1lID0gb3B0Lm5hbWVUcmFuc2Zvcm1cclxuICAgICAgICAgID8gb3B0Lm5hbWVUcmFuc2Zvcm0ob3BCYXNlLCBwYXRoKVxyXG4gICAgICAgICAgOiBvcEJhc2U7XHJcbiAgICAgICAgY29uc3Qgd3JhcHBlZCA9IHRoaXMuY3JlYXRlV3JhcHBlcihcclxuICAgICAgICAgIG9yaWdpbmFsLFxyXG4gICAgICAgICAgb3BOYW1lLFxyXG4gICAgICAgICAgb3B0LnByZXNlcnZlVG9TdHJpbmchXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gU29tYnJhIG5vIG9iamV0byAobsOjbyBhbHRlcmEgcHJvdG90eXBlIGdsb2JhbClcclxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGFyZ2V0LCBrZXksIHtcclxuICAgICAgICAgIHZhbHVlOiB3cmFwcGVkLFxyXG4gICAgICAgICAgd3JpdGFibGU6IHRydWUsXHJcbiAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0gY2F0Y2gge31cclxuICAgIH07XHJcblxyXG4gICAgLy8gSW5zdHJ1bWVudGEgcHLDs3ByaWFzIHByb3ByaWVkYWRlc1xyXG4gICAgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMob2JqKS5mb3JFYWNoKChrKSA9PiBpbnN0cnVtZW50UHJvcChvYmosIGssIFtrXSkpO1xyXG5cclxuICAgIC8vIEluc3RydW1lbnRhIG3DqXRvZG9zIGRvIHByb3RvdHlwZSAoc29icmVzY3JldmVuZG8gbm8gaW5zdGFuY2UpXHJcbiAgICBjb25zdCBwcm90byA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihvYmopO1xyXG4gICAgaWYgKHByb3RvICYmIHByb3RvICE9PSBPYmplY3QucHJvdG90eXBlKSB7XHJcbiAgICAgIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHByb3RvKVxyXG4gICAgICAgIC5maWx0ZXIoKGspID0+IGsgIT09ICdjb25zdHJ1Y3RvcicpXHJcbiAgICAgICAgLmZvckVhY2goKGspID0+IGluc3RydW1lbnRQcm9wKG9iaiwgaywgW2tdKSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn4yQIEluc3RydW1lbnRhIGZ1bsOnw7VlcyBlbSB1bSBuYW1lc3BhY2UgKGV4Ljogd2luZG93KSBjb20gZmlsdHJvcyBlIHByb2Z1bmRpZGFkZVxyXG4gICAqIEBwYXJhbSByb290IE9iamV0byByYWl6IChleC46IHdpbmRvdylcclxuICAgKiBAcGFyYW0gb3B0aW9ucyBpbmNsdWRlL2V4Y2x1ZGUsIG5hbWVUcmFuc2Zvcm0sIHByZXNlcnZlVG9TdHJpbmcsIG1heERlcHRoXHJcbiAgICovXHJcbiAgcHVibGljIGluc3RydW1lbnROYW1lc3BhY2Uocm9vdDogYW55LCBvcHRpb25zPzogSW5zdHJ1bWVudE9wdGlvbnMpOiB2b2lkIHtcclxuICAgIGlmICghcm9vdCB8fCB0eXBlb2Ygcm9vdCAhPT0gJ29iamVjdCcpIHJldHVybjtcclxuICAgIGNvbnN0IG9wdDogSW5zdHJ1bWVudE9wdGlvbnMgPSB7XHJcbiAgICAgIHByZXNlcnZlVG9TdHJpbmc6IHRydWUsXHJcbiAgICAgIG1heERlcHRoOiAyLFxyXG4gICAgICAuLi5vcHRpb25zLFxyXG4gICAgfTtcclxuXHJcbiAgICBjb25zdCBzaG91bGRJbmNsdWRlID0gKG5hbWU6IHN0cmluZykgPT4ge1xyXG4gICAgICBjb25zdCBpbmMgPSBvcHQuaW5jbHVkZTtcclxuICAgICAgY29uc3QgZXhjID0gb3B0LmV4Y2x1ZGU7XHJcbiAgICAgIGNvbnN0IG1hdGNoID0gKHA6IHN0cmluZyB8IFJlZ0V4cCkgPT5cclxuICAgICAgICB0eXBlb2YgcCA9PT0gJ3N0cmluZycgPyBuYW1lLmluY2x1ZGVzKHApIDogcC50ZXN0KG5hbWUpO1xyXG4gICAgICBjb25zdCBva0luYyA9ICFpbmMgfHwgaW5jLnNvbWUobWF0Y2gpO1xyXG4gICAgICBjb25zdCBva0V4YyA9IGV4YyA/ICFleGMuc29tZShtYXRjaCkgOiB0cnVlO1xyXG4gICAgICByZXR1cm4gb2tJbmMgJiYgb2tFeGM7XHJcbiAgICB9O1xyXG5cclxuICAgIGNvbnN0IHZpc2l0ZWQgPSBuZXcgV2Vha1NldDxvYmplY3Q+KCk7XHJcblxyXG4gICAgY29uc3Qgd2FsayA9IChub2RlOiBhbnksIGRlcHRoOiBudW1iZXIsIHBhdGg6IHN0cmluZ1tdKSA9PiB7XHJcbiAgICAgIGlmICghbm9kZSB8fCB0eXBlb2Ygbm9kZSAhPT0gJ29iamVjdCcpIHJldHVybjtcclxuICAgICAgaWYgKHZpc2l0ZWQuaGFzKG5vZGUpKSByZXR1cm47XHJcbiAgICAgIHZpc2l0ZWQuYWRkKG5vZGUpO1xyXG5cclxuICAgICAgaWYgKGRlcHRoID4gKG9wdC5tYXhEZXB0aCB8fCAyKSkgcmV0dXJuO1xyXG5cclxuICAgICAgY29uc3Qga2V5czogc3RyaW5nW10gPSBbXTtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBrZXlzLnB1c2goLi4uT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMobm9kZSkpO1xyXG4gICAgICB9IGNhdGNoIHt9XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBrZXlzKSB7XHJcbiAgICAgICAgbGV0IHZhbHVlOiBhbnk7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIHZhbHVlID0gKG5vZGUgYXMgYW55KVtrZXldO1xyXG4gICAgICAgIH0gY2F0Y2gge1xyXG4gICAgICAgICAgY29udGludWU7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgICAgICBjb25zdCBvcmlnaW5hbDogRnVuY3Rpb24gPSB2YWx1ZTtcclxuICAgICAgICAgIGlmICgob3JpZ2luYWwgYXMgYW55KS5fX3BtX2luc3RydW1lbnRlZCkgY29udGludWU7XHJcbiAgICAgICAgICBpZiAoIXNob3VsZEluY2x1ZGUoa2V5KSkgY29udGludWU7XHJcblxyXG4gICAgICAgICAgY29uc3Qgb3BCYXNlID0ga2V5O1xyXG4gICAgICAgICAgY29uc3Qgb3BOYW1lID0gb3B0Lm5hbWVUcmFuc2Zvcm1cclxuICAgICAgICAgICAgPyBvcHQubmFtZVRyYW5zZm9ybShvcEJhc2UsIHBhdGguY29uY2F0KGtleSkpXHJcbiAgICAgICAgICAgIDogb3BCYXNlO1xyXG4gICAgICAgICAgY29uc3Qgd3JhcHBlZCA9IHRoaXMuY3JlYXRlV3JhcHBlcihcclxuICAgICAgICAgICAgb3JpZ2luYWwsXHJcbiAgICAgICAgICAgIG9wTmFtZSxcclxuICAgICAgICAgICAgb3B0LnByZXNlcnZlVG9TdHJpbmchXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgLy8gVGVudGEgc29icmVzY3JldmVyIGZ1bsOnw6NvIG5vIG5hbWVzcGFjZVxyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG5vZGUsIGtleSwge1xyXG4gICAgICAgICAgICAgIHZhbHVlOiB3cmFwcGVkLFxyXG4gICAgICAgICAgICAgIHdyaXRhYmxlOiB0cnVlLFxyXG4gICAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICB9IGNhdGNoIHt9XHJcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlKSB7XHJcbiAgICAgICAgICAvLyBSZWN1cnNlXHJcbiAgICAgICAgICB3YWxrKHZhbHVlLCBkZXB0aCArIDEsIHBhdGguY29uY2F0KGtleSkpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB3YWxrKHJvb3QsIDAsIFtdKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfqp0gRW52b2x2ZSBhIGZ1bsOnw6NvIHNldFNlcnZpY2UodGFyZ2V0LnNldFNlcnZpY2UpIHBhcmEgaW5zdHJ1bWVudGFyIG8gc2VydmnDp28gcGFzc2Fkb1xyXG4gICAqIEBwYXJhbSB0YXJnZXQgT2JqZXRvIHF1ZSBwb3NzdWkgc2V0U2VydmljZShzZXJ2aWNlKVxyXG4gICAqIEBwYXJhbSBsYWJlbCBSw7N0dWxvIHVzYWRvIG5vIG5vbWUgZGFzIG9wZXJhw6fDtWVzIChleC46IFwicGFja1RlbGFcIilcclxuICAgKiBAcGFyYW0gb3B0aW9ucyBPcMOnw7VlcyBkZSBpbnN0cnVtZW50YcOnw6NvIChuYW1lVHJhbnNmb3JtLCBleGNsdWRlLCBldGMuKVxyXG4gICAqL1xyXG4gIHB1YmxpYyBob29rU2V0U2VydmljZShcclxuICAgIHRhcmdldDogYW55LFxyXG4gICAgbGFiZWw/OiBzdHJpbmcsXHJcbiAgICBvcHRpb25zPzogSW5zdHJ1bWVudE9wdGlvbnNcclxuICApOiB2b2lkIHtcclxuICAgIGlmICghdGFyZ2V0IHx8IHR5cGVvZiB0YXJnZXQgIT09ICdvYmplY3QnKSByZXR1cm47XHJcbiAgICBjb25zdCBmbiA9ICh0YXJnZXQgYXMgYW55KS5zZXRTZXJ2aWNlO1xyXG4gICAgaWYgKHR5cGVvZiBmbiAhPT0gJ2Z1bmN0aW9uJykgcmV0dXJuO1xyXG5cclxuICAgIGNvbnN0IGFscmVhZHlIb29rZWQgPSAoZm4gYXMgYW55KS5fX3BtX3NldHNlcnZpY2VfaG9va2VkO1xyXG4gICAgaWYgKGFscmVhZHlIb29rZWQpIHJldHVybjtcclxuXHJcbiAgICBjb25zdCBvcHQ6IEluc3RydW1lbnRPcHRpb25zID0ge1xyXG4gICAgICBwcmVzZXJ2ZVRvU3RyaW5nOiB0cnVlLFxyXG4gICAgICBleGNsdWRlOiBbJ2NvbnN0cnVjdG9yJ10sXHJcbiAgICAgIC4uLm9wdGlvbnMsXHJcbiAgICB9O1xyXG5cclxuICAgIGNvbnN0IGxhYmVsRmluYWwgPVxyXG4gICAgICBsYWJlbCB8fFxyXG4gICAgICAodGFyZ2V0Py5jb25zdHJ1Y3Rvcj8ubmFtZSA/IFN0cmluZyh0YXJnZXQuY29uc3RydWN0b3IubmFtZSkgOiAnc2VydmljZScpO1xyXG4gICAgLy8gR2FyYW50ZSBxdWUgbyBsYWJlbCAocGFjaykgZW50cmUgbmEgcGF0aFswXSBxdWFuZG8gaG91dmVyIG5hbWVUcmFuc2Zvcm0gY3VzdG9taXphZG9cclxuICAgIGNvbnN0IG5hbWVUcmFuc2Zvcm0gPSBvcHQubmFtZVRyYW5zZm9ybVxyXG4gICAgICA/IChuOiBzdHJpbmcsIHBhdGg/OiBzdHJpbmdbXSkgPT5cclxuICAgICAgICAgIG9wdC5uYW1lVHJhbnNmb3JtIShuLCBbbGFiZWxGaW5hbF0uY29uY2F0KHBhdGggfHwgW10pKVxyXG4gICAgICA6IChuOiBzdHJpbmcpID0+IGAke2xhYmVsRmluYWx9LiR7bn1gO1xyXG5cclxuICAgIGNvbnN0IG9yaWdpbmFsID0gZm4gYXMgRnVuY3Rpb247XHJcbiAgICBjb25zdCBsb2dnZXIgPSB0aGlzO1xyXG4gICAgY29uc3Qgd3JhcHBlZCA9IGZ1bmN0aW9uICh0aGlzOiBhbnksIHNlcnZpY2VJbnN0YW5jZTogYW55LCAuLi5yZXN0OiBhbnlbXSkge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEluc3RydW1lbnRhIG8gcHLDs3ByaW8gb2JqZXRvIGFsdm8gKHBhY2spLCBwb2lzIHPDo28gc2V1cyBtw6l0b2RvcyBxdWUgcXVlcmVtb3MgbWVkaXJcclxuICAgICAgICBjb25zdCBwYWNrT2JqID0gdGhpcyB8fCB0YXJnZXQ7XHJcbiAgICAgICAgaWYgKHBhY2tPYmogJiYgdHlwZW9mIHBhY2tPYmogPT09ICdvYmplY3QnKSB7XHJcbiAgICAgICAgICBjb25zdCBhbHJlYWR5SW5zdHJ1bWVudGVkUGFjayA9IChwYWNrT2JqIGFzIGFueSlcclxuICAgICAgICAgICAgLl9fcG1fcGFja19pbnN0cnVtZW50ZWQ7XHJcbiAgICAgICAgICBpZiAoIWFscmVhZHlJbnN0cnVtZW50ZWRQYWNrKSB7XHJcbiAgICAgICAgICAgIGxvZ2dlci5pbnN0cnVtZW50T2JqZWN0KHBhY2tPYmosIHtcclxuICAgICAgICAgICAgICAuLi5vcHQsXHJcbiAgICAgICAgICAgICAgbmFtZVRyYW5zZm9ybSxcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHBhY2tPYmosICdfX3BtX3BhY2tfaW5zdHJ1bWVudGVkJywge1xyXG4gICAgICAgICAgICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXHJcbiAgICAgICAgICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcclxuICAgICAgICAgICAgICAgIHdyaXRhYmxlOiBmYWxzZSxcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBjYXRjaCB7fVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSBjYXRjaCB7fVxyXG4gICAgICByZXR1cm4gb3JpZ2luYWwuYXBwbHkodGhpcywgW3NlcnZpY2VJbnN0YW5jZSwgLi4ucmVzdF0pO1xyXG4gICAgfSBhcyBGdW5jdGlvbjtcclxuXHJcbiAgICAvLyBtYXJjYSBjb21vIGhvb2thZG8gcGFyYSBldml0YXIgZHVwbGljYcOnw6NvXHJcbiAgICAod3JhcHBlZCBhcyBhbnkpLl9fcG1fc2V0c2VydmljZV9ob29rZWQgPSB0cnVlO1xyXG4gICAgdHJ5IHtcclxuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwgJ3NldFNlcnZpY2UnLCB7XHJcbiAgICAgICAgdmFsdWU6IHdyYXBwZWQsXHJcbiAgICAgICAgd3JpdGFibGU6IHRydWUsXHJcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2gge31cclxuXHJcbiAgICAvLyBJbnN0cnVtZW50YSBpbWVkaWF0YW1lbnRlIG8gcGFjayAoY29icmUgY2Fzb3Mgb25kZSBzZXRTZXJ2aWNlIGrDoSBmb2kgY2hhbWFkbyBhbnRlcyBkbyBob29rKVxyXG4gICAgdHJ5IHtcclxuICAgICAgY29uc3QgcGFja09iaiA9IHRhcmdldDtcclxuICAgICAgY29uc3QgYWxyZWFkeUluc3RydW1lbnRlZFBhY2sgPSAocGFja09iaiBhcyBhbnkpLl9fcG1fcGFja19pbnN0cnVtZW50ZWQ7XHJcbiAgICAgIGlmICghYWxyZWFkeUluc3RydW1lbnRlZFBhY2spIHtcclxuICAgICAgICB0aGlzLmluc3RydW1lbnRPYmplY3QocGFja09iaiwge1xyXG4gICAgICAgICAgLi4ub3B0LFxyXG4gICAgICAgICAgbmFtZVRyYW5zZm9ybSxcclxuICAgICAgICB9KTtcclxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkocGFja09iaiwgJ19fcG1fcGFja19pbnN0cnVtZW50ZWQnLCB7XHJcbiAgICAgICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcclxuICAgICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxyXG4gICAgICAgICAgd3JpdGFibGU6IGZhbHNlLFxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIHt9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn6qdIEhvb2sgZGUgc2V0U2VydmljZSBwYXJhIHbDoXJpb3MgYWx2b3MgZW0gdW1hIMO6bmljYSBjaGFtYWRhXHJcbiAgICogQHBhcmFtIHRhcmdldHMgTWFwYSBkZSBsYWJlbCAtPiBvYmpldG8gcXVlIGNvbnTDqW0gc2V0U2VydmljZVxyXG4gICAqIEBwYXJhbSBvcHRpb25zIE9ww6fDtWVzIGRlIGluc3RydW1lbnRhw6fDo29cclxuICAgKi9cclxuICBwdWJsaWMgaG9va1NldFNlcnZpY2VCdWxrKFxyXG4gICAgdGFyZ2V0czogUmVjb3JkPHN0cmluZywgYW55PixcclxuICAgIG9wdGlvbnM/OiBJbnN0cnVtZW50T3B0aW9uc1xyXG4gICk6IHZvaWQge1xyXG4gICAgaWYgKCF0YXJnZXRzIHx8IHR5cGVvZiB0YXJnZXRzICE9PSAnb2JqZWN0JykgcmV0dXJuO1xyXG4gICAgZm9yIChjb25zdCBbbGFiZWwsIG9ial0gb2YgT2JqZWN0LmVudHJpZXModGFyZ2V0cykpIHtcclxuICAgICAgY29uc3QgaGFzU2V0U2VydmljZSA9ICEhKFxyXG4gICAgICAgIG9iaiAmJiB0eXBlb2YgKG9iaiBhcyBhbnkpLnNldFNlcnZpY2UgPT09ICdmdW5jdGlvbidcclxuICAgICAgKTtcclxuICAgICAgaWYgKGhhc1NldFNlcnZpY2UpIHtcclxuICAgICAgICB0aGlzLmhvb2tTZXRTZXJ2aWNlKG9iaiwgbGFiZWwsIG9wdGlvbnMpO1xyXG4gICAgICB9IGVsc2UgaWYgKG9iaiAmJiB0eXBlb2Ygb2JqID09PSAnb2JqZWN0Jykge1xyXG4gICAgICAgIC8vIEluc3RydW1lbnRhIG9iamV0b3Mgc2VtIHNldFNlcnZpY2UgdXNhbmRvIG8gbGFiZWwgY29tbyBwcmVmaXhvXHJcbiAgICAgICAgY29uc3Qgb3B0ID0geyAuLi5vcHRpb25zIH07XHJcbiAgICAgICAgY29uc3QgbmFtZVRyYW5zZm9ybSA9IG9wdC5uYW1lVHJhbnNmb3JtXHJcbiAgICAgICAgICA/IChuOiBzdHJpbmcsIHBhdGg/OiBzdHJpbmdbXSkgPT5cclxuICAgICAgICAgICAgICBvcHQubmFtZVRyYW5zZm9ybSEobiwgW1N0cmluZyhsYWJlbCldLmNvbmNhdChwYXRoIHx8IFtdKSlcclxuICAgICAgICAgIDogKG46IHN0cmluZykgPT4gYCR7U3RyaW5nKGxhYmVsKX0uJHtufWA7XHJcbiAgICAgICAgdGhpcy5pbnN0cnVtZW50T2JqZWN0KG9iaiwge1xyXG4gICAgICAgICAgLi4ub3B0LFxyXG4gICAgICAgICAgbmFtZVRyYW5zZm9ybSxcclxuICAgICAgICAgIGV4Y2x1ZGU6IFsnY29uc3RydWN0b3InLCAuLi4ob3B0LmV4Y2x1ZGUgfHwgW10pXSxcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+MkCBWYXJyZSB1bSBuYW1lc3BhY2UgZSBhcGxpY2EgaG9vayBlbSBxdWFscXVlciBmdW7Dp8OjbyBzZXRTZXJ2aWNlIGVuY29udHJhZGFcclxuICAgKiBAcGFyYW0gcm9vdCBPYmpldG8gcmFpeiAoZXguOiB3aW5kb3csIG1vZHVsZSBzY29wZSB3cmFwcGVyLCBldGMuKVxyXG4gICAqIEBwYXJhbSBvcHRpb25zIEZpbHRyb3MgZSByZWdyYXMgZGUgbm9tZWHDp8Ojb1xyXG4gICAqL1xyXG4gIHB1YmxpYyBob29rU2V0U2VydmljZU5hbWVzcGFjZShcclxuICAgIHJvb3Q6IGFueSxcclxuICAgIG9wdGlvbnM/OiBIb29rU2V0U2VydmljZU9wdGlvbnNcclxuICApOiB2b2lkIHtcclxuICAgIGlmICghcm9vdCB8fCB0eXBlb2Ygcm9vdCAhPT0gJ29iamVjdCcpIHJldHVybjtcclxuICAgIGNvbnN0IG9wdDogSG9va1NldFNlcnZpY2VPcHRpb25zID0ge1xyXG4gICAgICBwcmVzZXJ2ZVRvU3RyaW5nOiB0cnVlLFxyXG4gICAgICBleGNsdWRlOiBbJ2NvbnN0cnVjdG9yJ10sXHJcbiAgICAgIG1heFdhbGtEZXB0aDogMixcclxuICAgICAgLi4ub3B0aW9ucyxcclxuICAgIH07XHJcblxyXG4gICAgY29uc3Qgc2hvdWxkSW5jbHVkZU9iaiA9IChwYXRoU3RyOiBzdHJpbmcpID0+IHtcclxuICAgICAgY29uc3QgaW5jID0gb3B0LmluY2x1ZGVPYmplY3RzO1xyXG4gICAgICBjb25zdCBleGMgPSBvcHQuZXhjbHVkZU9iamVjdHM7XHJcbiAgICAgIGNvbnN0IG1hdGNoID0gKHA6IHN0cmluZyB8IFJlZ0V4cCkgPT5cclxuICAgICAgICB0eXBlb2YgcCA9PT0gJ3N0cmluZycgPyBwYXRoU3RyLmluY2x1ZGVzKHApIDogcC50ZXN0KHBhdGhTdHIpO1xyXG4gICAgICBjb25zdCBva0luYyA9ICFpbmMgfHwgaW5jLnNvbWUobWF0Y2gpO1xyXG4gICAgICBjb25zdCBva0V4YyA9IGV4YyA/ICFleGMuc29tZShtYXRjaCkgOiB0cnVlO1xyXG4gICAgICByZXR1cm4gb2tJbmMgJiYgb2tFeGM7XHJcbiAgICB9O1xyXG5cclxuICAgIGNvbnN0IHZpc2l0ZWQgPSBuZXcgV2Vha1NldDxvYmplY3Q+KCk7XHJcblxyXG4gICAgY29uc3Qgd2FsayA9IChub2RlOiBhbnksIGRlcHRoOiBudW1iZXIsIHBhdGg6IHN0cmluZ1tdKSA9PiB7XHJcbiAgICAgIGlmICghbm9kZSB8fCB0eXBlb2Ygbm9kZSAhPT0gJ29iamVjdCcpIHJldHVybjtcclxuICAgICAgaWYgKHZpc2l0ZWQuaGFzKG5vZGUpKSByZXR1cm47XHJcbiAgICAgIHZpc2l0ZWQuYWRkKG5vZGUpO1xyXG4gICAgICBpZiAoZGVwdGggPiAob3B0Lm1heFdhbGtEZXB0aCB8fCAyKSkgcmV0dXJuO1xyXG5cclxuICAgICAgY29uc3Qga2V5czogc3RyaW5nW10gPSBbXTtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBrZXlzLnB1c2goLi4uT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMobm9kZSkpO1xyXG4gICAgICB9IGNhdGNoIHt9XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBrZXlzKSB7XHJcbiAgICAgICAgbGV0IHZhbHVlOiBhbnk7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIHZhbHVlID0gKG5vZGUgYXMgYW55KVtrZXldO1xyXG4gICAgICAgIH0gY2F0Y2gge1xyXG4gICAgICAgICAgY29udGludWU7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25zdCBwYXRoTm93ID0gcGF0aC5jb25jYXQoa2V5KTtcclxuICAgICAgICBjb25zdCBwYXRoU3RyID0gcGF0aE5vdy5qb2luKCcuJyk7XHJcblxyXG4gICAgICAgIGlmICh2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSB7XHJcbiAgICAgICAgICAvLyBTZSBvIG9iamV0byB0aXZlciBzZXRTZXJ2aWNlLCBhcGxpY2EgaG9va1xyXG4gICAgICAgICAgY29uc3QgZm4gPSAodmFsdWUgYXMgYW55KS5zZXRTZXJ2aWNlO1xyXG4gICAgICAgICAgaWYgKHR5cGVvZiBmbiA9PT0gJ2Z1bmN0aW9uJyAmJiBzaG91bGRJbmNsdWRlT2JqKHBhdGhTdHIpKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGxhYmVsRnJvbVBhdGggPVxyXG4gICAgICAgICAgICAgIG9wdC5sYWJlbEZyb21QYXRoIHx8ICgocDogc3RyaW5nW10pID0+IHAuam9pbignLicpKTtcclxuICAgICAgICAgICAgdGhpcy5ob29rU2V0U2VydmljZSh2YWx1ZSwgbGFiZWxGcm9tUGF0aChwYXRoTm93KSwgb3B0KTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAvLyBDb250aW51YSBhIHZhcnJlZHVyYVxyXG4gICAgICAgICAgd2Fsayh2YWx1ZSwgZGVwdGggKyAxLCBwYXRoTm93KTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgd2Fsayhyb290LCAwLCBbXSk7XHJcbiAgfVxyXG5cclxuICAvLyA9PT09PSBIZWxwZXJzID09PT09XHJcbiAgLyoqXHJcbiAgICogQ3JpYSB3cmFwcGVyIHF1ZSBpbmljaWEvZW5jZXJyYSB0aW1lciBwcmVzZXJ2YW5kbyBjb250ZXh0byBlIHRvU3RyaW5nKClcclxuICAgKi9cclxuICBwcml2YXRlIGNyZWF0ZVdyYXBwZXIoXHJcbiAgICBvcmlnaW5hbDogRnVuY3Rpb24sXHJcbiAgICBvcE5hbWU6IHN0cmluZyxcclxuICAgIHByZXNlcnZlVG9TdHJpbmc6IGJvb2xlYW5cclxuICApOiBGdW5jdGlvbiB7XHJcbiAgICAvLyBJZGVtcG90w6puY2lhOiByZXV0aWxpemEgd3JhcHBlciBzZSBqw6EgZXhpc3RpclxyXG4gICAgY29uc3QgZXhpc3RpbmcgPSB0aGlzLmluc3RydW1lbnRlZEZucy5nZXQob3JpZ2luYWwpO1xyXG4gICAgaWYgKGV4aXN0aW5nKSByZXR1cm4gZXhpc3Rpbmc7XHJcblxyXG4gICAgY29uc3QgbG9nZ2VyID0gdGhpcztcclxuICAgIGNvbnN0IHdyYXBwZWQgPSBmdW5jdGlvbiAodGhpczogYW55LCAuLi5hcmdzOiBhbnlbXSkge1xyXG4gICAgICAvLyBEZXRlcm1pbmEgbm9tZSBmaW5hbCBjb20gZmFsbGJhY2sgYW8gbm9tZSBkbyBhcnF1aXZvIChwYWNrKSB2aWEgc3RhY2t0cmFjZVxyXG4gICAgICBsZXQgZmluYWxOYW1lID0gb3BOYW1lO1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHBhcnRzID0gU3RyaW5nKG9wTmFtZSkuc3BsaXQoJy4nKTtcclxuICAgICAgICBjb25zdCBtZXRob2ROYW1lID0gcGFydHNbcGFydHMubGVuZ3RoIC0gMV07XHJcbiAgICAgICAgY29uc3QgcHJlZml4ID0gcGFydHMubGVuZ3RoID4gMSA/IHBhcnRzWzBdIDogdW5kZWZpbmVkO1xyXG4gICAgICAgIGlmICghcHJlZml4IHx8IHByZWZpeC50b0xvd2VyQ2FzZSgpID09PSBtZXRob2ROYW1lLnRvTG93ZXJDYXNlKCkpIHtcclxuICAgICAgICAgIGNvbnN0IGZpbGVMYWJlbCA9IGxvZ2dlci5ndWVzc0ZpbGVMYWJlbEZyb21TdGFjaygpO1xyXG4gICAgICAgICAgaWYgKGZpbGVMYWJlbCkge1xyXG4gICAgICAgICAgICBmaW5hbE5hbWUgPSBgJHtmaWxlTGFiZWx9LiR7bWV0aG9kTmFtZX1gO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSBjYXRjaCB7fVxyXG5cclxuICAgICAgLy8gSGVyZGEgbGFiZWwgZG8gZXZlbnRvIGF0aXZvIChqw6EgZ2FyYW50aWRvIHBlbG8gbG9nZ2VyKVxyXG4gICAgICBsb2dnZXIuc3RhcnRUaW1lcihmaW5hbE5hbWUpO1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IG9yaWdpbmFsLmFwcGx5KHRoaXMsIGFyZ3MpO1xyXG4gICAgICAgIGlmIChyZXN1bHQgJiYgdHlwZW9mIChyZXN1bHQgYXMgYW55KS50aGVuID09PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgICAgICAvLyBQcm9taXNlcy9hc3luY1xyXG4gICAgICAgICAgcmV0dXJuIChyZXN1bHQgYXMgUHJvbWlzZTxhbnk+KS5maW5hbGx5KCgpID0+IHtcclxuICAgICAgICAgICAgbG9nZ2VyLmVuZFRpbWVyKGZpbmFsTmFtZSk7XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgbG9nZ2VyLmVuZFRpbWVyKGZpbmFsTmFtZSk7XHJcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgIH1cclxuICAgICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAgIGxvZ2dlci5lbmRUaW1lcihmaW5hbE5hbWUsICdlcnJvJyk7XHJcbiAgICAgICAgdGhyb3cgZTtcclxuICAgICAgfVxyXG4gICAgfSBhcyBGdW5jdGlvbjtcclxuXHJcbiAgICAvLyBNYXJjYSBpbnN0cnVtZW50YWRvXHJcbiAgICAob3JpZ2luYWwgYXMgYW55KS5fX3BtX2luc3RydW1lbnRlZCA9IHRydWU7XHJcbiAgICAod3JhcHBlZCBhcyBhbnkpLl9fcG1faW5zdHJ1bWVudGVkID0gdHJ1ZTtcclxuXHJcbiAgICAvLyBQcmVzZXJ2YSB0b1N0cmluZygpIHBhcmEgY29tcGF0aWJpbGlkYWRlIGNvbSByZWdleFxyXG4gICAgaWYgKHByZXNlcnZlVG9TdHJpbmcpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod3JhcHBlZCwgJ3RvU3RyaW5nJywge1xyXG4gICAgICAgICAgdmFsdWU6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIG9yaWdpbmFsLnRvU3RyaW5nKCk7XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgd3JpdGFibGU6IGZhbHNlLFxyXG4gICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGNhdGNoIHt9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGVudGEgaWd1YWxhciBvIG5vbWUgKG5lbSBzZW1wcmUgw6kgcG9zc8OtdmVsKVxyXG4gICAgdHJ5IHtcclxuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHdyYXBwZWQsICduYW1lJywge1xyXG4gICAgICAgIHZhbHVlOiBvcmlnaW5hbC5uYW1lIHx8IG9wTmFtZSxcclxuICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCB7fVxyXG5cclxuICAgIHRoaXMuaW5zdHJ1bWVudGVkRm5zLnNldChvcmlnaW5hbCwgd3JhcHBlZCk7XHJcbiAgICByZXR1cm4gd3JhcHBlZDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCflI4gVGVudGEgaW5mZXJpciBvIG5vbWUgZG8gYXJxdWl2byAocGFjaykgYSBwYXJ0aXIgZG8gc3RhY2t0cmFjZVxyXG4gICAqIFByZWZlcsOqbmNpYSBwb3Igbm9tZXMgcXVlIGNvbWXDp2FtIGNvbSBcInBhY2tcIlxyXG4gICAqL1xyXG4gIHByaXZhdGUgZ3Vlc3NGaWxlTGFiZWxGcm9tU3RhY2soKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGNvbnN0IGVyciA9IG5ldyBFcnJvcigpO1xyXG4gICAgICBjb25zdCBzdGFjayA9IFN0cmluZygoZXJyIGFzIGFueSkuc3RhY2sgfHwgJycpO1xyXG4gICAgICBjb25zdCBsaW5lcyA9IHN0YWNrLnNwbGl0KCdcXG4nKTtcclxuICAgICAgY29uc3QgY2FuZGlkYXRlczogc3RyaW5nW10gPSBbXTtcclxuICAgICAgZm9yIChjb25zdCBsaW5lIG9mIGxpbmVzKSB7XHJcbiAgICAgICAgY29uc3QgbSA9IGxpbmUubWF0Y2goXHJcbiAgICAgICAgICAvW1xcXFxcXC9dKFtBLVphLXowLTlfLV0rKVxcLig/OnRzfGpzKSg/OjpcXGQrOlxcZCt8XFw/fCQpL1xyXG4gICAgICAgICk7XHJcbiAgICAgICAgaWYgKG0gJiYgbVsxXSkge1xyXG4gICAgICAgICAgY29uc3QgYmFzZSA9IG1bMV07XHJcbiAgICAgICAgICBpZiAoL15wYWNrL2kudGVzdChiYXNlKSkge1xyXG4gICAgICAgICAgICByZXR1cm4gYmFzZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGNhbmRpZGF0ZXMucHVzaChiYXNlKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGNhbmRpZGF0ZXNbMF07XHJcbiAgICB9IGNhdGNoIHtcclxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfkr4gRXhwb3J0YSBkYWRvcyBkZSBwZXJmb3JtYW5jZSBwYXJhIEpTT05cclxuICAgKiBAcmV0dXJucyBTdHJpbmcgSlNPTiBjb20gdG9kb3Mgb3MgZGFkb3NcclxuICAgKi9cclxuICBwdWJsaWMgZXhwb3J0RGF0YSgpOiBzdHJpbmcge1xyXG4gICAgY29uc3QgZGF0YSA9IHtcclxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXHJcbiAgICAgIHNlcnZpY2VOYW1lOiB0aGlzLnNlcnZpY2VOYW1lLFxyXG4gICAgICBzdGF0aXN0aWNzOiB0aGlzLmdldFN0YXRpc3RpY3MoKSxcclxuICAgICAgb3BlcmF0aW9uczogQXJyYXkuZnJvbSh0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5lbnRyaWVzKCkpLm1hcChcclxuICAgICAgICAoW25hbWUsIHN0YXRzXSkgPT4gKHtcclxuICAgICAgICAgIG5hbWUsXHJcbiAgICAgICAgICAuLi5zdGF0cyxcclxuICAgICAgICAgIGF2ZXJhZ2VUaW1lOiBNYXRoLnJvdW5kKHN0YXRzLnRvdGFsVGltZSAvIHN0YXRzLmNvdW50KSxcclxuICAgICAgICB9KVxyXG4gICAgICApLFxyXG4gICAgfTtcclxuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShkYXRhLCBudWxsLCAyKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfjq8gQ2FsY3VsYSB0aHJlc2hvbGRzIGRpbsOibWljb3MgYmFzZWFkb3MgbmEgcXVhbnRpZGFkZSBkZSBleGVjdcOnw7Vlc1xyXG4gICAqIEBwYXJhbSBleGVjdXRpb25Db3VudCBOw7ptZXJvIGRlIGV4ZWN1w6fDtWVzIGRhIG9wZXJhw6fDo29cclxuICAgKiBAcmV0dXJucyBPYmpldG8gY29tIHRocmVzaG9sZHMgY2FsY3VsYWRvcyBkaW5hbWljYW1lbnRlXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjYWxjdWxhdGVEeW5hbWljVGhyZXNob2xkcyhcclxuICAgIGV4ZWN1dGlvbkNvdW50OiBudW1iZXJcclxuICApOiBEeW5hbWljVGhyZXNob2xkcyB7XHJcbiAgICBpZiAoZXhlY3V0aW9uQ291bnQgPT09IDEpIHtcclxuICAgICAgLy8gUHJpbWVpcmEgZXhlY3XDp8OjbyAtIGV4cGVjdGF0aXZhcyBtYWlzIHJlbGF4YWRhc1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG9rOiAxMDAwLCAvLyAxIHNlZ3VuZG9cclxuICAgICAgICBsZW50bzogMjAwMCwgLy8gMiBzZWd1bmRvc1xyXG4gICAgICAgIGNyaXRpY286IDIwMDAsIC8vIDIgc2VndW5kb3MgKGxlbnRvIGUgY3JpdGljbyBpZ3VhaXMgcGFyYSBtYW50ZXIgc8OzIDMgZXN0YWRvcylcclxuICAgICAgfTtcclxuICAgIH0gZWxzZSBpZiAoZXhlY3V0aW9uQ291bnQgPD0gNSkge1xyXG4gICAgICAvLyBBdMOpIDUgZXhlY3XDp8O1ZXMgLSBzaXN0ZW1hIGFpbmRhIGFxdWVjZW5kb1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG9rOiA1MDAsIC8vIDUwMG1zXHJcbiAgICAgICAgbGVudG86IDEwMDAsIC8vIDEgc2VndW5kb1xyXG4gICAgICAgIGNyaXRpY286IDEwMDAsIC8vIDEgc2VndW5kb1xyXG4gICAgICB9O1xyXG4gICAgfSBlbHNlIGlmIChleGVjdXRpb25Db3VudCA8PSAxMCkge1xyXG4gICAgICAvLyBBdMOpIDEwIGV4ZWN1w6fDtWVzIC0gc2lzdGVtYSBvdGltaXphZG9cclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBvazogMTAwLCAvLyAxMDBtc1xyXG4gICAgICAgIGxlbnRvOiAyNTAsIC8vIDI1MG1zXHJcbiAgICAgICAgY3JpdGljbzogMjUwLCAvLyAyNTBtc1xyXG4gICAgICB9O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQWNpbWEgZGUgMTAgZXhlY3XDp8O1ZXMgLSBleHBlY3RhdGl2YXMgYWx0YXNcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBvazogMjAsIC8vIDIwbXNcclxuICAgICAgICBsZW50bzogNjAsIC8vIDYwbXNcclxuICAgICAgICBjcml0aWNvOiA2MCwgLy8gNjBtc1xyXG4gICAgICB9O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHVibGljIGluamVjdE1vbml0b3JCdXR0b24oKTogdm9pZCB7XHJcbiAgICBpZiAoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2J0bi1tb25pdG9yYXItcGVyZm9ybWFuY2UnKSkgcmV0dXJuO1xyXG5cclxuICAgIC8vID09PT09PSBFU1RJTE8gTU9ERVJOTyBFIEJPVMODTyBERSBPTEhPID09PT09PVxyXG4gICAgY29uc3QgQlVUVE9OX0NPTE9SID0gJyMyMzI3MmYnOyAvLyBjaW56YSBlc2N1cm8gZWxlZ2FudGVcclxuICAgIGNvbnN0IEJVVFRPTl9URVhUX0NPTE9SID0gJyNmM2Y0ZjYnO1xyXG4gICAgY29uc3QgQlVUVE9OX1JBRElVUyA9ICc4cHgnO1xyXG4gICAgY29uc3QgQlVUVE9OX0ZPTlRfU0laRSA9ICcxM3B4JztcclxuICAgIGNvbnN0IEJVVFRPTl9QQURESU5HID0gJzEwcHggNXB4JztcclxuICAgIGNvbnN0IEJVVFRPTl9XSURUSCA9ICcyMTBweCc7XHJcbiAgICBjb25zdCBCVVRUT05fSEVJR0hUID0gJzQ0cHgnO1xyXG4gICAgY29uc3QgQlVUVE9OX0JPWF9TSEFET1cgPSAnMCAycHggMTJweCAjMDAwMic7XHJcbiAgICBjb25zdCBCVVRUT05fQk9SREVSID0gJzFweCBzb2xpZCAjMzUzYTQwJztcclxuXHJcbiAgICAvLyBDb250YWluZXIgcGFyYSBhbmltYcOnw6NvXHJcbiAgICBjb25zdCBjb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuICAgIGNvbnRhaW5lci5pZCA9ICdwZXJmb3JtYW5jZS1tb25pdG9yLWNvbnRhaW5lcic7XHJcbiAgICBPYmplY3QuYXNzaWduKGNvbnRhaW5lci5zdHlsZSwge1xyXG4gICAgICBwb3NpdGlvbjogJ2ZpeGVkJyxcclxuICAgICAgYm90dG9tOiAnNXB4JyxcclxuICAgICAgbGVmdDogJzUwcHgnLFxyXG4gICAgICB6SW5kZXg6ICc5OTk5JyxcclxuICAgICAgZGlzcGxheTogJ2ZsZXgnLFxyXG4gICAgICBmbGV4RGlyZWN0aW9uOiAnY29sdW1uJyxcclxuICAgICAgYWxpZ25JdGVtczogJ2NlbnRlcicsXHJcbiAgICAgIGp1c3RpZnlDb250ZW50OiAnZmxleC1lbmQnLFxyXG4gICAgICB0cmFuc2l0aW9uOiAndHJhbnNmb3JtIDAuNXMgY3ViaWMtYmV6aWVyKC40LDIsLjYsMSknLFxyXG4gICAgICBnYXA6ICcxMHB4JyxcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEZ1bsOnw6NvIHBhcmEgY3JpYXIgYm90w7VlcyBwYWRyb25pemFkb3NcclxuICAgIGNvbnN0IGNyaWFyQm90YW8gPSAoaWQ6IHN0cmluZywgdGV4dG86IHN0cmluZykgPT4ge1xyXG4gICAgICBjb25zdCBidG4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdidXR0b24nKTtcclxuICAgICAgYnRuLmlkID0gaWQ7XHJcbiAgICAgIGJ0bi5pbm5lclRleHQgPSB0ZXh0bztcclxuICAgICAgT2JqZWN0LmFzc2lnbihidG4uc3R5bGUsIHtcclxuICAgICAgICB3aWR0aDogQlVUVE9OX1dJRFRILFxyXG4gICAgICAgIGhlaWdodDogQlVUVE9OX0hFSUdIVCxcclxuICAgICAgICBiYWNrZ3JvdW5kOiBCVVRUT05fQ09MT1IsXHJcbiAgICAgICAgY29sb3I6IEJVVFRPTl9URVhUX0NPTE9SLFxyXG4gICAgICAgIGJvcmRlclJhZGl1czogQlVUVE9OX1JBRElVUyxcclxuICAgICAgICBib3JkZXI6IEJVVFRPTl9CT1JERVIsXHJcbiAgICAgICAgcGFkZGluZzogQlVUVE9OX1BBRERJTkcsXHJcbiAgICAgICAgZm9udFNpemU6IEJVVFRPTl9GT05UX1NJWkUsXHJcbiAgICAgICAgZm9udFdlaWdodDogJzYwMCcsXHJcbiAgICAgICAgY3Vyc29yOiAncG9pbnRlcicsXHJcbiAgICAgICAgYm94U2hhZG93OiBCVVRUT05fQk9YX1NIQURPVyxcclxuICAgICAgICBsZXR0ZXJTcGFjaW5nOiAnMC4wMWVtJyxcclxuICAgICAgICB0ZXh0QWxpZ246ICdjZW50ZXInLFxyXG4gICAgICAgIHRyYW5zaXRpb246XHJcbiAgICAgICAgICAnYmFja2dyb3VuZCAwLjJzLCBjb2xvciAwLjJzLCB0cmFuc2Zvcm0gMC41cyBjdWJpYy1iZXppZXIoLjQsMiwuNiwxKScsXHJcbiAgICAgIH0pO1xyXG4gICAgICBidG4ub25tb3VzZWVudGVyID0gKCkgPT4ge1xyXG4gICAgICAgIGJ0bi5zdHlsZS5iYWNrZ3JvdW5kID0gJyMzNTNhNDAnO1xyXG4gICAgICAgIGJ0bi5zdHlsZS5jb2xvciA9ICcjZmZmJztcclxuICAgICAgfTtcclxuICAgICAgYnRuLm9ubW91c2VsZWF2ZSA9ICgpID0+IHtcclxuICAgICAgICBidG4uc3R5bGUuYmFja2dyb3VuZCA9IEJVVFRPTl9DT0xPUjtcclxuICAgICAgICBidG4uc3R5bGUuY29sb3IgPSBCVVRUT05fVEVYVF9DT0xPUjtcclxuICAgICAgfTtcclxuICAgICAgcmV0dXJuIGJ0bjtcclxuICAgIH07XHJcblxyXG4gICAgLy8gQm90w7VlcyBwcmluY2lwYWlzXHJcbiAgICBjb25zdCBidG5NYWluID0gY3JpYXJCb3RhbyhcclxuICAgICAgJ2J0bi1tb25pdG9yYXItcGVyZm9ybWFuY2UnLFxyXG4gICAgICAnUGFyYXIgbW9uaXRvcmFtZW50bydcclxuICAgICk7XHJcbiAgICBjb25zdCBidG5GaW5hbGl6YXIgPSBjcmlhckJvdGFvKFxyXG4gICAgICAnYnRuLWZpbmFsaXphci1tb25pdG9yYW1lbnRvJyxcclxuICAgICAgJ0ZpbmFsaXphciBtb25pdG9yYW1lbnRvJ1xyXG4gICAgKTtcclxuICAgIGNvbnN0IGJ0blJlcXVpc2ljb2VzRGV0YWxoYWRhcyA9IGNyaWFyQm90YW8oXHJcbiAgICAgICdidG4tcmVxLWRldGFsaGFkYXMtcGVyZm9ybWFuY2UnLFxyXG4gICAgICAnUmVxdWlzacOnw7VlcyBkZXRhbGhhZGFzJ1xyXG4gICAgKTtcclxuICAgIGNvbnN0IGJ0bkFuYWxpc2VEZXRhbGhhZGEgPSBjcmlhckJvdGFvKFxyXG4gICAgICAnYnRuLWFuYWxpc2UtZGV0YWxoYWRhLXBlcmZvcm1hbmNlJyxcclxuICAgICAgJ0Fuw6FsaXNlIGRldGFsaGFkYSdcclxuICAgICk7XHJcbiAgICBjb25zdCBidG5SZWxhdG9yaW9FdmVudG8gPSBjcmlhckJvdGFvKFxyXG4gICAgICAnYnRuLXJlbGF0b3Jpby1ldmVudG8tcGVyZm9ybWFuY2UnLFxyXG4gICAgICAnUmVsYXTDs3JpbyBzZXBhcmFkbydcclxuICAgICk7XHJcblxyXG4gICAgLy8gSW5pY2lhbG1lbnRlIGVzY29uZGlkb3NcclxuICAgIGJ0blJlcXVpc2ljb2VzRGV0YWxoYWRhcy5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgYnRuQW5hbGlzZURldGFsaGFkYS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgYnRuRmluYWxpemFyLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICBidG5SZWxhdG9yaW9FdmVudG8uc3R5bGUuZGlzcGxheSA9ICdub25lJztcclxuXHJcbiAgICAvLyBCb3TDo28gZGUgZXNjb25kZXIvbW9zdHJhciBjb20gw61jb25lIGRlIG9saG8gKGZvcmEgZG8gY29udGFpbmVyKVxyXG4gICAgY29uc3QgYnRuVG9nZ2xlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYnV0dG9uJyk7XHJcbiAgICBidG5Ub2dnbGUuaWQgPSAnYnRuLXRvZ2dsZS1wZXJmb3JtYW5jZSc7XHJcbiAgICBidG5Ub2dnbGUuaW5uZXJIVE1MID0gYFxyXG4gICAgPGltZ1xyXG4gICAgICBzcmM9XCJodHRwczovL2Nkbi1pY29ucy1wbmcuZmxhdGljb24uY29tLzUxMi81NjUvNTY1NjU1LnBuZ1wiXHJcbiAgICAgIGFsdD1cImVzY29uZGVyXCJcclxuICAgICAgc3R5bGU9XCJ3aWR0aDoxNXB4OyBoZWlnaHQ6MTVweDsgdmVydGljYWwtYWxpZ246bWlkZGxlOyBmaWx0ZXI6IGludmVydCgxKTtcIlxyXG4gICAgLz5cclxuICAgIGA7XHJcblxyXG4gICAgT2JqZWN0LmFzc2lnbihidG5Ub2dnbGUuc3R5bGUsIHtcclxuICAgICAgd2lkdGg6ICczOHB4JyxcclxuICAgICAgaGVpZ2h0OiAnMzhweCcsXHJcbiAgICAgIGJhY2tncm91bmQ6ICcjMjMyNzJmJyxcclxuICAgICAgY29sb3I6ICcjZjNmNGY2JyxcclxuICAgICAgYm9yZGVyUmFkaXVzOiAnNTAlJyxcclxuICAgICAgYm9yZGVyOiBCVVRUT05fQk9SREVSLFxyXG4gICAgICBmb250U2l6ZTogJzIwcHgnLFxyXG4gICAgICBmb250V2VpZ2h0OiAnYm9sZCcsXHJcbiAgICAgIGN1cnNvcjogJ3BvaW50ZXInLFxyXG4gICAgICBib3hTaGFkb3c6IEJVVFRPTl9CT1hfU0hBRE9XLFxyXG4gICAgICBwb3NpdGlvbjogJ2ZpeGVkJyxcclxuICAgICAgbGVmdDogJzVweCcsXHJcbiAgICAgIGJvdHRvbTogJzVweCcsXHJcbiAgICAgIGRpc3BsYXk6ICdmbGV4JyxcclxuICAgICAgYWxpZ25JdGVtczogJ2NlbnRlcicsXHJcbiAgICAgIGp1c3RpZnlDb250ZW50OiAnY2VudGVyJyxcclxuICAgICAgekluZGV4OiAnMTAwMDAnLFxyXG4gICAgfSk7XHJcbiAgICBidG5Ub2dnbGUub25tb3VzZWVudGVyID0gKCkgPT4ge1xyXG4gICAgICBidG5Ub2dnbGUuc3R5bGUuYmFja2dyb3VuZCA9ICcjMzUzYTQwJztcclxuICAgICAgYnRuVG9nZ2xlLnN0eWxlLmNvbG9yID0gJyNmZmYnO1xyXG4gICAgfTtcclxuICAgIGJ0blRvZ2dsZS5vbm1vdXNlbGVhdmUgPSAoKSA9PiB7XHJcbiAgICAgIGJ0blRvZ2dsZS5zdHlsZS5iYWNrZ3JvdW5kID0gJyMyMzI3MmYnO1xyXG4gICAgICBidG5Ub2dnbGUuc3R5bGUuY29sb3IgPSAnI2YzZjRmNic7XHJcbiAgICB9O1xyXG5cclxuICAgIGxldCBoaWRkZW4gPSBmYWxzZTtcclxuICAgIGJ0blRvZ2dsZS5vbmNsaWNrID0gKCkgPT4ge1xyXG4gICAgICBoaWRkZW4gPSAhaGlkZGVuO1xyXG4gICAgICBpZiAoaGlkZGVuKSB7XHJcbiAgICAgICAgY29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgICAgYnRuVG9nZ2xlLmlubmVySFRNTCA9IGBcclxuICAgIDxpbWdcclxuICAgICAgc3JjPVwiaHR0cHM6Ly9jZG4taWNvbnMtcG5nLmZsYXRpY29uLmNvbS81MTIvMTU5LzE1OTYwNC5wbmdcIlxyXG4gICAgICBhbHQ9XCJtb3N0cmFyXCJcclxuICAgICAgc3R5bGU9XCJ3aWR0aDoxNXB4OyBoZWlnaHQ6MTVweDsgdmVydGljYWwtYWxpZ246bWlkZGxlOyBmaWx0ZXI6IGludmVydCgxKTtcIlxyXG4gICAgLz5cclxuICBgO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnRhaW5lci5zdHlsZS5kaXNwbGF5ID0gJ2ZsZXgnO1xyXG4gICAgICAgIGJ0blRvZ2dsZS5pbm5lckhUTUwgPSBgXHJcbiAgICA8aW1nXHJcbiAgICAgIHNyYz1cImh0dHBzOi8vY2RuLWljb25zLXBuZy5mbGF0aWNvbi5jb20vNTEyLzU2NS81NjU2NTUucG5nXCJcclxuICAgICAgYWx0PVwiZXNjb25kZXJcIlxyXG4gICAgICBzdHlsZT1cIndpZHRoOjE1cHg7IGhlaWdodDoxNXB4OyB2ZXJ0aWNhbC1hbGlnbjptaWRkbGU7IGZpbHRlcjogaW52ZXJ0KDEpO1wiXHJcbiAgICAvPlxyXG4gIGA7XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgLy8gRXN0YWRvIGRvcyBib3TDtWVzXHJcbiAgICBsZXQgZXN0YWRvOlxyXG4gICAgICB8ICdpbmF0aXZvJ1xyXG4gICAgICB8ICdtb25pdG9yYW5kbydcclxuICAgICAgfCAncmVsYXRvcmlvJ1xyXG4gICAgICB8ICdyZWxhdG9yaW9fZ2VyYWRvJ1xyXG4gICAgICB8ICdyZXF1aXNpY2FvJyA9ICdtb25pdG9yYW5kbyc7XHJcblxyXG4gICAgY29uc3QgYXR1YWxpemFyQm90b2VzID0gKG5vdm9Fc3RhZG86IHR5cGVvZiBlc3RhZG8pID0+IHtcclxuICAgICAgZXN0YWRvID0gbm92b0VzdGFkbztcclxuICAgICAgc3dpdGNoIChlc3RhZG8pIHtcclxuICAgICAgICBjYXNlICdpbmF0aXZvJzpcclxuICAgICAgICAgIGJ0bk1haW4uaW5uZXJUZXh0ID0gJ0luaWNpYXIgbW9uaXRvcmFtZW50byc7XHJcbiAgICAgICAgICB0aGlzLm1vbml0b3JhbWVudG9BdGl2byA9IGZhbHNlO1xyXG4gICAgICAgICAgYnRuRmluYWxpemFyLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgICAgICBidG5SZXF1aXNpY29lc0RldGFsaGFkYXMuc3R5bGUuZGlzcGxheSA9ICdub25lJztcclxuICAgICAgICAgIGJ0bkFuYWxpc2VEZXRhbGhhZGEuc3R5bGUuZGlzcGxheSA9ICdub25lJztcclxuICAgICAgICAgIGJ0blJlbGF0b3Jpb0V2ZW50by5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgY2FzZSAnbW9uaXRvcmFuZG8nOlxyXG4gICAgICAgICAgYnRuTWFpbi5pbm5lclRleHQgPSAnUGFyYXIgbW9uaXRvcmFtZW50byc7XHJcbiAgICAgICAgICB0aGlzLm1vbml0b3JhbWVudG9BdGl2byA9IHRydWU7XHJcbiAgICAgICAgICBidG5GaW5hbGl6YXIuc3R5bGUuZGlzcGxheSA9ICdub25lJztcclxuICAgICAgICAgIGJ0blJlcXVpc2ljb2VzRGV0YWxoYWRhcy5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgICAgICAgYnRuQW5hbGlzZURldGFsaGFkYS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgICAgICAgYnRuUmVsYXRvcmlvRXZlbnRvLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICBjYXNlICdyZWxhdG9yaW8nOlxyXG4gICAgICAgICAgYnRuTWFpbi5pbm5lclRleHQgPSAnR2VyYXIgcmVsYXTDs3Jpbyc7XHJcbiAgICAgICAgICB0aGlzLm1vbml0b3JhbWVudG9BdGl2byA9IGZhbHNlO1xyXG4gICAgICAgICAgYnRuRmluYWxpemFyLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgICAgICBidG5SZXF1aXNpY29lc0RldGFsaGFkYXMuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XHJcbiAgICAgICAgICBidG5BbmFsaXNlRGV0YWxoYWRhLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xyXG4gICAgICAgICAgYnRuUmVsYXRvcmlvRXZlbnRvLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgY2FzZSAncmVsYXRvcmlvX2dlcmFkbyc6XHJcbiAgICAgICAgICBidG5NYWluLmlubmVyVGV4dCA9ICdHZXJhciByZWxhdMOzcmlvJztcclxuICAgICAgICAgIHRoaXMubW9uaXRvcmFtZW50b0F0aXZvID0gZmFsc2U7XHJcbiAgICAgICAgICBidG5GaW5hbGl6YXIuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XHJcbiAgICAgICAgICBidG5SZXF1aXNpY29lc0RldGFsaGFkYXMuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XHJcbiAgICAgICAgICBidG5BbmFsaXNlRGV0YWxoYWRhLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xyXG4gICAgICAgICAgYnRuUmVsYXRvcmlvRXZlbnRvLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgLy8gQcOnw7VlcyBkb3MgYm90w7Vlc1xyXG4gICAgYnRuTWFpbi5vbmNsaWNrID0gKCkgPT4ge1xyXG4gICAgICBpZiAoZXN0YWRvID09PSAnaW5hdGl2bycpIHtcclxuICAgICAgICB0aGlzLnJlc2V0UGVyZm9ybWFuY2VEYXRhKCk7XHJcbiAgICAgICAgdGhpcy5zaG93V2VsY29tZU1lc3NhZ2UoKTtcclxuICAgICAgICBhdHVhbGl6YXJCb3RvZXMoJ21vbml0b3JhbmRvJyk7XHJcbiAgICAgIH0gZWxzZSBpZiAoZXN0YWRvID09PSAnbW9uaXRvcmFuZG8nKSB7XHJcbiAgICAgICAgYXR1YWxpemFyQm90b2VzKCdyZWxhdG9yaW8nKTtcclxuICAgICAgfSBlbHNlIGlmIChlc3RhZG8gPT09ICdyZWxhdG9yaW8nIHx8IGVzdGFkbyA9PT0gJ3JlbGF0b3Jpb19nZXJhZG8nKSB7XHJcbiAgICAgICAgdGhpcy5zaG93UGVyZm9ybWFuY2VTdW1tYXJ5KGZhbHNlKTtcclxuICAgICAgICBhdHVhbGl6YXJCb3RvZXMoJ3JlbGF0b3Jpb19nZXJhZG8nKTtcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBidG5GaW5hbGl6YXIub25jbGljayA9ICgpID0+IHtcclxuICAgICAgdGhpcy5yZXNldFBlcmZvcm1hbmNlRGF0YSgpO1xyXG4gICAgICBhdHVhbGl6YXJCb3RvZXMoJ2luYXRpdm8nKTtcclxuICAgIH07XHJcblxyXG4gICAgLy8gQXDDqm5kaWNlXHJcbiAgICB0aGlzLnNob3dXZWxjb21lTWVzc2FnZSgpO1xyXG4gICAgY29udGFpbmVyLmFwcGVuZENoaWxkKGJ0bk1haW4pO1xyXG4gICAgY29udGFpbmVyLmFwcGVuZENoaWxkKGJ0blJlcXVpc2ljb2VzRGV0YWxoYWRhcyk7XHJcbiAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQoYnRuUmVsYXRvcmlvRXZlbnRvKTtcclxuICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZChidG5BbmFsaXNlRGV0YWxoYWRhKTtcclxuICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZChidG5GaW5hbGl6YXIpO1xyXG4gICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChjb250YWluZXIpO1xyXG4gICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChidG5Ub2dnbGUpO1xyXG5cclxuICAgIC8vIEHDp8OjbyBkbyBib3TDo28gZGUgcmVxdWlzacOnw7VlcyBkZXRhbGhhZGFzXHJcbiAgICBidG5SZXF1aXNpY29lc0RldGFsaGFkYXMub25jbGljayA9ICgpID0+IHtcclxuICAgICAgdGhpcy5zaG93SHR0cFJlcXVlc3RzUmVwb3J0KCk7XHJcbiAgICB9O1xyXG4gICAgLy8gQcOnw6NvIGRvIGJvdMOjbyBkZSBhbsOhbGlzZSBkZXRhbGhhZGFcclxuICAgIGJ0bkFuYWxpc2VEZXRhbGhhZGEub25jbGljayA9ICgpID0+IHtcclxuICAgICAgdGhpcy5nZW5lcmF0ZURldGFpbGVkQW5hbHlzaXMoKTtcclxuICAgIH07XHJcbiAgICAvLyBBw6fDo28gZG8gcmVsYXTDs3JpbyBwb3IgZXZlbnRvXHJcbiAgICBidG5SZWxhdG9yaW9FdmVudG8ub25jbGljayA9ICgpID0+IHtcclxuICAgICAgdGhpcy5zaG93RXZlbnRSZXBvcnQodHJ1ZSk7XHJcbiAgICB9O1xyXG5cclxuICAgIC8vID09PT09PSBDYXB0dXJhIGF1dG9tw6F0aWNhIGRlIGV2ZW50b3MgZGUgVUkgcGFyYSBzZXBhcmFyIHBvciBldmVudG8gPT09PT09XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBFdml0YSBhZGljaW9uYXIgbcO6bHRpcGxvcyBsaXN0ZW5lcnNcclxuICAgICAgY29uc3QgYW55V2luZG93ID0gd2luZG93IGFzIGFueTtcclxuICAgICAgaWYgKCFhbnlXaW5kb3cuX19wbV9hdXRvX3VpX2xpc3RlbmVyc19hZGRlZCkge1xyXG4gICAgICAgIGFueVdpbmRvdy5fX3BtX2F1dG9fdWlfbGlzdGVuZXJzX2FkZGVkID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgY29uc3QgZGVzY3JpYmVUYXJnZXQgPSAoZWw6IGFueSwgZXY/OiBFdmVudCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgaXNLZXlib2FyZCA9XHJcbiAgICAgICAgICAgICAgdHlwZW9mIEtleWJvYXJkRXZlbnQgIT09ICd1bmRlZmluZWQnICYmXHJcbiAgICAgICAgICAgICAgZXYgaW5zdGFuY2VvZiBLZXlib2FyZEV2ZW50O1xyXG4gICAgICAgICAgICBjb25zdCBrZXlQYXJ0ID1cclxuICAgICAgICAgICAgICBpc0tleWJvYXJkICYmIChldiBhcyBLZXlib2FyZEV2ZW50KS5rZXlcclxuICAgICAgICAgICAgICAgID8gYFskeyhldiBhcyBLZXlib2FyZEV2ZW50KS5rZXl9XWBcclxuICAgICAgICAgICAgICAgIDogJyc7XHJcbiAgICAgICAgICAgIGlmICghZWwgfHwgdHlwZW9mIGVsICE9PSAnb2JqZWN0JykgcmV0dXJuIGB1aSR7a2V5UGFydH1gO1xyXG4gICAgICAgICAgICBjb25zdCB0YWcgPVxyXG4gICAgICAgICAgICAgIChlbC50YWdOYW1lIHx8IGVsLm5vZGVOYW1lIHx8ICcnKS50b1N0cmluZygpLnRvTG93ZXJDYXNlKCkgfHxcclxuICAgICAgICAgICAgICAnZWxlbWVudCc7XHJcbiAgICAgICAgICAgIGNvbnN0IGlkID0gZWwuaWQgPyBgIyR7ZWwuaWR9YCA6ICcnO1xyXG4gICAgICAgICAgICBjb25zdCByYXdDbGFzcyA9XHJcbiAgICAgICAgICAgICAgdHlwZW9mIGVsLmNsYXNzTmFtZSA9PT0gJ3N0cmluZydcclxuICAgICAgICAgICAgICAgID8gZWwuY2xhc3NOYW1lXHJcbiAgICAgICAgICAgICAgICA6IGVsLmNsYXNzTGlzdCAmJlxyXG4gICAgICAgICAgICAgICAgICB0eXBlb2YgZWwuY2xhc3NMaXN0ID09PSAnb2JqZWN0JyAmJlxyXG4gICAgICAgICAgICAgICAgICB0eXBlb2YgZWwuY2xhc3NMaXN0LnRvU3RyaW5nID09PSAnZnVuY3Rpb24nXHJcbiAgICAgICAgICAgICAgICA/IGVsLmNsYXNzTGlzdC50b1N0cmluZygpXHJcbiAgICAgICAgICAgICAgICA6ICcnO1xyXG4gICAgICAgICAgICBjb25zdCBmaWx0ZXJlZCA9IHJhd0NsYXNzXHJcbiAgICAgICAgICAgICAgLnNwbGl0KCcgJylcclxuICAgICAgICAgICAgICAuZmlsdGVyKFxyXG4gICAgICAgICAgICAgICAgKGM6IHN0cmluZykgPT5cclxuICAgICAgICAgICAgICAgICAgYyAmJiAhYy5zdGFydHNXaXRoKCduZy0nKSAmJiAhYy5zdGFydHNXaXRoKCdjZGstJylcclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnNsaWNlKDAsIDIpXHJcbiAgICAgICAgICAgICAgLmpvaW4oJy4nKTtcclxuICAgICAgICAgICAgY29uc3QgY2xzID0gZmlsdGVyZWQgPyBgLiR7ZmlsdGVyZWR9YCA6ICcnO1xyXG4gICAgICAgICAgICBjb25zdCBpbmNsdWRlVGV4dCA9IHRhZyA9PT0gJ2J1dHRvbicgfHwgdGFnID09PSAnYSc7XHJcbiAgICAgICAgICAgIGNvbnN0IHR4dCA9XHJcbiAgICAgICAgICAgICAgaW5jbHVkZVRleHQgJiYgdHlwZW9mIGVsLmlubmVyVGV4dCA9PT0gJ3N0cmluZydcclxuICAgICAgICAgICAgICAgID8gZWwuaW5uZXJUZXh0LnRyaW0oKS5zbGljZSgwLCAzMClcclxuICAgICAgICAgICAgICAgIDogJyc7XHJcbiAgICAgICAgICAgIHJldHVybiBgJHt0YWd9JHtpZH0ke2Nsc30ke2tleVBhcnR9JHt0eHQgPyBgOlwiJHt0eHR9XCJgIDogJyd9YDtcclxuICAgICAgICAgIH0gY2F0Y2gge1xyXG4gICAgICAgICAgICByZXR1cm4gJ3VpJztcclxuICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICBsZXQgdWlFdmVudEVuZFRpbWVyOiBhbnkgPSBudWxsO1xyXG4gICAgICAgIGxldCB1aUV2ZW50RW5kSW50ZXJ2YWw6IGFueSA9IG51bGw7XHJcbiAgICAgICAgY29uc3Qgc3RhcnRVaUV2ZW50Q29udGV4dCA9IChsYWJlbDogc3RyaW5nKSA9PiB7XHJcbiAgICAgICAgICBpZiAodWlFdmVudEVuZFRpbWVyKSB7XHJcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh1aUV2ZW50RW5kVGltZXIpO1xyXG4gICAgICAgICAgICB1aUV2ZW50RW5kVGltZXIgPSBudWxsO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgaWYgKHVpRXZlbnRFbmRJbnRlcnZhbCkge1xyXG4gICAgICAgICAgICBjbGVhckludGVydmFsKHVpRXZlbnRFbmRJbnRlcnZhbCk7XHJcbiAgICAgICAgICAgIHVpRXZlbnRFbmRJbnRlcnZhbCA9IG51bGw7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICB0aGlzLmJlZ2luRXZlbnRDb250ZXh0KGxhYmVsKTtcclxuICAgICAgICAgIC8vIFNlIGrDoSBow6EgdW0gY29udGV4dG8gYWJlcnRvLCBuw6NvIGNyaWEgbm92YSBqYW5lbGEgZGUgZW5jZXJyYW1lbnRvIChldmVudG8gYW5pbmhhZG8pXHJcbiAgICAgICAgICBpZiAodGhpcy5ldmVudENvbnRleHRTdGFjay5sZW5ndGggPiAxKSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAvLyBKYW5lbGEgaW50ZWxpZ2VudGU6IGVzcGVyYSBwcmltZWlybyB0aW1lciBlIGZlY2hhIGFww7NzIHBlcsOtb2RvIGRlIHNpbMOqbmNpb1xyXG4gICAgICAgICAgY29uc3QgTUFYX1dJTkRPV19NUyA9IDYwMDAwO1xyXG4gICAgICAgICAgY29uc3QgR1JBQ0VfTVMgPSAyMDAwOyAvLyB0ZW1wbyBwYXJhIHBlcm1pdGlyIHRpbWVycyBxdWUgY29tZcOnYW0gZGVwb2lzXHJcbiAgICAgICAgICBjb25zdCBRVUlFVF9NUyA9IDYwMDsgLy8gdGVtcG8gc2VtIGF0aXZpZGFkZSBwYXJhIGNvbnNpZGVyYXIgZmx1eG8gZW5jZXJyYWRvXHJcblxyXG4gICAgICAgICAgdWlFdmVudEVuZEludGVydmFsID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xyXG4gICAgICAgICAgICBjb25zdCBhY3RpdmUgPSB0aGlzLmhhc0FjdGl2ZVRpbWVycygpO1xyXG4gICAgICAgICAgICBjb25zdCBiZWdpbkF0ID0gdGhpcy5jdXJyZW50RXZlbnRCZWdpbkF0ID8/IG5vdztcclxuICAgICAgICAgICAgY29uc3QgaGFzU3RhcnRlZCA9IHRoaXMuZmlyc3RUaW1lckluRXZlbnRBdCAhPT0gbnVsbDtcclxuICAgICAgICAgICAgY29uc3QgZ3JhY2VFeGNlZWRlZCA9IG5vdyAtIGJlZ2luQXQgPiBHUkFDRV9NUztcclxuICAgICAgICAgICAgY29uc3QgbGFzdEFjdGl2aXR5ID0gdGhpcy5sYXN0VGltZXJBY3Rpdml0eUF0ID8/IGJlZ2luQXQ7XHJcbiAgICAgICAgICAgIGNvbnN0IHF1aWV0RW5vdWdoID1cclxuICAgICAgICAgICAgICBoYXNTdGFydGVkICYmICFhY3RpdmUgJiYgbm93IC0gbGFzdEFjdGl2aXR5ID4gUVVJRVRfTVM7XHJcbiAgICAgICAgICAgIGNvbnN0IGV4Y2VlZGVkTWF4ID0gbm93IC0gYmVnaW5BdCA+IE1BWF9XSU5ET1dfTVM7XHJcblxyXG4gICAgICAgICAgICBpZiAocXVpZXRFbm91Z2ggfHwgKCFoYXNTdGFydGVkICYmIGdyYWNlRXhjZWVkZWQpIHx8IGV4Y2VlZGVkTWF4KSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5lbmRFdmVudENvbnRleHQoKTtcclxuICAgICAgICAgICAgICBjbGVhckludGVydmFsKHVpRXZlbnRFbmRJbnRlcnZhbCk7XHJcbiAgICAgICAgICAgICAgdWlFdmVudEVuZEludGVydmFsID0gbnVsbDtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSwgMjUwKTtcclxuXHJcbiAgICAgICAgICAvLyBGYWxsYmFjazogZmVjaGEgbm8gbcOheGltbyBhcMOzcyBNQVhfV0lORE9XX01TXHJcbiAgICAgICAgICB1aUV2ZW50RW5kVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAgICAgaWYgKHVpRXZlbnRFbmRJbnRlcnZhbCkge1xyXG4gICAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwodWlFdmVudEVuZEludGVydmFsKTtcclxuICAgICAgICAgICAgICB1aUV2ZW50RW5kSW50ZXJ2YWwgPSBudWxsO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHRoaXMuZW5kRXZlbnRDb250ZXh0KCk7XHJcbiAgICAgICAgICAgIHVpRXZlbnRFbmRUaW1lciA9IG51bGw7XHJcbiAgICAgICAgICB9LCBNQVhfV0lORE9XX01TKTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICBbJ2NsaWNrJywgJ3N1Ym1pdCcsICdjaGFuZ2UnLCAna2V5ZG93biddLmZvckVhY2goKHR5cGUpID0+IHtcclxuICAgICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXHJcbiAgICAgICAgICAgIHR5cGUsXHJcbiAgICAgICAgICAgIChldjogRXZlbnQpID0+IHtcclxuICAgICAgICAgICAgICBjb25zdCB0YXJnZXQgPSBldi50YXJnZXQgYXMgYW55O1xyXG4gICAgICAgICAgICAgIGNvbnN0IGxhYmVsID0gYFVzZXJJbnB1dDoke3R5cGV9ICR7ZGVzY3JpYmVUYXJnZXQodGFyZ2V0LCBldil9YDtcclxuICAgICAgICAgICAgICBzdGFydFVpRXZlbnRDb250ZXh0KGxhYmVsKTtcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgdHJ1ZSAvLyBjYXB0dXJhIGNlZG8gbmEgZmFzZSBkZSBjYXB0dXJhXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBDb250ZXh0byBpbmljaWFsIHBhcmEgb3BlcmHDp8O1ZXMgZGUgaW5pY2lhbGl6YcOnw6NvIGRhIHRlbGFcclxuICAgICAgICB0aGlzLmJlZ2luRXZlbnRDb250ZXh0KCdBcHBJbml0Jyk7XHJcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLmVuZEV2ZW50Q29udGV4dCgpLCAzMDAwKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICAvLyBFdml0YSBxdWVicmFyIGNhc28gYW1iaWVudGUgbsOjbyBwZXJtaXRhIGFjZXNzbyBhbyBkb2N1bWVudFxyXG4gICAgICBjb25zb2xlLndhcm4oXHJcbiAgICAgICAgJ1tQZXJmb3JtYW5jZU1vbml0b3JdIEZhbGhhIGFvIGF0aXZhciBjYXB0dXJhIGF1dG9tw6F0aWNhIGRlIFVJOicsXHJcbiAgICAgICAgZVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHVibGljIHNob3dFdmVudFJlcG9ydChpbmNsdWRlSHR0cDogYm9vbGVhbiA9IHRydWUpOiB2b2lkIHtcclxuICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAnJWNSRUxBVMOTUklPIFBPUiBFVkVOVE8nLFxyXG4gICAgICAnY29sb3I6ICNiYmM3YzhmZjsgZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsgdGV4dC1zaGFkb3c6IDFweCAxcHggIzAwMDsgYmFja2dyb3VuZC1jb2xvcjogIzQzMjQ4YmZmOyBib3JkZXItcmFkaXVzOiA1cHg7IHBhZGRpbmc6IDEwcHggMjBweDsnXHJcbiAgICApO1xyXG5cclxuICAgIGlmICh0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5zaXplID09PSAwKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKCdOZW5odW1hIG9wZXJhw6fDo28gbW9uaXRvcmFkYSBhaW5kYS4nKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGV2ZW50cyA9IG5ldyBNYXA8XHJcbiAgICAgIHN0cmluZyxcclxuICAgICAge1xyXG4gICAgICAgIHRvdGFsVGltZTogbnVtYmVyO1xyXG4gICAgICAgIHRvdGFsRXhlYzogbnVtYmVyO1xyXG4gICAgICAgIG9wZXJhdGlvbnM6IEFycmF5PHsgbmFtZTogc3RyaW5nOyBzdGF0czogUGVyZm9ybWFuY2VTdGF0cyB9PjtcclxuICAgICAgfVxyXG4gICAgPigpO1xyXG5cclxuICAgIHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LmZvckVhY2goKHN0YXRzLCBmdWxsTmFtZSkgPT4ge1xyXG4gICAgICBjb25zdCBwYXJ0cyA9IGZ1bGxOYW1lLnNwbGl0KCcgfCAnKTtcclxuICAgICAgY29uc3QgZXZlbnQgPSBwYXJ0cy5sZW5ndGggPiAxID8gcGFydHNbMF0gOiAnU2VtRXZlbnRvJztcclxuICAgICAgY29uc3Qgb3BOYW1lID0gcGFydHMubGVuZ3RoID4gMSA/IHBhcnRzLnNsaWNlKDEpLmpvaW4oJyB8ICcpIDogZnVsbE5hbWU7XHJcblxyXG4gICAgICBpZiAoIWV2ZW50cy5oYXMoZXZlbnQpKSB7XHJcbiAgICAgICAgZXZlbnRzLnNldChldmVudCwgeyB0b3RhbFRpbWU6IDAsIHRvdGFsRXhlYzogMCwgb3BlcmF0aW9uczogW10gfSk7XHJcbiAgICAgIH1cclxuICAgICAgY29uc3QgZ3JvdXAgPSBldmVudHMuZ2V0KGV2ZW50KSE7XHJcbiAgICAgIGdyb3VwLnRvdGFsVGltZSArPSBzdGF0cy50b3RhbFRpbWU7XHJcbiAgICAgIGdyb3VwLnRvdGFsRXhlYyArPSBzdGF0cy5jb3VudDtcclxuICAgICAgZ3JvdXAub3BlcmF0aW9ucy5wdXNoKHsgbmFtZTogb3BOYW1lLCBzdGF0cyB9KTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCBvdmVyYWxsVGltZSA9IDA7XHJcbiAgICBsZXQgb3ZlcmFsbEV4ZWMgPSAwO1xyXG5cclxuICAgIEFycmF5LmZyb20oZXZlbnRzLmVudHJpZXMoKSlcclxuICAgICAgLnNvcnQoKGEsIGIpID0+IGJbMV0udG90YWxUaW1lIC0gYVsxXS50b3RhbFRpbWUpXHJcbiAgICAgIC5mb3JFYWNoKChbZXZlbnQsIGdyb3VwXSkgPT4ge1xyXG4gICAgICAgIG92ZXJhbGxUaW1lICs9IGdyb3VwLnRvdGFsVGltZTtcclxuICAgICAgICBvdmVyYWxsRXhlYyArPSBncm91cC50b3RhbEV4ZWM7XHJcblxyXG4gICAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICAgYCVjRVZFTlRPOiAke2V2ZW50fSAgfCAgVGVtcG86ICR7TWF0aC5yb3VuZChcclxuICAgICAgICAgICAgZ3JvdXAudG90YWxUaW1lXHJcbiAgICAgICAgICApfW1zICB8ICBFeGVjdcOnw7VlczogJHtncm91cC50b3RhbEV4ZWN9YCxcclxuICAgICAgICAgICdjb2xvcjogI2ZmZjsgYmFja2dyb3VuZDogIzI4NjQ3YjsgZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogYm9sZDsgYm9yZGVyLXJhZGl1czogNHB4OyBwYWRkaW5nOiAzcHggOHB4OydcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICBjb25zdCB0YWJsZSA9IE9iamVjdC5mcm9tRW50cmllcyhcclxuICAgICAgICAgIGdyb3VwLm9wZXJhdGlvbnNcclxuICAgICAgICAgICAgLnNvcnQoKGEsIGIpID0+IGIuc3RhdHMudG90YWxUaW1lIC0gYS5zdGF0cy50b3RhbFRpbWUpXHJcbiAgICAgICAgICAgIC5tYXAoKHsgbmFtZSwgc3RhdHMgfSkgPT4ge1xyXG4gICAgICAgICAgICAgIGNvbnN0IGF2Z1RpbWUgPSBNYXRoLnJvdW5kKHN0YXRzLnRvdGFsVGltZSAvIHN0YXRzLmNvdW50KTtcclxuICAgICAgICAgICAgICBjb25zdCB7IGVtb2ppLCBzdGF0dXMgfSA9IHRoaXMuZ2V0UGVyZm9ybWFuY2VTdGF0dXMoXHJcbiAgICAgICAgICAgICAgICBhdmdUaW1lLFxyXG4gICAgICAgICAgICAgICAgc3RhdHMuY3VzdG9tVGhyZXNob2xkcyxcclxuICAgICAgICAgICAgICAgIG5hbWVcclxuICAgICAgICAgICAgICApO1xyXG4gICAgICAgICAgICAgIHJldHVybiBbXHJcbiAgICAgICAgICAgICAgICBuYW1lLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBFeGVjdcOnw7Vlczogc3RhdHMuY291bnQsXHJcbiAgICAgICAgICAgICAgICAgICdNw6lkaWEobXMpJzogYCR7YXZnVGltZX1tcyAoJHtzdGF0dXN9KSAke2Vtb2ppfWAudHJpbSgpLFxyXG4gICAgICAgICAgICAgICAgICAnTcOtbmltbyhtcyknOiBzdGF0cy5taW5UaW1lLFxyXG4gICAgICAgICAgICAgICAgICAnTcOheGltbyhtcyknOiBzdGF0cy5tYXhUaW1lLFxyXG4gICAgICAgICAgICAgICAgICAnVG90YWwobXMpJzogTWF0aC5yb3VuZChzdGF0cy50b3RhbFRpbWUpLFxyXG4gICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICBdO1xyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIGNvbnNvbGUudGFibGUodGFibGUpO1xyXG5cclxuICAgICAgICBpZiAoaW5jbHVkZUh0dHApIHtcclxuICAgICAgICAgIGNvbnN0IGh0dHBUYWJsZTogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xyXG4gICAgICAgICAgdGhpcy5odHRwUmVxdWVzdHMuZm9yRWFjaCgoZGFkb3MsIGtleSkgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCBwYXJ0cyA9IGtleS5zcGxpdCgnIHwgJyk7XHJcbiAgICAgICAgICAgIGNvbnN0IGh0dHBFdmVudCA9IHBhcnRzLmxlbmd0aCA+IDEgPyBwYXJ0c1swXSA6ICdTZW1FdmVudG8nO1xyXG4gICAgICAgICAgICBjb25zdCBodHRwTmFtZSA9XHJcbiAgICAgICAgICAgICAgcGFydHMubGVuZ3RoID4gMSA/IHBhcnRzLnNsaWNlKDEpLmpvaW4oJyB8ICcpIDoga2V5O1xyXG4gICAgICAgICAgICBpZiAoaHR0cEV2ZW50ID09PSBldmVudCkge1xyXG4gICAgICAgICAgICAgIGh0dHBUYWJsZVtodHRwTmFtZV0gPSB7XHJcbiAgICAgICAgICAgICAgICBFeGVjdcOnw7VlczogZGFkb3MuZXhlY3Vjb2VzLFxyXG4gICAgICAgICAgICAgICAgTcOpZGlhOiBgJHtNYXRoLnJvdW5kKFxyXG4gICAgICAgICAgICAgICAgICBkYWRvcy50ZW1wb1RvdGFsIC8gTWF0aC5tYXgoZGFkb3MuZXhlY3Vjb2VzLCAxKVxyXG4gICAgICAgICAgICAgICAgKX1tc2AsXHJcbiAgICAgICAgICAgICAgICAnVGVtcG8gVG90YWwnOiBgJHtNYXRoLnJvdW5kKGRhZG9zLnRlbXBvVG90YWwpfW1zYCxcclxuICAgICAgICAgICAgICAgIEVycm9zOiBkYWRvcy5lcnJvcnMsXHJcbiAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgY29uc3QgaGFzSHR0cFJvd3MgPSBPYmplY3Qua2V5cyhodHRwVGFibGUpLmxlbmd0aCA+IDA7XHJcbiAgICAgICAgICBpZiAoaGFzSHR0cFJvd3MpIHtcclxuICAgICAgICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgICAgICAgYCVjSFRUUCAoJHtldmVudH0pYCxcclxuICAgICAgICAgICAgICAnY29sb3I6ICNmZmY7IGJhY2tncm91bmQ6ICMyODMzNmI7IGZvbnQtc2l6ZTogMTJweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJvcmRlci1yYWRpdXM6IDRweDsgcGFkZGluZzogMnB4IDhweDsnXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIGNvbnNvbGUudGFibGUoaHR0cFRhYmxlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICBgJWNUT1RBTCBHRVJBTDogJHtNYXRoLnJvdW5kKFxyXG4gICAgICAgIG92ZXJhbGxUaW1lXHJcbiAgICAgICl9bXMgIHwgIEV4ZWN1w6fDtWVzOiAke292ZXJhbGxFeGVjfWAsXHJcbiAgICAgICdjb2xvcjogI2ZmZjsgYmFja2dyb3VuZDogIzQzMjQ4YmZmOyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBib3JkZXItcmFkaXVzOiA0cHg7IHBhZGRpbmc6IDRweCAxMnB4OyBtYXJnaW4tdG9wOiA4cHg7J1xyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiDwn4+tIEZhY3RvcnkgZnVuY3Rpb24gcGFyYSBjcmlhciBpbnN0w6JuY2lhIGRvIExvZ3NQZXJmb3JtYXRpY29cclxuICogQHBhcmFtIHNlcnZpY2VOYW1lIE5vbWUgZG8gc2VydmnDp28gKHBhcmEgbG9ncyBwZXJzb25hbGl6YWRvcylcclxuICogQHJldHVybnMgTm92YSBpbnN0w6JuY2lhIGRlIExvZ3NQZXJmb3JtYXRpY29cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQZXJmb3JtYW5jZUxvZ2dlcihcclxuICBzZXJ2aWNlTmFtZTogc3RyaW5nID0gJ1NlcnZpY2UnXHJcbik6IExvZ3NQZXJmb3JtYXRpY28ge1xyXG4gIHJldHVybiBuZXcgTG9nc1BlcmZvcm1hdGljbyhzZXJ2aWNlTmFtZSk7XHJcbn1cclxuIl19