performance-monitor-logger
Version:
Performance monitor logger for Angular applications
757 lines • 109 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.19
* @since 2025-07-11
*/
export class LogsPerformatico {
// 🆕 Adiciona requests para registrar requisições HTTP
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.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;
const nome = ((_a = authReq.body) === null || _a === void 0 ? void 0 : _a.name) ||
this.extrairNomeDeSQL((_b = authReq.body) === null || _b === void 0 ? void 0 : _b.sqlInstruction) ||
'(desconhecido)';
const atual = this.httpRequests.get(nome) || {
tempoTotal: 0,
execucoes: 0,
errors: 0,
};
atual.tempoTotal += tempo;
atual.execucoes += 1;
if (error)
atual.errors += 1;
this.httpRequests.set(nome, 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);
console.log(`║ [INÍCIO] ${operationName} - ${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;
if (!this.monitoramentoAtivo)
return;
const startTime = this.performanceTimers.get(operationName);
if (!startTime) {
console.warn(`⚠️ Timer não encontrado para: ${operationName}`);
return;
}
const elapsedTime = Date.now() - startTime;
this.performanceTimers.delete(operationName);
// Desempilha contexto de função monitorada
if (this.functionContextStack[this.functionContextStack.length - 1] ===
operationName) {
this.functionContextStack.pop();
}
// Determina status baseado no tempo (com thresholds customizados se fornecidos ou dinâmicos)
const { emoji, status, color } = this.getPerformanceStatus(elapsedTime, customThresholds, operationName);
// Log com emoji e cor (com mensagem customizada se fornecida)
const message = customMessage
? `${operationName} - ${customMessage}`
: `${operationName}`;
const fixedStatus = `[${status}]`.padEnd(5); // Ex: '[OK] '
const fixedMessage = message.padEnd(10); // Nome da função
const fixedTime = elapsedTime.toString().padStart(5); // 5 para " 16ms", "2193ms"
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<${(_a = customThresholds.ok) !== null && _a !== void 0 ? _a : 500}ms, LENTO<${(_b = customThresholds.lento) !== null && _b !== void 0 ? _b : 2000}ms`);
}
// Atualiza sumário (com thresholds customizados se fornecidos)
this.updatePerformanceSummary(operationName, elapsedTime, 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: `${avgTime}ms (${status}) ${emoji}`.trim(),
Mínimo: `${stats.minTime}ms`,
Máximo: `${stats.maxTime}ms`,
Total: `${stats.totalTime}ms`,
},
];
}));
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();
}
/**
* 🧹 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.performanceTimers.size > 0;
}
/**
* 🗑️ Limpa apenas os timers ativos (não as estatísticas)
*/
clearActiveTimers() {
this.performanceTimers.clear();
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;');
}
/**
* 💾 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');
// Inicialmente escondidos
btnRequisicoesDetalhadas.style.display = 'none';
btnAnaliseDetalhada.style.display = 'none';
btnFinalizar.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';
break;
case 'monitorando':
btnMain.innerText = 'Parar monitoramento';
this.monitoramentoAtivo = true;
btnFinalizar.style.display = 'none';
btnRequisicoesDetalhadas.style.display = 'none';
btnAnaliseDetalhada.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';
break;
case 'relatorio_gerado':
btnMain.innerText = 'Gerar relatório';
this.monitoramentoAtivo = false;
btnFinalizar.style.display = 'block';
btnRequisicoesDetalhadas.style.display = 'block';
btnAnaliseDetalhada.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(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();
};
}
}
/**
* 🏭 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nLXBlcmZvcm1hdGljby5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3BlcmZvcm1hbmNlLW1vbml0b3ItbG9nZ2VyL3NyYy9saWIvbG9nLXBlcmZvcm1hdGljby50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQWdCSCxNQUFNLE9BQU8sZ0JBQWdCO0lBYTNCLHVEQUF1RDtJQUV2RCxZQUFZLGNBQXNCLFNBQVM7UUFkbkMsdUJBQWtCLEdBQVksSUFBSSxDQUFDLENBQUMsK0JBQStCO1FBQzNFLDZCQUE2QjtRQUNyQixzQkFBaUIsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUM5Qyx1QkFBa0IsR0FBRyxJQUFJLEdBQUcsRUFBNEIsQ0FBQztRQUV6RCxpQkFBWSxHQUdoQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRWQsOENBQThDO1FBQ3RDLHlCQUFvQixHQUFhLEVBQUUsQ0FBQztRQUkxQyxJQUFJLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztJQUNqQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsbUJBQW1CLENBQ2pCLE9BQVksRUFDWixLQUFhLEVBQ2IsUUFBaUIsS0FBSzs7UUFFdEIsTUFBTSxJQUFJLEdBQ1IsT0FBQSxPQUFPLENBQUMsSUFBSSwwQ0FBRSxJQUFJO1lBQ2xCLElBQUksQ0FBQyxnQkFBZ0IsT0FBQyxPQUFPLENBQUMsSUFBSSwwQ0FBRSxjQUFjLENBQUM7WUFDbkQsZ0JBQWdCLENBQUM7UUFFbkIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUk7WUFDM0MsVUFBVSxFQUFFLENBQUM7WUFDYixTQUFTLEVBQUUsQ0FBQztZQUNaLE1BQU0sRUFBRSxDQUFDO1NBQ1YsQ0FBQztRQUVGLEtBQUssQ0FBQyxVQUFVLElBQUksS0FBSyxDQUFDO1FBQzFCLEtBQUssQ0FBQyxTQUFTLElBQUks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LE9BQU8sSUFBSSxnQkFBZ0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUMzQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXHJcbiAqIPCfk4ogU0lTVEVNQSBERSBMT0dTIERFIFBFUkZPUk1BTkNFXHJcbiAqXHJcbiAqIFNpc3RlbWEgY29tcGxldG8gZGUgbW9uaXRvcmFtZW50byBkZSBwZXJmb3JtYW5jZSBwYXJhIGFwbGljYcOnw7VlcyBBbmd1bGFyXHJcbiAqIGNvbSBmZWVkYmFjayB2aXN1YWwgYXRyYXbDqXMgZGUgZW1vamlzIGUgcmVsYXTDs3Jpb3MgYXV0b23DoXRpY29zLlxyXG4gKlxyXG4gKiBDYXJhY3RlcsOtc3RpY2FzOlxyXG4gKiAtIPCfk4ggTW9uaXRvcmFtZW50byBlbSBUZW1wbyBSZWFsXHJcbiAqIC0g8J+fovCfn6Hwn5S0IENsYXNzaWZpY2HDp8OjbyBWaXN1YWwgcG9yIFBlcmZvcm1hbmNlXHJcbiAqIC0g4o+wIFJlbGF0w7NyaW9zIEF1dG9tw6F0aWNvcyBhcMOzcyBJbmF0aXZpZGFkZVxyXG4gKiAtIPCfk4ogQW7DoWxpc2UgRGV0YWxoYWRhIGNvbSBSZWNvbWVuZGHDp8O1ZXNcclxuICogLSDwn5ug77iPIEFQSSBQw7pibGljYSBwYXJhIENvbnRyb2xlIE1hbnVhbFxyXG4gKlxyXG4gKiBAYXV0aG9yIFBlZHJvIEhlbnJpcXVlIGRvcyBTYW50b3MgTGV1Y2hzXHJcbiAqIEB2ZXJzaW9uIDEuMC4xOVxyXG4gKiBAc2luY2UgMjAyNS0wNy0xMVxyXG4gKi9cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgUGVyZm9ybWFuY2VTdGF0cyB7XHJcbiAgY291bnQ6IG51bWJlcjtcclxuICB0b3RhbFRpbWU6IG51bWJlcjtcclxuICBtaW5UaW1lOiBudW1iZXI7XHJcbiAgbWF4VGltZTogbnVtYmVyO1xyXG4gIGN1c3RvbVRocmVzaG9sZHM/OiB7IG9rPzogbnVtYmVyOyBsZW50bz86IG51bWJlcjsgY3JpdGljbz86IG51bWJlciB9OyAvLyDwn4aVIEFybWF6ZW5hIHRocmVzaG9sZHMgY3VzdG9taXphZG9zXHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgRHluYW1pY1RocmVzaG9sZHMge1xyXG4gIG9rOiBudW1iZXI7XHJcbiAgbGVudG86IG51bWJlcjtcclxuICBjcml0aWNvOiBudW1iZXI7XHJcbn1cclxuXHJcbmV4cG9ydCBjbGFzcyBMb2dzUGVyZm9ybWF0aWNvIHtcclxuICBwcml2YXRlIG1vbml0b3JhbWVudG9BdGl2bzogYm9vbGVhbiA9IHRydWU7IC8vIENvbWXDp2EgYXRpdm8gbmEgcHJpbWVpcmEgdmV6XHJcbiAgLy8g8J+TiiBQcm9wcmllZGFkZXMgZG8gU2lzdGVtYVxyXG4gIHByaXZhdGUgcGVyZm9ybWFuY2VUaW1lcnMgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xyXG4gIHByaXZhdGUgcGVyZm9ybWFuY2VTdW1tYXJ5ID0gbmV3IE1hcDxzdHJpbmcsIFBlcmZvcm1hbmNlU3RhdHM+KCk7XHJcbiAgcHJpdmF0ZSBzZXJ2aWNlTmFtZTogc3RyaW5nO1xyXG4gIHByaXZhdGUgaHR0cFJlcXVlc3RzOiBNYXA8XHJcbiAgICBzdHJpbmcsXHJcbiAgICB7IHRlbXBvVG90YWw6IG51bWJlcjsgZXhlY3Vjb2VzOiBudW1iZXI7IGVycm9yczogbnVtYmVyIH1cclxuICA+ID0gbmV3IE1hcCgpO1xyXG5cclxuICAvLyDwn4aVIFN0YWNrIHBhcmEgY29udGV4dG8gZGUgZnVuw6fDo28gbW9uaXRvcmFkYVxyXG4gIHByaXZhdGUgZnVuY3Rpb25Db250ZXh0U3RhY2s6IHN0cmluZ1tdID0gW107XHJcbiAgLy8g8J+GlSBBZGljaW9uYSByZXF1ZXN0cyBwYXJhIHJlZ2lzdHJhciByZXF1aXNpw6fDtWVzIEhUVFBcclxuXHJcbiAgY29uc3RydWN0b3Ioc2VydmljZU5hbWU6IHN0cmluZyA9ICdTZXJ2aWNlJykge1xyXG4gICAgdGhpcy5zZXJ2aWNlTmFtZSA9IHNlcnZpY2VOYW1lO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmVnaXN0cmEgcmVxdWlzacOnw6NvIEhUVFAgYXNzb2NpYW5kbyDDoCBmdW7Dp8OjbyBtb25pdG9yYWRhIGF0aXZhIChzZSBob3V2ZXIpXHJcbiAgICogQHBhcmFtIHBheWxvYWQgRGFkb3MgZGEgcmVxdWlzacOnw6NvXHJcbiAgICovXHJcbiAgcmVnaXN0ZXJIdHRwUmVxdWVzdChcclxuICAgIGF1dGhSZXE6IGFueSxcclxuICAgIHRlbXBvOiBudW1iZXIsXHJcbiAgICBlcnJvcjogYm9vbGVhbiA9IGZhbHNlXHJcbiAgKTogdm9pZCB7XHJcbiAgICBjb25zdCBub21lID1cclxuICAgICAgYXV0aFJlcS5ib2R5Py5uYW1lIHx8XHJcbiAgICAgIHRoaXMuZXh0cmFpck5vbWVEZVNRTChhdXRoUmVxLmJvZHk/LnNxbEluc3RydWN0aW9uKSB8fFxyXG4gICAgICAnKGRlc2NvbmhlY2lkbyknO1xyXG5cclxuICAgIGNvbnN0IGF0dWFsID0gdGhpcy5odHRwUmVxdWVzdHMuZ2V0KG5vbWUpIHx8IHtcclxuICAgICAgdGVtcG9Ub3RhbDogMCxcclxuICAgICAgZXhlY3Vjb2VzOiAwLFxyXG4gICAgICBlcnJvcnM6IDAsXHJcbiAgICB9O1xyXG5cclxuICAgIGF0dWFsLnRlbXBvVG90YWwgKz0gdGVtcG87XHJcbiAgICBhdHVhbC5leGVjdWNvZXMgKz0gMTtcclxuICAgIGlmIChlcnJvcikgYXR1YWwuZXJyb3JzICs9IDE7XHJcblxyXG4gICAgdGhpcy5odHRwUmVxdWVzdHMuc2V0KG5vbWUsIGF0dWFsKTtcclxuICB9XHJcblxyXG4gIC8vIEZ1bsOnw6NvIGF1eGlsaWFyIHBhcmEgZXh0cmFpciBub21lIGRhIGZ1bsOnw6NvIGRlIHVtIFNRTCwgZXg6IFBBQ0tfUEFSTUdFTi5DT05TVUxUQV9QQVJBTUVUUk8oLi4uKVxyXG4gIHByaXZhdGUgZXh0cmFpck5vbWVEZVNRTChzcWw6IHN0cmluZyk6IHN0cmluZyB8IG51bGwge1xyXG4gICAgaWYgKCFzcWwpIHJldHVybiBudWxsO1xyXG4gICAgY29uc3QgbWF0Y2ggPSBzcWwubWF0Y2goLyhbQS1aMC05X10rXFwuW0EtWjAtOV9dKykvaSk7XHJcbiAgICByZXR1cm4gbWF0Y2ggPyBtYXRjaFsxXSA6IG51bGw7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn5qAIE1lbnNhZ2VtIGRlIGJvYXMtdmluZGFzIGRvIHNpc3RlbWFcclxuICAgKi9cclxuICBwdWJsaWMgc2hvd1dlbGNvbWVNZXNzYWdlKCk6IHZvaWQge1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIGAlY1NJU1RFTUEgREUgTU9OSVRPUkFNRU5UTyBERSBQRVJGT1JNQU5DRWAsXHJcbiAgICAgICdjb2xvcjogI2JiYzdjOGZmOyBmb250LXNpemU6IDE4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyB0ZXh0LXNoYWRvdzogMXB4IDFweCAjMDAwOyBiYWNrZ3JvdW5kLWNvbG9yOiAjNDMyNDhiZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMTBweCAyMHB4OydcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDij7HvuI8gSW5pY2lhIGNyb27DtG1ldHJvIHBhcmEgdW1hIG9wZXJhw6fDo29cclxuICAgKiBAcGFyYW0gb3BlcmF0aW9uTmFtZSBOb21lIGRhIG9wZXJhw6fDo28gYSBzZXIgbW9uaXRvcmFkYVxyXG4gICAqL1xyXG4gIHB1YmxpYyBzdGFydFRpbWVyKG9wZXJhdGlvbk5hbWU6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLm1vbml0b3JhbWVudG9BdGl2bykgcmV0dXJuO1xyXG4gICAgLy8gU2UgZm9yIGEgcHJpbWVpcmEgb3BlcmHDp8OjbywgYWJyZSBib3JkYSB2aXN1YWxcclxuICAgIGlmIChcclxuICAgICAgdGhpcy5wZXJmb3JtYW5jZVRpbWVycy5zaXplID09PSAwICYmXHJcbiAgICAgIHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LnNpemUgPT09IDBcclxuICAgICkge1xyXG4gICAgICBjb25zdCBib3JkZXIgPSAn4pWQJy5yZXBlYXQoNTYpO1xyXG5cclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgYCVjSU7DjUNJTyBETyBNT05JVE9SQU1FTlRPIERFIFBFUkZPUk1BTkNFYCxcclxuICAgICAgICAnY29sb3I6ICNiYmM3YzhmZjsgZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsgdGV4dC1zaGFkb3c6IDFweCAxcHggIzAwMDsgYmFja2dyb3VuZC1jb2xvcjogIzQzMjQ4YmZmOyBib3JkZXItcmFkaXVzOiA1cHg7IHBhZGRpbmc6IDEwcHggMjBweDsnXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICB0aGlzLnBlcmZvcm1hbmNlVGltZXJzLnNldChvcGVyYXRpb25OYW1lLCBEYXRlLm5vdygpKTtcclxuICAgIC8vIEVtcGlsaGEgY29udGV4dG8gZGUgZnVuw6fDo28gbW9uaXRvcmFkYVxyXG4gICAgdGhpcy5mdW5jdGlvbkNvbnRleHRTdGFjay5wdXNoKG9wZXJhdGlvbk5hbWUpO1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIGDilZEgW0lOw41DSU9dICR7b3BlcmF0aW9uTmFtZX0gLSAke25ldyBEYXRlKCkudG9Mb2NhbGVUaW1lU3RyaW5nKCl9YFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfj4EgRmluYWxpemEgY3JvbsO0bWV0cm8gZSBleGliZSByZXN1bHRhZG8gY29tIGVtb2ppXHJcbiAgICogQHBhcmFtIG9wZXJhdGlvbk5hbWUgTm9tZSBkYSBvcGVyYcOnw6NvXHJcbiAgICogQHBhcmFtIGN1c3RvbU1lc3NhZ2UgTWVuc2FnZW0gY3VzdG9taXphZGEgb3BjaW9uYWwgKGV4OiBwYXJhIGVycm9zKVxyXG4gICAqIEBwYXJhbSBjdXN0b21UaHJlc2hvbGRzIFRocmVzaG9sZHMgY3VzdG9taXphZG9zIHBhcmEgZXN0YSBvcGVyYcOnw6NvIGVzcGVjw61maWNhXHJcbiAgICovXHJcbiAgcHVibGljIGVuZFRpbWVyKFxyXG4gICAgb3BlcmF0aW9uTmFtZTogc3RyaW5nLFxyXG4gICAgY3VzdG9tTWVzc2FnZT86IHN0cmluZyxcclxuICAgIGN1c3RvbVRocmVzaG9sZHM/OiB7IG9rPzogbnVtYmVyOyBsZW50bz86IG51bWJlcjsgY3JpdGljbz86IG51bWJlciB9XHJcbiAgKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMubW9uaXRvcmFtZW50b0F0aXZvKSByZXR1cm47XHJcbiAgICBjb25zdCBzdGFydFRpbWUgPSB0aGlzLnBlcmZvcm1hbmNlVGltZXJzLmdldChvcGVyYXRpb25OYW1lKTtcclxuICAgIGlmICghc3RhcnRUaW1lKSB7XHJcbiAgICAgIGNvbnNvbGUud2Fybihg4pqg77iPIFRpbWVyIG7Do28gZW5jb250cmFkbyBwYXJhOiAke29wZXJhdGlvbk5hbWV9YCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBlbGFwc2VkVGltZSA9IERhdGUubm93KCkgLSBzdGFydFRpbWU7XHJcbiAgICB0aGlzLnBlcmZvcm1hbmNlVGltZXJzLmRlbGV0ZShvcGVyYXRpb25OYW1lKTtcclxuICAgIC8vIERlc2VtcGlsaGEgY29udGV4dG8gZGUgZnVuw6fDo28gbW9uaXRvcmFkYVxyXG4gICAgaWYgKFxyXG4gICAgICB0aGlzLmZ1bmN0aW9uQ29udGV4dFN0YWNrW3RoaXMuZnVuY3Rpb25Db250ZXh0U3RhY2subGVuZ3RoIC0gMV0gPT09XHJcbiAgICAgIG9wZXJhdGlvbk5hbWVcclxuICAgICkge1xyXG4gICAgICB0aGlzLmZ1bmN0aW9uQ29udGV4dFN0YWNrLnBvcCgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERldGVybWluYSBzdGF0dXMgYmFzZWFkbyBubyB0ZW1wbyAoY29tIHRocmVzaG9sZHMgY3VzdG9taXphZG9zIHNlIGZvcm5lY2lkb3Mgb3UgZGluw6JtaWNvcylcclxuICAgIGNvbnN0IHsgZW1vamksIHN0YXR1cywgY29sb3IgfSA9IHRoaXMuZ2V0UGVyZm9ybWFuY2VTdGF0dXMoXHJcbiAgICAgIGVsYXBzZWRUaW1lLFxyXG4gICAgICBjdXN0b21UaHJlc2hvbGRzLFxyXG4gICAgICBvcGVyYXRpb25OYW1lXHJcbiAgICApO1xyXG5cclxuICAgIC8vIExvZyBjb20gZW1vamkgZSBjb3IgKGNvbSBtZW5zYWdlbSBjdXN0b21pemFkYSBzZSBmb3JuZWNpZGEpXHJcbiAgICBjb25zdCBtZXNzYWdlID0gY3VzdG9tTWVzc2FnZVxyXG4gICAgICA/IGAke29wZXJhdGlvbk5hbWV9IC0gJHtjdXN0b21NZXNzYWdlfWBcclxuICAgICAgOiBgJHtvcGVyYXRpb25OYW1lfWA7XHJcbiAgICBjb25zdCBmaXhlZFN0YXR1cyA9IGBbJHtzdGF0dXN9XWAucGFkRW5kKDUpOyAvLyBFeDogJ1tPS10gICAgICAnXHJcbiAgICBjb25zdCBmaXhlZE1lc3NhZ2UgPSBtZXNzYWdlLnBhZEVuZCgxMCk7IC8vIE5vbWUgZGEgZnVuw6fDo29cclxuICAgIGNvbnN0IGZpeGVkVGltZSA9IGVsYXBzZWRUaW1lLnRvU3RyaW5nKCkucGFkU3RhcnQoNSk7IC8vIDUgcGFyYSBcIiAxNm1zXCIsIFwiMjE5M21zXCJcclxuXHJcbiAgICBjb25zb2xlLmxvZyhcclxuICAgICAgYOKVkSAlYyR7ZW1vaml9ICR7Zml4ZWRTdGF0dXN9ICR7Zml4ZWRNZXNzYWdlfSAtICR7Zml4ZWRUaW1lfW1zIGAsXHJcbiAgICAgIGNvbG9yXHJcbiAgICApO1xyXG5cclxuICAgIC8vIE1vc3RyYSB0aHJlc2hvbGRzIGN1c3RvbWl6YWRvcyBzZSBlc3RpdmVyZW0gc2VuZG8gdXNhZG9zXHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbVRocmVzaG9sZHMgJiZcclxuICAgICAgKGN1c3RvbVRocmVzaG9sZHMub2sgfHxcclxuICAgICAgICBjdXN0b21UaHJlc2hvbGRzLmxlbnRvIHx8XHJcbiAgICAgICAgY3VzdG9tVGhyZXNob2xkcy5jcml0aWNvKVxyXG4gICAgKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgIGDimpnvuI8gVGhyZXNob2xkcyBjdXN0b21pemFkb3M6IE9LPCR7XHJcbiAgICAgICAgICBjdXN0b21UaHJlc2hvbGRzLm9rID8/IDUwMFxyXG4gICAgICAgIH1tcywgTEVOVE88JHtjdXN0b21UaHJlc2hvbGRzLmxlbnRvID8/IDIwMDB9bXNgXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQXR1YWxpemEgc3Vtw6FyaW8gKGNvbSB0aHJlc2hvbGRzIGN1c3RvbWl6YWRvcyBzZSBmb3JuZWNpZG9zKVxyXG4gICAgdGhpcy51cGRhdGVQZXJmb3JtYW5jZVN1bW1hcnkob3BlcmF0aW9uTmFtZSwgZWxhcHNlZFRpbWUsIGN1c3RvbVRocmVzaG9sZHMpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+OqCBEZXRlcm1pbmEgc3RhdHVzIGRlIHBlcmZvcm1hbmNlIGJhc2VhZG8gbm8gdGVtcG9cclxuICAgKiBAcGFyYW0gZWxhcHNlZFRpbWUgVGVtcG8gZGVjb3JyaWRvIGVtIG1pbGlzc2VndW5kb3NcclxuICAgKiBAcGFyYW0gY3VzdG9tVGhyZXNob2xkcyBUaHJlc2hvbGRzIGN1c3RvbWl6YWRvcyBwYXJhIGVzdGEgb3BlcmHDp8OjbyBlc3BlY8OtZmljYVxyXG4gICAqIEBwYXJhbSBvcGVyYXRpb25OYW1lIE5vbWUgZGEgb3BlcmHDp8OjbyAocGFyYSBjYWxjdWxhciB0aHJlc2hvbGRzIGRpbsOibWljb3MpXHJcbiAgICogQHJldHVybnMgT2JqZXRvIGNvbSBlbW9qaSwgc3RhdHVzIGUgY29yXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRQZXJmb3JtYW5jZVN0YXR1cyhcclxuICAgIGVsYXBzZWRUaW1lOiBudW1iZXIsXHJcbiAgICBjdXN0b21UaHJlc2hvbGRzPzogeyBvaz86IG51bWJlcjsgbGVudG8/OiBudW1iZXI7IGNyaXRpY28/OiBudW1iZXIgfSxcclxuICAgIG9wZXJhdGlvbk5hbWU/OiBzdHJpbmdcclxuICApOiB7IGVtb2ppOiBzdHJpbmc7IHN0YXR1czogc3RyaW5nOyBjb2xvcjogc3RyaW5nIH0ge1xyXG4gICAgbGV0IG9rVGhyZXNob2xkOiBudW1iZXI7XHJcbiAgICBsZXQgbGVudG9UaHJlc2hvbGQ6IG51bWJlcjtcclxuICAgIGxldCBjcml0aWNvVGhyZXNob2xkOiBudW1iZXI7XHJcblxyXG4gICAgaWYgKFxyXG4gICAgICBjdXN0b21UaHJlc2hvbGRzICYmXHJcbiAgICAgIChjdXN0b21UaHJlc2hvbGRzLm9rIHx8XHJcbiAgICAgICAgY3VzdG9tVGhyZXNob2xkcy5sZW50byB8fFxyXG4gICAgICAgIGN1c3RvbVRocmVzaG9sZHMuY3JpdGljbylcclxuICAgICkge1xyXG4gICAgICAvLyBVc2EgdGhyZXNob2xkcyBjdXN0b21pemFkb3Mgc2UgZm9ybmVjaWRvc1xyXG4gICAgICBva1RocmVzaG9sZCA9IGN1c3RvbVRocmVzaG9sZHMub2sgPz8gNTAwO1xyXG4gICAgICBsZW50b1RocmVzaG9sZCA9IGN1c3RvbVRocmVzaG9sZHMubGVudG8gPz8gMjAwMDtcclxuICAgICAgY3JpdGljb1RocmVzaG9sZCA9IGN1c3RvbVRocmVzaG9sZHMuY3JpdGljbyA/PyBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUjtcclxuICAgIH0gZWxzZSBpZiAob3BlcmF0aW9uTmFtZSkge1xyXG4gICAgICAvLyBDYWxjdWxhIHRocmVzaG9sZHMgZGluw6JtaWNvcyBiYXNlYWRvcyBuYSBxdWFudGlkYWRlIGRlIGV4ZWN1w6fDtWVzXHJcbiAgICAgIGNvbnN0IHN0YXRzID0gdGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuZ2V0KG9wZXJhdGlvbk5hbWUpO1xyXG4gICAgICAvLyBDb3JyaWdlOiBzb21hICsxIHBhcmEgY29uc2lkZXJhciBhIGV4ZWN1w6fDo28gYXR1YWxcclxuICAgICAgY29uc3QgZXhlY3V0aW9uQ291bnQgPSBzdGF0cyA/IHN0YXRzLmNvdW50ICsgMSA6IDE7XHJcbiAgICAgIGNvbnN0IGR5bmFtaWNUaHJlc2hvbGRzID0gdGhpcy5jYWxjdWxhdGVEeW5hbWljVGhyZXNob2xkcyhleGVjdXRpb25Db3VudCk7XHJcblxyXG4gICAgICBva1RocmVzaG9sZCA9IGR5bmFtaWNUaHJlc2hvbGRzLm9rO1xyXG4gICAgICBsZW50b1RocmVzaG9sZCA9IGR5bmFtaWNUaHJlc2hvbGRzLmxlbnRvO1xyXG4gICAgICBjcml0aWNvVGhyZXNob2xkID0gZHluYW1pY1RocmVzaG9sZHMuY3JpdGljbztcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIFVzYSB0aHJlc2hvbGRzIHBhZHLDtWVzXHJcbiAgICAgIG9rVGhyZXNob2xkID0gNTAwO1xyXG4gICAgICBsZW50b1RocmVzaG9sZCA9IDIwMDA7XHJcbiAgICAgIGNyaXRpY29UaHJlc2hvbGQgPSBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUjtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZWxhcHNlZFRpbWUgPCBva1RocmVzaG9sZCkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIGVtb2ppOiAn8J+foicsXHJcbiAgICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICAgIGNvbG9yOiAnY29sb3I6IGdyZWVuOyBmb250LXdlaWdodDogYm9sZDsnLFxyXG4gICAgICB9O1xyXG4gICAgfSBlbHNlIGlmIChlbGFwc2VkVGltZSA8IGxlbnRvVGhyZXNob2xkKSB7XHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgZW1vamk6ICfwn5+hJyxcclxuICAgICAgICBzdGF0dXM6ICdMRU5UTycsXHJcbiAgICAgICAgY29sb3I6ICdjb2xvcjogb3JhbmdlOyBmb250LXdlaWdodDogYm9sZDsnLFxyXG4gICAgICB9O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBlbW9qaTogJ/CflLQnLFxyXG4gICAgICAgIHN0YXR1czogJ0NSw41USUNPJyxcclxuICAgICAgICBjb2xvcjogJ2NvbG9yOiByZWQ7IGZvbnQtd2VpZ2h0OiBib2xkOycsXHJcbiAgICAgIH07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn5OIIEF0dWFsaXphIGVzdGF0w61zdGljYXMgZGUgcGVyZm9ybWFuY2UgcGFyYSBvIHN1bcOhcmlvXHJcbiAgICogQHBhcmFtIG9wZXJhdGlvbk5hbWUgTm9tZSBkYSBvcGVyYcOnw6NvXHJcbiAgICogQHBhcmFtIGVsYXBzZWRUaW1lIFRlbXBvIGRlY29ycmlkbyBlbSBtaWxpc3NlZ3VuZG9zXHJcbiAgICogQHBhcmFtIGN1c3RvbVRocmVzaG9sZHMgVGhyZXNob2xkcyBjdXN0b21pemFkb3MgcGFyYSBhcm1hemVuYXIgKG9wY2lvbmFsKVxyXG4gICAqL1xyXG4gIHByaXZhdGUgdXBkYXRlUGVyZm9ybWFuY2VTdW1tYXJ5KFxyXG4gICAgb3BlcmF0aW9uTmFtZTogc3RyaW5nLFxyXG4gICAgZWxhcHNlZFRpbWU6IG51bWJlcixcclxuICAgIGN1c3RvbVRocmVzaG9sZHM/OiB7IG9rPzogbnVtYmVyOyBsZW50bz86IG51bWJlcjsgY3JpdGljbz86IG51bWJlciB9XHJcbiAgKTogdm9pZCB7XHJcbiAgICBjb25zdCBleGlzdGluZyA9IHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LmdldChvcGVyYXRpb25OYW1lKTtcclxuXHJcbiAgICBpZiAoZXhpc3RpbmcpIHtcclxuICAgICAgZXhpc3RpbmcuY291bnQrKztcclxuICAgICAgZXhpc3RpbmcudG90YWxUaW1lICs9IGVsYXBzZWRUaW1lO1xyXG4gICAgICBleGlzdGluZy5taW5UaW1lID0gTWF0aC5taW4oZXhpc3RpbmcubWluVGltZSwgZWxhcHNlZFRpbWUpO1xyXG4gICAgICBleGlzdGluZy5tYXhUaW1lID0gTWF0aC5tYXgoZXhpc3RpbmcubWF4VGltZSwgZWxhcHNlZFRpbWUpO1xyXG5cclxuICAgICAgLy8gQXR1YWxpemEgdGhyZXNob2xkcyBjdXN0b21pemFkb3Mgc2UgZm9ybmVjaWRvc1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgY3VzdG9tVGhyZXNob2xkcyAmJlxyXG4gICAgICAgIChjdXN0b21UaHJlc2hvbGRzLm9rIHx8XHJcbiAgICAgICAgICBjdXN0b21UaHJlc2hvbGRzLmxlbnRvIHx8XHJcbiAgICAgICAgICBjdXN0b21UaHJlc2hvbGRzLmNyaXRpY28pXHJcbiAgICAgICkge1xyXG4gICAgICAgIGV4aXN0aW5nLmN1c3RvbVRocmVzaG9sZHMgPSBjdXN0b21UaHJlc2hvbGRzO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5zZXQob3BlcmF0aW9uTmFtZSwge1xyXG4gICAgICAgIGNvdW50OiAxLFxyXG4gICAgICAgIHRvdGFsVGltZTogZWxhcHNlZFRpbWUsXHJcbiAgICAgICAgbWluVGltZTogZWxhcHNlZFRpbWUsXHJcbiAgICAgICAgbWF4VGltZTogZWxhcHNlZFRpbWUsXHJcbiAgICAgICAgY3VzdG9tVGhyZXNob2xkczogY3VzdG9tVGhyZXNob2xkcyxcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTsOjbyBmYXogbWFpcyBuYWRhIGFxdWksIHJlbGF0w7NyaW8gc8OzIG1hbnVhbFxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+TiiBFeGliZSByZWxhdMOzcmlvIHJlc3VtaWRvIGRlIHRvZGFzIGFzIG9wZXJhw6fDtWVzIChjb21wYWN0YWRvKVxyXG4gICAqL1xyXG4gIHB1YmxpYyBzaG93UGVyZm9ybWFuY2VTdW1tYXJ5KHNob3dGdWxsRGV0YWlscyA9IGZhbHNlKTogdm9pZCB7XHJcbiAgICAvLyBGZWNoYSBib3JkYSBkbyBtb25pdG9yYW1lbnRvIGFvIGdlcmFyIHJlbGF0w7NyaW9cclxuICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAnJWMgUkVMQVTDk1JJTyBERSBQRVJGT1JNQU5DRScsXHJcbiAgICAgICdjb2xvcjogI2JiYzdjOGZmOyBmb250LXNpemU6IDE4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyB0ZXh0LXNoYWRvdzogMXB4IDFweCAjMDAwOyBiYWNrZ3JvdW5kLWNvbG9yOiAjNDMyNDhiZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMTBweCAyMHB4OydcclxuICAgICk7XHJcblxyXG4gICAgaWYgKHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LnNpemUgPT09IDApIHtcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgJyVjIE5lbmh1bWEgb3BlcmHDp8OjbyBtb25pdG9yYWRhIGFpbmRhLicsXHJcbiAgICAgICAgJ2NvbG9yOiBncmF5OyBmb250LXN0eWxlOiBpdGFsaWM7J1xyXG4gICAgICApO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3Qgc29ydGVkRW50cmllcyA9IEFycmF5LmZyb20odGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuZW50cmllcygpKS5zb3J0KFxyXG4gICAgICAoYSwgYikgPT4gYlsxXS5tYXhUaW1lIC0gYVsxXS5tYXhUaW1lXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHRhYmxlID0gT2JqZWN0LmZyb21FbnRyaWVzKFxyXG4gICAgICBzb3J0ZWRFbnRyaWVzLm1hcCgoW29wZXJhdGlvbiwgc3RhdHNdKSA9PiB7XHJcbiAgICAgICAgY29uc3QgYXZnVGltZSA9IE1hdGgucm91bmQoc3RhdHMudG90YWxUaW1lIC8gc3RhdHMuY291bnQpO1xyXG4gICAgICAgIGNvbnN0IHsgZW1vamksIHN0YXR1cyB9ID0gdGhpcy5nZXRQZXJmb3JtYW5jZVN0YXR1cyhcclxuICAgICAgICAgIGF2Z1RpbWUsXHJcbiAgICAgICAgICBzdGF0cy5jdXN0b21UaHJlc2hvbGRzLFxyXG4gICAgICAgICAgb3BlcmF0aW9uXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIFtcclxuICAgICAgICAgIG9wZXJhdGlvbixcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgRXhlY3XDp8O1ZXM6IHN0YXRzLmNvdW50LFxyXG4gICAgICAgICAgICBNw6lkaWE6IGAke2F2Z1RpbWV9bXMgKCR7c3RhdHVzfSkgJHtlbW9qaX1gLnRyaW0oKSxcclxuICAgICAgICAgICAgTcOtbmltbzogYCR7c3RhdHMubWluVGltZX1tc2AsXHJcbiAgICAgICAgICAgIE3DoXhpbW86IGAke3N0YXRzLm1heFRpbWV9bXNgLFxyXG4gICAgICAgICAgICBUb3RhbDogYCR7c3RhdHMudG90YWxUaW1lfW1zYCxcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgXTtcclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgY29uc29sZS50YWJsZSh0YWJsZSk7XHJcblxyXG4gICAgLy8gUmVtb3ZpZG86IGFnb3JhIGEgYW7DoWxpc2UgZGV0YWxoYWRhIMOpIGNoYW1hZGEgYXBlbmFzIHBlbG8gYm90w6NvXHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIPCfk5EgRXhpYmUgcmVsYXTDs3JpbyBkZXRhbGhhZG8gZGUgcmVxdWlzacOnw7VlcyBIVFRQIGFncnVwYWRhcyBwb3IgZnVuw6fDo29cclxuICAgKi9cclxuICBwdWJsaWMgc2hvd0h0dHBSZXF1ZXN0c1JlcG9ydCgpOiB2b2lkIHtcclxuICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICBgJWNSRUxBVMOTUklPIERFVEFMSEFETyBERSBSRVFVSVNJw4fDlUVTIEhUVFBgLFxyXG4gICAgICAnY29sb3I6ICNiYmM3YzhmZjsgZm9udC1zaXplOiAxOHB4OyBmb250LXdlaWdodDogYm9sZDsgdGV4dC1zaGFkb3c6IDFweCAxcHggIzAwMDsgYmFja2dyb3VuZC1jb2xvcjogIzQzMjQ4YmZmOyBib3JkZXItcmFkaXVzOiA1cHg7IHBhZGRpbmc6IDEwcHggMjBweDsnXHJcbiAgICApO1xyXG5cclxuICAgIGlmICh0aGlzLmh0dHBSZXF1ZXN0cy5zaXplID09PSAwKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKCdOZW5odW1hIHJlcXVpc2nDp8OjbyBIVFRQIHJlZ2lzdHJhZGEuJyk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB0YWJlbGEgPSBPYmplY3QuZnJvbUVudHJpZXMoXHJcbiAgICAgIEFycmF5LmZyb20odGhpcy5odHRwUmVxdWVzdHMuZW50cmllcygpKVxyXG4gICAgICAgIC5zb3J0KChhLCBiKSA9PiBiWzFdLnRlbXBvVG90YWwgLSBhWzFdLnRlbXBvVG90YWwpXHJcbiAgICAgICAgLm1hcCgoW25vbWUsIGRhZG9zXSkgPT4gW1xyXG4gICAgICAgICAgbm9tZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgRXhlY3XDp8O1ZXM6IGRhZG9zLmV4ZWN1Y29lcyxcclxuICAgICAgICAgICAgTcOpZGlhOiBgJHtNYXRoLnJvdW5kKGRhZG9zLnRlbXBvVG90YWwgLyBkYWRvcy5leGVjdWNvZXMpfW1zYCxcclxuICAgICAgICAgICAgJ1RlbXBvIFRvdGFsJzogYCR7TWF0aC5yb3VuZChkYWRvcy50ZW1wb1RvdGFsKX1tc2AsXHJcbiAgICAgICAgICAgIEVycm9zOiBkYWRvcy5lcnJvcnMsXHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgIF0pXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnNvbGUudGFibGUodGFiZWxhKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCflI0gR2VyYSBhbsOhbGlzZSBkZXRhbGhhZGEgZGUgcGVyZm9ybWFuY2VcclxuICAgKi9cclxuICBwdWJsaWMgZ2VuZXJhdGVEZXRhaWxlZEFuYWx5c2lzKCk6IHZvaWQge1xyXG4gICAgLy8gVMOtdHVsbyBkaXNjcmV0b1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgICclY0FOw4FMSVNFIERFVEFMSEFEQSBERSBQRVJGT1JNQU5DRScsXHJcbiAgICAgICdjb2xvcjogI2JiYzdjOGZmOyBmb250LXNpemU6IDE4cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyB0ZXh0LXNoYWRvdzogMXB4IDFweCAjMDAwOyBiYWNrZ3JvdW5kLWNvbG9yOiAjNDMyNDhiZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMTBweCAyMHB4OydcclxuICAgICk7XHJcbiAgICBjb25zb2xlLmxvZygnJyk7XHJcblxyXG4gICAgaWYgKHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LnNpemUgPT09IDApIHtcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgJyVjTmVuaHVtYSBvcGVyYcOnw6NvIHJlZ2lzdHJhZGEgcGFyYSBhbsOhbGlzZS4nLFxyXG4gICAgICAgICdjb2xvcjogI2JiYjsgZm9udC1zdHlsZTogaXRhbGljOyBmb250LXNpemU6IDE0cHg7IHBhZGRpbmc6IDRweCAwIDRweCAxMHB4OydcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgY3JpdGljYWxPcGVyYXRpb25zLCBzbG93T3BlcmF0aW9ucywgZmFzdE9wZXJhdGlvbnMgfSA9XHJcbiAgICAgIHRoaXMuY2F0ZWdvcml6ZU9wZXJhdGlvbnMoKTtcclxuXHJcbiAgICAvLyBIZWxwZXIgcGFyYSBibG9jbyBkaXNjcmV0byBjb20gdGV4dG8gY2xhcm9cclxuICAgIGNvbnN0IHByaW50QmxvY2sgPSAoXHJcbiAgICAgIGNvbG9yOiBzdHJpbmcsXHJcbiAgICAgIGVtb2ppOiBzdHJpbmcsXHJcbiAgICAgIG9wZXJhdGlvbjogc3RyaW5nLFxyXG4gICAgICBhdmc6IG51bWJlcixcclxuICAgICAgZXh0cmE6IHN0cmluZ1xyXG4gICAgKSA9PiB7XHJcbiAgICAgIGNvbnN0IHN0eWxlID0gYGJvcmRlci1sZWZ0OiA0cHggc29saWQgJHtjb2xvcn07IHBhZGRpbmc6IDJweCAwIDJweCAxMHB4OyBtYXJnaW46IDJweCAwIDJweCAwOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjZmZmOyBiYWNrZ3JvdW5kOiBub25lOyBmb250LXdlaWdodDogbm9ybWFsO2A7XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgIGAlYyR7ZW1vaml9ICR7b3BlcmF0aW9ufSAgLSAgJHthdmd9bXMgKG3DqWRpYSkgICR7ZXh0cmF9YC50cmltKCksXHJcbiAgICAgICAgc3R5bGVcclxuICAgICAgKTtcclxuICAgIH07XHJcblxyXG4gICAgaWYgKGNyaXRpY2FsT3BlcmF0aW9ucy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICclY/CflLQgQ1LDjVRJQ0FTICggPiAyMDAwbXMpJyxcclxuICAgICAgICAnY29sb3I6ICNmZmY7IGZvbnQtc2l6ZTogMTRweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IG1hcmdpbi10b3A6IDEwcHg7J1xyXG4gICAgICApO1xyXG4gICAgICBjcml0aWNhbE9wZXJhdGlvbnMuZm9yRWFjaCgoW29wZXJhdGlvbiwgc3RhdHNdKSA9PiB7XHJcbiAgICAgICAgY29uc3QgYXZnID0gTWF0aC5yb3VuZChzdGF0cy50b3RhbFRpbWUgLyBzdGF0cy5jb3VudCk7XHJcbiAgICAgICAgY29uc3QgeyBlbW9qaSB9ID0gdGhpcy5nZXRQZXJmb3JtYW5jZVN0YXR1cyhcclxuICAgICAgICAgIGF2ZyxcclxuICAgICAgICAgIHN0YXRzLmN1c3RvbVRocmVzaG9sZHMsXHJcbiAgICAgICAgICBvcGVyYXRpb25cclxuICAgICAgICApO1xyXG4gICAgICAgIHByaW50QmxvY2soJyNjNTMwMzAnLCBlbW9qaSwgb3BlcmF0aW9uLCBhdmcsICd8IG90aW1pemFyIHVyZ2VudGUnKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHNsb3dPcGVyYXRpb25zLmxlbmd0aCA+IDApIHtcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgJyVj8J+foSBMRU5UQVMgKDUwMG1zIC0gMjAwMG1zKScsXHJcbiAgICAgICAgJ2NvbG9yOiAjZmZmOyBmb250LXNpemU6IDE0cHg7IGZvbnQtd2VpZ2h0OiBib2xkOyBtYXJnaW4tdG9wOiAxMHB4OydcclxuICAgICAgKTtcclxuICAgICAgc2xvd09wZXJhdGlvbnMuZm9yRWFjaCgoW29wZXJhdGlvbiwgc3RhdHNdKSA9PiB7XHJcbiAgICAgICAgY29uc3QgYXZnID0gTWF0aC5yb3VuZChzdGF0cy50b3RhbFRpbWUgLyBzdGF0cy5jb3VudCk7XHJcbiAgICAgICAgY29uc3QgeyBlbW9qaSB9ID0gdGhpcy5nZXRQZXJmb3JtYW5jZVN0YXR1cyhcclxuICAgICAgICAgIGF2ZyxcclxuICAgICAgICAgIHN0YXRzLmN1c3RvbVRocmVzaG9sZHMsXHJcbiAgICAgICAgICBvcGVyYXRpb25cclxuICAgICAgICApO1xyXG4gICAgICAgIHByaW50QmxvY2soJyNiNzc5MWYnLCBlbW9qaSwgb3BlcmF0aW9uLCBhdmcsICd8IHBvZGUgc2VyIG1lbGhvcmFkYScpO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZmFzdE9wZXJhdGlvbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAnJWPwn5+iIFLDgVBJREFTICggPCA1MDBtcyknLFxyXG4gICAgICAgICdjb2xvcjogI2ZmZjsgZm9udC1zaXplOiAxNHB4OyBmb250LXdlaWdodDogYm9sZDsgbWFyZ2luLXRvcDogMTBweDsnXHJcbiAgICAgICk7XHJcbiAgICAgIGZhc3RPcGVyYXRpb25zLmZvckVhY2goKFtvcGVyYXRpb24sIHN0YXRzXSkgPT4ge1xyXG4gICAgICAgIGNvbnN0IGF2ZyA9IE1hdGgucm91bmQoc3RhdHMudG90YWxUaW1lIC8gc3RhdHMuY291bnQpO1xyXG4gICAgICAgIGNvbnN0IHsgZW1vamkgfSA9IHRoaXMuZ2V0UGVyZm9ybWFuY2VTdGF0dXMoXHJcbiAgICAgICAgICBhdmcsXHJcbiAgICAgICAgICBzdGF0cy5jdXN0b21UaHJlc2hvbGRzLFxyXG4gICAgICAgICAgb3BlcmF0aW9uXHJcbiAgICAgICAgKTtcclxuICAgICAgICBwcmludEJsb2NrKCcjMzhhMTY5JywgZW1vamksIG9wZXJhdGlvbiwgYXZnLCAnfCBleGNlbGVudGUnKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVjb21lbmRhw6fDtWVzXHJcbiAgICBjb25zb2xlLmxvZyhcclxuICAgICAgJyVjUmVjb21lbmRhw6fDtWVzOicsXHJcbiAgICAgICdjb2xvcjogI2ZmZjsgZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogYm9sZDsgbWFyZ2luLXRvcDogMTRweDsgcGFkZGluZzogMnB4IDAgMnB4IDA7J1xyXG4gICAgKTtcclxuICAgIGlmIChjcml0aWNhbE9wZXJhdGlvbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAnJWPigKIgUHJpb3JpemUgYSBvdGltaXphw6fDo28gZGFzIG9wZXJhw6fDtWVzIGNyw610aWNhcy4nLFxyXG4gICAgICAgICdjb2xvcjogI2ZmZjsgZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogbm9ybWFsOydcclxuICAgICAgKTtcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgJyVj4oCiIENvbnNpZGVyZSBpbXBsZW1lbnRhciBjYWNoZSBvdSBvdGltaXphciBjb25zdWx0YXMgU1FMIHBhcmEgZXNzYXMgb3BlcmHDp8O1ZXMuJyxcclxuICAgICAgICAnY29sb3I6ICNmZmY7IGZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsnXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBpZiAoc2xvd09wZXJhdGlvbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAnJWPigKIgT3BlcmHDp8O1ZXMgbGVudGFzIHBvZGVtIHNlIGJlbmVmaWNpYXIgZGUgw61uZGljZXMgbm8gYmFuY28gZGUgZGFkb3MuJyxcclxuICAgICAgICAnY29sb3I6ICNmZmY7IGZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsnXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBpZiAoY3JpdGljYWxPcGVyYXRpb25zLmxlbmd0aCA9PT0gMCAmJiBzbG93T3BlcmF0aW9ucy5sZW5ndGggPT09IDApIHtcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgJyVj4oCiIFRvZGFzIGFzIG9wZXJhw6fDtWVzIGVzdMOjbyBjb20gcGVyZm9ybWFuY2UgZXhjZWxlbnRlIScsXHJcbiAgICAgICAgJ2NvbG9yOiAjZmZmOyBmb250LXNpemU6IDEzcHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7J1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNjb3JlXHJcbiAgICBjb25zdCB0b3RhbE9wZXJhdGlvbnMgPSB0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5zaXplO1xyXG4gICAgY29uc3QgZmFzdENvdW50ID0gZmFzdE9wZXJhdGlvbnMubGVuZ3RoO1xyXG4gICAgY29uc3QgcGVyZm9ybWFuY2VTY29yZSA9XHJcbiAgICAgIHRvdGFsT3BlcmF0aW9ucyA+IDBcclxuICAgICAgICA/IE1hdGgucm91bmQoKGZhc3RDb3VudCAvIHRvdGFsT3BlcmF0aW9ucykgKiAxMDApXHJcbiAgICAgICAgOiAxMDA7XHJcbiAgICBsZXQgc2NvcmVDb2xvciA9XHJcbiAgICAgIHBlcmZvcm1hbmNlU2NvcmUgPj0gODBcclxuICAgICAgICA/ICcjMzhhMTY5J1xyXG4gICAgICAgIDogcGVyZm9ybWFuY2VTY29yZSA+PSA2MFxyXG4gICAgICAgID8gJyNmNmUwNWUnXHJcbiAgICAgICAgOiAnI2M1MzAzMCc7XHJcbiAgICBsZXQgc2NvcmVNc2cgPVxyXG4gICAgICBwZXJmb3JtYW5jZVNjb3JlID49IDgwXHJcbiAgICAgICAgPyAnRXhjZWxlbnRlISBBIG1haW9yaWEgZGFzIG9wZXJhw6fDtWVzIGVzdMOhIHBlcmZvcm1hbmRvIGJlbS4nXHJcbiAgICAgICAgOiBwZXJmb3JtYW5jZVNjb3JlID49IDYwXHJcbiAgICAgICAgPyAnTcOpZGlvLiBIw6EgZXNwYcOnbyBwYXJhIG1lbGhvcmlhcyBkZSBwZXJmb3JtYW5jZS4nXHJcbiAgICAgICAgOiAnQ3LDrXRpY28uIE11aXRhcyBvcGVyYcOnw7VlcyBwcmVjaXNhbSBkZSBvdGltaXphw6fDo28gdXJnZW50ZS4nO1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIGAlY1Njb3JlIGRlIHBlcmZvcm1hbmNlOiAke3BlcmZvcm1hbmNlU2NvcmV9JWAsXHJcbiAgICAgIGBjb2xvcjogI2ZmZjsgYmFja2dyb3VuZDogJHtzY29yZUNvbG9yfTsgZm9udC1zaXplOiAxNHB4OyBmb250LXdlaWdodDogYm9sZDsgbWFyZ2luLXRvcDogMTBweDsgcGFkZGluZzogMnB4IDhweDsgYm9yZGVyLXJhZGl1czogM3B4O2BcclxuICAgICk7XHJcbiAgICBjb25zb2xlLmxvZyhcclxuICAgICAgYCVjJHtzY29yZU1zZ31gLFxyXG4gICAgICBgY29sb3I6ICNmZmY7IGZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IG5vcm1hbDsgbWFyZ2luLWJvdHRvbTogOHB4O2BcclxuICAgICk7XHJcbiAgICBjb25zb2xlLmxvZygnJyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn5OLIENhdGVnb3JpemEgb3BlcmHDp8O1ZXMgcG9yIHBlcmZvcm1hbmNlXHJcbiAgICogQHJldHVybnMgT2JqZXRvIGNvbSBhcnJheXMgZGUgb3BlcmHDp8O1ZXMgY2F0ZWdvcml6YWRhc1xyXG4gICAqL1xyXG4gIHByaXZhdGUgY2F0ZWdvcml6ZU9wZXJhdGlvbnMoKSB7XHJcbiAgICBjb25zdCBjcml0aWNhbE9wZXJhdGlvbnMgPSBBcnJheS5mcm9tKFxyXG4gICAgICB0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5lbnRyaWVzKClcclxuICAgICkuZmlsdGVyKChbXywgc3RhdHNdKSA9PiBzdGF0cy50b3RhbFRpbWUgLyBzdGF0cy5jb3VudCA+IDIwMDApO1xyXG5cclxuICAgIGNvbnN0IHNsb3dPcGVyYXRpb25zID0gQXJyYXkuZnJvbSh0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5lbnRyaWVzKCkpLmZpbHRlcihcclxuICAgICAgKFtfLCBzdGF0c10pID0+IHtcclxuICAgICAgICBjb25zdCBhdmcgPSBzdGF0cy50b3RhbFRpbWUgLyBzdGF0cy5jb3VudDtcclxuICAgICAgICByZXR1cm4gYXZnID49IDUwMCAmJiBhdmcgPD0gMjAwMDtcclxuICAgICAgfVxyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCBmYXN0T3BlcmF0aW9ucyA9IEFycmF5LmZyb20odGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuZW50cmllcygpKS5maWx0ZXIoXHJcbiAgICAgIChbXywgc3RhdHNdKSA9PiBzdGF0cy50b3RhbFRpbWUgLyBzdGF0cy5jb3VudCA8IDUwMFxyXG4gICAgKTtcclxuXHJcbiAgICByZXR1cm4geyBjcml0aWNhbE9wZXJhdGlvbnMsIHNsb3dPcGVyYXRpb25zLCBmYXN0T3BlcmF0aW9ucyB9O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+SoSBFeGliZSByZWNvbWVuZGHDp8O1ZXMgYmFzZWFkYXMgbmEgYW7DoWxpc2VcclxuICAgKiBAcGFyYW0gY3JpdGljYWxPcGVyYXRpb25zIEFycmF5IGRlIG9wZXJhw6fDtWVzIGNyw610aWNhc1xyXG4gICAqIEBwYXJhbSBzbG93T3BlcmF0aW9ucyBBcnJheSBkZSBvcGVyYcOnw7VlcyBsZW50YXNcclxuICAgKi9cclxuICBwcml2YXRlIHNob3dSZWNvbW1lbmRhdGlvbnMoXHJcbiAgICBjcml0aWNhbE9wZXJhdGlvbnM6IGFueVtdLFxyXG4gICAgc2xvd09wZXJhdGlvbnM6IGFueVtdXHJcbiAgKTogdm9pZCB7XHJcbiAgICBjb25zb2xlLmxvZygnUkVDT01FTkRBw4fDlUVTOicpO1xyXG4gICAgaWYgKGNyaXRpY2FsT3BlcmF0aW9ucy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKCcgICBQcmlvcml6ZSBhIG90aW1pemHDp8OjbyBkYXMgb3BlcmHDp8O1ZXMgY3LDrXRpY2FzLicpO1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAnICAgQ29uc2lkZXJlIGltcGxlbWVudGFyIGNhY2hlIG91IG90aW1pemFyIGNvbnN1bHRhcyBTUUwgcGFyYSBlc3NhcyBvcGVyYcOnw7Vlcy4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBpZiAoc2xvd09wZXJhdGlvbnMubGVuZ3RoID4gMCkge1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAnICAgT3BlcmHDp8O1ZXMgbGVudGFzIHBvZGVtIHNlIGJlbmVmaWNpYXIgZGUgw61uZGljZXMgbm8gYmFuY28gZGUgZGFkb3MuJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgaWYgKGNyaXRpY2FsT3BlcmF0aW9ucy5sZW5ndGggPT09IDAgJiYgc2xvd09wZXJhdGlvbnMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKCcgICBUb2RhcyBhcyBvcGVyYcOnw7VlcyBlc3TDo28gY29tIHBlcmZvcm1hbmNlIGV4Y2VsZW50ZSEnKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfk4ogRXhpYmUgc2NvcmUgZGUgcGVyZm9ybWFuY2VcclxuICAgKiBAcGFyYW0gZmFzdE9wZXJhdGlvbnNDb3VudCBOw7ptZXJvIGRlIG9wZXJhw6fDtWVzIHLDoXBpZGFzXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBzaG93UGVyZm9ybWFuY2VTY29yZShmYXN0T3BlcmF0aW9uc0NvdW50OiBudW1iZXIpOiB2b2lkIHtcclxuICAgIGNvbnN0IHRvdGFsT3BlcmF0aW9ucyA9IHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LnNpemU7XHJcbiAgICBjb25zdCBwZXJmb3JtYW5jZVNjb3JlID0gTWF0aC5yb3VuZChcclxuICAgICAgKGZhc3RPcGVyYXRpb25zQ291bnQgLyB0b3RhbE9wZXJhdGlvbnMpICogMTAwXHJcbiAgICApO1xyXG4gICAgY29uc29sZS5sb2coYFNDT1JFIERFIFBFUkZPUk1BTkNFOiAke3BlcmZvcm1hbmNlU2NvcmV9JWApO1xyXG4gICAgaWYgKHBlcmZvcm1hbmNlU2NvcmUgPj0gODApIHtcclxuICAgICAgY29uc29sZS5sb2coJ0V4Y2VsZW50ZSEgQSBtYWlvcmlhIGRhcyBvcGVyYcOnw7VlcyBlc3TDoSBwZXJmb3JtYW5kbyBiZW0uJyk7XHJcbiAgICB9IGVsc2UgaWYgKHBlcmZvcm1hbmNlU2NvcmUgPj0gNjApIHtcclxuICAgICAgY29uc29sZS5sb2coJ03DqWRpby4gSMOhIGVzcGHDp28gcGFyYSBtZWxob3JpYXMgZGUgcGVyZm9ybWFuY2UuJyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb25zb2xlLmxvZygnQ3LDrXRpY28uIE11aXRhcyBvcGVyYcOnw7VlcyBwcmVjaXNhbSBkZSBvdGltaXphw6fDo28gdXJnZW50ZS4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vID09PT09IEFQSSBQw5pCTElDQSA9PT09PVxyXG5cclxuICAvKipcclxuICAgKiDwn5OKIE3DqXRvZG8gcMO6YmxpY28gcGFyYSBleGliaXIgcmVsYXTDs3JpbyBkZSBwZXJmb3JtYW5jZVxyXG4gICAqIFBvZGUgc2VyIGNoYW1hZG8gbm8gY29uc29sZSBkbyBuYXZlZ2Fkb3IgcGFyYSBhbsOhbGlzZVxyXG4gICAqL1xyXG4gIHB1YmxpYyBnZXRQZXJmb3JtYW5jZVJlcG9ydCgpOiB2b2lkIHtcclxuICAgIHRoaXMuc2hvd1BlcmZvcm1hbmNlU3VtbWFyeSgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+nuSBNw6l0b2RvIHDDumJsaWNvIHBhcmEgbGltcGFyIGRhZG9zIGRlIHBlcmZvcm1hbmNlXHJcbiAgICogw5p0aWwgcGFyYSByZXNldGFyIGVzdGF0w61zdGljYXMgZSBjb21lw6dhciBub3ZhIGFuw6FsaXNlXHJcbiAgICovXHJcbiAgcHVibGljIHJlc2V0UGVyZm9ybWFuY2VEYXRhKCk6IHZvaWQge1xyXG4gICAgdGhpcy5wZXJmb3JtYW5jZVRpbWVycy5jbGVhcigpO1xyXG4gICAgdGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuY2xlYXIoKTtcclxuICAgIHRoaXMuaHR0cFJlcXVlc3RzLmNsZWFyKCk7XHJcblxyXG4gICAgLy8gTWVuc2FnZW0gZXN0aWxpemFkYSBkZSBsaW1wZXphXHJcbiAgICBjb25zb2xlLmxvZyhcclxuICAgICAgJyVj8J+nuSBbQ0xFQU5VUF0gRGFkb3MgZGUgcGVyZm9ybWFuY2UgbGltcG9zJyxcclxuICAgICAgJ2NvbG9yOiAjZmZmOyBiYWNrZ3JvdW5kOiAjNDMyNDhiZmY7IGZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJvcmRlci1yYWRpdXM6IDRweDsgcGFkZGluZzogNHB4IDEycHg7IG1hcmdpbjogNnB4IDA7J1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIOKPsCBDb25maWd1cmEgbyBkZWxheSBwYXJhIHJlbGF0w7NyaW8gcG9yIGluYXRpdmlkYWRlXHJcbiAgICogQHBhcmFtIHNlY29uZHMgTsO6bWVybyBkZSBzZWd1bmRvcyBkZSBpbmF0aXZpZGFkZSBwYXJhIG1vc3RyYXIgcmVsYXTDs3Jpb1xyXG4gICAqL1xyXG4gIHB1YmxpYyBzZXRJbmFjdGl2aXR5RGVsYXkoc2Vjb25kczogbnVtYmVyKTogdm9pZCB7XHJcbiAgICAvLyBEZXNhYmlsaXRhZG9cclxuICAgIGNvbnNvbGUubG9nKCfij7AgUmVsYXTDs3JpbyBwb3IgaW5hdGl2aWRhZGUgZXN0w6EgZGVzYWJpbGl0YWRvLicpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+UhyBEZXNhYmlsaXRhIHJlbGF0w7NyaW8gYXV0b23DoXRpY28gcG9yIGluYXRpdmlkYWRlXHJcbiAgICovXHJcbiAgcHVibGljIGRpc2FibGVJbmFjdGl2aXR5UmVwb3J0KCk6IHZvaWQge1xyXG4gICAgLy8gRGVzYWJpbGl0YWRvXHJcbiAgICBjb25zb2xlLmxvZygn8J+UhyBSZWxhdMOzcmlvIHBvciBpbmF0aXZpZGFkZSBqw6EgZXN0w6EgZGVzYWJpbGl0YWRvJyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDimpnvuI8gQ29uZmlndXJhIG8gdGhyZXNob2xkIHBhcmEgcmVsYXTDs3JpbyBhdXRvbcOhdGljb1xyXG4gICAqIEBwYXJhbSB0aHJlc2hvbGQgTsO6bWVybyBkZSBvcGVyYcOnw7VlcyBwYXJhIG1vc3RyYXIgcmVsYXTDs3JpbyBhdXRvbWF0aWNhbWVudGVcclxuICAgKi9cclxuICBwdWJsaWMgc2V0QXV0b1JlcG9ydFRocmVzaG9sZCh0aHJlc2hvbGQ6IG51bWJlcik6IHZvaWQge1xyXG4gICAgLy8gRGVzYWJpbGl0YWRvXHJcbiAgICBjb25zb2xlLmxvZygn4pqZ77iPIFRocmVzaG9sZCBwYXJhIHJlbGF0w7NyaW8gYXV0b23DoXRpY28gZXN0w6EgZGVzYWJpbGl0YWRvLicpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICog8J+UhyBEZXNhYmlsaXRhIHJlbGF0w7NyaW8gYXV0b23DoXRpY29cclxuICAgKi9cclxuICBwdWJsaWMgZGlzYWJsZUF1dG9SZXBvcnQoKTogdm9pZCB7XHJcbiAgICAvLyBEZXNhYmlsaXRhZG9cclxuICAgIGNvbnNvbGUubG9nKCfwn5SHIFJlbGF0w7NyaW8gYXV0b23DoXRpY28gZGVzYWJpbGl0YWRvJyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiDwn5OIIE9idMOpbSBlc3RhdMOtc3RpY2FzIHJlc3VtaWRhcyBzZW0gZXhpYmlyIG5vIGNvbnNvbGVcclxuICAgKiBAcmV0dXJucyBPYmpldG8gY29tIGVzdGF0w61zdGljYXMgZGUgcGVyZm9ybWFuY2VcclxuICAgKi9cclxuICBwdWJsaWMgZ2V0U3RhdGlzdGljcygpOiB7XHJcbiAgICB0b3RhbE9wZXJhdGlvbnM6IG51bWJlcjtcclxuICAgIGF2ZXJhZ2VUaW1lOiBudW1iZXI7XHJcbiAgICBmYXN0T3BlcmF0aW9uczogbnVtYmVyO1xyXG4gICAgc2xvd09wZXJhdGlvbnM6IG51bWJlcjtcclxuICAgIGNyaXRpY2FsT3BlcmF0aW9uczogbnVtYmVyO1xyXG4gICAgcGVyZm9ybWFuY2VTY29yZTogbnVtYmVyO1xyXG4gIH0ge1xyXG4gICAgY29uc3QgeyBjcml0aWNhbE9wZXJhdGlvbnMsIHNsb3dPcGVyYXRpb25zLCBmYXN0T3BlcmF0aW9ucyB9ID1cclxuICAgICAgdGhpcy5jYXRlZ29yaXplT3BlcmF0aW9ucygpO1xyXG4gICAgY29uc3QgdG90YWxPcGVyYXRpb25zID0gdGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkuc2l6ZTtcclxuXHJcbiAgICBsZXQgdG90YWxUaW1lID0gMDtcclxuICAgIGxldCB0b3RhbENvdW50ID0gMDtcclxuXHJcbiAgICB0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5mb3JFYWNoKChzdGF0cykgPT4ge1xyXG4gICAgICB0b3RhbFRpbWUgKz0gc3RhdHMudG90YWxUaW1lO1xyXG4gICAgICB0b3RhbENvdW50ICs9IHN0YXRzLmNvdW50O1xyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgYXZlcmFnZVRpbWUgPSB0b3RhbENvdW50ID4gMCA/IE1hdGgucm91bmQodG90YWxUaW1lIC8gdG90YWxDb3VudCkgOiAwO1xyXG4gICAgY29uc3QgcGVyZm9ybWFuY2VTY29yZSA9XHJcbiAgICAgIHRvdGFsT3BlcmF0aW9ucyA+IDBcclxuICAgICAgICA/IE1hdGgucm91bmQoKGZhc3RPcGVyYXRpb25zLmxlbmd0aCAvIHRvdGFsT3BlcmF0aW9ucykgKiAxMDApXHJcbiAgICAgICAgOiAxMDA7XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgdG90YWxPcGVyYXRpb25zLFxyXG4gICAgICBhdmVyYWdlVGltZSxcclxuICAgICAgZmFzdE9wZXJhdGlvbnM6IGZhc3RPcGVyYXRpb25zLmxlbmd0aCxcclxuICAgICAgc2xvd09wZXJhdGlvbnM6IHNsb3dPcGVyYXRpb25zLmxlbmd0aCxcclxuICAgICAgY3JpdGljYWxPcGVyYXRpb25zOiBjcml0aWNhbE9wZXJhdGlvbnMubGVuZ3RoLFxyXG4gICAgICBwZXJmb3JtYW5jZVNjb3JlLFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfjq8gT2J0w6ltIGRhZG9zIGRlIHVtYSBvcGVyYcOnw6NvIGVzcGVjw61maWNhXHJcbiAgICogQHBhcmFtIG9wZXJhdGlvbk5hbWUgTm9tZSBkYSBvcGVyYcOnw6NvXHJcbiAgICogQHJldHVybnMgRXN0YXTDrXN0aWNhcyBkYSBvcGVyYcOnw6NvIG91IG51bGwgc2UgbsOjbyBlbmNvbnRyYWRhXHJcbiAgICovXHJcbiAgcHVibGljIGdldE9wZXJhdGlvblN0YXRzKFxyXG4gICAgb3BlcmF0aW9uTmFtZTogc3RyaW5nXHJcbiAgKTogKFBlcmZvcm1hbmNlU3RhdHMgJiB7IGh0dHBDYWxsczogc3RyaW5nW10gfSkgfCBudWxsIHtcclxuICAgIGNvbnN0IGJhc2VTdGF0cyA9IHRoaXMucGVyZm9ybWFuY2VTdW1tYXJ5LmdldChvcGVyYXRpb25OYW1lKTtcclxuICAgIGlmICghYmFzZVN0YXRzKSByZXR1cm4gbnVsbDtcclxuXHJcbiAgICAvLyBFeHRyYWkgbm9tZXMgZGFzIHJlcXVpc2nDp8O1ZXMgSFRUUCBjb21vIGFycmF5IGRlIHN0cmluZ3NcclxuICAgIGNvbnN0IGh0dHBSZXF1ZXN0RW50cnkgPSB0aGlzLmh0dHBSZXF1ZXN0cy5nZXQob3BlcmF0aW9uTmFtZSk7XHJcbiAgICBjb25zdCBodHRwQ2FsbHM6IHN0cmluZ1tdID0gaHR0cFJlcXVlc3RFbnRyeSA/IFtvcGVyYXRpb25OYW1lXSA6IFtdO1xyXG4gICAgcmV0dXJuIHsgLi4uYmFzZVN0YXRzLCBodHRwQ2FsbHMgfTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfk4sgTGlzdGEgdG9kYXMgYXMgb3BlcmHDp8O1ZXMgbW9uaXRvcmFkYXNcclxuICAgKiBAcmV0dXJucyBBcnJheSBjb20gbm9tZXMgZGFzIG9wZXJhw6fDtWVzXHJcbiAgICovXHJcbiAgcHVibGljIGdldE1vbml0b3JlZE9wZXJhdGlvbnMoKTogc3RyaW5nW10ge1xyXG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5wZXJmb3JtYW5jZVN1bW1hcnkua2V5cygpKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCflIQgVmVyaWZpY2Egc2UgaMOhIHRpbWVycyBhdGl2b3NcclxuICAgKiBAcmV0dXJucyB0cnVlIHNlIGjDoSB0aW1lcnMgZW0gZXhlY3XDp8Ojb1xyXG4gICAqL1xyXG4gIHB1YmxpYyBoYXNBY3RpdmVUaW1lcnMoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5wZXJmb3JtYW5jZVRpbWVycy5zaXplID4gMDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfl5HvuI8gTGltcGEgYXBlbmFzIG9zIHRpbWVycyBhdGl2b3MgKG7Do28gYXMgZXN0YXTDrXN0aWNhcylcclxuICAgKi9cclxuICBwdWJsaWMgY2xlYXJBY3RpdmVUaW1lcnMoKTogdm9pZCB7XHJcbiAgICB0aGlzLnBlcmZvcm1hbmNlVGltZXJzLmNsZWFyKCk7XHJcbiAgICBjb25zb2xlLmxvZyhcclxuICAgICAgJyVj8J+Xke+4jyBbQ0xFQU5VUF0gVGltZXJzIGF0aXZvcyBsaW1wb3MnLFxyXG4gICAgICAnY29sb3I6ICNmZmY7IGJhY2tncm91bmQ6ICMyMzI3MmY7IGZvbnQtc2l6ZTogMTNweDsgZm9udC13ZWlnaHQ6IGJvbGQ7IGJvcmRlci1yYWRpdXM6IDRweDsgcGFkZGluZzogNHB4IDEycHg7IG1hcmdpbjogNnB4IDA7J1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfkr4gRXhwb3J0YSBkYWRvcyBkZSBwZXJmb3JtYW5jZSBwYXJhIEpTT05cclxuICAgKiBAcmV0dXJucyBTdHJpbmcgSlNPTiBjb20gdG9kb3Mgb3MgZGFkb3NcclxuICAgKi9cclxuICBwdWJsaWMgZXhwb3J0RGF0YSgpOiBzdHJpbmcge1xyXG4gICAgY29uc3QgZGF0YSA9IHtcclxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXHJcbiAgICAgIHNlcnZpY2VOYW1lOiB0aGlzLnNlcnZpY2VOYW1lLFxyXG4gICAgICBzdGF0aXN0aWNzOiB0aGlzLmdldFN0YXRpc3RpY3MoKSxcclxuICAgICAgb3BlcmF0aW9uczogQXJyYXkuZnJvbSh0aGlzLnBlcmZvcm1hbmNlU3VtbWFyeS5lbnRyaWVzKCkpLm1hcChcclxuICAgICAgICAoW25hbWUsIHN0YXRzXSkgPT4gKHtcclxuICAgICAgICAgIG5hbWUsXHJcbiAgICAgICAgICAuLi5zdGF0cyxcclxuICAgICAgICAgIGF2ZXJhZ2VUaW1lOiBNYXRoLnJvdW5kKHN0YXRzLnRvdGFsVGltZSAvIHN0YXRzLmNvdW50KSxcclxuICAgICAgICB9KVxyXG4gICAgICApLFxyXG4gICAgfTtcclxuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShkYXRhLCBudWxsLCAyKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIPCfjq8gQ2FsY3VsYSB0aHJlc2hvbGRzIGRpbsOibWljb3MgYmFzZWFkb3MgbmEgcXVhbnRpZGFkZSBkZSBleGVjdcOnw7Vlc1xyXG4gICAqIEBwYXJhbSBleGVjdXRpb25Db3VudCBOw7ptZXJvIGRlIGV4ZWN1w6fDtWVzIGRhIG9wZXJhw6fDo29cclxuICAgKiBAcmV0dXJucyBPYmpldG8gY29tIHRocmVzaG9sZHMgY2FsY3VsYWRvcyBkaW5hbWljYW1lbnRlXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjYWxjdWxhdGVEeW5hbWljVGhyZXNob2xkcyhcclxuICAgIGV4ZWN1dGlvbkNvdW50OiBudW1iZXJcclxuICApOiBEeW5hbWljVGhyZXNob2xkcyB7XHJcbiAgICBpZiAoZXhlY3V0aW9uQ291bnQgPT09IDEpIHtcclxuICAgICAgLy8gUHJpbWVpcmEgZXhlY3XDp8OjbyAtIGV4cGVjdGF0aXZhcyBtYWlzIHJlbGF4YWRhc1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG9rOiAxMDAwLCAvLyAxIHNlZ3VuZG9cclxuICAgICAgICBsZW50bzogMjAwMCwgLy8gMiBzZWd1bmRvc1xyXG4gICAgICAgIGNyaXRpY286IDIwMDAsIC8vIDIgc2VndW5kb3MgKGxlbnRvIGUgY3JpdGljbyBpZ3VhaXMgcGFyYSBtYW50ZXIgc8OzIDMgZXN0YWRvcylcclxuICAgICAgfTtcclxuICAgIH0gZWxzZSBpZiAoZXhlY3V0aW9uQ291bnQgPD0gNSkge1xyXG4gICAgICAvLyBBdMOpIDUgZXhlY3XDp8O1ZXMgLSBzaXN0ZW1hIGFpbmRhIGFxdWVjZW5kb1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG9rOiA1MDAsIC8vIDUwMG1zXHJcbiAgICAgICAgbGVudG86IDEwMDAsIC8vIDEgc2VndW5kb1xyXG4gICAgICAgIGNyaXRpY286IDEwMDAsIC8vIDEgc2VndW5kb1xyXG4gICAgICB9O1xyXG4gICAgfSBlbHNlIGlmIChleGVjdXRpb25Db3VudCA8PSAxMCkge1xyXG4gICAgICAvLyBBdMOpIDEwIGV4ZWN1w6fDtWVzIC0gc2lzdGVtYSBvdGltaXphZG9cclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBvazogMTAwLCAvLyAxMDBtc1xyXG4gICAgICAgIGxlbnRvOiAyNTAsIC8vIDI1MG1zXHJcbiAgICAgICAgY3JpdGljbzogMjUwLCAvLyAyNTBtc1xyXG4gICAgICB9O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQWNpbWEgZGUgMTAgZXhlY3XDp8O1ZXMgLSBleHBlY3RhdGl2YXMgYWx0YXNcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBvazogMjAsIC8vIDIwbXNcclxuICAgICAgICBsZW50bzogNjAsIC8vIDYwbXNcclxuICAgICAgICBjcml0aWNvOiA2MCwgLy8gNjBtc1xyXG4gICAgICB9O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHVibGljIGluamVjdE1vbml0b3JCdXR0b24oKTogdm9pZCB7XHJcbiAgICBpZiAoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2J0bi1tb25pdG9yYXItcGVyZm9ybWFuY2UnKSkgcmV0dXJuO1xyXG5cclxuICAgIC8vID09PT09PSBFU1RJTE8gTU9ERVJOTyBFIEJPVMODTyBERSBPTEhPID09PT09PVxyXG4gICAgY29uc3QgQlVUVE9OX0NPTE9SID0gJyMyMzI3MmYnOyAvLyBjaW56YSBlc2N1cm8gZWxlZ2FudGVcclxuICAgIGNvbnN0IEJVVFRPTl9URVhUX0NPTE9SID0gJyNmM2Y0ZjYnO1xyXG4gICAgY29uc3QgQlVUVE9OX1JBRElVUyA9ICc4cHgnO1xyXG4gICAgY29uc3QgQlVUVE9OX0ZPTlRfU0laRSA9ICcxM3B4JztcclxuICAgIGNvbnN0IEJVVFRPTl9QQURESU5HID0gJzEwcHggNXB4JztcclxuICAgIGNvbnN0IEJVVFRPTl9XSURUSCA9ICcyMTBweCc7XHJcbiAgICBjb25zdCBCVVRUT05fSEVJR0hUID0gJzQ0cHgnO1xyXG4gICAgY29uc3QgQlVUVE9OX0JPWF9TSEFET1cgPSAnMCAycHggMTJweCAjMDAwMic7XHJcbiAgICBjb25zdCBCVVRUT05fQk9SREVSID0gJzFweCBzb2xpZCAjMzUzYTQwJztcclxuXHJcbiAgICAvLyBDb250YWluZXIgcGFyYSBhbmltYcOnw6NvXHJcbiAgICBjb25zdCBjb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuICAgIGNvbnRhaW5lci5pZCA9ICdwZXJmb3JtYW5jZS1tb25pdG9yLWNvbnRhaW5lcic7XHJcbiAgICBPYmplY3QuYXNzaWduKGNvbnRhaW5lci5zdHlsZSwge1xyXG4gICAgICBwb3NpdGlvbjogJ2ZpeGVkJyxcclxuICAgICAgYm90dG9tOiAnNXB4JyxcclxuICAgICAgbGVmdDogJzUwcHgnLFxyXG4gICAgICB6SW5kZXg6ICc5OTk5JyxcclxuICAgICAgZGlzcGxheTogJ2ZsZXgnLFxyXG4gICAgICBmbGV4RGlyZWN0aW9uOiAnY29sdW1uJyxcclxuICAgICAgYWxpZ25JdGVtczogJ2NlbnRlcicsXHJcbiAgICAgIGp1c3RpZnlDb250ZW50OiAnZmxleC1lbmQnLFxyXG4gICAgICB0cmFuc2l0aW9uOiAndHJhbnNmb3JtIDAuNXMgY3ViaWMtYmV6aWVyKC40LDIsLjYsMSknLFxyXG4gICAgICBnYXA6ICcxMHB4JyxcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEZ1bsOnw6NvIHBhcmEgY3JpYXIgYm90w7VlcyBwYWRyb25pemFkb3NcclxuICAgIGNvbnN0IGNyaWFyQm90YW8gPSAoaWQ6IHN0cmluZywgdGV4dG86IHN0cmluZykgPT4ge1xyXG4gICAgICBjb25zdCBidG4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdidXR0b24nKTtcclxuICAgICAgYnRuLmlkID0gaWQ7XHJcbiAgICAgIGJ0bi5pbm5lclRleHQgPSB0ZXh0bztcclxuICAgICAgT2JqZWN0LmFzc2lnbihidG4uc3R5bGUsIHtcclxuICAgICAgICB3aWR0aDogQlVUVE9OX1dJRFRILFxyXG4gICAgICAgIGhlaWdodDogQlVUVE9OX0hFSUdIVCxcclxuICAgICAgICBiYWNrZ3JvdW5kOiBCVVRUT05fQ09MT1IsXHJcbiAgICAgICAgY29sb3I6IEJVVFRPTl9URVhUX0NPTE9SLFxyXG4gICAgICAgIGJvcmRlclJhZGl1czogQlVUVE9OX1JBRElVUyxcclxuICAgICAgICBib3JkZXI6IEJVVFRPTl9CT1JERVIsXHJcbiAgICAgICAgcGFkZGluZzogQlVUVE9OX1BBRERJTkcsXHJcbiAgICAgICAgZm9udFNpemU6IEJVVFRPTl9GT05UX1NJWkUsXHJcbiAgICAgICAgZm9udFdlaWdodDogJzYwMCcsXHJcbiAgICAgICAgY3Vyc29yOiAncG9pbnRlcicsXHJcbiAgICAgICAgYm94U2hhZG93OiBCVVRUT05fQk9YX1NIQURPVyxcclxuICAgICAgICBsZXR0ZXJTcGFjaW5nOiAnMC4wMWVtJyxcclxuICAgICAgICB0ZXh0QWxpZ246ICdjZW50ZXInLFxyXG4gICAgICAgIHRyYW5zaXRpb246XHJcbiAgICAgICAgICAnYmFja2dyb3VuZCAwLjJzLCBjb2xvciAwLjJzLCB0cmFuc2Zvcm0gMC41cyBjdWJpYy1iZXppZXIoLjQsMiwuNiwxKScsXHJcbiAgICAgIH0pO1xyXG4gICAgICBidG4ub25tb3VzZWVudGVyID0gKCkgPT4ge1xyXG4gICAgICAgIGJ0bi5zdHlsZS5iYWNrZ3JvdW5kID0gJyMzNTNhNDAnO1xyXG4gICAgICAgIGJ0bi5zdHlsZS5jb2xvciA9ICcjZmZmJztcclxuICAgICAgfTtcclxuICAgICAgYnRuLm9ubW91c2VsZWF2ZSA9ICgpID0+IHtcclxuICAgICAgICBidG4uc3R5bGUuYmFja2dyb3VuZCA9IEJVVFRPTl9DT0xPUjtcclxuICAgICAgICBidG4uc3R5bGUuY29sb3IgPSBCVVRUT05fVEVYVF9DT0xPUjtcclxuICAgICAgfTtcclxuICAgICAgcmV0dXJuIGJ0bjtcclxuICAgIH07XHJcblxyXG4gICAgLy8gQm90w7VlcyBwcmluY2lwYWlzXHJcbiAgICBjb25zdCBidG5NYWluID0gY3JpYXJCb3RhbyhcclxuICAgICAgJ2J0bi1tb25pdG9yYXItcGVyZm9ybWFuY2UnLFxyXG4gICAgICAnUGFyYXIgbW9uaXRvcmFtZW50bydcclxuICAgICk7XHJcbiAgICBjb25zdCBidG5GaW5hbGl6YXIgPSBjcmlhckJvdGFvKFxyXG4gICAgICAnYnRuLWZpbmFsaXphci1tb25pdG9yYW1lbnRvJyxcclxuICAgICAgJ0ZpbmFsaXphciBtb25pdG9yYW1lbnRvJ1xyXG4gICAgKTtcclxuICAgIGNvbnN0IGJ0blJlcXVpc2ljb2VzRGV0YWxoYWRhcyA9IGNyaWFyQm90YW8oXHJcbiAgICAgICdidG4tcmVxLWRldGFsaGFkYXMtcGVyZm9ybWFuY2UnLFxyXG4gICAgICAnUmVxdWlzacOnw7VlcyBkZXRhbGhhZGFzJ1xyXG4gICAgKTtcclxuICAgIGNvbnN0IGJ0bkFuYWxpc2VEZXRhbGhhZGEgPSBjcmlhckJvdGFvKFxyXG4gICAgICAnYnRuLWFuYWxpc2UtZGV0YWxoYWRhLXBlcmZvcm1hbmNlJyxcclxuICAgICAgJ0Fuw6FsaXNlIGRldGFsaGFkYSdcclxuICAgICk7XHJcblxyXG4gICAgLy8gSW5pY2lhbG1lbnRlIGVzY29uZGlkb3NcclxuICAgIGJ0blJlcXVpc2ljb2VzRGV0YWxoYWRhcy5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgYnRuQW5hbGlzZURldGFsaGFkYS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgYnRuRmluYWxpemFyLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcblxyXG4gICAgLy8gQm90w6NvIGRlIGVzY29uZGVyL21vc3RyYXIgY29tIMOtY29uZSBkZSBvbGhvIChmb3JhIGRvIGNvbnRhaW5lcilcclxuICAgIGNvbnN0IGJ0blRvZ2dsZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2J1dHRvbicpO1xyXG4gICAgYnRuVG9nZ2xlLmlkID0gJ2J0bi10b2dnbGUtcGVyZm9ybWFuY2UnO1xyXG4gICAgYnRuVG9nZ2xlLmlubmVySFRNTCA9IGBcclxuICAgIDxpbWdcclxuICAgICAgc3JjPVwiaHR0cHM6Ly9jZG4taWNvbnMtcG5nLmZsYXRpY29uLmNvbS81MTIvNTY1LzU2NTY1NS5wbmdcIlxyXG4gICAgICBhbHQ9XCJlc2NvbmRlclwiXHJcbiAgICAgIHN0eWxlPVwid2lkdGg6MTVweDsgaGVpZ2h0OjE1cHg7IHZlcnRpY2FsLWFsaWduOm1pZGRsZTsgZmlsdGVyOiBpbnZlcnQoMSk7XCJcclxuICAgIC8+XHJcbiAgICBgO1xyXG5cclxuICAgIE9iamVjdC5hc3NpZ24oYnRuVG9nZ2xlLnN0eWxlLCB7XHJcbiAgICAgIHdpZHRoOiAnMzhweCcsXHJcbiAgICAgIGhlaWdodDogJzM4cHgnLFxyXG4gICAgICBiYWNrZ3JvdW5kOiAnIzIzMjcyZicsXHJcbiAgICAgIGNvbG9yOiAnI2YzZjRmNicsXHJcbiAgICAgIGJvcmRlclJhZGl1czogJzUwJScsXHJcbiAgICAgIGJvcmRlcjogQlVUVE9OX0JPUkRFUixcclxuICAgICAgZm9udFNpemU6ICcyMHB4JyxcclxuICAgICAgZm9udFdlaWdodDogJ2JvbGQnLFxyXG4gICAgICBjdXJzb3I6ICdwb2ludGVyJyxcclxuICAgICAgYm94U2hhZG93OiBCVVRUT05fQk9YX1NIQURPVyxcclxuICAgICAgcG9zaXRpb246ICdmaXhlZCcsXHJcbiAgICAgIGxlZnQ6ICc1cHgnLFxyXG4gICAgICBib3R0b206ICc1cHgnLFxyXG4gICAgICBkaXNwbGF5OiAnZmxleCcsXHJcbiAgICAgIGFsaWduSXRlbXM6ICdjZW50ZXInLFxyXG4gICAgICBqdXN0aWZ5Q29udGVudDogJ2NlbnRlcicsXHJcbiAgICAgIHpJbmRleDogJzEwMDAwJyxcclxuICAgIH0pO1xyXG4gICAgYnRuVG9nZ2xlLm9ubW91c2VlbnRlciA9ICgpID0+IHtcclxuICAgICAgYnRuVG9nZ2xlLnN0eWxlLmJhY2tncm91bmQgPSAnIzM1M2E0MCc7XHJcbiAgICAgIGJ0blRvZ2dsZS5zdHlsZS5jb2xvciA9ICcjZmZmJztcclxuICAgIH07XHJcbiAgICBidG5Ub2dnbGUub25tb3VzZWxlYXZlID0gKCkgPT4ge1xyXG4gICAgICBidG5Ub2dnbGUuc3R5bGUuYmFja2dyb3VuZCA9ICcjMjMyNzJmJztcclxuICAgICAgYnRuVG9nZ2xlLnN0eWxlLmNvbG9yID0gJyNmM2Y0ZjYnO1xyXG4gICAgfTtcclxuXHJcbiAgICBsZXQgaGlkZGVuID0gZmFsc2U7XHJcbiAgICBidG5Ub2dnbGUub25jbGljayA9ICgpID0+IHtcclxuICAgICAgaGlkZGVuID0gIWhpZGRlbjtcclxuICAgICAgaWYgKGhpZGRlbikge1xyXG4gICAgICAgIGNvbnRhaW5lci5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgICAgIGJ0blRvZ2dsZS5pbm5lckhUTUwgPSBgXHJcbiAgICA8aW1nXHJcbiAgICAgIHNyYz1cImh0dHBzOi8vY2RuLWljb25zLXBuZy5mbGF0aWNvbi5jb20vNTEyLzE1OS8xNTk2MDQucG5nXCJcclxuICAgICAgYWx0PVwibW9zdHJhclwiXHJcbiAgICAgIHN0eWxlPVwid2lkdGg6MTVweDsgaGVpZ2h0OjE1cHg7IHZlcnRpY2FsLWFsaWduOm1pZGRsZTsgZmlsdGVyOiBpbnZlcnQoMSk7XCJcclxuICAgIC8+XHJcbiAgYDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBjb250YWluZXIuc3R5bGUuZGlzcGxheSA9ICdmbGV4JztcclxuICAgICAgICBidG5Ub2dnbGUuaW5uZXJIVE1MID0gYFxyXG4gICAgPGltZ1xyXG4gICAgICBzcmM9XCJodHRwczovL2Nkbi1pY29ucy1wbmcuZmxhdGljb24uY29tLzUxMi81NjUvNTY1NjU1LnBuZ1wiXHJcbiAgICAgIGFsdD1cImVzY29uZGVyXCJcclxuICAgICAgc3R5bGU9XCJ3aWR0aDoxNXB4OyBoZWlnaHQ6MTVweDsgdmVydGljYWwtYWxpZ246bWlkZGxlOyBmaWx0ZXI6IGludmVydCgxKTtcIlxyXG4gICAgLz5cclxuICBgO1xyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIC8vIEVzdGFkbyBkb3MgYm90w7Vlc1xyXG4gICAgbGV0IGVzdGFkbzpcclxuICAgICAgfCAnaW5hdGl2bydcclxuICAgICAgfCAnbW9uaXRvcmFuZG8nXHJcbiAgICAgIHwgJ3JlbGF0b3JpbydcclxuICAgICAgfCAncmVsYXRvcmlvX2dlcmFkbydcclxuICAgICAgfCAncmVxdWlzaWNhbycgPSAnbW9uaXRvcmFuZG8nO1xyXG5cclxuICAgIGNvbnN0IGF0dWFsaXphckJvdG9lcyA9IChub3ZvRXN0YWRvOiB0eXBlb2YgZXN0YWRvKSA9PiB7XHJcbiAgICAgIGVzdGFkbyA9IG5vdm9Fc3RhZG87XHJcbiAgICAgIHN3aXRjaCAoZXN0YWRvKSB7XHJcbiAgICAgICAgY2FzZSAnaW5hdGl2byc6XHJcbiAgICAgICAgICBidG5NYWluLmlubmVyVGV4dCA9ICdJbmljaWFyIG1vbml0b3JhbWVudG8nO1xyXG4gICAgICAgICAgdGhpcy5tb25pdG9yYW1lbnRvQXRpdm8gPSBmYWxzZTtcclxuICAgICAgICAgIGJ0bkZpbmFsaXphci5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgICAgICAgYnRuUmVxdWlzaWNvZXNEZXRhbGhhZGFzLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgICAgICBidG5BbmFsaXNlRGV0YWxoYWRhLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICBjYXNlICdtb25pdG9yYW5kbyc6XHJcbiAgICAgICAgICBidG5NYWluLmlubmVyVGV4dCA9ICdQYXJhciBtb25pdG9yYW1lbnRvJztcclxuICAgICAgICAgIHRoaXMubW9uaXRvcmFtZW50b0F0aXZvID0gdHJ1ZTtcclxuICAgICAgICAgIGJ0bkZpbmFsaXphci5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xyXG4gICAgICAgICAgYnRuUmVxdWlzaWNvZXNEZXRhbGhhZGFzLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgICAgICBidG5BbmFsaXNlRGV0YWxoYWRhLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICBjYXNlICdyZWxhdG9yaW8nOlxyXG4gICAgICAgICAgYnRuTWFpbi5pbm5lclRleHQgPSAnR2VyYXIgcmVsYXTDs3Jpbyc7XHJcbiAgICAgICAgICB0aGlzLm1vbml0b3JhbWVudG9BdGl2byA9IGZhbHNlO1xyXG4gICAgICAgICAgYnRuRmluYWxpemFyLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICAgICAgICBidG5SZXF1aXNpY29lc0RldGFsaGFkYXMuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XHJcbiAgICAgICAgICBidG5BbmFsaXNlRGV0YWxoYWRhLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgY2FzZSAncmVsYXRvcmlvX2dlcmFkbyc6XHJcbiAgICAgICAgICBidG5NYWluLmlubmVyVGV4dCA9ICdHZXJhciByZWxhdMOzcmlvJztcclxuICAgICAgICAgIHRoaXMubW9uaXRvcmFtZW50b0F0aXZvID0gZmFsc2U7XHJcbiAgICAgICAgICBidG5GaW5hbGl6YXIuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XHJcbiAgICAgICAgICBidG5SZXF1aXNpY29lc0RldGFsaGFkYXMuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XHJcbiAgICAgICAgICBidG5BbmFsaXNlRGV0YWxoYWRhLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgLy8gQcOnw7VlcyBkb3MgYm90w7Vlc1xyXG4gICAgYnRuTWFpbi5vbmNsaWNrID0gKCkgPT4ge1xyXG4gICAgICBpZiAoZXN0YWRvID09PSAnaW5hdGl2bycpIHtcclxuICAgICAgICB0aGlzLnJlc2V0UGVyZm9ybWFuY2VEYXRhKCk7XHJcbiAgICAgICAgdGhpcy5zaG93V2VsY29tZU1lc3NhZ2UoKTtcclxuICAgICAgICBhdHVhbGl6YXJCb3RvZXMoJ21vbml0b3JhbmRvJyk7XHJcbiAgICAgIH0gZWxzZSBpZiAoZXN0YWRvID09PSAnbW9uaXRvcmFuZG8nKSB7XHJcbiAgICAgICAgYXR1YWxpemFyQm90b2VzKCdyZWxhdG9yaW8nKTtcclxuICAgICAgfSBlbHNlIGlmIChlc3RhZG8gPT09ICdyZWxhdG9yaW8nIHx8IGVzdGFkbyA9PT0gJ3JlbGF0b3Jpb19nZXJhZG8nKSB7XHJcbiAgICAgICAgdGhpcy5zaG93UGVyZm9ybWFuY2VTdW1tYXJ5KGZhbHNlKTtcclxuICAgICAgICBhdHVhbGl6YXJCb3RvZXMoJ3JlbGF0b3Jpb19nZXJhZG8nKTtcclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICBidG5GaW5hbGl6YXIub25jbGljayA9ICgpID0+IHtcclxuICAgICAgdGhpcy5yZXNldFBlcmZvcm1hbmNlRGF0YSgpO1xyXG4gICAgICBhdHVhbGl6YXJCb3RvZXMoJ2luYXRpdm8nKTtcclxuICAgIH07XHJcblxyXG4gICAgLy8gQXDDqm5kaWNlXHJcbiAgICB0aGlzLnNob3dXZWxjb21lTWVzc2FnZSgpO1xyXG4gICAgY29udGFpbmVyLmFwcGVuZENoaWxkKGJ0bk1haW4pO1xyXG4gICAgY29udGFpbmVyLmFwcGVuZENoaWxkKGJ0blJlcXVpc2ljb2VzRGV0YWxoYWRhcyk7XHJcbiAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQoYnRuQW5hbGlzZURldGFsaGFkYSk7XHJcbiAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQoYnRuRmluYWxpemFyKTtcclxuICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoY29udGFpbmVyKTtcclxuICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoYnRuVG9nZ2xlKTtcclxuXHJcbiAgICAvLyBBw6fDo28gZG8gYm90w6NvIGRlIHJlcXVpc2nDp8O1ZXMgZGV0YWxoYWRhc1xyXG4gICAgYnRuUmVxdWlzaWNvZXNEZXRhbGhhZGFzLm9uY2xpY2sgPSAoKSA9PiB7XHJcbiAgICAgIHRoaXMuc2hvd0h0dHBSZXF1ZXN0c1JlcG9ydCgpO1xyXG4gICAgfTtcclxuICAgIC8vIEHDp8OjbyBkbyBib3TDo28gZGUgYW7DoWxpc2UgZGV0YWxoYWRhXHJcbiAgICBidG5BbmFsaXNlRGV0YWxoYWRhLm9uY2xpY2sgPSAoKSA9PiB7XHJcbiAgICAgIHRoaXMuZ2VuZXJhdGVEZXRhaWxlZEFuYWx5c2lzKCk7XHJcbiAgICB9O1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIPCfj60gRmFjdG9yeSBmdW5jdGlvbiBwYXJhIGNyaWFyIGluc3TDom5jaWEgZG8gTG9nc1BlcmZvcm1hdGljb1xyXG4gKiBAcGFyYW0gc2VydmljZU5hbWUgTm9tZSBkbyBzZXJ2acOnbyAocGFyYSBsb2dzIHBlcnNvbmFsaXphZG9zKVxyXG4gKiBAcmV0dXJucyBOb3ZhIGluc3TDom5jaWEgZGUgTG9nc1BlcmZvcm1hdGljb1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVBlcmZvcm1hbmNlTG9nZ2VyKFxyXG4gIHNlcnZpY2VOYW1lOiBzdHJpbmcgPSAnU2VydmljZSdcclxuKTogTG9nc1BlcmZvcm1hdGljbyB7XHJcbiAgcmV0dXJuIG5ldyBMb2dzUGVyZm9ybWF0aWNvKHNlcnZpY2VOYW1lKTtcclxufVxyXG4iXX0=