!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var o;"undefined"!=typeof window?o=window:"undefined"!=typeof global?o=global:"undefined"!=typeof self&&(o=self),o.pianoroll=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/**
* scripts/main.js
*
* This is the starting point for your application.
* Take a look at http://browserify.org/ for more info
*/
'use strict';
var PIXI = require('pixi');
// Config vars
var logger = false;
var sceneWidth = 1920;
var prHeight1 = 435;
var prHeight2 = 645;
var sceneHeight = prHeight1 + prHeight2;
var sceneBgColor = 0xFFFFFF;
var lineColor = 0x444444;
var pixelsPerSecond1 = Math.floor(sceneWidth / 10); // nb of pixels per second
var manualFramerate = pixelsPerSecond1 / 4;
var pixelsPerSecond2 = Math.floor(sceneWidth / 60); // nb of pixels per second
var lineInterval = 5000; // means line every 5 seconds
var nbLines = -1;
var noteHeight = 110;
var noteColors = [0xB90000, 0x4BDD71, 0xAF931E, 0x1C28BA, 0x536991];
var colorsReg = {};
// Vars
var noteDict = [];
// Timecode method
var timePageLoaded = Date.now();
var offsetMusic = false;
//create an new instance of a pixi stage
var stage = new PIXI.Stage(sceneBgColor);
//create a renderer instance.
var renderer = PIXI.autoDetectRenderer(sceneWidth, sceneHeight);
//add the renderer view element to the DOM
document.getElementById('canvasContainer').appendChild(renderer.view);
var uberContainer = new PIXI.DisplayObjectContainer();
uberContainer.position.x = Math.floor(sceneWidth*9/10);
uberContainer.position.y = 0;
stage.addChild(uberContainer);
var PianoRoll = require('./pianoroll.js')
// Init containers
var containerList = [];
containerList.push(new PianoRoll(uberContainer, 0, 0, prHeight1, true, pixelsPerSecond1, sceneWidth, noteColors, colorsReg, lineColor, lineInterval, offsetMusic, prHeight1 / 128));
containerList.push(new PianoRoll(uberContainer, 0, prHeight1, prHeight2, false, pixelsPerSecond2, sceneWidth, noteColors, colorsReg, lineColor, lineInterval, offsetMusic, prHeight2 / 128));
// Line between two containers
var graphics = new PIXI.Graphics();
graphics.beginFill(0xFFFF00);
graphics.lineStyle(1, lineColor);
graphics.moveTo(0, prHeight1);
graphics.lineTo(sceneWidth, prHeight1);
graphics.endFill();
stage.addChild(graphics);
function replaceContainers(){
var diff = (Date.now() - timePageLoaded)/1000;// nb of seconds since page loaded
//console.log("replace ! diff1 = ", container1.x - Math.floor(-diff*pixelsPerSecond1), ", diff 2 = ", container2.x - Math.floor(-diff*pixelsPerSecond2));
for(var i=0;i<containerList.length;i++){
containerList[i].moveTo(-diff);
}
renderer.render(stage);
}
function addNotes(data){
if(!offsetMusic){
// get difference between the current note timecode and my zero to set the difference between the canvas's zero and the music's zero
// in order to place in real time
var now = Date.now();
var timeBetweenNowAndStart = now - timePageLoaded;
offsetMusic = timeBetweenNowAndStart - data.content[1];
//console.log("start: ", timePageLoaded, ", now: ", now, ", timeBetweenNowAndStart = ", timeBetweenNowAndStart, ", offsetMusic = ", offsetMusic);
}
var note = data.content[3];
var velocity = data.content[4];
if(velocity===0){
if(typeof noteDict[data.content[2]][note]!=='undefined'){
// We close the note in container one
//console.log("coucou 2", data);
var duration = data.content[1] - noteDict[data.content[2]][note].ts;
for(var i=0;i<containerList.length;i++){
// addNote(note, startTime, duration, velocity, canal)
containerList[i].addNote(note, noteDict[data.content[2]][note].ts, duration, noteDict[data.content[2]][note].velocity, data.content[2]);
}
// delete entry
delete noteDict[data.content[2]][note];
}
}
else{
if(typeof noteDict[data.content[2]]==='undefined'){
noteDict[data.content[2]] = {};
}
noteDict[data.content[2]][note] = {ts: data.content[1], velocity:velocity};
}
}
function addLine(){
nbLines++;
for(var i=0;i<containerList.length;i++){
containerList[i].addLine(nbLines);
}
}
// Socket management
var sock = null;
var ellog = null;
function log(m) {
if(logger){
ellog.innerHTML += m + '\n';
ellog.scrollTop = ellog.scrollHeight;
}
}
window.onload = function(){
if(logger){
ellog = document.getElementById('log');
}
else{
document.body.removeChild(document.getElementById('log'));
}
var wsuri;
if (window.location.protocol === 'file:') {
wsuri = 'ws://127.0.0.1:8090/broadcast';
} else {
wsuri = 'ws://' + window.location.hostname + ':8090/broadcast';
}
wsuri = wsuri + '?channel=PIANOROLL&event_code='+eventCode;
if ('WebSocket' in window) {
sock = new WebSocket(wsuri);
} else if ('MozWebSocket' in window) {
sock = new MozWebSocket(wsuri);
} else {
log('Browser does not support WebSocket!');
window.location = 'http://autobahn.ws/unsupportedbrowser';
}
if (sock) {
sock.onopen = function(){
if(logger){
log('Connected to ' + wsuri);
}
};
sock.onclose = function(e) {
if(logger){
log('Connection closed (wasClean = ' + e.wasClean + ', code = ' + e.code + ', reason = \'' + e.reason + '\')');
}
sock = null;
};
sock.onmessage = function(e) {
if(logger){
log('Got message: ' + e.data);
}
addNotes(JSON.parse(e.data));
};
}
};
// Init page and intervals
addLine();
var moveInterval = window.setInterval(replaceContainers, 1000/manualFramerate);
var verticalLinesInterval = window.setInterval(addLine, lineInterval);
// Little inteval to show time
var nbSec = 0;
var mySpan = document.getElementById('myspan');
function updateTime(){
nbSec++;
var hours = parseInt( nbSec / 3600 ) % 24;
var minutes = parseInt( nbSec / 60 ) % 60;
var seconds = nbSec % 60;
var timeStr = (hours < 10 ? '0' + hours : hours) + ':' + (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds);
mySpan.innerHTML = timeStr;
}
var secondInterval = window.setInterval(updateTime, 1000);
module.exports = {
moveInterval: moveInterval,
verticalLinesInterval: verticalLinesInterval,
secondInterval: secondInterval
};
},{"./pianoroll.js":2,"pixi":"pixi"}],2:[function(require,module,exports){
/**
* js/pianoroll.js
*
* pianoroll basic component
*
*/
'use strict';
var PIXI = require('pixi');
var randomColor = require('randomColor');
function PianoRoll(parentContainer, xInit, yInit, height, linesDown, pixelsPerSecond, width, noteColors, colorsReg, lineColor, lineInterval, offsetMusic, noteHeight){
var _this = this;
this.container = new PIXI.DisplayObjectContainer();
this.container.position.x = xInit;
this.container.position.y = yInit;
parentContainer.addChild(this.container);
this.linesDown = linesDown;
this.height = height;
this.pixelsPerSecond = pixelsPerSecond;
this.width = width;
this.noteColors = noteColors;
this.colorsReg = colorsReg || {};
this.lineColor = lineColor;
this.lineInterval = lineInterval;
this.offsetMusic = offsetMusic || 0;
this.noteHeight = noteHeight;
this.addNote = function(note, startTime, duration, velocity, canal){
//console.log("coucou 1", note, timeFromZero, ts, velocity, pixelsPerSecond, container, prHeight);
var beginX = (this.offsetMusic + startTime) * this.pixelsPerSecond / 1000;
var width = duration * this.pixelsPerSecond / 1000;
if((beginX+width) < Math.abs(this.container.x) - this.width) {
// not visible. do nothing
return;
}
// We draw the rectangle
var graphics = new PIXI.Graphics();
//console.log("beginX = ", beginX, "canal = ", canal, "color = ", noteColor[canal], "width = ", width, "note = ", note, "velocity = ", velocity);
var color = this.colorsReg[canal];
if(typeof(color) === 'undefined') {
var colorsRegSize = Object.keys(this.colorsReg).length;
if(colorsRegSize < this.noteColors.length) {
color = this.colorsReg[canal] = this.noteColors[colorsRegSize];
}
else {
color = this.colorsReg[canal] = parseInt(randomColor({ luminosity: 'light', hue: 'random', format:'hex'}).replace(/^#/, ''), 16);
}
}
graphics.beginFill(color, (velocity / 128));
var y = (128-note) * this.height / 128; // (128-note) because y = 0 is for note = 128 and y = 128 for note = 0
graphics.drawRect(0, Math.floor(y - (noteHeight/2) + ((this.height / 128)/2)), width, noteHeight);
graphics.endFill();
graphics.x = beginX;
this.container.addChild(graphics);
};
this.addLine = function(lineNb){
var graphics = new PIXI.Graphics();
var x = -this.container.x;
graphics.beginFill(0xFFFF00);
graphics.lineStyle(1, this.lineColor);
var y = this.linesDown ? this.height - 20 : 0;
graphics.moveTo(x, y);
graphics.lineTo(x, y + 20);
graphics.endFill();
this.container.addChild(graphics);
// Add text
var totalSec = lineNb * this.lineInterval / 1000;
var hours = parseInt( totalSec / 3600 ) % 24;
var minutes = parseInt( totalSec / 60 ) % 60;
var seconds = totalSec % 60;
var timeStr = (hours < 10 ? '0' + hours : hours) + ':' + (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds);
var fontObj = { font: '10pt Arial', fill: '#444444' };
var t = new PIXI.Text(timeStr, fontObj);
t.x = x + 2;
t.y = this.linesDown ? this.height - 15 : 2;
this.container.addChild(t);
};
this.moveTo = function(diffTime){
this.container.x = Math.floor(diffTime*this.pixelsPerSecond);
};
this.removePassedObjets = function(){
var nbChilds = _this.container.children.length;
var i = 0, childIsNowDisplayed = false, childrenToRemove = [];
while(i<nbChilds && !childIsNowDisplayed){
var child = _this.container.children[i++];
//console.log("remove ? ", child.x, child.width, ((child.x + child.width) < (Math.abs(_this.container.x) - _this.width)));
if(typeof(child) == 'undefined') {
continue;
}
if((child.x + child.width) < (Math.abs(_this.container.x) - _this.width)){
childrenToRemove.push(child);
//console.log(" remove !!!");
}
else {
childIsNowDisplayed = true;
//console.log(" childIsNowDisplayed");
}
}
childrenToRemove.forEach(function(child) {
_this.container.removeChild(child);
});
//console.log("before : ", nbChilds, ", after : ", _this.container.children.length);
};
// remove notes each scene width
//var removeInterval = window.setInterval(this.removePassedObjets, 1000 * sceneWidth / this.pixelsPerSecond );
window.setInterval(this.removePassedObjets, 1000 * this.width / this.pixelsPerSecond );
}
module.exports = PianoRoll;
},{"pixi":"pixi","randomColor":"randomColor"}]},{},[1])(1)
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIuL2FwcC9qcy9tYWluLmpzIiwiL1VzZXJzL3ltaC9kZXYvcHJvamVjdHMvbW9ucy9kZXYvY2xpZW50L3BpYW5vcm9sbC9hcHAvanMvcGlhbm9yb2xsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdE1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qKlxuICogc2NyaXB0cy9tYWluLmpzXG4gKlxuICogVGhpcyBpcyB0aGUgc3RhcnRpbmcgcG9pbnQgZm9yIHlvdXIgYXBwbGljYXRpb24uXG4gKiBUYWtlIGEgbG9vayBhdCBodHRwOi8vYnJvd3NlcmlmeS5vcmcvIGZvciBtb3JlIGluZm9cbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cblxudmFyIFBJWEkgPSByZXF1aXJlKCdwaXhpJyk7XG5cbi8vIENvbmZpZyB2YXJzXG52YXIgbG9nZ2VyID0gZmFsc2U7XG52YXIgc2NlbmVXaWR0aCA9IDE5MjA7XG52YXIgcHJIZWlnaHQxID0gNDM1O1xudmFyIHBySGVpZ2h0MiA9IDY0NTtcbnZhciBzY2VuZUhlaWdodCA9IHBySGVpZ2h0MSArIHBySGVpZ2h0MjtcbnZhciBzY2VuZUJnQ29sb3IgPSAweEZGRkZGRjtcbnZhciBsaW5lQ29sb3IgPSAweDQ0NDQ0NDtcbnZhciBwaXhlbHNQZXJTZWNvbmQxID0gTWF0aC5mbG9vcihzY2VuZVdpZHRoIC8gMTApOyAvLyBuYiBvZiBwaXhlbHMgcGVyIHNlY29uZFxudmFyIG1hbnVhbEZyYW1lcmF0ZSA9IHBpeGVsc1BlclNlY29uZDEgLyA0O1xudmFyIHBpeGVsc1BlclNlY29uZDIgPSBNYXRoLmZsb29yKHNjZW5lV2lkdGggLyA2MCk7IC8vIG5iIG9mIHBpeGVscyBwZXIgc2Vjb25kXG52YXIgbGluZUludGVydmFsID0gNTAwMDsgLy8gbWVhbnMgbGluZSBldmVyeSA1IHNlY29uZHNcbnZhciBuYkxpbmVzID0gLTE7XG52YXIgbm90ZUhlaWdodCA9IDExMDtcbnZhciBub3RlQ29sb3JzID0gWzB4QjkwMDAwLCAweDRCREQ3MSwgMHhBRjkzMUUsIDB4MUMyOEJBLCAweDUzNjk5MV07XG52YXIgY29sb3JzUmVnID0ge307XG4vLyBWYXJzXG52YXIgbm90ZURpY3QgPSBbXTtcbi8vIFRpbWVjb2RlIG1ldGhvZFxudmFyIHRpbWVQYWdlTG9hZGVkID0gRGF0ZS5ub3coKTtcbnZhciBvZmZzZXRNdXNpYyA9IGZhbHNlO1xuXG5cbi8vY3JlYXRlIGFuIG5ldyBpbnN0YW5jZSBvZiBhIHBpeGkgc3RhZ2VcbnZhciBzdGFnZSA9IG5ldyBQSVhJLlN0YWdlKHNjZW5lQmdDb2xvcik7XG5cbi8vY3JlYXRlIGEgcmVuZGVyZXIgaW5zdGFuY2UuXG52YXIgcmVuZGVyZXIgPSBQSVhJLmF1dG9EZXRlY3RSZW5kZXJlcihzY2VuZVdpZHRoLCBzY2VuZUhlaWdodCk7XG5cbi8vYWRkIHRoZSByZW5kZXJlciB2aWV3IGVsZW1lbnQgdG8gdGhlIERPTVxuZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NhbnZhc0NvbnRhaW5lcicpLmFwcGVuZENoaWxkKHJlbmRlcmVyLnZpZXcpO1xuXG52YXIgdWJlckNvbnRhaW5lciA9IG5ldyBQSVhJLkRpc3BsYXlPYmplY3RDb250YWluZXIoKTtcbnViZXJDb250YWluZXIucG9zaXRpb24ueCA9IE1hdGguZmxvb3Ioc2NlbmVXaWR0aCo5LzEwKTtcbnViZXJDb250YWluZXIucG9zaXRpb24ueSA9IDA7XG5zdGFnZS5hZGRDaGlsZCh1YmVyQ29udGFpbmVyKTtcblxudmFyIFBpYW5vUm9sbCA9IHJlcXVpcmUoJy4vcGlhbm9yb2xsLmpzJylcblxuLy8gSW5pdCBjb250YWluZXJzXG52YXIgY29udGFpbmVyTGlzdCA9IFtdO1xuY29udGFpbmVyTGlzdC5wdXNoKG5ldyBQaWFub1JvbGwodWJlckNvbnRhaW5lciwgMCwgMCwgcHJIZWlnaHQxLCB0cnVlLCBwaXhlbHNQZXJTZWNvbmQxLCBzY2VuZVdpZHRoLCBub3RlQ29sb3JzLCBjb2xvcnNSZWcsIGxpbmVDb2xvciwgbGluZUludGVydmFsLCBvZmZzZXRNdXNpYywgcHJIZWlnaHQxIC8gMTI4KSk7XG5jb250YWluZXJMaXN0LnB1c2gobmV3IFBpYW5vUm9sbCh1YmVyQ29udGFpbmVyLCAwLCBwckhlaWdodDEsIHBySGVpZ2h0MiwgZmFsc2UsIHBpeGVsc1BlclNlY29uZDIsIHNjZW5lV2lkdGgsIG5vdGVDb2xvcnMsIGNvbG9yc1JlZywgbGluZUNvbG9yLCBsaW5lSW50ZXJ2YWwsIG9mZnNldE11c2ljLCBwckhlaWdodDIgLyAxMjgpKTtcblxuLy8gTGluZSBiZXR3ZWVuIHR3byBjb250YWluZXJzXG52YXIgZ3JhcGhpY3MgPSBuZXcgUElYSS5HcmFwaGljcygpO1xuZ3JhcGhpY3MuYmVnaW5GaWxsKDB4RkZGRjAwKTtcbmdyYXBoaWNzLmxpbmVTdHlsZSgxLCBsaW5lQ29sb3IpO1xuZ3JhcGhpY3MubW92ZVRvKDAsIHBySGVpZ2h0MSk7XG5ncmFwaGljcy5saW5lVG8oc2NlbmVXaWR0aCwgcHJIZWlnaHQxKTtcbmdyYXBoaWNzLmVuZEZpbGwoKTtcbnN0YWdlLmFkZENoaWxkKGdyYXBoaWNzKTtcblxuXG5mdW5jdGlvbiByZXBsYWNlQ29udGFpbmVycygpe1xuICAgIHZhciBkaWZmID0gKERhdGUubm93KCkgLSB0aW1lUGFnZUxvYWRlZCkvMTAwMDsvLyBuYiBvZiBzZWNvbmRzIHNpbmNlIHBhZ2UgbG9hZGVkXG4gICAgLy9jb25zb2xlLmxvZyhcInJlcGxhY2UgISBkaWZmMSA9IFwiLCBjb250YWluZXIxLnggLSBNYXRoLmZsb29yKC1kaWZmKnBpeGVsc1BlclNlY29uZDEpLCBcIiwgZGlmZiAyID0gXCIsIGNvbnRhaW5lcjIueCAtIE1hdGguZmxvb3IoLWRpZmYqcGl4ZWxzUGVyU2Vjb25kMikpO1xuICAgIGZvcih2YXIgaT0wO2k8Y29udGFpbmVyTGlzdC5sZW5ndGg7aSsrKXtcbiAgICAgICAgY29udGFpbmVyTGlzdFtpXS5tb3ZlVG8oLWRpZmYpO1xuICAgIH1cbiAgICByZW5kZXJlci5yZW5kZXIoc3RhZ2UpO1xufVxuXG5mdW5jdGlvbiBhZGROb3RlcyhkYXRhKXtcbiAgICBpZighb2Zmc2V0TXVzaWMpe1xuICAgICAgICAvLyBnZXQgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBjdXJyZW50IG5vdGUgdGltZWNvZGUgYW5kIG15IHplcm8gdG8gc2V0IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGNhbnZhcydzIHplcm8gYW5kIHRoZSBtdXNpYydzIHplcm9cbiAgICAgICAgLy8gaW4gb3JkZXIgdG8gcGxhY2UgaW4gcmVhbCB0aW1lXG4gICAgICAgIHZhciBub3cgPSBEYXRlLm5vdygpO1xuICAgICAgICB2YXIgdGltZUJldHdlZW5Ob3dBbmRTdGFydCA9IG5vdyAtIHRpbWVQYWdlTG9hZGVkO1xuICAgICAgICBvZmZzZXRNdXNpYyA9IHRpbWVCZXR3ZWVuTm93QW5kU3RhcnQgLSBkYXRhLmNvbnRlbnRbMV07XG4gICAgICAgIC8vY29uc29sZS5sb2coXCJzdGFydDogXCIsIHRpbWVQYWdlTG9hZGVkLCBcIiwgbm93OiBcIiwgbm93LCBcIiwgdGltZUJldHdlZW5Ob3dBbmRTdGFydCA9IFwiLCB0aW1lQmV0d2Vlbk5vd0FuZFN0YXJ0LCBcIiwgb2Zmc2V0TXVzaWMgPSBcIiwgb2Zmc2V0TXVzaWMpO1xuICAgIH1cbiAgICB2YXIgbm90ZSA9IGRhdGEuY29udGVudFszXTtcbiAgICB2YXIgdmVsb2NpdHkgPSBkYXRhLmNvbnRlbnRbNF07XG4gICAgaWYodmVsb2NpdHk9PT0wKXtcbiAgICAgICAgaWYodHlwZW9mIG5vdGVEaWN0W2RhdGEuY29udGVudFsyXV1bbm90ZV0hPT0ndW5kZWZpbmVkJyl7XG4gICAgICAgICAgICAvLyBXZSBjbG9zZSB0aGUgbm90ZSBpbiBjb250YWluZXIgb25lXG4gICAgICAgICAgICAvL2NvbnNvbGUubG9nKFwiY291Y291IDJcIiwgZGF0YSk7XG4gICAgICAgICAgICB2YXIgZHVyYXRpb24gPSBkYXRhLmNvbnRlbnRbMV0gLSBub3RlRGljdFtkYXRhLmNvbnRlbnRbMl1dW25vdGVdLnRzO1xuICAgICAgICAgICAgZm9yKHZhciBpPTA7aTxjb250YWluZXJMaXN0Lmxlbmd0aDtpKyspe1xuICAgICAgICAgICAgICAgIC8vICAgICAgICAgICAgICAgYWRkTm90ZShub3RlLCBzdGFydFRpbWUsICAgICAgICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbiwgdmVsb2NpdHksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FuYWwpXG4gICAgICAgICAgICAgICAgY29udGFpbmVyTGlzdFtpXS5hZGROb3RlKG5vdGUsIG5vdGVEaWN0W2RhdGEuY29udGVudFsyXV1bbm90ZV0udHMsIGR1cmF0aW9uLCBub3RlRGljdFtkYXRhLmNvbnRlbnRbMl1dW25vdGVdLnZlbG9jaXR5LCBkYXRhLmNvbnRlbnRbMl0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gZGVsZXRlIGVudHJ5XG4gICAgICAgICAgICBkZWxldGUgbm90ZURpY3RbZGF0YS5jb250ZW50WzJdXVtub3RlXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNle1xuICAgICAgICBpZih0eXBlb2Ygbm90ZURpY3RbZGF0YS5jb250ZW50WzJdXT09PSd1bmRlZmluZWQnKXtcbiAgICAgICAgICAgIG5vdGVEaWN0W2RhdGEuY29udGVudFsyXV0gPSB7fTtcbiAgICAgICAgfVxuICAgICAgICBub3RlRGljdFtkYXRhLmNvbnRlbnRbMl1dW25vdGVdID0ge3RzOiBkYXRhLmNvbnRlbnRbMV0sIHZlbG9jaXR5OnZlbG9jaXR5fTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGFkZExpbmUoKXtcbiAgICBuYkxpbmVzKys7XG4gICAgZm9yKHZhciBpPTA7aTxjb250YWluZXJMaXN0Lmxlbmd0aDtpKyspe1xuICAgICAgICBjb250YWluZXJMaXN0W2ldLmFkZExpbmUobmJMaW5lcyk7XG4gICAgfVxufVxuXG5cblxuLy8gU29ja2V0IG1hbmFnZW1lbnRcbnZhciBzb2NrID0gbnVsbDtcbnZhciBlbGxvZyA9IG51bGw7XG5mdW5jdGlvbiBsb2cobSkge1xuICAgIGlmKGxvZ2dlcil7XG4gICAgICAgIGVsbG9nLmlubmVySFRNTCArPSBtICsgJ1xcbic7XG4gICAgICAgIGVsbG9nLnNjcm9sbFRvcCA9IGVsbG9nLnNjcm9sbEhlaWdodDtcbiAgICB9XG59XG53aW5kb3cub25sb2FkID0gZnVuY3Rpb24oKXtcblxuICAgIGlmKGxvZ2dlcil7XG4gICAgICAgIGVsbG9nID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xvZycpO1xuICAgIH1cbiAgICBlbHNle1xuICAgICAgICBkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2cnKSk7XG4gICAgfVxuXG4gICAgdmFyIHdzdXJpO1xuICAgIGlmICh3aW5kb3cubG9jYXRpb24ucHJvdG9jb2wgPT09ICdmaWxlOicpIHtcbiAgICAgICAgd3N1cmkgPSAnd3M6Ly8xMjcuMC4wLjE6ODA5MC9icm9hZGNhc3QnO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHdzdXJpID0gJ3dzOi8vJyArIHdpbmRvdy5sb2NhdGlvbi5ob3N0bmFtZSArICc6ODA5MC9icm9hZGNhc3QnO1xuICAgIH1cbiAgICB3c3VyaSA9IHdzdXJpICsgJz9jaGFubmVsPVBJQU5PUk9MTCZldmVudF9jb2RlPScrZXZlbnRDb2RlO1xuXG4gICAgaWYgKCdXZWJTb2NrZXQnIGluIHdpbmRvdykge1xuICAgICAgICBzb2NrID0gbmV3IFdlYlNvY2tldCh3c3VyaSk7XG4gICAgfSBlbHNlIGlmICgnTW96V2ViU29ja2V0JyBpbiB3aW5kb3cpIHtcbiAgICAgICAgc29jayA9IG5ldyBNb3pXZWJTb2NrZXQod3N1cmkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZygnQnJvd3NlciBkb2VzIG5vdCBzdXBwb3J0IFdlYlNvY2tldCEnKTtcbiAgICAgICAgd2luZG93LmxvY2F0aW9uID0gJ2h0dHA6Ly9hdXRvYmFobi53cy91bnN1cHBvcnRlZGJyb3dzZXInO1xuICAgIH1cblxuICAgIGlmIChzb2NrKSB7XG4gICAgICAgIHNvY2sub25vcGVuID0gZnVuY3Rpb24oKXtcbiAgICAgICAgICAgIGlmKGxvZ2dlcil7XG4gICAgICAgICAgICAgICAgbG9nKCdDb25uZWN0ZWQgdG8gJyArIHdzdXJpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBzb2NrLm9uY2xvc2UgPSBmdW5jdGlvbihlKSB7XG4gICAgICAgICAgICBpZihsb2dnZXIpe1xuICAgICAgICAgICAgICAgIGxvZygnQ29ubmVjdGlvbiBjbG9zZWQgKHdhc0NsZWFuID0gJyArIGUud2FzQ2xlYW4gKyAnLCBjb2RlID0gJyArIGUuY29kZSArICcsIHJlYXNvbiA9IFxcJycgKyBlLnJlYXNvbiArICdcXCcpJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzb2NrID0gbnVsbDtcbiAgICAgICAgfTtcblxuICAgICAgICBzb2NrLm9ubWVzc2FnZSA9IGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgICAgIGlmKGxvZ2dlcil7XG4gICAgICAgICAgICAgICAgbG9nKCdHb3QgbWVzc2FnZTogJyArIGUuZGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhZGROb3RlcyhKU09OLnBhcnNlKGUuZGF0YSkpO1xuICAgICAgICB9O1xuICAgIH1cbn07XG5cblxuLy8gSW5pdCBwYWdlIGFuZCBpbnRlcnZhbHNcbmFkZExpbmUoKTtcbnZhciBtb3ZlSW50ZXJ2YWwgPSB3aW5kb3cuc2V0SW50ZXJ2YWwocmVwbGFjZUNvbnRhaW5lcnMsIDEwMDAvbWFudWFsRnJhbWVyYXRlKTtcbnZhciB2ZXJ0aWNhbExpbmVzSW50ZXJ2YWwgPSB3aW5kb3cuc2V0SW50ZXJ2YWwoYWRkTGluZSwgbGluZUludGVydmFsKTtcblxuLy8gTGl0dGxlIGludGV2YWwgdG8gc2hvdyB0aW1lXG52YXIgbmJTZWMgPSAwO1xudmFyIG15U3BhbiA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdteXNwYW4nKTtcbmZ1bmN0aW9uIHVwZGF0ZVRpbWUoKXtcbiAgICBuYlNlYysrO1xuICAgIHZhciBob3VycyA9IHBhcnNlSW50KCBuYlNlYyAvIDM2MDAgKSAlIDI0O1xuICAgIHZhciBtaW51dGVzID0gcGFyc2VJbnQoIG5iU2VjIC8gNjAgKSAlIDYwO1xuICAgIHZhciBzZWNvbmRzID0gbmJTZWMgJSA2MDtcbiAgICB2YXIgdGltZVN0ciA9IChob3VycyA8IDEwID8gJzAnICsgaG91cnMgOiBob3VycykgKyAnOicgKyAobWludXRlcyA8IDEwID8gJzAnICsgbWludXRlcyA6IG1pbnV0ZXMpICsgJzonICsgKHNlY29uZHMgIDwgMTAgPyAnMCcgKyBzZWNvbmRzIDogc2Vjb25kcyk7XG4gICAgbXlTcGFuLmlubmVySFRNTCA9IHRpbWVTdHI7XG59XG52YXIgc2Vjb25kSW50ZXJ2YWwgPSB3aW5kb3cuc2V0SW50ZXJ2YWwodXBkYXRlVGltZSwgMTAwMCk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIG1vdmVJbnRlcnZhbDogbW92ZUludGVydmFsLFxuICAgIHZlcnRpY2FsTGluZXNJbnRlcnZhbDogdmVydGljYWxMaW5lc0ludGVydmFsLFxuICAgIHNlY29uZEludGVydmFsOiBzZWNvbmRJbnRlcnZhbFxufTtcbiIsIi8qKlxuKiBqcy9waWFub3JvbGwuanNcbipcbiogcGlhbm9yb2xsIGJhc2ljIGNvbXBvbmVudFxuKlxuKi9cblxuJ3VzZSBzdHJpY3QnO1xuXG52YXIgUElYSSA9IHJlcXVpcmUoJ3BpeGknKTtcbnZhciByYW5kb21Db2xvciA9IHJlcXVpcmUoJ3JhbmRvbUNvbG9yJyk7XG5cbmZ1bmN0aW9uIFBpYW5vUm9sbChwYXJlbnRDb250YWluZXIsIHhJbml0LCB5SW5pdCwgaGVpZ2h0LCBsaW5lc0Rvd24sIHBpeGVsc1BlclNlY29uZCwgd2lkdGgsIG5vdGVDb2xvcnMsIGNvbG9yc1JlZywgbGluZUNvbG9yLCBsaW5lSW50ZXJ2YWwsIG9mZnNldE11c2ljLCBub3RlSGVpZ2h0KXtcbiAgICB2YXIgX3RoaXMgPSB0aGlzO1xuICAgIHRoaXMuY29udGFpbmVyID0gbmV3IFBJWEkuRGlzcGxheU9iamVjdENvbnRhaW5lcigpO1xuICAgIHRoaXMuY29udGFpbmVyLnBvc2l0aW9uLnggPSB4SW5pdDtcbiAgICB0aGlzLmNvbnRhaW5lci5wb3NpdGlvbi55ID0geUluaXQ7XG4gICAgcGFyZW50Q29udGFpbmVyLmFkZENoaWxkKHRoaXMuY29udGFpbmVyKTtcblxuICAgIHRoaXMubGluZXNEb3duID0gbGluZXNEb3duO1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xuICAgIHRoaXMucGl4ZWxzUGVyU2Vjb25kID0gcGl4ZWxzUGVyU2Vjb25kO1xuICAgIHRoaXMud2lkdGggPSB3aWR0aDtcbiAgICB0aGlzLm5vdGVDb2xvcnMgPSBub3RlQ29sb3JzO1xuICAgIHRoaXMuY29sb3JzUmVnID0gY29sb3JzUmVnIHx8IHt9O1xuICAgIHRoaXMubGluZUNvbG9yID0gbGluZUNvbG9yO1xuICAgIHRoaXMubGluZUludGVydmFsID0gbGluZUludGVydmFsO1xuICAgIHRoaXMub2Zmc2V0TXVzaWMgPSBvZmZzZXRNdXNpYyB8fCAwO1xuICAgIHRoaXMubm90ZUhlaWdodCA9IG5vdGVIZWlnaHQ7XG5cbiAgICB0aGlzLmFkZE5vdGUgPSBmdW5jdGlvbihub3RlLCBzdGFydFRpbWUsIGR1cmF0aW9uLCB2ZWxvY2l0eSwgY2FuYWwpe1xuICAgICAgICAvL2NvbnNvbGUubG9nKFwiY291Y291IDFcIiwgbm90ZSwgdGltZUZyb21aZXJvLCB0cywgdmVsb2NpdHksIHBpeGVsc1BlclNlY29uZCwgY29udGFpbmVyLCBwckhlaWdodCk7XG4gICAgICAgIHZhciBiZWdpblggPSAodGhpcy5vZmZzZXRNdXNpYyArIHN0YXJ0VGltZSkgKiB0aGlzLnBpeGVsc1BlclNlY29uZCAvIDEwMDA7XG4gICAgICAgIHZhciB3aWR0aCA9IGR1cmF0aW9uICogdGhpcy5waXhlbHNQZXJTZWNvbmQgLyAxMDAwO1xuICAgICAgICBpZigoYmVnaW5YK3dpZHRoKSA8ICBNYXRoLmFicyh0aGlzLmNvbnRhaW5lci54KSAtIHRoaXMud2lkdGgpIHtcbiAgICAgICAgICAgIC8vIG5vdCB2aXNpYmxlLiBkbyBub3RoaW5nXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gV2UgZHJhdyB0aGUgcmVjdGFuZ2xlXG4gICAgICAgIHZhciBncmFwaGljcyA9IG5ldyBQSVhJLkdyYXBoaWNzKCk7XG4gICAgICAgIC8vY29uc29sZS5sb2coXCJiZWdpblggPSBcIiwgYmVnaW5YLCBcImNhbmFsID0gXCIsIGNhbmFsLCBcImNvbG9yID0gXCIsIG5vdGVDb2xvcltjYW5hbF0sIFwid2lkdGggPSBcIiwgd2lkdGgsIFwibm90ZSA9IFwiLCBub3RlLCBcInZlbG9jaXR5ID0gXCIsIHZlbG9jaXR5KTtcbiAgICAgICAgdmFyIGNvbG9yID0gdGhpcy5jb2xvcnNSZWdbY2FuYWxdO1xuICAgICAgICBpZih0eXBlb2YoY29sb3IpID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgdmFyIGNvbG9yc1JlZ1NpemUgPSBPYmplY3Qua2V5cyh0aGlzLmNvbG9yc1JlZykubGVuZ3RoO1xuICAgICAgICAgICAgaWYoY29sb3JzUmVnU2l6ZSA8IHRoaXMubm90ZUNvbG9ycy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBjb2xvciA9IHRoaXMuY29sb3JzUmVnW2NhbmFsXSA9IHRoaXMubm90ZUNvbG9yc1tjb2xvcnNSZWdTaXplXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbG9yID0gdGhpcy5jb2xvcnNSZWdbY2FuYWxdID0gcGFyc2VJbnQocmFuZG9tQ29sb3IoeyBsdW1pbm9zaXR5OiAnbGlnaHQnLCBodWU6ICdyYW5kb20nLCBmb3JtYXQ6J2hleCd9KS5yZXBsYWNlKC9eIy8sICcnKSwgMTYpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGdyYXBoaWNzLmJlZ2luRmlsbChjb2xvciwgKHZlbG9jaXR5IC8gMTI4KSk7XG4gICAgICAgIHZhciB5ID0gKDEyOC1ub3RlKSAqIHRoaXMuaGVpZ2h0IC8gMTI4OyAvLyAoMTI4LW5vdGUpIGJlY2F1c2UgeSA9IDAgaXMgZm9yIG5vdGUgPSAxMjggYW5kIHkgPSAxMjggZm9yIG5vdGUgPSAwXG4gICAgICAgIGdyYXBoaWNzLmRyYXdSZWN0KDAsIE1hdGguZmxvb3IoeSAtIChub3RlSGVpZ2h0LzIpICsgKCh0aGlzLmhlaWdodCAvIDEyOCkvMikpLCB3aWR0aCwgbm90ZUhlaWdodCk7XG4gICAgICAgIGdyYXBoaWNzLmVuZEZpbGwoKTtcbiAgICAgICAgZ3JhcGhpY3MueCA9IGJlZ2luWDtcbiAgICAgICAgdGhpcy5jb250YWluZXIuYWRkQ2hpbGQoZ3JhcGhpY3MpO1xuICAgIH07XG5cbiAgICB0aGlzLmFkZExpbmUgPSBmdW5jdGlvbihsaW5lTmIpe1xuICAgICAgICB2YXIgZ3JhcGhpY3MgPSBuZXcgUElYSS5HcmFwaGljcygpO1xuICAgICAgICB2YXIgeCA9IC10aGlzLmNvbnRhaW5lci54O1xuICAgICAgICBncmFwaGljcy5iZWdpbkZpbGwoMHhGRkZGMDApO1xuICAgICAgICBncmFwaGljcy5saW5lU3R5bGUoMSwgdGhpcy5saW5lQ29sb3IpO1xuICAgICAgICB2YXIgeSA9IHRoaXMubGluZXNEb3duID8gdGhpcy5oZWlnaHQgLSAyMCA6IDA7XG4gICAgICAgIGdyYXBoaWNzLm1vdmVUbyh4LCB5KTtcbiAgICAgICAgZ3JhcGhpY3MubGluZVRvKHgsIHkgKyAyMCk7XG4gICAgICAgIGdyYXBoaWNzLmVuZEZpbGwoKTtcbiAgICAgICAgdGhpcy5jb250YWluZXIuYWRkQ2hpbGQoZ3JhcGhpY3MpO1xuICAgICAgICAvLyBBZGQgdGV4dFxuICAgICAgICB2YXIgdG90YWxTZWMgPSBsaW5lTmIgKiB0aGlzLmxpbmVJbnRlcnZhbCAvIDEwMDA7XG4gICAgICAgIHZhciBob3VycyA9IHBhcnNlSW50KCB0b3RhbFNlYyAvIDM2MDAgKSAlIDI0O1xuICAgICAgICB2YXIgbWludXRlcyA9IHBhcnNlSW50KCB0b3RhbFNlYyAvIDYwICkgJSA2MDtcbiAgICAgICAgdmFyIHNlY29uZHMgPSB0b3RhbFNlYyAlIDYwO1xuICAgICAgICB2YXIgdGltZVN0ciA9IChob3VycyA8IDEwID8gJzAnICsgaG91cnMgOiBob3VycykgKyAnOicgKyAobWludXRlcyA8IDEwID8gJzAnICsgbWludXRlcyA6IG1pbnV0ZXMpICsgJzonICsgKHNlY29uZHMgIDwgMTAgPyAnMCcgKyBzZWNvbmRzIDogc2Vjb25kcyk7XG4gICAgICAgIHZhciBmb250T2JqID0geyBmb250OiAnMTBwdCBBcmlhbCcsIGZpbGw6ICcjNDQ0NDQ0JyB9O1xuICAgICAgICB2YXIgdCA9IG5ldyBQSVhJLlRleHQodGltZVN0ciwgZm9udE9iaik7XG4gICAgICAgIHQueCA9IHggKyAyO1xuICAgICAgICB0LnkgPSB0aGlzLmxpbmVzRG93biA/IHRoaXMuaGVpZ2h0IC0gMTUgOiAyO1xuICAgICAgICB0aGlzLmNvbnRhaW5lci5hZGRDaGlsZCh0KTtcbiAgICB9O1xuXG4gICAgdGhpcy5tb3ZlVG8gPSBmdW5jdGlvbihkaWZmVGltZSl7XG4gICAgICAgIHRoaXMuY29udGFpbmVyLnggPSBNYXRoLmZsb29yKGRpZmZUaW1lKnRoaXMucGl4ZWxzUGVyU2Vjb25kKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZW1vdmVQYXNzZWRPYmpldHMgPSBmdW5jdGlvbigpe1xuICAgICAgICB2YXIgbmJDaGlsZHMgPSBfdGhpcy5jb250YWluZXIuY2hpbGRyZW4ubGVuZ3RoO1xuICAgICAgICB2YXIgaSA9IDAsIGNoaWxkSXNOb3dEaXNwbGF5ZWQgPSBmYWxzZSwgY2hpbGRyZW5Ub1JlbW92ZSA9IFtdO1xuICAgICAgICB3aGlsZShpPG5iQ2hpbGRzICYmICFjaGlsZElzTm93RGlzcGxheWVkKXtcbiAgICAgICAgICAgIHZhciBjaGlsZCA9IF90aGlzLmNvbnRhaW5lci5jaGlsZHJlbltpKytdO1xuICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhcInJlbW92ZSA/IFwiLCBjaGlsZC54LCBjaGlsZC53aWR0aCwgKChjaGlsZC54ICsgY2hpbGQud2lkdGgpIDwgKE1hdGguYWJzKF90aGlzLmNvbnRhaW5lci54KSAtIF90aGlzLndpZHRoKSkpO1xuICAgICAgICAgICAgaWYodHlwZW9mKGNoaWxkKSA9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYoKGNoaWxkLnggKyBjaGlsZC53aWR0aCkgPCAoTWF0aC5hYnMoX3RoaXMuY29udGFpbmVyLngpIC0gX3RoaXMud2lkdGgpKXtcbiAgICAgICAgICAgICAgICBjaGlsZHJlblRvUmVtb3ZlLnB1c2goY2hpbGQpO1xuICAgICAgICAgICAgICAgIC8vY29uc29sZS5sb2coXCIgICAgcmVtb3ZlICEhIVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGNoaWxkSXNOb3dEaXNwbGF5ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIC8vY29uc29sZS5sb2coXCIgICAgY2hpbGRJc05vd0Rpc3BsYXllZFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjaGlsZHJlblRvUmVtb3ZlLmZvckVhY2goZnVuY3Rpb24oY2hpbGQpIHtcbiAgICAgICAgICAgIF90aGlzLmNvbnRhaW5lci5yZW1vdmVDaGlsZChjaGlsZCk7XG4gICAgICAgIH0pO1xuICAgICAgICAvL2NvbnNvbGUubG9nKFwiYmVmb3JlIDogXCIsIG5iQ2hpbGRzLCBcIiwgYWZ0ZXIgOiBcIiwgX3RoaXMuY29udGFpbmVyLmNoaWxkcmVuLmxlbmd0aCk7XG4gICAgfTtcblxuICAgIC8vIHJlbW92ZSBub3RlcyBlYWNoIHNjZW5lIHdpZHRoXG4gICAgLy92YXIgcmVtb3ZlSW50ZXJ2YWwgPSB3aW5kb3cuc2V0SW50ZXJ2YWwodGhpcy5yZW1vdmVQYXNzZWRPYmpldHMsIDEwMDAgKiBzY2VuZVdpZHRoIC8gdGhpcy5waXhlbHNQZXJTZWNvbmQgKTtcbiAgICB3aW5kb3cuc2V0SW50ZXJ2YWwodGhpcy5yZW1vdmVQYXNzZWRPYmpldHMsIDEwMDAgKiB0aGlzLndpZHRoIC8gdGhpcy5waXhlbHNQZXJTZWNvbmQgKTtcblxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFBpYW5vUm9sbDtcbiJdfQ==