17430 lines
1.5 MiB
17430 lines
1.5 MiB
(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){
|
||
(function (process){
|
||
/**
|
||
* This is the web browser implementation of `debug()`.
|
||
*
|
||
* Expose `debug()` as the module.
|
||
*/
|
||
|
||
exports = module.exports = require('./debug');
|
||
exports.log = log;
|
||
exports.formatArgs = formatArgs;
|
||
exports.save = save;
|
||
exports.load = load;
|
||
exports.useColors = useColors;
|
||
exports.storage = 'undefined' != typeof chrome
|
||
&& 'undefined' != typeof chrome.storage
|
||
? chrome.storage.local
|
||
: localstorage();
|
||
|
||
/**
|
||
* Colors.
|
||
*/
|
||
|
||
exports.colors = [
|
||
'lightseagreen',
|
||
'forestgreen',
|
||
'goldenrod',
|
||
'dodgerblue',
|
||
'darkorchid',
|
||
'crimson'
|
||
];
|
||
|
||
/**
|
||
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
|
||
* and the Firebug extension (any Firefox version) are known
|
||
* to support "%c" CSS customizations.
|
||
*
|
||
* TODO: add a `localStorage` variable to explicitly enable/disable colors
|
||
*/
|
||
|
||
function useColors() {
|
||
// NB: In an Electron preload script, document will be defined but not fully
|
||
// initialized. Since we know we're in Chrome, we'll just detect this case
|
||
// explicitly
|
||
if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') {
|
||
return true;
|
||
}
|
||
|
||
// is webkit? http://stackoverflow.com/a/16459606/376773
|
||
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
|
||
return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
|
||
// is firebug? http://stackoverflow.com/a/398120/376773
|
||
(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
|
||
// is firefox >= v31?
|
||
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
|
||
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
|
||
// double check webkit in userAgent just in case we are in a worker
|
||
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
|
||
}
|
||
|
||
/**
|
||
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
|
||
*/
|
||
|
||
exports.formatters.j = function(v) {
|
||
try {
|
||
return JSON.stringify(v);
|
||
} catch (err) {
|
||
return '[UnexpectedJSONParseError]: ' + err.message;
|
||
}
|
||
};
|
||
|
||
|
||
/**
|
||
* Colorize log arguments if enabled.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function formatArgs(args) {
|
||
var useColors = this.useColors;
|
||
|
||
args[0] = (useColors ? '%c' : '')
|
||
+ this.namespace
|
||
+ (useColors ? ' %c' : ' ')
|
||
+ args[0]
|
||
+ (useColors ? '%c ' : ' ')
|
||
+ '+' + exports.humanize(this.diff);
|
||
|
||
if (!useColors) return;
|
||
|
||
var c = 'color: ' + this.color;
|
||
args.splice(1, 0, c, 'color: inherit')
|
||
|
||
// the final "%c" is somewhat tricky, because there could be other
|
||
// arguments passed either before or after the %c, so we need to
|
||
// figure out the correct index to insert the CSS into
|
||
var index = 0;
|
||
var lastC = 0;
|
||
args[0].replace(/%[a-zA-Z%]/g, function(match) {
|
||
if ('%%' === match) return;
|
||
index++;
|
||
if ('%c' === match) {
|
||
// we only are interested in the *last* %c
|
||
// (the user may have provided their own)
|
||
lastC = index;
|
||
}
|
||
});
|
||
|
||
args.splice(lastC, 0, c);
|
||
}
|
||
|
||
/**
|
||
* Invokes `console.log()` when available.
|
||
* No-op when `console.log` is not a "function".
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function log() {
|
||
// this hackery is required for IE8/9, where
|
||
// the `console.log` function doesn't have 'apply'
|
||
return 'object' === typeof console
|
||
&& console.log
|
||
&& Function.prototype.apply.call(console.log, console, arguments);
|
||
}
|
||
|
||
/**
|
||
* Save `namespaces`.
|
||
*
|
||
* @param {String} namespaces
|
||
* @api private
|
||
*/
|
||
|
||
function save(namespaces) {
|
||
try {
|
||
if (null == namespaces) {
|
||
exports.storage.removeItem('debug');
|
||
} else {
|
||
exports.storage.debug = namespaces;
|
||
}
|
||
} catch(e) {}
|
||
}
|
||
|
||
/**
|
||
* Load `namespaces`.
|
||
*
|
||
* @return {String} returns the previously persisted debug modes
|
||
* @api private
|
||
*/
|
||
|
||
function load() {
|
||
var r;
|
||
try {
|
||
r = exports.storage.debug;
|
||
} catch(e) {}
|
||
|
||
// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
|
||
if (!r && typeof process !== 'undefined' && 'env' in process) {
|
||
r = process.env.DEBUG;
|
||
}
|
||
|
||
return r;
|
||
}
|
||
|
||
/**
|
||
* Enable namespaces listed in `localStorage.debug` initially.
|
||
*/
|
||
|
||
exports.enable(load());
|
||
|
||
/**
|
||
* Localstorage attempts to return the localstorage.
|
||
*
|
||
* This is necessary because safari throws
|
||
* when a user disables cookies/localstorage
|
||
* and you attempt to access it.
|
||
*
|
||
* @return {LocalStorage}
|
||
* @api private
|
||
*/
|
||
|
||
function localstorage() {
|
||
try {
|
||
return window.localStorage;
|
||
} catch (e) {}
|
||
}
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"./debug":2,"_process":114}],2:[function(require,module,exports){
|
||
|
||
/**
|
||
* This is the common logic for both the Node.js and web browser
|
||
* implementations of `debug()`.
|
||
*
|
||
* Expose `debug()` as the module.
|
||
*/
|
||
|
||
exports = module.exports = createDebug.debug = createDebug['default'] = createDebug;
|
||
exports.coerce = coerce;
|
||
exports.disable = disable;
|
||
exports.enable = enable;
|
||
exports.enabled = enabled;
|
||
exports.humanize = require('ms');
|
||
|
||
/**
|
||
* The currently active debug mode names, and names to skip.
|
||
*/
|
||
|
||
exports.names = [];
|
||
exports.skips = [];
|
||
|
||
/**
|
||
* Map of special "%n" handling functions, for the debug "format" argument.
|
||
*
|
||
* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
|
||
*/
|
||
|
||
exports.formatters = {};
|
||
|
||
/**
|
||
* Previous log timestamp.
|
||
*/
|
||
|
||
var prevTime;
|
||
|
||
/**
|
||
* Select a color.
|
||
* @param {String} namespace
|
||
* @return {Number}
|
||
* @api private
|
||
*/
|
||
|
||
function selectColor(namespace) {
|
||
var hash = 0, i;
|
||
|
||
for (i in namespace) {
|
||
hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
|
||
hash |= 0; // Convert to 32bit integer
|
||
}
|
||
|
||
return exports.colors[Math.abs(hash) % exports.colors.length];
|
||
}
|
||
|
||
/**
|
||
* Create a debugger with the given `namespace`.
|
||
*
|
||
* @param {String} namespace
|
||
* @return {Function}
|
||
* @api public
|
||
*/
|
||
|
||
function createDebug(namespace) {
|
||
|
||
function debug() {
|
||
// disabled?
|
||
if (!debug.enabled) return;
|
||
|
||
var self = debug;
|
||
|
||
// set `diff` timestamp
|
||
var curr = +new Date();
|
||
var ms = curr - (prevTime || curr);
|
||
self.diff = ms;
|
||
self.prev = prevTime;
|
||
self.curr = curr;
|
||
prevTime = curr;
|
||
|
||
// turn the `arguments` into a proper Array
|
||
var args = new Array(arguments.length);
|
||
for (var i = 0; i < args.length; i++) {
|
||
args[i] = arguments[i];
|
||
}
|
||
|
||
args[0] = exports.coerce(args[0]);
|
||
|
||
if ('string' !== typeof args[0]) {
|
||
// anything else let's inspect with %O
|
||
args.unshift('%O');
|
||
}
|
||
|
||
// apply any `formatters` transformations
|
||
var index = 0;
|
||
args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
|
||
// if we encounter an escaped % then don't increase the array index
|
||
if (match === '%%') return match;
|
||
index++;
|
||
var formatter = exports.formatters[format];
|
||
if ('function' === typeof formatter) {
|
||
var val = args[index];
|
||
match = formatter.call(self, val);
|
||
|
||
// now we need to remove `args[index]` since it's inlined in the `format`
|
||
args.splice(index, 1);
|
||
index--;
|
||
}
|
||
return match;
|
||
});
|
||
|
||
// apply env-specific formatting (colors, etc.)
|
||
exports.formatArgs.call(self, args);
|
||
|
||
var logFn = debug.log || exports.log || console.log.bind(console);
|
||
logFn.apply(self, args);
|
||
}
|
||
|
||
debug.namespace = namespace;
|
||
debug.enabled = exports.enabled(namespace);
|
||
debug.useColors = exports.useColors();
|
||
debug.color = selectColor(namespace);
|
||
|
||
// env-specific initialization logic for debug instances
|
||
if ('function' === typeof exports.init) {
|
||
exports.init(debug);
|
||
}
|
||
|
||
return debug;
|
||
}
|
||
|
||
/**
|
||
* Enables a debug mode by namespaces. This can include modes
|
||
* separated by a colon and wildcards.
|
||
*
|
||
* @param {String} namespaces
|
||
* @api public
|
||
*/
|
||
|
||
function enable(namespaces) {
|
||
exports.save(namespaces);
|
||
|
||
exports.names = [];
|
||
exports.skips = [];
|
||
|
||
var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
|
||
var len = split.length;
|
||
|
||
for (var i = 0; i < len; i++) {
|
||
if (!split[i]) continue; // ignore empty strings
|
||
namespaces = split[i].replace(/\*/g, '.*?');
|
||
if (namespaces[0] === '-') {
|
||
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
|
||
} else {
|
||
exports.names.push(new RegExp('^' + namespaces + '$'));
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Disable debug output.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function disable() {
|
||
exports.enable('');
|
||
}
|
||
|
||
/**
|
||
* Returns true if the given mode name is enabled, false otherwise.
|
||
*
|
||
* @param {String} name
|
||
* @return {Boolean}
|
||
* @api public
|
||
*/
|
||
|
||
function enabled(name) {
|
||
var i, len;
|
||
for (i = 0, len = exports.skips.length; i < len; i++) {
|
||
if (exports.skips[i].test(name)) {
|
||
return false;
|
||
}
|
||
}
|
||
for (i = 0, len = exports.names.length; i < len; i++) {
|
||
if (exports.names[i].test(name)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Coerce `val`.
|
||
*
|
||
* @param {Mixed} val
|
||
* @return {Mixed}
|
||
* @api private
|
||
*/
|
||
|
||
function coerce(val) {
|
||
if (val instanceof Error) return val.stack || val.message;
|
||
return val;
|
||
}
|
||
|
||
},{"ms":21}],3:[function(require,module,exports){
|
||
/* jshint node: true */
|
||
'use strict';
|
||
|
||
var normalice = require('normalice');
|
||
|
||
/**
|
||
# freeice
|
||
|
||
The `freeice` module is a simple way of getting random STUN or TURN server
|
||
for your WebRTC application. The list of servers (just STUN at this stage)
|
||
were sourced from this [gist](https://gist.github.com/zziuni/3741933).
|
||
|
||
## Example Use
|
||
|
||
The following demonstrates how you can use `freeice` with
|
||
[rtc-quickconnect](https://github.com/rtc-io/rtc-quickconnect):
|
||
|
||
<<< examples/quickconnect.js
|
||
|
||
As the `freeice` module generates ice servers in a list compliant with the
|
||
WebRTC spec you will be able to use it with raw `RTCPeerConnection`
|
||
constructors and other WebRTC libraries.
|
||
|
||
## Hey, don't use my STUN/TURN server!
|
||
|
||
If for some reason your free STUN or TURN server ends up in the
|
||
list of servers ([stun](https://github.com/DamonOehlman/freeice/blob/master/stun.json) or
|
||
[turn](https://github.com/DamonOehlman/freeice/blob/master/turn.json))
|
||
that is used in this module, you can feel
|
||
free to open an issue on this repository and those servers will be removed
|
||
within 24 hours (or sooner). This is the quickest and probably the most
|
||
polite way to have something removed (and provides us some visibility
|
||
if someone opens a pull request requesting that a server is added).
|
||
|
||
## Please add my server!
|
||
|
||
If you have a server that you wish to add to the list, that's awesome! I'm
|
||
sure I speak on behalf of a whole pile of WebRTC developers who say thanks.
|
||
To get it into the list, feel free to either open a pull request or if you
|
||
find that process a bit daunting then just create an issue requesting
|
||
the addition of the server (make sure you provide all the details, and if
|
||
you have a Terms of Service then including that in the PR/issue would be
|
||
awesome).
|
||
|
||
## I know of a free server, can I add it?
|
||
|
||
Sure, if you do your homework and make sure it is ok to use (I'm currently
|
||
in the process of reviewing the terms of those STUN servers included from
|
||
the original list). If it's ok to go, then please see the previous entry
|
||
for how to add it.
|
||
|
||
## Current List of Servers
|
||
|
||
* current as at the time of last `README.md` file generation
|
||
|
||
### STUN
|
||
|
||
<<< stun.json
|
||
|
||
### TURN
|
||
|
||
<<< turn.json
|
||
|
||
**/
|
||
|
||
var freeice = module.exports = function(opts) {
|
||
// if a list of servers has been provided, then use it instead of defaults
|
||
var servers = {
|
||
stun: (opts || {}).stun || require('./stun.json'),
|
||
turn: (opts || {}).turn || require('./turn.json')
|
||
};
|
||
|
||
var stunCount = (opts || {}).stunCount || 2;
|
||
var turnCount = (opts || {}).turnCount || 0;
|
||
var selected;
|
||
|
||
function getServers(type, count) {
|
||
var out = [];
|
||
var input = [].concat(servers[type]);
|
||
var idx;
|
||
|
||
while (input.length && out.length < count) {
|
||
idx = (Math.random() * input.length) | 0;
|
||
out = out.concat(input.splice(idx, 1));
|
||
}
|
||
|
||
return out.map(function(url) {
|
||
//If it's a not a string, don't try to "normalice" it otherwise using type:url will screw it up
|
||
if ((typeof url !== 'string') && (! (url instanceof String))) {
|
||
return url;
|
||
} else {
|
||
return normalice(type + ':' + url);
|
||
}
|
||
});
|
||
}
|
||
|
||
// add stun servers
|
||
selected = [].concat(getServers('stun', stunCount));
|
||
|
||
if (turnCount) {
|
||
selected = selected.concat(getServers('turn', turnCount));
|
||
}
|
||
|
||
return selected;
|
||
};
|
||
|
||
},{"./stun.json":4,"./turn.json":5,"normalice":22}],4:[function(require,module,exports){
|
||
module.exports=[
|
||
"stun.l.google.com:19302",
|
||
"stun1.l.google.com:19302",
|
||
"stun2.l.google.com:19302",
|
||
"stun3.l.google.com:19302",
|
||
"stun4.l.google.com:19302",
|
||
"stun.ekiga.net",
|
||
"stun.ideasip.com",
|
||
"stun.schlund.de",
|
||
"stun.stunprotocol.org:3478",
|
||
"stun.voiparound.com",
|
||
"stun.voipbuster.com",
|
||
"stun.voipstunt.com",
|
||
"stun.voxgratia.org",
|
||
"stun.services.mozilla.com"
|
||
]
|
||
|
||
},{}],5:[function(require,module,exports){
|
||
module.exports=[]
|
||
|
||
},{}],6:[function(require,module,exports){
|
||
var WildEmitter = require('wildemitter');
|
||
|
||
function getMaxVolume (analyser, fftBins) {
|
||
var maxVolume = -Infinity;
|
||
analyser.getFloatFrequencyData(fftBins);
|
||
|
||
for(var i=4, ii=fftBins.length; i < ii; i++) {
|
||
if (fftBins[i] > maxVolume && fftBins[i] < 0) {
|
||
maxVolume = fftBins[i];
|
||
}
|
||
};
|
||
|
||
return maxVolume;
|
||
}
|
||
|
||
|
||
var audioContextType = window.AudioContext || window.webkitAudioContext;
|
||
// use a single audio context due to hardware limits
|
||
var audioContext = null;
|
||
module.exports = function(stream, options) {
|
||
var harker = new WildEmitter();
|
||
|
||
|
||
// make it not break in non-supported browsers
|
||
if (!audioContextType) return harker;
|
||
|
||
//Config
|
||
var options = options || {},
|
||
smoothing = (options.smoothing || 0.1),
|
||
interval = (options.interval || 50),
|
||
threshold = options.threshold,
|
||
play = options.play,
|
||
history = options.history || 10,
|
||
running = true;
|
||
|
||
//Setup Audio Context
|
||
if (!audioContext) {
|
||
audioContext = new audioContextType();
|
||
}
|
||
var sourceNode, fftBins, analyser;
|
||
|
||
analyser = audioContext.createAnalyser();
|
||
analyser.fftSize = 512;
|
||
analyser.smoothingTimeConstant = smoothing;
|
||
fftBins = new Float32Array(analyser.fftSize);
|
||
|
||
if (stream.jquery) stream = stream[0];
|
||
if (stream instanceof HTMLAudioElement || stream instanceof HTMLVideoElement) {
|
||
//Audio Tag
|
||
sourceNode = audioContext.createMediaElementSource(stream);
|
||
if (typeof play === 'undefined') play = true;
|
||
threshold = threshold || -50;
|
||
} else {
|
||
//WebRTC Stream
|
||
sourceNode = audioContext.createMediaStreamSource(stream);
|
||
threshold = threshold || -50;
|
||
}
|
||
|
||
sourceNode.connect(analyser);
|
||
if (play) analyser.connect(audioContext.destination);
|
||
|
||
harker.speaking = false;
|
||
|
||
harker.setThreshold = function(t) {
|
||
threshold = t;
|
||
};
|
||
|
||
harker.setInterval = function(i) {
|
||
interval = i;
|
||
};
|
||
|
||
harker.stop = function() {
|
||
running = false;
|
||
harker.emit('volume_change', -100, threshold);
|
||
if (harker.speaking) {
|
||
harker.speaking = false;
|
||
harker.emit('stopped_speaking');
|
||
}
|
||
};
|
||
harker.speakingHistory = [];
|
||
for (var i = 0; i < history; i++) {
|
||
harker.speakingHistory.push(0);
|
||
}
|
||
|
||
// Poll the analyser node to determine if speaking
|
||
// and emit events if changed
|
||
var looper = function() {
|
||
setTimeout(function() {
|
||
|
||
//check if stop has been called
|
||
if(!running) {
|
||
return;
|
||
}
|
||
|
||
var currentVolume = getMaxVolume(analyser, fftBins);
|
||
|
||
harker.emit('volume_change', currentVolume, threshold);
|
||
|
||
var history = 0;
|
||
if (currentVolume > threshold && !harker.speaking) {
|
||
// trigger quickly, short history
|
||
for (var i = harker.speakingHistory.length - 3; i < harker.speakingHistory.length; i++) {
|
||
history += harker.speakingHistory[i];
|
||
}
|
||
if (history >= 2) {
|
||
harker.speaking = true;
|
||
harker.emit('speaking');
|
||
}
|
||
} else if (currentVolume < threshold && harker.speaking) {
|
||
for (var i = 0; i < harker.speakingHistory.length; i++) {
|
||
history += harker.speakingHistory[i];
|
||
}
|
||
if (history == 0) {
|
||
harker.speaking = false;
|
||
harker.emit('stopped_speaking');
|
||
}
|
||
}
|
||
harker.speakingHistory.shift();
|
||
harker.speakingHistory.push(0 + (currentVolume > threshold));
|
||
|
||
looper();
|
||
}, interval);
|
||
};
|
||
looper();
|
||
|
||
|
||
return harker;
|
||
}
|
||
|
||
},{"wildemitter":101}],7:[function(require,module,exports){
|
||
if (typeof Object.create === 'function') {
|
||
// implementation from standard node.js 'util' module
|
||
module.exports = function inherits(ctor, superCtor) {
|
||
ctor.super_ = superCtor
|
||
ctor.prototype = Object.create(superCtor.prototype, {
|
||
constructor: {
|
||
value: ctor,
|
||
enumerable: false,
|
||
writable: true,
|
||
configurable: true
|
||
}
|
||
});
|
||
};
|
||
} else {
|
||
// old school shim for old browsers
|
||
module.exports = function inherits(ctor, superCtor) {
|
||
ctor.super_ = superCtor
|
||
var TempCtor = function () {}
|
||
TempCtor.prototype = superCtor.prototype
|
||
ctor.prototype = new TempCtor()
|
||
ctor.prototype.constructor = ctor
|
||
}
|
||
}
|
||
|
||
},{}],8:[function(require,module,exports){
|
||
(function (global){
|
||
/*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */
|
||
;(function () {
|
||
// Detect the `define` function exposed by asynchronous module loaders. The
|
||
// strict `define` check is necessary for compatibility with `r.js`.
|
||
var isLoader = typeof define === "function" && define.amd;
|
||
|
||
// A set of types used to distinguish objects from primitives.
|
||
var objectTypes = {
|
||
"function": true,
|
||
"object": true
|
||
};
|
||
|
||
// Detect the `exports` object exposed by CommonJS implementations.
|
||
var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
|
||
|
||
// Use the `global` object exposed by Node (including Browserify via
|
||
// `insert-module-globals`), Narwhal, and Ringo as the default context,
|
||
// and the `window` object in browsers. Rhino exports a `global` function
|
||
// instead.
|
||
var root = objectTypes[typeof window] && window || this,
|
||
freeGlobal = freeExports && objectTypes[typeof module] && module && !module.nodeType && typeof global == "object" && global;
|
||
|
||
if (freeGlobal && (freeGlobal["global"] === freeGlobal || freeGlobal["window"] === freeGlobal || freeGlobal["self"] === freeGlobal)) {
|
||
root = freeGlobal;
|
||
}
|
||
|
||
// Public: Initializes JSON 3 using the given `context` object, attaching the
|
||
// `stringify` and `parse` functions to the specified `exports` object.
|
||
function runInContext(context, exports) {
|
||
context || (context = root["Object"]());
|
||
exports || (exports = root["Object"]());
|
||
|
||
// Native constructor aliases.
|
||
var Number = context["Number"] || root["Number"],
|
||
String = context["String"] || root["String"],
|
||
Object = context["Object"] || root["Object"],
|
||
Date = context["Date"] || root["Date"],
|
||
SyntaxError = context["SyntaxError"] || root["SyntaxError"],
|
||
TypeError = context["TypeError"] || root["TypeError"],
|
||
Math = context["Math"] || root["Math"],
|
||
nativeJSON = context["JSON"] || root["JSON"];
|
||
|
||
// Delegate to the native `stringify` and `parse` implementations.
|
||
if (typeof nativeJSON == "object" && nativeJSON) {
|
||
exports.stringify = nativeJSON.stringify;
|
||
exports.parse = nativeJSON.parse;
|
||
}
|
||
|
||
// Convenience aliases.
|
||
var objectProto = Object.prototype,
|
||
getClass = objectProto.toString,
|
||
isProperty, forEach, undef;
|
||
|
||
// Test the `Date#getUTC*` methods. Based on work by @Yaffle.
|
||
var isExtended = new Date(-3509827334573292);
|
||
try {
|
||
// The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical
|
||
// results for certain dates in Opera >= 10.53.
|
||
isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 &&
|
||
// Safari < 2.0.2 stores the internal millisecond time value correctly,
|
||
// but clips the values returned by the date methods to the range of
|
||
// signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]).
|
||
isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708;
|
||
} catch (exception) {}
|
||
|
||
// Internal: Determines whether the native `JSON.stringify` and `parse`
|
||
// implementations are spec-compliant. Based on work by Ken Snyder.
|
||
function has(name) {
|
||
if (has[name] !== undef) {
|
||
// Return cached feature test result.
|
||
return has[name];
|
||
}
|
||
var isSupported;
|
||
if (name == "bug-string-char-index") {
|
||
// IE <= 7 doesn't support accessing string characters using square
|
||
// bracket notation. IE 8 only supports this for primitives.
|
||
isSupported = "a"[0] != "a";
|
||
} else if (name == "json") {
|
||
// Indicates whether both `JSON.stringify` and `JSON.parse` are
|
||
// supported.
|
||
isSupported = has("json-stringify") && has("json-parse");
|
||
} else {
|
||
var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';
|
||
// Test `JSON.stringify`.
|
||
if (name == "json-stringify") {
|
||
var stringify = exports.stringify, stringifySupported = typeof stringify == "function" && isExtended;
|
||
if (stringifySupported) {
|
||
// A test function object with a custom `toJSON` method.
|
||
(value = function () {
|
||
return 1;
|
||
}).toJSON = value;
|
||
try {
|
||
stringifySupported =
|
||
// Firefox 3.1b1 and b2 serialize string, number, and boolean
|
||
// primitives as object literals.
|
||
stringify(0) === "0" &&
|
||
// FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object
|
||
// literals.
|
||
stringify(new Number()) === "0" &&
|
||
stringify(new String()) == '""' &&
|
||
// FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or
|
||
// does not define a canonical JSON representation (this applies to
|
||
// objects with `toJSON` properties as well, *unless* they are nested
|
||
// within an object or array).
|
||
stringify(getClass) === undef &&
|
||
// IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and
|
||
// FF 3.1b3 pass this test.
|
||
stringify(undef) === undef &&
|
||
// Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s,
|
||
// respectively, if the value is omitted entirely.
|
||
stringify() === undef &&
|
||
// FF 3.1b1, 2 throw an error if the given value is not a number,
|
||
// string, array, object, Boolean, or `null` literal. This applies to
|
||
// objects with custom `toJSON` methods as well, unless they are nested
|
||
// inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON`
|
||
// methods entirely.
|
||
stringify(value) === "1" &&
|
||
stringify([value]) == "[1]" &&
|
||
// Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of
|
||
// `"[null]"`.
|
||
stringify([undef]) == "[null]" &&
|
||
// YUI 3.0.0b1 fails to serialize `null` literals.
|
||
stringify(null) == "null" &&
|
||
// FF 3.1b1, 2 halts serialization if an array contains a function:
|
||
// `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3
|
||
// elides non-JSON values from objects and arrays, unless they
|
||
// define custom `toJSON` methods.
|
||
stringify([undef, getClass, null]) == "[null,null,null]" &&
|
||
// Simple serialization test. FF 3.1b1 uses Unicode escape sequences
|
||
// where character escape codes are expected (e.g., `\b` => `\u0008`).
|
||
stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized &&
|
||
// FF 3.1b1 and b2 ignore the `filter` and `width` arguments.
|
||
stringify(null, value) === "1" &&
|
||
stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" &&
|
||
// JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly
|
||
// serialize extended years.
|
||
stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' &&
|
||
// The milliseconds are optional in ES 5, but required in 5.1.
|
||
stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' &&
|
||
// Firefox <= 11.0 incorrectly serializes years prior to 0 as negative
|
||
// four-digit years instead of six-digit years. Credits: @Yaffle.
|
||
stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' &&
|
||
// Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond
|
||
// values less than 1000. Credits: @Yaffle.
|
||
stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"';
|
||
} catch (exception) {
|
||
stringifySupported = false;
|
||
}
|
||
}
|
||
isSupported = stringifySupported;
|
||
}
|
||
// Test `JSON.parse`.
|
||
if (name == "json-parse") {
|
||
var parse = exports.parse;
|
||
if (typeof parse == "function") {
|
||
try {
|
||
// FF 3.1b1, b2 will throw an exception if a bare literal is provided.
|
||
// Conforming implementations should also coerce the initial argument to
|
||
// a string prior to parsing.
|
||
if (parse("0") === 0 && !parse(false)) {
|
||
// Simple parsing test.
|
||
value = parse(serialized);
|
||
var parseSupported = value["a"].length == 5 && value["a"][0] === 1;
|
||
if (parseSupported) {
|
||
try {
|
||
// Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings.
|
||
parseSupported = !parse('"\t"');
|
||
} catch (exception) {}
|
||
if (parseSupported) {
|
||
try {
|
||
// FF 4.0 and 4.0.1 allow leading `+` signs and leading
|
||
// decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow
|
||
// certain octal literals.
|
||
parseSupported = parse("01") !== 1;
|
||
} catch (exception) {}
|
||
}
|
||
if (parseSupported) {
|
||
try {
|
||
// FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal
|
||
// points. These environments, along with FF 3.1b1 and 2,
|
||
// also allow trailing commas in JSON objects and arrays.
|
||
parseSupported = parse("1.") !== 1;
|
||
} catch (exception) {}
|
||
}
|
||
}
|
||
}
|
||
} catch (exception) {
|
||
parseSupported = false;
|
||
}
|
||
}
|
||
isSupported = parseSupported;
|
||
}
|
||
}
|
||
return has[name] = !!isSupported;
|
||
}
|
||
|
||
if (!has("json")) {
|
||
// Common `[[Class]]` name aliases.
|
||
var functionClass = "[object Function]",
|
||
dateClass = "[object Date]",
|
||
numberClass = "[object Number]",
|
||
stringClass = "[object String]",
|
||
arrayClass = "[object Array]",
|
||
booleanClass = "[object Boolean]";
|
||
|
||
// Detect incomplete support for accessing string characters by index.
|
||
var charIndexBuggy = has("bug-string-char-index");
|
||
|
||
// Define additional utility methods if the `Date` methods are buggy.
|
||
if (!isExtended) {
|
||
var floor = Math.floor;
|
||
// A mapping between the months of the year and the number of days between
|
||
// January 1st and the first of the respective month.
|
||
var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
|
||
// Internal: Calculates the number of days between the Unix epoch and the
|
||
// first day of the given month.
|
||
var getDay = function (year, month) {
|
||
return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400);
|
||
};
|
||
}
|
||
|
||
// Internal: Determines if a property is a direct property of the given
|
||
// object. Delegates to the native `Object#hasOwnProperty` method.
|
||
if (!(isProperty = objectProto.hasOwnProperty)) {
|
||
isProperty = function (property) {
|
||
var members = {}, constructor;
|
||
if ((members.__proto__ = null, members.__proto__ = {
|
||
// The *proto* property cannot be set multiple times in recent
|
||
// versions of Firefox and SeaMonkey.
|
||
"toString": 1
|
||
}, members).toString != getClass) {
|
||
// Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but
|
||
// supports the mutable *proto* property.
|
||
isProperty = function (property) {
|
||
// Capture and break the object's prototype chain (see section 8.6.2
|
||
// of the ES 5.1 spec). The parenthesized expression prevents an
|
||
// unsafe transformation by the Closure Compiler.
|
||
var original = this.__proto__, result = property in (this.__proto__ = null, this);
|
||
// Restore the original prototype chain.
|
||
this.__proto__ = original;
|
||
return result;
|
||
};
|
||
} else {
|
||
// Capture a reference to the top-level `Object` constructor.
|
||
constructor = members.constructor;
|
||
// Use the `constructor` property to simulate `Object#hasOwnProperty` in
|
||
// other environments.
|
||
isProperty = function (property) {
|
||
var parent = (this.constructor || constructor).prototype;
|
||
return property in this && !(property in parent && this[property] === parent[property]);
|
||
};
|
||
}
|
||
members = null;
|
||
return isProperty.call(this, property);
|
||
};
|
||
}
|
||
|
||
// Internal: Normalizes the `for...in` iteration algorithm across
|
||
// environments. Each enumerated key is yielded to a `callback` function.
|
||
forEach = function (object, callback) {
|
||
var size = 0, Properties, members, property;
|
||
|
||
// Tests for bugs in the current environment's `for...in` algorithm. The
|
||
// `valueOf` property inherits the non-enumerable flag from
|
||
// `Object.prototype` in older versions of IE, Netscape, and Mozilla.
|
||
(Properties = function () {
|
||
this.valueOf = 0;
|
||
}).prototype.valueOf = 0;
|
||
|
||
// Iterate over a new instance of the `Properties` class.
|
||
members = new Properties();
|
||
for (property in members) {
|
||
// Ignore all properties inherited from `Object.prototype`.
|
||
if (isProperty.call(members, property)) {
|
||
size++;
|
||
}
|
||
}
|
||
Properties = members = null;
|
||
|
||
// Normalize the iteration algorithm.
|
||
if (!size) {
|
||
// A list of non-enumerable properties inherited from `Object.prototype`.
|
||
members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"];
|
||
// IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable
|
||
// properties.
|
||
forEach = function (object, callback) {
|
||
var isFunction = getClass.call(object) == functionClass, property, length;
|
||
var hasProperty = !isFunction && typeof object.constructor != "function" && objectTypes[typeof object.hasOwnProperty] && object.hasOwnProperty || isProperty;
|
||
for (property in object) {
|
||
// Gecko <= 1.0 enumerates the `prototype` property of functions under
|
||
// certain conditions; IE does not.
|
||
if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) {
|
||
callback(property);
|
||
}
|
||
}
|
||
// Manually invoke the callback for each non-enumerable property.
|
||
for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property));
|
||
};
|
||
} else if (size == 2) {
|
||
// Safari <= 2.0.4 enumerates shadowed properties twice.
|
||
forEach = function (object, callback) {
|
||
// Create a set of iterated properties.
|
||
var members = {}, isFunction = getClass.call(object) == functionClass, property;
|
||
for (property in object) {
|
||
// Store each property name to prevent double enumeration. The
|
||
// `prototype` property of functions is not enumerated due to cross-
|
||
// environment inconsistencies.
|
||
if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) {
|
||
callback(property);
|
||
}
|
||
}
|
||
};
|
||
} else {
|
||
// No bugs detected; use the standard `for...in` algorithm.
|
||
forEach = function (object, callback) {
|
||
var isFunction = getClass.call(object) == functionClass, property, isConstructor;
|
||
for (property in object) {
|
||
if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) {
|
||
callback(property);
|
||
}
|
||
}
|
||
// Manually invoke the callback for the `constructor` property due to
|
||
// cross-environment inconsistencies.
|
||
if (isConstructor || isProperty.call(object, (property = "constructor"))) {
|
||
callback(property);
|
||
}
|
||
};
|
||
}
|
||
return forEach(object, callback);
|
||
};
|
||
|
||
// Public: Serializes a JavaScript `value` as a JSON string. The optional
|
||
// `filter` argument may specify either a function that alters how object and
|
||
// array members are serialized, or an array of strings and numbers that
|
||
// indicates which properties should be serialized. The optional `width`
|
||
// argument may be either a string or number that specifies the indentation
|
||
// level of the output.
|
||
if (!has("json-stringify")) {
|
||
// Internal: A map of control characters and their escaped equivalents.
|
||
var Escapes = {
|
||
92: "\\\\",
|
||
34: '\\"',
|
||
8: "\\b",
|
||
12: "\\f",
|
||
10: "\\n",
|
||
13: "\\r",
|
||
9: "\\t"
|
||
};
|
||
|
||
// Internal: Converts `value` into a zero-padded string such that its
|
||
// length is at least equal to `width`. The `width` must be <= 6.
|
||
var leadingZeroes = "000000";
|
||
var toPaddedString = function (width, value) {
|
||
// The `|| 0` expression is necessary to work around a bug in
|
||
// Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`.
|
||
return (leadingZeroes + (value || 0)).slice(-width);
|
||
};
|
||
|
||
// Internal: Double-quotes a string `value`, replacing all ASCII control
|
||
// characters (characters with code unit values between 0 and 31) with
|
||
// their escaped equivalents. This is an implementation of the
|
||
// `Quote(value)` operation defined in ES 5.1 section 15.12.3.
|
||
var unicodePrefix = "\\u00";
|
||
var quote = function (value) {
|
||
var result = '"', index = 0, length = value.length, useCharIndex = !charIndexBuggy || length > 10;
|
||
var symbols = useCharIndex && (charIndexBuggy ? value.split("") : value);
|
||
for (; index < length; index++) {
|
||
var charCode = value.charCodeAt(index);
|
||
// If the character is a control character, append its Unicode or
|
||
// shorthand escape sequence; otherwise, append the character as-is.
|
||
switch (charCode) {
|
||
case 8: case 9: case 10: case 12: case 13: case 34: case 92:
|
||
result += Escapes[charCode];
|
||
break;
|
||
default:
|
||
if (charCode < 32) {
|
||
result += unicodePrefix + toPaddedString(2, charCode.toString(16));
|
||
break;
|
||
}
|
||
result += useCharIndex ? symbols[index] : value.charAt(index);
|
||
}
|
||
}
|
||
return result + '"';
|
||
};
|
||
|
||
// Internal: Recursively serializes an object. Implements the
|
||
// `Str(key, holder)`, `JO(value)`, and `JA(value)` operations.
|
||
var serialize = function (property, object, callback, properties, whitespace, indentation, stack) {
|
||
var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result;
|
||
try {
|
||
// Necessary for host object support.
|
||
value = object[property];
|
||
} catch (exception) {}
|
||
if (typeof value == "object" && value) {
|
||
className = getClass.call(value);
|
||
if (className == dateClass && !isProperty.call(value, "toJSON")) {
|
||
if (value > -1 / 0 && value < 1 / 0) {
|
||
// Dates are serialized according to the `Date#toJSON` method
|
||
// specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15
|
||
// for the ISO 8601 date time string format.
|
||
if (getDay) {
|
||
// Manually compute the year, month, date, hours, minutes,
|
||
// seconds, and milliseconds if the `getUTC*` methods are
|
||
// buggy. Adapted from @Yaffle's `date-shim` project.
|
||
date = floor(value / 864e5);
|
||
for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++);
|
||
for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++);
|
||
date = 1 + date - getDay(year, month);
|
||
// The `time` value specifies the time within the day (see ES
|
||
// 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used
|
||
// to compute `A modulo B`, as the `%` operator does not
|
||
// correspond to the `modulo` operation for negative numbers.
|
||
time = (value % 864e5 + 864e5) % 864e5;
|
||
// The hours, minutes, seconds, and milliseconds are obtained by
|
||
// decomposing the time within the day. See section 15.9.1.10.
|
||
hours = floor(time / 36e5) % 24;
|
||
minutes = floor(time / 6e4) % 60;
|
||
seconds = floor(time / 1e3) % 60;
|
||
milliseconds = time % 1e3;
|
||
} else {
|
||
year = value.getUTCFullYear();
|
||
month = value.getUTCMonth();
|
||
date = value.getUTCDate();
|
||
hours = value.getUTCHours();
|
||
minutes = value.getUTCMinutes();
|
||
seconds = value.getUTCSeconds();
|
||
milliseconds = value.getUTCMilliseconds();
|
||
}
|
||
// Serialize extended years correctly.
|
||
value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) +
|
||
"-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) +
|
||
// Months, dates, hours, minutes, and seconds should have two
|
||
// digits; milliseconds should have three.
|
||
"T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) +
|
||
// Milliseconds are optional in ES 5.0, but required in 5.1.
|
||
"." + toPaddedString(3, milliseconds) + "Z";
|
||
} else {
|
||
value = null;
|
||
}
|
||
} else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) {
|
||
// Prototype <= 1.6.1 adds non-standard `toJSON` methods to the
|
||
// `Number`, `String`, `Date`, and `Array` prototypes. JSON 3
|
||
// ignores all `toJSON` methods on these objects unless they are
|
||
// defined directly on an instance.
|
||
value = value.toJSON(property);
|
||
}
|
||
}
|
||
if (callback) {
|
||
// If a replacement function was provided, call it to obtain the value
|
||
// for serialization.
|
||
value = callback.call(object, property, value);
|
||
}
|
||
if (value === null) {
|
||
return "null";
|
||
}
|
||
className = getClass.call(value);
|
||
if (className == booleanClass) {
|
||
// Booleans are represented literally.
|
||
return "" + value;
|
||
} else if (className == numberClass) {
|
||
// JSON numbers must be finite. `Infinity` and `NaN` are serialized as
|
||
// `"null"`.
|
||
return value > -1 / 0 && value < 1 / 0 ? "" + value : "null";
|
||
} else if (className == stringClass) {
|
||
// Strings are double-quoted and escaped.
|
||
return quote("" + value);
|
||
}
|
||
// Recursively serialize objects and arrays.
|
||
if (typeof value == "object") {
|
||
// Check for cyclic structures. This is a linear search; performance
|
||
// is inversely proportional to the number of unique nested objects.
|
||
for (length = stack.length; length--;) {
|
||
if (stack[length] === value) {
|
||
// Cyclic structures cannot be serialized by `JSON.stringify`.
|
||
throw TypeError();
|
||
}
|
||
}
|
||
// Add the object to the stack of traversed objects.
|
||
stack.push(value);
|
||
results = [];
|
||
// Save the current indentation level and indent one additional level.
|
||
prefix = indentation;
|
||
indentation += whitespace;
|
||
if (className == arrayClass) {
|
||
// Recursively serialize array elements.
|
||
for (index = 0, length = value.length; index < length; index++) {
|
||
element = serialize(index, value, callback, properties, whitespace, indentation, stack);
|
||
results.push(element === undef ? "null" : element);
|
||
}
|
||
result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]";
|
||
} else {
|
||
// Recursively serialize object members. Members are selected from
|
||
// either a user-specified list of property names, or the object
|
||
// itself.
|
||
forEach(properties || value, function (property) {
|
||
var element = serialize(property, value, callback, properties, whitespace, indentation, stack);
|
||
if (element !== undef) {
|
||
// According to ES 5.1 section 15.12.3: "If `gap` {whitespace}
|
||
// is not the empty string, let `member` {quote(property) + ":"}
|
||
// be the concatenation of `member` and the `space` character."
|
||
// The "`space` character" refers to the literal space
|
||
// character, not the `space` {width} argument provided to
|
||
// `JSON.stringify`.
|
||
results.push(quote(property) + ":" + (whitespace ? " " : "") + element);
|
||
}
|
||
});
|
||
result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}";
|
||
}
|
||
// Remove the object from the traversed object stack.
|
||
stack.pop();
|
||
return result;
|
||
}
|
||
};
|
||
|
||
// Public: `JSON.stringify`. See ES 5.1 section 15.12.3.
|
||
exports.stringify = function (source, filter, width) {
|
||
var whitespace, callback, properties, className;
|
||
if (objectTypes[typeof filter] && filter) {
|
||
if ((className = getClass.call(filter)) == functionClass) {
|
||
callback = filter;
|
||
} else if (className == arrayClass) {
|
||
// Convert the property names array into a makeshift set.
|
||
properties = {};
|
||
for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1));
|
||
}
|
||
}
|
||
if (width) {
|
||
if ((className = getClass.call(width)) == numberClass) {
|
||
// Convert the `width` to an integer and create a string containing
|
||
// `width` number of space characters.
|
||
if ((width -= width % 1) > 0) {
|
||
for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " ");
|
||
}
|
||
} else if (className == stringClass) {
|
||
whitespace = width.length <= 10 ? width : width.slice(0, 10);
|
||
}
|
||
}
|
||
// Opera <= 7.54u2 discards the values associated with empty string keys
|
||
// (`""`) only if they are used directly within an object member list
|
||
// (e.g., `!("" in { "": 1})`).
|
||
return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []);
|
||
};
|
||
}
|
||
|
||
// Public: Parses a JSON source string.
|
||
if (!has("json-parse")) {
|
||
var fromCharCode = String.fromCharCode;
|
||
|
||
// Internal: A map of escaped control characters and their unescaped
|
||
// equivalents.
|
||
var Unescapes = {
|
||
92: "\\",
|
||
34: '"',
|
||
47: "/",
|
||
98: "\b",
|
||
116: "\t",
|
||
110: "\n",
|
||
102: "\f",
|
||
114: "\r"
|
||
};
|
||
|
||
// Internal: Stores the parser state.
|
||
var Index, Source;
|
||
|
||
// Internal: Resets the parser state and throws a `SyntaxError`.
|
||
var abort = function () {
|
||
Index = Source = null;
|
||
throw SyntaxError();
|
||
};
|
||
|
||
// Internal: Returns the next token, or `"$"` if the parser has reached
|
||
// the end of the source string. A token may be a string, number, `null`
|
||
// literal, or Boolean literal.
|
||
var lex = function () {
|
||
var source = Source, length = source.length, value, begin, position, isSigned, charCode;
|
||
while (Index < length) {
|
||
charCode = source.charCodeAt(Index);
|
||
switch (charCode) {
|
||
case 9: case 10: case 13: case 32:
|
||
// Skip whitespace tokens, including tabs, carriage returns, line
|
||
// feeds, and space characters.
|
||
Index++;
|
||
break;
|
||
case 123: case 125: case 91: case 93: case 58: case 44:
|
||
// Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at
|
||
// the current position.
|
||
value = charIndexBuggy ? source.charAt(Index) : source[Index];
|
||
Index++;
|
||
return value;
|
||
case 34:
|
||
// `"` delimits a JSON string; advance to the next character and
|
||
// begin parsing the string. String tokens are prefixed with the
|
||
// sentinel `@` character to distinguish them from punctuators and
|
||
// end-of-string tokens.
|
||
for (value = "@", Index++; Index < length;) {
|
||
charCode = source.charCodeAt(Index);
|
||
if (charCode < 32) {
|
||
// Unescaped ASCII control characters (those with a code unit
|
||
// less than the space character) are not permitted.
|
||
abort();
|
||
} else if (charCode == 92) {
|
||
// A reverse solidus (`\`) marks the beginning of an escaped
|
||
// control character (including `"`, `\`, and `/`) or Unicode
|
||
// escape sequence.
|
||
charCode = source.charCodeAt(++Index);
|
||
switch (charCode) {
|
||
case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114:
|
||
// Revive escaped control characters.
|
||
value += Unescapes[charCode];
|
||
Index++;
|
||
break;
|
||
case 117:
|
||
// `\u` marks the beginning of a Unicode escape sequence.
|
||
// Advance to the first character and validate the
|
||
// four-digit code point.
|
||
begin = ++Index;
|
||
for (position = Index + 4; Index < position; Index++) {
|
||
charCode = source.charCodeAt(Index);
|
||
// A valid sequence comprises four hexdigits (case-
|
||
// insensitive) that form a single hexadecimal value.
|
||
if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) {
|
||
// Invalid Unicode escape sequence.
|
||
abort();
|
||
}
|
||
}
|
||
// Revive the escaped character.
|
||
value += fromCharCode("0x" + source.slice(begin, Index));
|
||
break;
|
||
default:
|
||
// Invalid escape sequence.
|
||
abort();
|
||
}
|
||
} else {
|
||
if (charCode == 34) {
|
||
// An unescaped double-quote character marks the end of the
|
||
// string.
|
||
break;
|
||
}
|
||
charCode = source.charCodeAt(Index);
|
||
begin = Index;
|
||
// Optimize for the common case where a string is valid.
|
||
while (charCode >= 32 && charCode != 92 && charCode != 34) {
|
||
charCode = source.charCodeAt(++Index);
|
||
}
|
||
// Append the string as-is.
|
||
value += source.slice(begin, Index);
|
||
}
|
||
}
|
||
if (source.charCodeAt(Index) == 34) {
|
||
// Advance to the next character and return the revived string.
|
||
Index++;
|
||
return value;
|
||
}
|
||
// Unterminated string.
|
||
abort();
|
||
default:
|
||
// Parse numbers and literals.
|
||
begin = Index;
|
||
// Advance past the negative sign, if one is specified.
|
||
if (charCode == 45) {
|
||
isSigned = true;
|
||
charCode = source.charCodeAt(++Index);
|
||
}
|
||
// Parse an integer or floating-point value.
|
||
if (charCode >= 48 && charCode <= 57) {
|
||
// Leading zeroes are interpreted as octal literals.
|
||
if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) {
|
||
// Illegal octal literal.
|
||
abort();
|
||
}
|
||
isSigned = false;
|
||
// Parse the integer component.
|
||
for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++);
|
||
// Floats cannot contain a leading decimal point; however, this
|
||
// case is already accounted for by the parser.
|
||
if (source.charCodeAt(Index) == 46) {
|
||
position = ++Index;
|
||
// Parse the decimal component.
|
||
for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);
|
||
if (position == Index) {
|
||
// Illegal trailing decimal.
|
||
abort();
|
||
}
|
||
Index = position;
|
||
}
|
||
// Parse exponents. The `e` denoting the exponent is
|
||
// case-insensitive.
|
||
charCode = source.charCodeAt(Index);
|
||
if (charCode == 101 || charCode == 69) {
|
||
charCode = source.charCodeAt(++Index);
|
||
// Skip past the sign following the exponent, if one is
|
||
// specified.
|
||
if (charCode == 43 || charCode == 45) {
|
||
Index++;
|
||
}
|
||
// Parse the exponential component.
|
||
for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);
|
||
if (position == Index) {
|
||
// Illegal empty exponent.
|
||
abort();
|
||
}
|
||
Index = position;
|
||
}
|
||
// Coerce the parsed value to a JavaScript number.
|
||
return +source.slice(begin, Index);
|
||
}
|
||
// A negative sign may only precede numbers.
|
||
if (isSigned) {
|
||
abort();
|
||
}
|
||
// `true`, `false`, and `null` literals.
|
||
if (source.slice(Index, Index + 4) == "true") {
|
||
Index += 4;
|
||
return true;
|
||
} else if (source.slice(Index, Index + 5) == "false") {
|
||
Index += 5;
|
||
return false;
|
||
} else if (source.slice(Index, Index + 4) == "null") {
|
||
Index += 4;
|
||
return null;
|
||
}
|
||
// Unrecognized token.
|
||
abort();
|
||
}
|
||
}
|
||
// Return the sentinel `$` character if the parser has reached the end
|
||
// of the source string.
|
||
return "$";
|
||
};
|
||
|
||
// Internal: Parses a JSON `value` token.
|
||
var get = function (value) {
|
||
var results, hasMembers;
|
||
if (value == "$") {
|
||
// Unexpected end of input.
|
||
abort();
|
||
}
|
||
if (typeof value == "string") {
|
||
if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") {
|
||
// Remove the sentinel `@` character.
|
||
return value.slice(1);
|
||
}
|
||
// Parse object and array literals.
|
||
if (value == "[") {
|
||
// Parses a JSON array, returning a new JavaScript array.
|
||
results = [];
|
||
for (;; hasMembers || (hasMembers = true)) {
|
||
value = lex();
|
||
// A closing square bracket marks the end of the array literal.
|
||
if (value == "]") {
|
||
break;
|
||
}
|
||
// If the array literal contains elements, the current token
|
||
// should be a comma separating the previous element from the
|
||
// next.
|
||
if (hasMembers) {
|
||
if (value == ",") {
|
||
value = lex();
|
||
if (value == "]") {
|
||
// Unexpected trailing `,` in array literal.
|
||
abort();
|
||
}
|
||
} else {
|
||
// A `,` must separate each array element.
|
||
abort();
|
||
}
|
||
}
|
||
// Elisions and leading commas are not permitted.
|
||
if (value == ",") {
|
||
abort();
|
||
}
|
||
results.push(get(value));
|
||
}
|
||
return results;
|
||
} else if (value == "{") {
|
||
// Parses a JSON object, returning a new JavaScript object.
|
||
results = {};
|
||
for (;; hasMembers || (hasMembers = true)) {
|
||
value = lex();
|
||
// A closing curly brace marks the end of the object literal.
|
||
if (value == "}") {
|
||
break;
|
||
}
|
||
// If the object literal contains members, the current token
|
||
// should be a comma separator.
|
||
if (hasMembers) {
|
||
if (value == ",") {
|
||
value = lex();
|
||
if (value == "}") {
|
||
// Unexpected trailing `,` in object literal.
|
||
abort();
|
||
}
|
||
} else {
|
||
// A `,` must separate each object member.
|
||
abort();
|
||
}
|
||
}
|
||
// Leading commas are not permitted, object property names must be
|
||
// double-quoted strings, and a `:` must separate each property
|
||
// name and value.
|
||
if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") {
|
||
abort();
|
||
}
|
||
results[value.slice(1)] = get(lex());
|
||
}
|
||
return results;
|
||
}
|
||
// Unexpected token encountered.
|
||
abort();
|
||
}
|
||
return value;
|
||
};
|
||
|
||
// Internal: Updates a traversed object member.
|
||
var update = function (source, property, callback) {
|
||
var element = walk(source, property, callback);
|
||
if (element === undef) {
|
||
delete source[property];
|
||
} else {
|
||
source[property] = element;
|
||
}
|
||
};
|
||
|
||
// Internal: Recursively traverses a parsed JSON object, invoking the
|
||
// `callback` function for each value. This is an implementation of the
|
||
// `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2.
|
||
var walk = function (source, property, callback) {
|
||
var value = source[property], length;
|
||
if (typeof value == "object" && value) {
|
||
// `forEach` can't be used to traverse an array in Opera <= 8.54
|
||
// because its `Object#hasOwnProperty` implementation returns `false`
|
||
// for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`).
|
||
if (getClass.call(value) == arrayClass) {
|
||
for (length = value.length; length--;) {
|
||
update(value, length, callback);
|
||
}
|
||
} else {
|
||
forEach(value, function (property) {
|
||
update(value, property, callback);
|
||
});
|
||
}
|
||
}
|
||
return callback.call(source, property, value);
|
||
};
|
||
|
||
// Public: `JSON.parse`. See ES 5.1 section 15.12.2.
|
||
exports.parse = function (source, callback) {
|
||
var result, value;
|
||
Index = 0;
|
||
Source = "" + source;
|
||
result = get(lex());
|
||
// If a JSON string contains multiple tokens, it is invalid.
|
||
if (lex() != "$") {
|
||
abort();
|
||
}
|
||
// Reset the parser state.
|
||
Index = Source = null;
|
||
return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result;
|
||
};
|
||
}
|
||
}
|
||
|
||
exports["runInContext"] = runInContext;
|
||
return exports;
|
||
}
|
||
|
||
if (freeExports && !isLoader) {
|
||
// Export for CommonJS environments.
|
||
runInContext(root, freeExports);
|
||
} else {
|
||
// Export for web browsers and JavaScript engines.
|
||
var nativeJSON = root.JSON,
|
||
previousJSON = root["JSON3"],
|
||
isRestored = false;
|
||
|
||
var JSON3 = runInContext(root, (root["JSON3"] = {
|
||
// Public: Restores the original value of the global `JSON` object and
|
||
// returns a reference to the `JSON3` object.
|
||
"noConflict": function () {
|
||
if (!isRestored) {
|
||
isRestored = true;
|
||
root.JSON = nativeJSON;
|
||
root["JSON3"] = previousJSON;
|
||
nativeJSON = previousJSON = null;
|
||
}
|
||
return JSON3;
|
||
}
|
||
}));
|
||
|
||
root.JSON = {
|
||
"parse": JSON3.parse,
|
||
"stringify": JSON3.stringify
|
||
};
|
||
}
|
||
|
||
// Export for asynchronous module loaders.
|
||
if (isLoader) {
|
||
define(function () {
|
||
return JSON3;
|
||
});
|
||
}
|
||
}).call(this);
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{}],9:[function(require,module,exports){
|
||
function Mapper()
|
||
{
|
||
var sources = {};
|
||
|
||
|
||
this.forEach = function(callback)
|
||
{
|
||
for(var key in sources)
|
||
{
|
||
var source = sources[key];
|
||
|
||
for(var key2 in source)
|
||
callback(source[key2]);
|
||
};
|
||
};
|
||
|
||
this.get = function(id, source)
|
||
{
|
||
var ids = sources[source];
|
||
if(ids == undefined)
|
||
return undefined;
|
||
|
||
return ids[id];
|
||
};
|
||
|
||
this.remove = function(id, source)
|
||
{
|
||
var ids = sources[source];
|
||
if(ids == undefined)
|
||
return;
|
||
|
||
delete ids[id];
|
||
|
||
// Check it's empty
|
||
for(var i in ids){return false}
|
||
|
||
delete sources[source];
|
||
};
|
||
|
||
this.set = function(value, id, source)
|
||
{
|
||
if(value == undefined)
|
||
return this.remove(id, source);
|
||
|
||
var ids = sources[source];
|
||
if(ids == undefined)
|
||
sources[source] = ids = {};
|
||
|
||
ids[id] = value;
|
||
};
|
||
};
|
||
|
||
|
||
Mapper.prototype.pop = function(id, source)
|
||
{
|
||
var value = this.get(id, source);
|
||
if(value == undefined)
|
||
return undefined;
|
||
|
||
this.remove(id, source);
|
||
|
||
return value;
|
||
};
|
||
|
||
|
||
module.exports = Mapper;
|
||
|
||
},{}],10:[function(require,module,exports){
|
||
/*
|
||
* (C) Copyright 2014 Kurento (http://kurento.org/)
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*
|
||
*/
|
||
|
||
var JsonRpcClient = require('./jsonrpcclient');
|
||
|
||
|
||
exports.JsonRpcClient = JsonRpcClient;
|
||
},{"./jsonrpcclient":11}],11:[function(require,module,exports){
|
||
/*
|
||
* (C) Copyright 2014 Kurento (http://kurento.org/)
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*
|
||
*/
|
||
|
||
var RpcBuilder = require('../..');
|
||
var WebSocketWithReconnection = require('./transports/webSocketWithReconnection');
|
||
|
||
Date.now = Date.now || function() {
|
||
return +new Date;
|
||
};
|
||
|
||
var PING_INTERVAL = 5000;
|
||
|
||
var RECONNECTING = 'RECONNECTING';
|
||
var CONNECTED = 'CONNECTED';
|
||
var DISCONNECTED = 'DISCONNECTED';
|
||
|
||
var RECONNECTING = "RECONNECTING";
|
||
var CONNECTED = "CONNECTED";
|
||
var DISCONNECTED = "DISCONNECTED";
|
||
|
||
|
||
/**
|
||
*
|
||
* heartbeat: interval in ms for each heartbeat message,
|
||
* sendCloseMessage : true / false, before closing the connection, it sends a closeSession message
|
||
* <pre>
|
||
* ws : {
|
||
* uri : URI to conntect to,
|
||
* useSockJS : true (use SockJS) / false (use WebSocket) by default,
|
||
* onconnected : callback method to invoke when connection is successful,
|
||
* ondisconnect : callback method to invoke when the connection is lost,
|
||
* onreconnecting : callback method to invoke when the client is reconnecting,
|
||
* onreconnected : callback method to invoke when the client succesfully reconnects,
|
||
* },
|
||
* rpc : {
|
||
* requestTimeout : timeout for a request,
|
||
* sessionStatusChanged: callback method for changes in session status,
|
||
* mediaRenegotiation: mediaRenegotiation
|
||
* }
|
||
* </pre>
|
||
*/
|
||
function JsonRpcClient(configuration) {
|
||
|
||
var self = this;
|
||
|
||
var wsConfig = configuration.ws;
|
||
|
||
var notReconnectIfNumLessThan = -1;
|
||
|
||
var pingNextNum = 0;
|
||
var enabledPings = true;
|
||
var pingPongStarted = false;
|
||
var pingInterval;
|
||
|
||
var status = DISCONNECTED;
|
||
|
||
var onreconnecting = wsConfig.onreconnecting;
|
||
var onreconnected = wsConfig.onreconnected;
|
||
var onconnected = wsConfig.onconnected;
|
||
|
||
configuration.rpc.pull = function(params, request) {
|
||
request.reply(null, "push");
|
||
}
|
||
|
||
wsConfig.onreconnecting = function() {
|
||
console.log("--------- ONRECONNECTING -----------");
|
||
if (status === RECONNECTING) {
|
||
console.error("Websocket already in RECONNECTING state when receiving a new ONRECONNECTING message. Ignoring it");
|
||
return;
|
||
}
|
||
|
||
status = RECONNECTING;
|
||
if (onreconnecting) {
|
||
onreconnecting();
|
||
}
|
||
}
|
||
|
||
wsConfig.onreconnected = function() {
|
||
console.log("--------- ONRECONNECTED -----------");
|
||
if (status === CONNECTED) {
|
||
console.error("Websocket already in CONNECTED state when receiving a new ONRECONNECTED message. Ignoring it");
|
||
return;
|
||
}
|
||
status = CONNECTED;
|
||
|
||
enabledPings = true;
|
||
updateNotReconnectIfLessThan();
|
||
usePing();
|
||
|
||
if (onreconnected) {
|
||
onreconnected();
|
||
}
|
||
}
|
||
|
||
wsConfig.onconnected = function() {
|
||
console.log("--------- ONCONNECTED -----------");
|
||
if (status === CONNECTED) {
|
||
console.error("Websocket already in CONNECTED state when receiving a new ONCONNECTED message. Ignoring it");
|
||
return;
|
||
}
|
||
status = CONNECTED;
|
||
|
||
enabledPings = true;
|
||
usePing();
|
||
|
||
if (onconnected) {
|
||
onconnected();
|
||
}
|
||
}
|
||
|
||
var ws = new WebSocketWithReconnection(wsConfig);
|
||
|
||
console.log('Connecting websocket to URI: ' + wsConfig.uri);
|
||
|
||
var rpcBuilderOptions = {
|
||
request_timeout: configuration.rpc.requestTimeout
|
||
};
|
||
|
||
var rpc = new RpcBuilder(RpcBuilder.packers.JsonRPC, rpcBuilderOptions, ws,
|
||
function(request) {
|
||
|
||
console.log('Received request: ' + JSON.stringify(request));
|
||
|
||
try {
|
||
var func = configuration.rpc[request.method];
|
||
|
||
if (func === undefined) {
|
||
console.error("Method " + request.method + " not registered in client");
|
||
} else {
|
||
func(request.params, request);
|
||
}
|
||
} catch (err) {
|
||
console.error('Exception processing request: ' + JSON.stringify(request));
|
||
console.error(err);
|
||
}
|
||
});
|
||
|
||
this.send = function(method, params, callback) {
|
||
if (method !== 'ping') {
|
||
console.log('Request: method:' + method + " params:" + JSON.stringify(params));
|
||
}
|
||
|
||
var requestTime = Date.now();
|
||
|
||
rpc.encode(method, params, function(error, result) {
|
||
if (error) {
|
||
try {
|
||
console.error("ERROR:" + error.message + " in Request: method:" + method + " params:" + JSON.stringify(params));
|
||
if (error.data) {
|
||
console.error("ERROR DATA:" + JSON.stringify(error.data));
|
||
}
|
||
} catch (e) {}
|
||
error.requestTime = requestTime;
|
||
}
|
||
if (callback) {
|
||
if (result != undefined && result.value !== 'pong') {
|
||
console.log('Response: ' + JSON.stringify(result));
|
||
}
|
||
callback(error, result);
|
||
}
|
||
});
|
||
}
|
||
|
||
function updateNotReconnectIfLessThan() {
|
||
notReconnectIfNumLessThan = pingNextNum;
|
||
console.log("notReconnectIfNumLessThan = " + notReconnectIfNumLessThan);
|
||
}
|
||
|
||
function sendPing() {
|
||
if (enabledPings) {
|
||
var params = null;
|
||
|
||
if (pingNextNum == 0 || pingNextNum == notReconnectIfNumLessThan) {
|
||
params = {
|
||
interval: PING_INTERVAL
|
||
};
|
||
}
|
||
|
||
pingNextNum++;
|
||
|
||
self.send('ping', params, (function(pingNum) {
|
||
return function(error, result) {
|
||
if (error) {
|
||
if (pingNum > notReconnectIfNumLessThan) {
|
||
enabledPings = false;
|
||
updateNotReconnectIfLessThan();
|
||
console.log("DSS did not respond to ping message " + pingNum + ". Reconnecting... ");
|
||
ws.reconnectWs();
|
||
}
|
||
}
|
||
}
|
||
})(pingNextNum));
|
||
} else {
|
||
console.log("Trying to send ping, but ping is not enabled");
|
||
}
|
||
}
|
||
|
||
/*
|
||
* If configuration.hearbeat has any value, the ping-pong will work with the interval
|
||
* of configuration.hearbeat
|
||
*/
|
||
function usePing() {
|
||
if (!pingPongStarted) {
|
||
console.log("Starting ping (if configured)")
|
||
pingPongStarted = true;
|
||
|
||
if (configuration.heartbeat != undefined) {
|
||
pingInterval = setInterval(sendPing, configuration.heartbeat);
|
||
sendPing();
|
||
}
|
||
}
|
||
}
|
||
|
||
this.close = function() {
|
||
console.log("Closing jsonRpcClient explicitely by client");
|
||
|
||
if (pingInterval != undefined) {
|
||
clearInterval(pingInterval);
|
||
}
|
||
pingPongStarted = false;
|
||
enabledPings = false;
|
||
|
||
if (configuration.sendCloseMessage) {
|
||
this.send('closeSession', null, function(error, result) {
|
||
if (error) {
|
||
console.error("Error sending close message: " + JSON.stringify(error));
|
||
}
|
||
|
||
ws.close();
|
||
});
|
||
} else {
|
||
ws.close();
|
||
}
|
||
}
|
||
|
||
// This method is only for testing
|
||
this.forceClose = function(millis) {
|
||
ws.forceClose(millis);
|
||
}
|
||
|
||
this.reconnect = function() {
|
||
ws.reconnectWs();
|
||
}
|
||
}
|
||
|
||
|
||
module.exports = JsonRpcClient;
|
||
|
||
},{"../..":14,"./transports/webSocketWithReconnection":13}],12:[function(require,module,exports){
|
||
/*
|
||
* (C) Copyright 2014 Kurento (http://kurento.org/)
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*
|
||
*/
|
||
|
||
var WebSocketWithReconnection = require('./webSocketWithReconnection');
|
||
|
||
|
||
exports.WebSocketWithReconnection = WebSocketWithReconnection;
|
||
},{"./webSocketWithReconnection":13}],13:[function(require,module,exports){
|
||
/*
|
||
* (C) Copyright 2013-2015 Kurento (http://kurento.org/)
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
"use strict";
|
||
|
||
var WebSocket = require('ws');
|
||
var SockJS = require('sockjs-client');
|
||
|
||
var MAX_RETRIES = 2000; // Forever...
|
||
var RETRY_TIME_MS = 3000; // FIXME: Implement exponential wait times...
|
||
var PING_INTERVAL = 5000;
|
||
var PING_MSG = JSON.stringify({
|
||
'method': 'ping'
|
||
});
|
||
|
||
var CONNECTING = 0;
|
||
var OPEN = 1;
|
||
var CLOSING = 2;
|
||
var CLOSED = 3;
|
||
|
||
/*
|
||
config = {
|
||
uri : wsUri,
|
||
useSockJS : true (use SockJS) / false (use WebSocket) by default,
|
||
onconnected : callback method to invoke when connection is successful,
|
||
ondisconnect : callback method to invoke when the connection is lost,
|
||
onreconnecting : callback method to invoke when the client is reconnecting,
|
||
onreconnected : callback method to invoke when the client succesfully reconnects,
|
||
};
|
||
*/
|
||
function WebSocketWithReconnection(config) {
|
||
|
||
var closing = false;
|
||
var registerMessageHandler;
|
||
var wsUri = config.uri;
|
||
var useSockJS = config.useSockJS;
|
||
var reconnecting = false;
|
||
|
||
var forcingDisconnection = false;
|
||
|
||
var ws;
|
||
|
||
if (useSockJS) {
|
||
ws = new SockJS(wsUri);
|
||
} else {
|
||
ws = new WebSocket(wsUri);
|
||
}
|
||
|
||
ws.onopen = function() {
|
||
logConnected(ws, wsUri);
|
||
config.onconnected();
|
||
};
|
||
|
||
ws.onerror = function(evt) {
|
||
config.onconnected(evt.data);
|
||
};
|
||
|
||
function logConnected(ws, wsUri) {
|
||
try {
|
||
console.log("WebSocket connected to " + wsUri);
|
||
} catch (e) {
|
||
console.error(e);
|
||
}
|
||
}
|
||
|
||
var reconnectionOnClose = function() {
|
||
if (ws.readyState === CLOSED) {
|
||
if (closing) {
|
||
console.log("Connection Closed by user");
|
||
} else {
|
||
console.log("Connection closed unexpectecly. Reconnecting...");
|
||
reconnectInNewUri(MAX_RETRIES, 1);
|
||
}
|
||
} else {
|
||
console.log("Close callback from previous websocket. Ignoring it");
|
||
}
|
||
};
|
||
|
||
ws.onclose = reconnectionOnClose;
|
||
|
||
function reconnectInNewUri(maxRetries, numRetries) {
|
||
console.log("reconnectInNewUri");
|
||
|
||
if (numRetries === 1) {
|
||
if (reconnecting) {
|
||
console
|
||
.warn("Trying to reconnect when reconnecting... Ignoring this reconnection.")
|
||
return;
|
||
} else {
|
||
reconnecting = true;
|
||
}
|
||
|
||
if (config.onreconnecting) {
|
||
config.onreconnecting();
|
||
}
|
||
}
|
||
|
||
if (forcingDisconnection) {
|
||
reconnect(maxRetries, numRetries, wsUri);
|
||
|
||
} else {
|
||
if (config.newWsUriOnReconnection) {
|
||
config.newWsUriOnReconnection(function(error, newWsUri) {
|
||
|
||
if (error) {
|
||
console.log(error);
|
||
setTimeout(function() {
|
||
reconnectInNewUri(maxRetries, numRetries + 1);
|
||
}, RETRY_TIME_MS);
|
||
} else {
|
||
reconnect(maxRetries, numRetries, newWsUri);
|
||
}
|
||
})
|
||
} else {
|
||
reconnect(maxRetries, numRetries, wsUri);
|
||
}
|
||
}
|
||
}
|
||
|
||
// TODO Test retries. How to force not connection?
|
||
function reconnect(maxRetries, numRetries, reconnectWsUri) {
|
||
|
||
console.log("Trying to reconnect " + numRetries + " times");
|
||
|
||
var newWs;
|
||
if (useSockJS) {
|
||
newWs = new SockJS(wsUri);
|
||
} else {
|
||
newWs = new WebSocket(wsUri);
|
||
}
|
||
|
||
newWs.onopen = function() {
|
||
console.log("Reconnected in " + numRetries + " retries...");
|
||
logConnected(newWs, reconnectWsUri);
|
||
reconnecting = false;
|
||
registerMessageHandler();
|
||
if (config.onreconnected()) {
|
||
config.onreconnected();
|
||
}
|
||
|
||
newWs.onclose = reconnectionOnClose;
|
||
};
|
||
|
||
var onErrorOrClose = function(error) {
|
||
console.log("Reconnection error: ", error);
|
||
|
||
if (numRetries === maxRetries) {
|
||
if (config.ondisconnect) {
|
||
config.ondisconnect();
|
||
}
|
||
} else {
|
||
setTimeout(function() {
|
||
reconnectInNewUri(maxRetries, numRetries + 1);
|
||
}, RETRY_TIME_MS);
|
||
}
|
||
};
|
||
|
||
newWs.onerror = onErrorOrClose;
|
||
|
||
ws = newWs;
|
||
}
|
||
|
||
this.close = function() {
|
||
closing = true;
|
||
ws.close();
|
||
};
|
||
|
||
|
||
// This method is only for testing
|
||
this.forceClose = function(millis) {
|
||
console.log("Testing: Force WebSocket close");
|
||
|
||
if (millis) {
|
||
console.log("Testing: Change wsUri for " + millis + " millis to simulate net failure");
|
||
var goodWsUri = wsUri;
|
||
wsUri = "wss://21.234.12.34.4:443/";
|
||
|
||
forcingDisconnection = true;
|
||
|
||
setTimeout(function() {
|
||
console.log("Testing: Recover good wsUri " + goodWsUri);
|
||
wsUri = goodWsUri;
|
||
|
||
forcingDisconnection = false;
|
||
|
||
}, millis);
|
||
}
|
||
|
||
ws.close();
|
||
};
|
||
|
||
this.reconnectWs = function() {
|
||
console.log("reconnectWs");
|
||
reconnectInNewUri(MAX_RETRIES, 1, wsUri);
|
||
};
|
||
|
||
this.send = function(message) {
|
||
ws.send(message);
|
||
};
|
||
|
||
this.addEventListener = function(type, callback) {
|
||
registerMessageHandler = function() {
|
||
ws.addEventListener(type, callback);
|
||
};
|
||
|
||
registerMessageHandler();
|
||
};
|
||
}
|
||
|
||
module.exports = WebSocketWithReconnection;
|
||
},{"sockjs-client":33,"ws":103}],14:[function(require,module,exports){
|
||
/*
|
||
* (C) Copyright 2014 Kurento (http://kurento.org/)
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*
|
||
*/
|
||
|
||
|
||
var defineProperty_IE8 = false
|
||
if(Object.defineProperty)
|
||
{
|
||
try
|
||
{
|
||
Object.defineProperty({}, "x", {});
|
||
}
|
||
catch(e)
|
||
{
|
||
defineProperty_IE8 = true
|
||
}
|
||
}
|
||
|
||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
|
||
if (!Function.prototype.bind) {
|
||
Function.prototype.bind = function(oThis) {
|
||
if (typeof this !== 'function') {
|
||
// closest thing possible to the ECMAScript 5
|
||
// internal IsCallable function
|
||
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
||
}
|
||
|
||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||
fToBind = this,
|
||
fNOP = function() {},
|
||
fBound = function() {
|
||
return fToBind.apply(this instanceof fNOP && oThis
|
||
? this
|
||
: oThis,
|
||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||
};
|
||
|
||
fNOP.prototype = this.prototype;
|
||
fBound.prototype = new fNOP();
|
||
|
||
return fBound;
|
||
};
|
||
}
|
||
|
||
|
||
var EventEmitter = require('events').EventEmitter;
|
||
|
||
var inherits = require('inherits');
|
||
|
||
var packers = require('./packers');
|
||
var Mapper = require('./Mapper');
|
||
|
||
|
||
var BASE_TIMEOUT = 5000;
|
||
|
||
|
||
function unifyResponseMethods(responseMethods)
|
||
{
|
||
if(!responseMethods) return {};
|
||
|
||
for(var key in responseMethods)
|
||
{
|
||
var value = responseMethods[key];
|
||
|
||
if(typeof value == 'string')
|
||
responseMethods[key] =
|
||
{
|
||
response: value
|
||
}
|
||
};
|
||
|
||
return responseMethods;
|
||
};
|
||
|
||
function unifyTransport(transport)
|
||
{
|
||
if(!transport) return;
|
||
|
||
// Transport as a function
|
||
if(transport instanceof Function)
|
||
return {send: transport};
|
||
|
||
// WebSocket & DataChannel
|
||
if(transport.send instanceof Function)
|
||
return transport;
|
||
|
||
// Message API (Inter-window & WebWorker)
|
||
if(transport.postMessage instanceof Function)
|
||
{
|
||
transport.send = transport.postMessage;
|
||
return transport;
|
||
}
|
||
|
||
// Stream API
|
||
if(transport.write instanceof Function)
|
||
{
|
||
transport.send = transport.write;
|
||
return transport;
|
||
}
|
||
|
||
// Transports that only can receive messages, but not send
|
||
if(transport.onmessage !== undefined) return;
|
||
if(transport.pause instanceof Function) return;
|
||
|
||
throw new SyntaxError("Transport is not a function nor a valid object");
|
||
};
|
||
|
||
|
||
/**
|
||
* Representation of a RPC notification
|
||
*
|
||
* @class
|
||
*
|
||
* @constructor
|
||
*
|
||
* @param {String} method -method of the notification
|
||
* @param params - parameters of the notification
|
||
*/
|
||
function RpcNotification(method, params)
|
||
{
|
||
if(defineProperty_IE8)
|
||
{
|
||
this.method = method
|
||
this.params = params
|
||
}
|
||
else
|
||
{
|
||
Object.defineProperty(this, 'method', {value: method, enumerable: true});
|
||
Object.defineProperty(this, 'params', {value: params, enumerable: true});
|
||
}
|
||
};
|
||
|
||
|
||
/**
|
||
* @class
|
||
*
|
||
* @constructor
|
||
*
|
||
* @param {object} packer
|
||
*
|
||
* @param {object} [options]
|
||
*
|
||
* @param {object} [transport]
|
||
*
|
||
* @param {Function} [onRequest]
|
||
*/
|
||
function RpcBuilder(packer, options, transport, onRequest)
|
||
{
|
||
var self = this;
|
||
|
||
if(!packer)
|
||
throw new SyntaxError('Packer is not defined');
|
||
|
||
if(!packer.pack || !packer.unpack)
|
||
throw new SyntaxError('Packer is invalid');
|
||
|
||
var responseMethods = unifyResponseMethods(packer.responseMethods);
|
||
|
||
|
||
if(options instanceof Function)
|
||
{
|
||
if(transport != undefined)
|
||
throw new SyntaxError("There can't be parameters after onRequest");
|
||
|
||
onRequest = options;
|
||
transport = undefined;
|
||
options = undefined;
|
||
};
|
||
|
||
if(options && options.send instanceof Function)
|
||
{
|
||
if(transport && !(transport instanceof Function))
|
||
throw new SyntaxError("Only a function can be after transport");
|
||
|
||
onRequest = transport;
|
||
transport = options;
|
||
options = undefined;
|
||
};
|
||
|
||
if(transport instanceof Function)
|
||
{
|
||
if(onRequest != undefined)
|
||
throw new SyntaxError("There can't be parameters after onRequest");
|
||
|
||
onRequest = transport;
|
||
transport = undefined;
|
||
};
|
||
|
||
if(transport && transport.send instanceof Function)
|
||
if(onRequest && !(onRequest instanceof Function))
|
||
throw new SyntaxError("Only a function can be after transport");
|
||
|
||
options = options || {};
|
||
|
||
|
||
EventEmitter.call(this);
|
||
|
||
if(onRequest)
|
||
this.on('request', onRequest);
|
||
|
||
|
||
if(defineProperty_IE8)
|
||
this.peerID = options.peerID
|
||
else
|
||
Object.defineProperty(this, 'peerID', {value: options.peerID});
|
||
|
||
var max_retries = options.max_retries || 0;
|
||
|
||
|
||
function transportMessage(event)
|
||
{
|
||
self.decode(event.data || event);
|
||
};
|
||
|
||
this.getTransport = function()
|
||
{
|
||
return transport;
|
||
}
|
||
this.setTransport = function(value)
|
||
{
|
||
// Remove listener from old transport
|
||
if(transport)
|
||
{
|
||
// W3C transports
|
||
if(transport.removeEventListener)
|
||
transport.removeEventListener('message', transportMessage);
|
||
|
||
// Node.js Streams API
|
||
else if(transport.removeListener)
|
||
transport.removeListener('data', transportMessage);
|
||
};
|
||
|
||
// Set listener on new transport
|
||
if(value)
|
||
{
|
||
// W3C transports
|
||
if(value.addEventListener)
|
||
value.addEventListener('message', transportMessage);
|
||
|
||
// Node.js Streams API
|
||
else if(value.addListener)
|
||
value.addListener('data', transportMessage);
|
||
};
|
||
|
||
transport = unifyTransport(value);
|
||
}
|
||
|
||
if(!defineProperty_IE8)
|
||
Object.defineProperty(this, 'transport',
|
||
{
|
||
get: this.getTransport.bind(this),
|
||
set: this.setTransport.bind(this)
|
||
})
|
||
|
||
this.setTransport(transport);
|
||
|
||
|
||
var request_timeout = options.request_timeout || BASE_TIMEOUT;
|
||
var response_timeout = options.response_timeout || BASE_TIMEOUT;
|
||
var duplicates_timeout = options.duplicates_timeout || BASE_TIMEOUT;
|
||
|
||
|
||
var requestID = 0;
|
||
|
||
var requests = new Mapper();
|
||
var responses = new Mapper();
|
||
var processedResponses = new Mapper();
|
||
|
||
var message2Key = {};
|
||
|
||
|
||
/**
|
||
* Store the response to prevent to process duplicate request later
|
||
*/
|
||
function storeResponse(message, id, dest)
|
||
{
|
||
var response =
|
||
{
|
||
message: message,
|
||
/** Timeout to auto-clean old responses */
|
||
timeout: setTimeout(function()
|
||
{
|
||
responses.remove(id, dest);
|
||
},
|
||
response_timeout)
|
||
};
|
||
|
||
responses.set(response, id, dest);
|
||
};
|
||
|
||
/**
|
||
* Store the response to ignore duplicated messages later
|
||
*/
|
||
function storeProcessedResponse(ack, from)
|
||
{
|
||
var timeout = setTimeout(function()
|
||
{
|
||
processedResponses.remove(ack, from);
|
||
},
|
||
duplicates_timeout);
|
||
|
||
processedResponses.set(timeout, ack, from);
|
||
};
|
||
|
||
|
||
/**
|
||
* Representation of a RPC request
|
||
*
|
||
* @class
|
||
* @extends RpcNotification
|
||
*
|
||
* @constructor
|
||
*
|
||
* @param {String} method -method of the notification
|
||
* @param params - parameters of the notification
|
||
* @param {Integer} id - identifier of the request
|
||
* @param [from] - source of the notification
|
||
*/
|
||
function RpcRequest(method, params, id, from, transport)
|
||
{
|
||
RpcNotification.call(this, method, params);
|
||
|
||
this.getTransport = function()
|
||
{
|
||
return transport;
|
||
}
|
||
this.setTransport = function(value)
|
||
{
|
||
transport = unifyTransport(value);
|
||
}
|
||
|
||
if(!defineProperty_IE8)
|
||
Object.defineProperty(this, 'transport',
|
||
{
|
||
get: this.getTransport.bind(this),
|
||
set: this.setTransport.bind(this)
|
||
})
|
||
|
||
var response = responses.get(id, from);
|
||
|
||
/**
|
||
* @constant {Boolean} duplicated
|
||
*/
|
||
if(!(transport || self.getTransport()))
|
||
{
|
||
if(defineProperty_IE8)
|
||
this.duplicated = Boolean(response)
|
||
else
|
||
Object.defineProperty(this, 'duplicated',
|
||
{
|
||
value: Boolean(response)
|
||
});
|
||
}
|
||
|
||
var responseMethod = responseMethods[method];
|
||
|
||
this.pack = packer.pack.bind(packer, this, id)
|
||
|
||
/**
|
||
* Generate a response to this request
|
||
*
|
||
* @param {Error} [error]
|
||
* @param {*} [result]
|
||
*
|
||
* @returns {string}
|
||
*/
|
||
this.reply = function(error, result, transport)
|
||
{
|
||
// Fix optional parameters
|
||
if(error instanceof Function || error && error.send instanceof Function)
|
||
{
|
||
if(result != undefined)
|
||
throw new SyntaxError("There can't be parameters after callback");
|
||
|
||
transport = error;
|
||
result = null;
|
||
error = undefined;
|
||
}
|
||
|
||
else if(result instanceof Function
|
||
|| result && result.send instanceof Function)
|
||
{
|
||
if(transport != undefined)
|
||
throw new SyntaxError("There can't be parameters after callback");
|
||
|
||
transport = result;
|
||
result = null;
|
||
};
|
||
|
||
transport = unifyTransport(transport);
|
||
|
||
// Duplicated request, remove old response timeout
|
||
if(response)
|
||
clearTimeout(response.timeout);
|
||
|
||
if(from != undefined)
|
||
{
|
||
if(error)
|
||
error.dest = from;
|
||
|
||
if(result)
|
||
result.dest = from;
|
||
};
|
||
|
||
var message;
|
||
|
||
// New request or overriden one, create new response with provided data
|
||
if(error || result != undefined)
|
||
{
|
||
if(self.peerID != undefined)
|
||
{
|
||
if(error)
|
||
error.from = self.peerID;
|
||
else
|
||
result.from = self.peerID;
|
||
}
|
||
|
||
// Protocol indicates that responses has own request methods
|
||
if(responseMethod)
|
||
{
|
||
if(responseMethod.error == undefined && error)
|
||
message =
|
||
{
|
||
error: error
|
||
};
|
||
|
||
else
|
||
{
|
||
var method = error
|
||
? responseMethod.error
|
||
: responseMethod.response;
|
||
|
||
message =
|
||
{
|
||
method: method,
|
||
params: error || result
|
||
};
|
||
}
|
||
}
|
||
else
|
||
message =
|
||
{
|
||
error: error,
|
||
result: result
|
||
};
|
||
|
||
message = packer.pack(message, id);
|
||
}
|
||
|
||
// Duplicate & not-overriden request, re-send old response
|
||
else if(response)
|
||
message = response.message;
|
||
|
||
// New empty reply, response null value
|
||
else
|
||
message = packer.pack({result: null}, id);
|
||
|
||
// Store the response to prevent to process a duplicated request later
|
||
storeResponse(message, id, from);
|
||
|
||
// Return the stored response so it can be directly send back
|
||
transport = transport || this.getTransport() || self.getTransport();
|
||
|
||
if(transport)
|
||
return transport.send(message);
|
||
|
||
return message;
|
||
}
|
||
};
|
||
inherits(RpcRequest, RpcNotification);
|
||
|
||
|
||
function cancel(message)
|
||
{
|
||
var key = message2Key[message];
|
||
if(!key) return;
|
||
|
||
delete message2Key[message];
|
||
|
||
var request = requests.pop(key.id, key.dest);
|
||
if(!request) return;
|
||
|
||
clearTimeout(request.timeout);
|
||
|
||
// Start duplicated responses timeout
|
||
storeProcessedResponse(key.id, key.dest);
|
||
};
|
||
|
||
/**
|
||
* Allow to cancel a request and don't wait for a response
|
||
*
|
||
* If `message` is not given, cancel all the request
|
||
*/
|
||
this.cancel = function(message)
|
||
{
|
||
if(message) return cancel(message);
|
||
|
||
for(var message in message2Key)
|
||
cancel(message);
|
||
};
|
||
|
||
|
||
this.close = function()
|
||
{
|
||
// Prevent to receive new messages
|
||
var transport = this.getTransport();
|
||
if(transport && transport.close)
|
||
transport.close();
|
||
|
||
// Request & processed responses
|
||
this.cancel();
|
||
|
||
processedResponses.forEach(clearTimeout);
|
||
|
||
// Responses
|
||
responses.forEach(function(response)
|
||
{
|
||
clearTimeout(response.timeout);
|
||
});
|
||
};
|
||
|
||
|
||
/**
|
||
* Generates and encode a JsonRPC 2.0 message
|
||
*
|
||
* @param {String} method -method of the notification
|
||
* @param params - parameters of the notification
|
||
* @param [dest] - destination of the notification
|
||
* @param {object} [transport] - transport where to send the message
|
||
* @param [callback] - function called when a response to this request is
|
||
* received. If not defined, a notification will be send instead
|
||
*
|
||
* @returns {string} A raw JsonRPC 2.0 request or notification string
|
||
*/
|
||
this.encode = function(method, params, dest, transport, callback)
|
||
{
|
||
// Fix optional parameters
|
||
if(params instanceof Function)
|
||
{
|
||
if(dest != undefined)
|
||
throw new SyntaxError("There can't be parameters after callback");
|
||
|
||
callback = params;
|
||
transport = undefined;
|
||
dest = undefined;
|
||
params = undefined;
|
||
}
|
||
|
||
else if(dest instanceof Function)
|
||
{
|
||
if(transport != undefined)
|
||
throw new SyntaxError("There can't be parameters after callback");
|
||
|
||
callback = dest;
|
||
transport = undefined;
|
||
dest = undefined;
|
||
}
|
||
|
||
else if(transport instanceof Function)
|
||
{
|
||
if(callback != undefined)
|
||
throw new SyntaxError("There can't be parameters after callback");
|
||
|
||
callback = transport;
|
||
transport = undefined;
|
||
};
|
||
|
||
if(self.peerID != undefined)
|
||
{
|
||
params = params || {};
|
||
|
||
params.from = self.peerID;
|
||
};
|
||
|
||
if(dest != undefined)
|
||
{
|
||
params = params || {};
|
||
|
||
params.dest = dest;
|
||
};
|
||
|
||
// Encode message
|
||
var message =
|
||
{
|
||
method: method,
|
||
params: params
|
||
};
|
||
|
||
if(callback)
|
||
{
|
||
var id = requestID++;
|
||
var retried = 0;
|
||
|
||
message = packer.pack(message, id);
|
||
|
||
function dispatchCallback(error, result)
|
||
{
|
||
self.cancel(message);
|
||
|
||
callback(error, result);
|
||
};
|
||
|
||
var request =
|
||
{
|
||
message: message,
|
||
callback: dispatchCallback,
|
||
responseMethods: responseMethods[method] || {}
|
||
};
|
||
|
||
var encode_transport = unifyTransport(transport);
|
||
|
||
function sendRequest(transport)
|
||
{
|
||
request.timeout = setTimeout(timeout,
|
||
request_timeout*Math.pow(2, retried++));
|
||
message2Key[message] = {id: id, dest: dest};
|
||
requests.set(request, id, dest);
|
||
|
||
transport = transport || encode_transport || self.getTransport();
|
||
if(transport)
|
||
return transport.send(message);
|
||
|
||
return message;
|
||
};
|
||
|
||
function retry(transport)
|
||
{
|
||
transport = unifyTransport(transport);
|
||
|
||
console.warn(retried+' retry for request message:',message);
|
||
|
||
var timeout = processedResponses.pop(id, dest);
|
||
clearTimeout(timeout);
|
||
|
||
return sendRequest(transport);
|
||
};
|
||
|
||
function timeout()
|
||
{
|
||
if(retried < max_retries)
|
||
return retry(transport);
|
||
|
||
var error = new Error('Request has timed out');
|
||
error.request = message;
|
||
|
||
error.retry = retry;
|
||
|
||
dispatchCallback(error)
|
||
};
|
||
|
||
return sendRequest(transport);
|
||
};
|
||
|
||
// Return the packed message
|
||
message = packer.pack(message);
|
||
|
||
transport = transport || this.getTransport();
|
||
if(transport)
|
||
return transport.send(message);
|
||
|
||
return message;
|
||
};
|
||
|
||
/**
|
||
* Decode and process a JsonRPC 2.0 message
|
||
*
|
||
* @param {string} message - string with the content of the message
|
||
*
|
||
* @returns {RpcNotification|RpcRequest|undefined} - the representation of the
|
||
* notification or the request. If a response was processed, it will return
|
||
* `undefined` to notify that it was processed
|
||
*
|
||
* @throws {TypeError} - Message is not defined
|
||
*/
|
||
this.decode = function(message, transport)
|
||
{
|
||
if(!message)
|
||
throw new TypeError("Message is not defined");
|
||
|
||
try
|
||
{
|
||
message = packer.unpack(message);
|
||
}
|
||
catch(e)
|
||
{
|
||
// Ignore invalid messages
|
||
return console.log(e, message);
|
||
};
|
||
|
||
var id = message.id;
|
||
var ack = message.ack;
|
||
var method = message.method;
|
||
var params = message.params || {};
|
||
|
||
var from = params.from;
|
||
var dest = params.dest;
|
||
|
||
// Ignore messages send by us
|
||
if(self.peerID != undefined && from == self.peerID) return;
|
||
|
||
// Notification
|
||
if(id == undefined && ack == undefined)
|
||
{
|
||
var notification = new RpcNotification(method, params);
|
||
|
||
if(self.emit('request', notification)) return;
|
||
return notification;
|
||
};
|
||
|
||
|
||
function processRequest()
|
||
{
|
||
// If we have a transport and it's a duplicated request, reply inmediatly
|
||
transport = unifyTransport(transport) || self.getTransport();
|
||
if(transport)
|
||
{
|
||
var response = responses.get(id, from);
|
||
if(response)
|
||
return transport.send(response.message);
|
||
};
|
||
|
||
var idAck = (id != undefined) ? id : ack;
|
||
var request = new RpcRequest(method, params, idAck, from, transport);
|
||
|
||
if(self.emit('request', request)) return;
|
||
return request;
|
||
};
|
||
|
||
function processResponse(request, error, result)
|
||
{
|
||
request.callback(error, result);
|
||
};
|
||
|
||
function duplicatedResponse(timeout)
|
||
{
|
||
console.warn("Response already processed", message);
|
||
|
||
// Update duplicated responses timeout
|
||
clearTimeout(timeout);
|
||
storeProcessedResponse(ack, from);
|
||
};
|
||
|
||
|
||
// Request, or response with own method
|
||
if(method)
|
||
{
|
||
// Check if it's a response with own method
|
||
if(dest == undefined || dest == self.peerID)
|
||
{
|
||
var request = requests.get(ack, from);
|
||
if(request)
|
||
{
|
||
var responseMethods = request.responseMethods;
|
||
|
||
if(method == responseMethods.error)
|
||
return processResponse(request, params);
|
||
|
||
if(method == responseMethods.response)
|
||
return processResponse(request, null, params);
|
||
|
||
return processRequest();
|
||
}
|
||
|
||
var processed = processedResponses.get(ack, from);
|
||
if(processed)
|
||
return duplicatedResponse(processed);
|
||
}
|
||
|
||
// Request
|
||
return processRequest();
|
||
};
|
||
|
||
var error = message.error;
|
||
var result = message.result;
|
||
|
||
// Ignore responses not send to us
|
||
if(error && error.dest && error.dest != self.peerID) return;
|
||
if(result && result.dest && result.dest != self.peerID) return;
|
||
|
||
// Response
|
||
var request = requests.get(ack, from);
|
||
if(!request)
|
||
{
|
||
var processed = processedResponses.get(ack, from);
|
||
if(processed)
|
||
return duplicatedResponse(processed);
|
||
|
||
return console.warn("No callback was defined for this message", message);
|
||
};
|
||
|
||
// Process response
|
||
processResponse(request, error, result);
|
||
};
|
||
};
|
||
inherits(RpcBuilder, EventEmitter);
|
||
|
||
|
||
RpcBuilder.RpcNotification = RpcNotification;
|
||
|
||
|
||
module.exports = RpcBuilder;
|
||
|
||
var clients = require('./clients');
|
||
var transports = require('./clients/transports');
|
||
|
||
RpcBuilder.clients = clients;
|
||
RpcBuilder.clients.transports = transports;
|
||
RpcBuilder.packers = packers;
|
||
|
||
},{"./Mapper":9,"./clients":10,"./clients/transports":12,"./packers":17,"events":113,"inherits":7}],15:[function(require,module,exports){
|
||
/**
|
||
* JsonRPC 2.0 packer
|
||
*/
|
||
|
||
/**
|
||
* Pack a JsonRPC 2.0 message
|
||
*
|
||
* @param {Object} message - object to be packaged. It requires to have all the
|
||
* fields needed by the JsonRPC 2.0 message that it's going to be generated
|
||
*
|
||
* @return {String} - the stringified JsonRPC 2.0 message
|
||
*/
|
||
function pack(message, id)
|
||
{
|
||
var result =
|
||
{
|
||
jsonrpc: "2.0"
|
||
};
|
||
|
||
// Request
|
||
if(message.method)
|
||
{
|
||
result.method = message.method;
|
||
|
||
if(message.params)
|
||
result.params = message.params;
|
||
|
||
// Request is a notification
|
||
if(id != undefined)
|
||
result.id = id;
|
||
}
|
||
|
||
// Response
|
||
else if(id != undefined)
|
||
{
|
||
if(message.error)
|
||
{
|
||
if(message.result !== undefined)
|
||
throw new TypeError("Both result and error are defined");
|
||
|
||
result.error = message.error;
|
||
}
|
||
else if(message.result !== undefined)
|
||
result.result = message.result;
|
||
else
|
||
throw new TypeError("No result or error is defined");
|
||
|
||
result.id = id;
|
||
};
|
||
|
||
return JSON.stringify(result);
|
||
};
|
||
|
||
/**
|
||
* Unpack a JsonRPC 2.0 message
|
||
*
|
||
* @param {String} message - string with the content of the JsonRPC 2.0 message
|
||
*
|
||
* @throws {TypeError} - Invalid JsonRPC version
|
||
*
|
||
* @return {Object} - object filled with the JsonRPC 2.0 message content
|
||
*/
|
||
function unpack(message)
|
||
{
|
||
var result = message;
|
||
|
||
if(typeof message === 'string' || message instanceof String)
|
||
result = JSON.parse(message);
|
||
|
||
// Check if it's a valid message
|
||
|
||
var version = result.jsonrpc;
|
||
if(version !== '2.0')
|
||
throw new TypeError("Invalid JsonRPC version '" + version + "': " + message);
|
||
|
||
// Response
|
||
if(result.method == undefined)
|
||
{
|
||
if(result.id == undefined)
|
||
throw new TypeError("Invalid message: "+message);
|
||
|
||
var result_defined = result.result !== undefined;
|
||
var error_defined = result.error !== undefined;
|
||
|
||
// Check only result or error is defined, not both or none
|
||
if(result_defined && error_defined)
|
||
throw new TypeError("Both result and error are defined: "+message);
|
||
|
||
if(!result_defined && !error_defined)
|
||
throw new TypeError("No result or error is defined: "+message);
|
||
|
||
result.ack = result.id;
|
||
delete result.id;
|
||
}
|
||
|
||
// Return unpacked message
|
||
return result;
|
||
};
|
||
|
||
|
||
exports.pack = pack;
|
||
exports.unpack = unpack;
|
||
|
||
},{}],16:[function(require,module,exports){
|
||
function pack(message)
|
||
{
|
||
throw new TypeError("Not yet implemented");
|
||
};
|
||
|
||
function unpack(message)
|
||
{
|
||
throw new TypeError("Not yet implemented");
|
||
};
|
||
|
||
|
||
exports.pack = pack;
|
||
exports.unpack = unpack;
|
||
|
||
},{}],17:[function(require,module,exports){
|
||
var JsonRPC = require('./JsonRPC');
|
||
var XmlRPC = require('./XmlRPC');
|
||
|
||
|
||
exports.JsonRPC = JsonRPC;
|
||
exports.XmlRPC = XmlRPC;
|
||
|
||
},{"./JsonRPC":15,"./XmlRPC":16}],18:[function(require,module,exports){
|
||
/*
|
||
* (C) Copyright 2014-2015 Kurento (http://kurento.org/)
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
var freeice = require('freeice')
|
||
var inherits = require('inherits')
|
||
var UAParser = require('ua-parser-js')
|
||
var uuid = require('uuid')
|
||
var hark = require('hark')
|
||
|
||
var EventEmitter = require('events').EventEmitter
|
||
var recursive = require('merge').recursive.bind(undefined, true)
|
||
var sdpTranslator = require('sdp-translator')
|
||
var logger = window.Logger || console
|
||
|
||
// var gUM = navigator.mediaDevices.getUserMedia || function (constraints) {
|
||
// return new Promise(navigator.getUserMedia(constraints, function (stream) {
|
||
// videoStream = stream
|
||
// start()
|
||
// }).eror(callback));
|
||
// }
|
||
|
||
try {
|
||
require('kurento-browser-extensions')
|
||
} catch (error) {
|
||
if (typeof getScreenConstraints === 'undefined') {
|
||
logger.warn('screen sharing is not available')
|
||
|
||
getScreenConstraints = function getScreenConstraints(sendSource, callback) {
|
||
callback(new Error("This library is not enabled for screen sharing"))
|
||
}
|
||
}
|
||
}
|
||
|
||
var MEDIA_CONSTRAINTS = {
|
||
audio: true,
|
||
video: {
|
||
width: 640,
|
||
framerate: 15
|
||
}
|
||
}
|
||
|
||
// Somehow, the UAParser constructor gets an empty window object.
|
||
// We need to pass the user agent string in order to get information
|
||
var ua = (window && window.navigator) ? window.navigator.userAgent : ''
|
||
var parser = new UAParser(ua)
|
||
var browser = parser.getBrowser()
|
||
|
||
var usePlanB = false
|
||
if (browser.name === 'Chrome' || browser.name === 'Chromium') {
|
||
logger.info(browser.name + ": using SDP PlanB")
|
||
usePlanB = true
|
||
}
|
||
|
||
function noop(error) {
|
||
if (error) logger.error(error)
|
||
}
|
||
|
||
function trackStop(track) {
|
||
track.stop && track.stop()
|
||
}
|
||
|
||
function streamStop(stream) {
|
||
stream.getTracks().forEach(trackStop)
|
||
}
|
||
|
||
/**
|
||
* Returns a string representation of a SessionDescription object.
|
||
*/
|
||
var dumpSDP = function (description) {
|
||
if (typeof description === 'undefined' || description === null) {
|
||
return ''
|
||
}
|
||
|
||
return 'type: ' + description.type + '\r\n' + description.sdp
|
||
}
|
||
|
||
function bufferizeCandidates(pc, onerror) {
|
||
var candidatesQueue = []
|
||
|
||
pc.addEventListener('signalingstatechange', function () {
|
||
if (this.signalingState === 'stable') {
|
||
while (candidatesQueue.length) {
|
||
var entry = candidatesQueue.shift()
|
||
|
||
this.addIceCandidate(entry.candidate, entry.callback, entry.callback)
|
||
}
|
||
}
|
||
})
|
||
|
||
return function (candidate, callback) {
|
||
callback = callback || onerror
|
||
|
||
switch (pc.signalingState) {
|
||
case 'closed':
|
||
callback(new Error('PeerConnection object is closed'))
|
||
break
|
||
case 'stable':
|
||
if (pc.remoteDescription) {
|
||
pc.addIceCandidate(candidate, callback, callback)
|
||
break
|
||
}
|
||
default:
|
||
candidatesQueue.push({
|
||
candidate: candidate,
|
||
callback: callback
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Simulcast utilities */
|
||
|
||
function removeFIDFromOffer(sdp) {
|
||
var n = sdp.indexOf("a=ssrc-group:FID");
|
||
|
||
if (n > 0) {
|
||
return sdp.slice(0, n);
|
||
} else {
|
||
return sdp;
|
||
}
|
||
}
|
||
|
||
function getSimulcastInfo(videoStream) {
|
||
var videoTracks = videoStream.getVideoTracks();
|
||
if (!videoTracks.length) {
|
||
logger.warn('No video tracks available in the video stream')
|
||
return ''
|
||
}
|
||
var lines = [
|
||
'a=x-google-flag:conference',
|
||
'a=ssrc-group:SIM 1 2 3',
|
||
'a=ssrc:1 cname:localVideo',
|
||
'a=ssrc:1 msid:' + videoStream.id + ' ' + videoTracks[0].id,
|
||
'a=ssrc:1 mslabel:' + videoStream.id,
|
||
'a=ssrc:1 label:' + videoTracks[0].id,
|
||
'a=ssrc:2 cname:localVideo',
|
||
'a=ssrc:2 msid:' + videoStream.id + ' ' + videoTracks[0].id,
|
||
'a=ssrc:2 mslabel:' + videoStream.id,
|
||
'a=ssrc:2 label:' + videoTracks[0].id,
|
||
'a=ssrc:3 cname:localVideo',
|
||
'a=ssrc:3 msid:' + videoStream.id + ' ' + videoTracks[0].id,
|
||
'a=ssrc:3 mslabel:' + videoStream.id,
|
||
'a=ssrc:3 label:' + videoTracks[0].id
|
||
];
|
||
|
||
lines.push('');
|
||
|
||
return lines.join('\n');
|
||
}
|
||
|
||
/**
|
||
* Wrapper object of an RTCPeerConnection. This object is aimed to simplify the
|
||
* development of WebRTC-based applications.
|
||
*
|
||
* @constructor module:kurentoUtils.WebRtcPeer
|
||
*
|
||
* @param {String} mode Mode in which the PeerConnection will be configured.
|
||
* Valid values are: 'recv', 'send', and 'sendRecv'
|
||
* @param localVideo Video tag for the local stream
|
||
* @param remoteVideo Video tag for the remote stream
|
||
* @param {MediaStream} videoStream Stream to be used as primary source
|
||
* (typically video and audio, or only video if combined with audioStream) for
|
||
* localVideo and to be added as stream to the RTCPeerConnection
|
||
* @param {MediaStream} audioStream Stream to be used as second source
|
||
* (typically for audio) for localVideo and to be added as stream to the
|
||
* RTCPeerConnection
|
||
*/
|
||
function WebRtcPeer(mode, options, callback) {
|
||
if (!(this instanceof WebRtcPeer)) {
|
||
return new WebRtcPeer(mode, options, callback)
|
||
}
|
||
|
||
WebRtcPeer.super_.call(this)
|
||
|
||
if (options instanceof Function) {
|
||
callback = options
|
||
options = undefined
|
||
}
|
||
|
||
options = options || {}
|
||
callback = (callback || noop).bind(this)
|
||
|
||
var self = this
|
||
var localVideo = options.localVideo
|
||
var remoteVideo = options.remoteVideo
|
||
var videoStream = options.videoStream
|
||
var audioStream = options.audioStream
|
||
var mediaConstraints = options.mediaConstraints
|
||
|
||
var connectionConstraints = options.connectionConstraints
|
||
var pc = options.peerConnection
|
||
var sendSource = options.sendSource || 'webcam'
|
||
|
||
var dataChannelConfig = options.dataChannelConfig
|
||
var useDataChannels = options.dataChannels || false
|
||
var dataChannel
|
||
|
||
var guid = uuid.v4()
|
||
var configuration = recursive({
|
||
iceServers: freeice()
|
||
},
|
||
options.configuration)
|
||
|
||
var onicecandidate = options.onicecandidate
|
||
if (onicecandidate) this.on('icecandidate', onicecandidate)
|
||
|
||
var oncandidategatheringdone = options.oncandidategatheringdone
|
||
if (oncandidategatheringdone) {
|
||
this.on('candidategatheringdone', oncandidategatheringdone)
|
||
}
|
||
|
||
var simulcast = options.simulcast
|
||
var multistream = options.multistream
|
||
var interop = new sdpTranslator.Interop()
|
||
var candidatesQueueOut = []
|
||
var candidategatheringdone = false
|
||
|
||
Object.defineProperties(this, {
|
||
'peerConnection': {
|
||
get: function () {
|
||
return pc
|
||
}
|
||
},
|
||
|
||
'id': {
|
||
value: options.id || guid,
|
||
writable: false
|
||
},
|
||
|
||
'remoteVideo': {
|
||
get: function () {
|
||
return remoteVideo
|
||
}
|
||
},
|
||
|
||
'localVideo': {
|
||
get: function () {
|
||
return localVideo
|
||
}
|
||
},
|
||
|
||
'dataChannel': {
|
||
get: function () {
|
||
return dataChannel
|
||
}
|
||
},
|
||
|
||
/**
|
||
* @member {(external:ImageData|undefined)} currentFrame
|
||
*/
|
||
'currentFrame': {
|
||
get: function () {
|
||
// [ToDo] Find solution when we have a remote stream but we didn't set
|
||
// a remoteVideo tag
|
||
if (!remoteVideo) return;
|
||
|
||
if (remoteVideo.readyState < remoteVideo.HAVE_CURRENT_DATA)
|
||
throw new Error('No video stream data available')
|
||
|
||
var canvas = document.createElement('canvas')
|
||
canvas.width = remoteVideo.videoWidth
|
||
canvas.height = remoteVideo.videoHeight
|
||
|
||
canvas.getContext('2d').drawImage(remoteVideo, 0, 0)
|
||
|
||
return canvas
|
||
}
|
||
}
|
||
})
|
||
|
||
// Init PeerConnection
|
||
if (!pc) {
|
||
pc = new RTCPeerConnection(configuration);
|
||
if (useDataChannels && !dataChannel) {
|
||
var dcId = 'WebRtcPeer-' + self.id
|
||
var dcOptions = undefined
|
||
if (dataChannelConfig) {
|
||
dcId = dataChannelConfig.id || dcId
|
||
dcOptions = dataChannelConfig.options
|
||
}
|
||
dataChannel = pc.createDataChannel(dcId, dcOptions);
|
||
if (dataChannelConfig) {
|
||
dataChannel.onopen = dataChannelConfig.onopen;
|
||
dataChannel.onclose = dataChannelConfig.onclose;
|
||
dataChannel.onmessage = dataChannelConfig.onmessage;
|
||
dataChannel.onbufferedamountlow = dataChannelConfig.onbufferedamountlow;
|
||
dataChannel.onerror = dataChannelConfig.onerror || noop;
|
||
}
|
||
}
|
||
}
|
||
|
||
pc.addEventListener('icecandidate', function (event) {
|
||
var candidate = event.candidate
|
||
|
||
if (EventEmitter.listenerCount(self, 'icecandidate') ||
|
||
EventEmitter.listenerCount(
|
||
self, 'candidategatheringdone')) {
|
||
if (candidate) {
|
||
var cand
|
||
|
||
if (multistream && usePlanB) {
|
||
cand = interop.candidateToUnifiedPlan(candidate)
|
||
} else {
|
||
cand = candidate
|
||
}
|
||
|
||
self.emit('icecandidate', cand)
|
||
candidategatheringdone = false
|
||
} else if (!candidategatheringdone) {
|
||
self.emit('candidategatheringdone')
|
||
candidategatheringdone = true
|
||
}
|
||
} else if (!candidategatheringdone) {
|
||
// Not listening to 'icecandidate' or 'candidategatheringdone' events, queue
|
||
// the candidate until one of them is listened
|
||
candidatesQueueOut.push(candidate)
|
||
|
||
if (!candidate) candidategatheringdone = true
|
||
}
|
||
})
|
||
|
||
pc.ontrack = options.onaddstream
|
||
pc.onnegotiationneeded = options.onnegotiationneeded
|
||
this.on('newListener', function (event, listener) {
|
||
if (event === 'icecandidate' || event === 'candidategatheringdone') {
|
||
while (candidatesQueueOut.length) {
|
||
var candidate = candidatesQueueOut.shift()
|
||
|
||
if (!candidate === (event === 'candidategatheringdone')) {
|
||
listener(candidate)
|
||
}
|
||
}
|
||
}
|
||
})
|
||
|
||
var addIceCandidate = bufferizeCandidates(pc)
|
||
|
||
/**
|
||
* Callback function invoked when an ICE candidate is received. Developers are
|
||
* expected to invoke this function in order to complete the SDP negotiation.
|
||
*
|
||
* @function module:kurentoUtils.WebRtcPeer.prototype.addIceCandidate
|
||
*
|
||
* @param iceCandidate - Literal object with the ICE candidate description
|
||
* @param callback - Called when the ICE candidate has been added.
|
||
*/
|
||
this.addIceCandidate = function (iceCandidate, callback) {
|
||
var candidate
|
||
|
||
if (multistream && usePlanB) {
|
||
candidate = interop.candidateToPlanB(iceCandidate)
|
||
} else {
|
||
candidate = new RTCIceCandidate(iceCandidate)
|
||
}
|
||
|
||
logger.debug('Remote ICE candidate received', iceCandidate)
|
||
callback = (callback || noop).bind(this)
|
||
addIceCandidate(candidate, callback)
|
||
}
|
||
|
||
this.generateOffer = function (callback) {
|
||
callback = callback.bind(this)
|
||
|
||
var offerAudio = true
|
||
var offerVideo = true
|
||
// Constraints must have both blocks
|
||
if (mediaConstraints) {
|
||
offerAudio = (typeof mediaConstraints.audio === 'boolean') ?
|
||
mediaConstraints.audio : true
|
||
offerVideo = (typeof mediaConstraints.video === 'boolean') ?
|
||
mediaConstraints.video : true
|
||
}
|
||
|
||
var browserDependantConstraints = {
|
||
offerToReceiveAudio: (mode !== 'sendonly' && offerAudio),
|
||
offerToReceiveVideo: (mode !== 'sendonly' && offerVideo)
|
||
}
|
||
|
||
//FIXME: clarify possible constraints passed to createOffer()
|
||
/*var constraints = recursive(browserDependantConstraints,
|
||
connectionConstraints)*/
|
||
|
||
var constraints = browserDependantConstraints;
|
||
|
||
logger.info('constraints: ' + JSON.stringify(constraints))
|
||
|
||
pc.createOffer(constraints).then(function (offer) {
|
||
logger.info('Created SDP offer')
|
||
offer = mangleSdpToAddSimulcast(offer)
|
||
return pc.setLocalDescription(offer)
|
||
}).then(function () {
|
||
var localDescription = pc.localDescription
|
||
logger.info('Local description set', localDescription.sdp)
|
||
if (multistream && usePlanB) {
|
||
localDescription = interop.toUnifiedPlan(localDescription)
|
||
logger.info('offer::origPlanB->UnifiedPlan', dumpSDP(
|
||
localDescription))
|
||
}
|
||
callback(null, localDescription.sdp, self.processAnswer.bind(
|
||
self))
|
||
}).catch(callback)
|
||
}
|
||
|
||
this.getLocalSessionDescriptor = function () {
|
||
return pc.localDescription
|
||
}
|
||
|
||
this.getRemoteSessionDescriptor = function () {
|
||
return pc.remoteDescription
|
||
}
|
||
|
||
function setRemoteVideo() {
|
||
if (remoteVideo) {
|
||
var stream = pc.getRemoteStreams()[0]
|
||
var url = stream ? URL.createObjectURL(stream) : ''
|
||
|
||
remoteVideo.pause()
|
||
remoteVideo.src = url
|
||
remoteVideo.load()
|
||
|
||
logger.info('Remote URL:', url)
|
||
}
|
||
}
|
||
|
||
this.showLocalVideo = function () {
|
||
localVideo.src = URL.createObjectURL(videoStream)
|
||
localVideo.muted = true
|
||
}
|
||
|
||
this.send = function (data) {
|
||
if (dataChannel && dataChannel.readyState === 'open') {
|
||
dataChannel.send(data)
|
||
} else {
|
||
logger.warn(
|
||
'Trying to send data over a non-existing or closed data channel')
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Callback function invoked when a SDP answer is received. Developers are
|
||
* expected to invoke this function in order to complete the SDP negotiation.
|
||
*
|
||
* @function module:kurentoUtils.WebRtcPeer.prototype.processAnswer
|
||
*
|
||
* @param sdpAnswer - Description of sdpAnswer
|
||
* @param callback -
|
||
* Invoked after the SDP answer is processed, or there is an error.
|
||
*/
|
||
this.processAnswer = function (sdpAnswer, callback) {
|
||
callback = (callback || noop).bind(this)
|
||
|
||
var answer = new RTCSessionDescription({
|
||
type: 'answer',
|
||
sdp: sdpAnswer
|
||
})
|
||
|
||
if (multistream && usePlanB) {
|
||
var planBAnswer = interop.toPlanB(answer)
|
||
logger.info('asnwer::planB', dumpSDP(planBAnswer))
|
||
answer = planBAnswer
|
||
}
|
||
|
||
logger.info('SDP answer received, setting remote description')
|
||
|
||
if (pc.signalingState === 'closed') {
|
||
return callback('PeerConnection is closed')
|
||
}
|
||
|
||
pc.setRemoteDescription(answer, function () {
|
||
setRemoteVideo()
|
||
|
||
callback()
|
||
},
|
||
callback)
|
||
}
|
||
|
||
/**
|
||
* Callback function invoked when a SDP offer is received. Developers are
|
||
* expected to invoke this function in order to complete the SDP negotiation.
|
||
*
|
||
* @function module:kurentoUtils.WebRtcPeer.prototype.processOffer
|
||
*
|
||
* @param sdpOffer - Description of sdpOffer
|
||
* @param callback - Called when the remote description has been set
|
||
* successfully.
|
||
*/
|
||
this.processOffer = function (sdpOffer, callback) {
|
||
callback = callback.bind(this)
|
||
|
||
var offer = new RTCSessionDescription({
|
||
type: 'offer',
|
||
sdp: sdpOffer
|
||
})
|
||
|
||
if (multistream && usePlanB) {
|
||
var planBOffer = interop.toPlanB(offer)
|
||
logger.info('offer::planB', dumpSDP(planBOffer))
|
||
offer = planBOffer
|
||
}
|
||
|
||
logger.info('SDP offer received, setting remote description')
|
||
|
||
if (pc.signalingState === 'closed') {
|
||
return callback('PeerConnection is closed')
|
||
}
|
||
|
||
pc.setRemoteDescription(offer).then(function () {
|
||
return setRemoteVideo()
|
||
}).then(function () {
|
||
return pc.createAnswer()
|
||
}).then(function (answer) {
|
||
answer = mangleSdpToAddSimulcast(answer)
|
||
logger.info('Created SDP answer')
|
||
return pc.setLocalDescription(answer)
|
||
}).then(function () {
|
||
var localDescription = pc.localDescription
|
||
if (multistream && usePlanB) {
|
||
localDescription = interop.toUnifiedPlan(localDescription)
|
||
logger.info('answer::origPlanB->UnifiedPlan', dumpSDP(
|
||
localDescription))
|
||
}
|
||
logger.info('Local description set', localDescription.sdp)
|
||
callback(null, localDescription.sdp)
|
||
}).catch(callback)
|
||
}
|
||
|
||
function mangleSdpToAddSimulcast(answer) {
|
||
if (simulcast) {
|
||
if (browser.name === 'Chrome' || browser.name === 'Chromium') {
|
||
logger.info('Adding multicast info')
|
||
answer = new RTCSessionDescription({
|
||
'type': answer.type,
|
||
'sdp': removeFIDFromOffer(answer.sdp) + getSimulcastInfo(
|
||
videoStream)
|
||
})
|
||
} else {
|
||
logger.warn('Simulcast is only available in Chrome browser.')
|
||
}
|
||
}
|
||
|
||
return answer
|
||
}
|
||
|
||
/**
|
||
* This function creates the RTCPeerConnection object taking into account the
|
||
* properties received in the constructor. It starts the SDP negotiation
|
||
* process: generates the SDP offer and invokes the onsdpoffer callback. This
|
||
* callback is expected to send the SDP offer, in order to obtain an SDP
|
||
* answer from another peer.
|
||
*/
|
||
function start() {
|
||
if (pc.signalingState === 'closed') {
|
||
callback(
|
||
'The peer connection object is in "closed" state. This is most likely due to an invocation of the dispose method before accepting in the dialogue'
|
||
)
|
||
}
|
||
|
||
if (videoStream && localVideo) {
|
||
self.showLocalVideo()
|
||
}
|
||
|
||
if (videoStream) {
|
||
pc.addStream(videoStream)
|
||
}
|
||
|
||
if (audioStream) {
|
||
pc.addStream(audioStream)
|
||
}
|
||
|
||
// [Hack] https://code.google.com/p/chromium/issues/detail?id=443558
|
||
var browser = parser.getBrowser()
|
||
if (mode === 'sendonly' &&
|
||
(browser.name === 'Chrome' || browser.name === 'Chromium') &&
|
||
browser.major === 39) {
|
||
mode = 'sendrecv'
|
||
}
|
||
|
||
callback()
|
||
}
|
||
|
||
if (mode !== 'recvonly' && !videoStream && !audioStream) {
|
||
function getMedia(constraints) {
|
||
if (constraints === undefined) {
|
||
constraints = MEDIA_CONSTRAINTS
|
||
}
|
||
|
||
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
|
||
videoStream = stream
|
||
start()
|
||
}).catch(callback);
|
||
}
|
||
if (sendSource === 'webcam') {
|
||
getMedia(mediaConstraints)
|
||
} else {
|
||
getScreenConstraints(sendSource, function (error, constraints_) {
|
||
if (error)
|
||
return callback(error)
|
||
|
||
constraints = [mediaConstraints]
|
||
constraints.unshift(constraints_)
|
||
getMedia(recursive.apply(undefined, constraints))
|
||
}, guid)
|
||
}
|
||
} else {
|
||
setTimeout(start, 0)
|
||
}
|
||
|
||
this.on('_dispose', function () {
|
||
if (localVideo) {
|
||
localVideo.pause()
|
||
localVideo.src = ''
|
||
localVideo.load()
|
||
//Unmute local video in case the video tag is later used for remote video
|
||
localVideo.muted = false
|
||
}
|
||
if (remoteVideo) {
|
||
remoteVideo.pause()
|
||
remoteVideo.src = ''
|
||
remoteVideo.load()
|
||
}
|
||
self.removeAllListeners()
|
||
|
||
if (window.cancelChooseDesktopMedia !== undefined) {
|
||
window.cancelChooseDesktopMedia(guid)
|
||
}
|
||
})
|
||
}
|
||
inherits(WebRtcPeer, EventEmitter)
|
||
|
||
function createEnableDescriptor(type) {
|
||
var method = 'get' + type + 'Tracks'
|
||
|
||
return {
|
||
enumerable: true,
|
||
get: function () {
|
||
// [ToDo] Should return undefined if not all tracks have the same value?
|
||
|
||
if (!this.peerConnection) return
|
||
|
||
var streams = this.peerConnection.getLocalStreams()
|
||
if (!streams.length) return
|
||
|
||
for (var i = 0, stream; stream = streams[i]; i++) {
|
||
var tracks = stream[method]()
|
||
for (var j = 0, track; track = tracks[j]; j++)
|
||
if (!track.enabled) return false
|
||
}
|
||
|
||
return true
|
||
},
|
||
set: function (value) {
|
||
function trackSetEnable(track) {
|
||
track.enabled = value
|
||
}
|
||
|
||
this.peerConnection.getLocalStreams().forEach(function (stream) {
|
||
stream[method]().forEach(trackSetEnable)
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
Object.defineProperties(WebRtcPeer.prototype, {
|
||
'enabled': {
|
||
enumerable: true,
|
||
get: function () {
|
||
return this.audioEnabled && this.videoEnabled
|
||
},
|
||
set: function (value) {
|
||
this.audioEnabled = this.videoEnabled = value
|
||
}
|
||
},
|
||
'audioEnabled': createEnableDescriptor('Audio'),
|
||
'videoEnabled': createEnableDescriptor('Video')
|
||
})
|
||
|
||
WebRtcPeer.prototype.getLocalStream = function (index) {
|
||
if (this.peerConnection) {
|
||
return this.peerConnection.getLocalStreams()[index || 0]
|
||
}
|
||
}
|
||
|
||
WebRtcPeer.prototype.getRemoteStream = function (index) {
|
||
if (this.peerConnection) {
|
||
return this.peerConnection.getRemoteStreams()[index || 0]
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description This method frees the resources used by WebRtcPeer.
|
||
*
|
||
* @function module:kurentoUtils.WebRtcPeer.prototype.dispose
|
||
*/
|
||
WebRtcPeer.prototype.dispose = function () {
|
||
logger.info('Disposing WebRtcPeer')
|
||
|
||
var pc = this.peerConnection
|
||
var dc = this.dataChannel
|
||
try {
|
||
if (dc) {
|
||
if (dc.signalingState === 'closed') return
|
||
|
||
dc.close()
|
||
}
|
||
|
||
if (pc) {
|
||
if (pc.signalingState === 'closed') return
|
||
|
||
pc.getLocalStreams().forEach(streamStop)
|
||
|
||
// FIXME This is not yet implemented in firefox
|
||
// if(videoStream) pc.removeStream(videoStream);
|
||
// if(audioStream) pc.removeStream(audioStream);
|
||
|
||
pc.close()
|
||
}
|
||
} catch (err) {
|
||
logger.warn('Exception disposing webrtc peer ' + err)
|
||
}
|
||
|
||
this.emit('_dispose')
|
||
}
|
||
|
||
//
|
||
// Specialized child classes
|
||
//
|
||
|
||
function WebRtcPeerRecvonly(options, callback) {
|
||
if (!(this instanceof WebRtcPeerRecvonly)) {
|
||
return new WebRtcPeerRecvonly(options, callback)
|
||
}
|
||
|
||
WebRtcPeerRecvonly.super_.call(this, 'recvonly', options, callback)
|
||
}
|
||
inherits(WebRtcPeerRecvonly, WebRtcPeer)
|
||
|
||
function WebRtcPeerSendonly(options, callback) {
|
||
if (!(this instanceof WebRtcPeerSendonly)) {
|
||
return new WebRtcPeerSendonly(options, callback)
|
||
}
|
||
|
||
WebRtcPeerSendonly.super_.call(this, 'sendonly', options, callback)
|
||
}
|
||
inherits(WebRtcPeerSendonly, WebRtcPeer)
|
||
|
||
function WebRtcPeerSendrecv(options, callback) {
|
||
if (!(this instanceof WebRtcPeerSendrecv)) {
|
||
return new WebRtcPeerSendrecv(options, callback)
|
||
}
|
||
|
||
WebRtcPeerSendrecv.super_.call(this, 'sendrecv', options, callback)
|
||
}
|
||
inherits(WebRtcPeerSendrecv, WebRtcPeer)
|
||
|
||
function harkUtils(stream, options) {
|
||
return hark(stream, options);
|
||
}
|
||
|
||
exports.bufferizeCandidates = bufferizeCandidates
|
||
|
||
exports.WebRtcPeerRecvonly = WebRtcPeerRecvonly
|
||
exports.WebRtcPeerSendonly = WebRtcPeerSendonly
|
||
exports.WebRtcPeerSendrecv = WebRtcPeerSendrecv
|
||
exports.hark = harkUtils
|
||
|
||
},{"events":113,"freeice":3,"hark":6,"inherits":7,"kurento-browser-extensions":undefined,"merge":20,"sdp-translator":29,"ua-parser-js":86,"uuid":90}],19:[function(require,module,exports){
|
||
/*
|
||
* (C) Copyright 2014 Kurento (http://kurento.org/)
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*
|
||
*/
|
||
|
||
/**
|
||
* This module contains a set of reusable components that have been found useful
|
||
* during the development of the WebRTC applications with Kurento.
|
||
*
|
||
* @module kurentoUtils
|
||
*
|
||
* @copyright 2014 Kurento (http://kurento.org/)
|
||
* @license ALv2
|
||
*/
|
||
|
||
var WebRtcPeer = require('./WebRtcPeer');
|
||
|
||
exports.WebRtcPeer = WebRtcPeer;
|
||
|
||
},{"./WebRtcPeer":18}],20:[function(require,module,exports){
|
||
/*!
|
||
* @name JavaScript/NodeJS Merge v1.2.0
|
||
* @author yeikos
|
||
* @repository https://github.com/yeikos/js.merge
|
||
|
||
* Copyright 2014 yeikos - MIT license
|
||
* https://raw.github.com/yeikos/js.merge/master/LICENSE
|
||
*/
|
||
|
||
;(function(isNode) {
|
||
|
||
/**
|
||
* Merge one or more objects
|
||
* @param bool? clone
|
||
* @param mixed,... arguments
|
||
* @return object
|
||
*/
|
||
|
||
var Public = function(clone) {
|
||
|
||
return merge(clone === true, false, arguments);
|
||
|
||
}, publicName = 'merge';
|
||
|
||
/**
|
||
* Merge two or more objects recursively
|
||
* @param bool? clone
|
||
* @param mixed,... arguments
|
||
* @return object
|
||
*/
|
||
|
||
Public.recursive = function(clone) {
|
||
|
||
return merge(clone === true, true, arguments);
|
||
|
||
};
|
||
|
||
/**
|
||
* Clone the input removing any reference
|
||
* @param mixed input
|
||
* @return mixed
|
||
*/
|
||
|
||
Public.clone = function(input) {
|
||
|
||
var output = input,
|
||
type = typeOf(input),
|
||
index, size;
|
||
|
||
if (type === 'array') {
|
||
|
||
output = [];
|
||
size = input.length;
|
||
|
||
for (index=0;index<size;++index)
|
||
|
||
output[index] = Public.clone(input[index]);
|
||
|
||
} else if (type === 'object') {
|
||
|
||
output = {};
|
||
|
||
for (index in input)
|
||
|
||
output[index] = Public.clone(input[index]);
|
||
|
||
}
|
||
|
||
return output;
|
||
|
||
};
|
||
|
||
/**
|
||
* Merge two objects recursively
|
||
* @param mixed input
|
||
* @param mixed extend
|
||
* @return mixed
|
||
*/
|
||
|
||
function merge_recursive(base, extend) {
|
||
|
||
if (typeOf(base) !== 'object')
|
||
|
||
return extend;
|
||
|
||
for (var key in extend) {
|
||
|
||
if (typeOf(base[key]) === 'object' && typeOf(extend[key]) === 'object') {
|
||
|
||
base[key] = merge_recursive(base[key], extend[key]);
|
||
|
||
} else {
|
||
|
||
base[key] = extend[key];
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return base;
|
||
|
||
}
|
||
|
||
/**
|
||
* Merge two or more objects
|
||
* @param bool clone
|
||
* @param bool recursive
|
||
* @param array argv
|
||
* @return object
|
||
*/
|
||
|
||
function merge(clone, recursive, argv) {
|
||
|
||
var result = argv[0],
|
||
size = argv.length;
|
||
|
||
if (clone || typeOf(result) !== 'object')
|
||
|
||
result = {};
|
||
|
||
for (var index=0;index<size;++index) {
|
||
|
||
var item = argv[index],
|
||
|
||
type = typeOf(item);
|
||
|
||
if (type !== 'object') continue;
|
||
|
||
for (var key in item) {
|
||
|
||
var sitem = clone ? Public.clone(item[key]) : item[key];
|
||
|
||
if (recursive) {
|
||
|
||
result[key] = merge_recursive(result[key], sitem);
|
||
|
||
} else {
|
||
|
||
result[key] = sitem;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return result;
|
||
|
||
}
|
||
|
||
/**
|
||
* Get type of variable
|
||
* @param mixed input
|
||
* @return string
|
||
*
|
||
* @see http://jsperf.com/typeofvar
|
||
*/
|
||
|
||
function typeOf(input) {
|
||
|
||
return ({}).toString.call(input).slice(8, -1).toLowerCase();
|
||
|
||
}
|
||
|
||
if (isNode) {
|
||
|
||
module.exports = Public;
|
||
|
||
} else {
|
||
|
||
window[publicName] = Public;
|
||
|
||
}
|
||
|
||
})(typeof module === 'object' && module && typeof module.exports === 'object' && module.exports);
|
||
},{}],21:[function(require,module,exports){
|
||
/**
|
||
* Helpers.
|
||
*/
|
||
|
||
var s = 1000;
|
||
var m = s * 60;
|
||
var h = m * 60;
|
||
var d = h * 24;
|
||
var y = d * 365.25;
|
||
|
||
/**
|
||
* Parse or format the given `val`.
|
||
*
|
||
* Options:
|
||
*
|
||
* - `long` verbose formatting [false]
|
||
*
|
||
* @param {String|Number} val
|
||
* @param {Object} [options]
|
||
* @throws {Error} throw an error if val is not a non-empty string or a number
|
||
* @return {String|Number}
|
||
* @api public
|
||
*/
|
||
|
||
module.exports = function(val, options) {
|
||
options = options || {};
|
||
var type = typeof val;
|
||
if (type === 'string' && val.length > 0) {
|
||
return parse(val);
|
||
} else if (type === 'number' && isNaN(val) === false) {
|
||
return options.long ? fmtLong(val) : fmtShort(val);
|
||
}
|
||
throw new Error(
|
||
'val is not a non-empty string or a valid number. val=' +
|
||
JSON.stringify(val)
|
||
);
|
||
};
|
||
|
||
/**
|
||
* Parse the given `str` and return milliseconds.
|
||
*
|
||
* @param {String} str
|
||
* @return {Number}
|
||
* @api private
|
||
*/
|
||
|
||
function parse(str) {
|
||
str = String(str);
|
||
if (str.length > 100) {
|
||
return;
|
||
}
|
||
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(
|
||
str
|
||
);
|
||
if (!match) {
|
||
return;
|
||
}
|
||
var n = parseFloat(match[1]);
|
||
var type = (match[2] || 'ms').toLowerCase();
|
||
switch (type) {
|
||
case 'years':
|
||
case 'year':
|
||
case 'yrs':
|
||
case 'yr':
|
||
case 'y':
|
||
return n * y;
|
||
case 'days':
|
||
case 'day':
|
||
case 'd':
|
||
return n * d;
|
||
case 'hours':
|
||
case 'hour':
|
||
case 'hrs':
|
||
case 'hr':
|
||
case 'h':
|
||
return n * h;
|
||
case 'minutes':
|
||
case 'minute':
|
||
case 'mins':
|
||
case 'min':
|
||
case 'm':
|
||
return n * m;
|
||
case 'seconds':
|
||
case 'second':
|
||
case 'secs':
|
||
case 'sec':
|
||
case 's':
|
||
return n * s;
|
||
case 'milliseconds':
|
||
case 'millisecond':
|
||
case 'msecs':
|
||
case 'msec':
|
||
case 'ms':
|
||
return n;
|
||
default:
|
||
return undefined;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Short format for `ms`.
|
||
*
|
||
* @param {Number} ms
|
||
* @return {String}
|
||
* @api private
|
||
*/
|
||
|
||
function fmtShort(ms) {
|
||
if (ms >= d) {
|
||
return Math.round(ms / d) + 'd';
|
||
}
|
||
if (ms >= h) {
|
||
return Math.round(ms / h) + 'h';
|
||
}
|
||
if (ms >= m) {
|
||
return Math.round(ms / m) + 'm';
|
||
}
|
||
if (ms >= s) {
|
||
return Math.round(ms / s) + 's';
|
||
}
|
||
return ms + 'ms';
|
||
}
|
||
|
||
/**
|
||
* Long format for `ms`.
|
||
*
|
||
* @param {Number} ms
|
||
* @return {String}
|
||
* @api private
|
||
*/
|
||
|
||
function fmtLong(ms) {
|
||
return plural(ms, d, 'day') ||
|
||
plural(ms, h, 'hour') ||
|
||
plural(ms, m, 'minute') ||
|
||
plural(ms, s, 'second') ||
|
||
ms + ' ms';
|
||
}
|
||
|
||
/**
|
||
* Pluralization helper.
|
||
*/
|
||
|
||
function plural(ms, n, name) {
|
||
if (ms < n) {
|
||
return;
|
||
}
|
||
if (ms < n * 1.5) {
|
||
return Math.floor(ms / n) + ' ' + name;
|
||
}
|
||
return Math.ceil(ms / n) + ' ' + name + 's';
|
||
}
|
||
|
||
},{}],22:[function(require,module,exports){
|
||
/**
|
||
# normalice
|
||
|
||
Normalize an ice server configuration object (or plain old string) into a format
|
||
that is usable in all browsers supporting WebRTC. Primarily this module is designed
|
||
to help with the transition of the `url` attribute of the configuration object to
|
||
the `urls` attribute.
|
||
|
||
## Example Usage
|
||
|
||
<<< examples/simple.js
|
||
|
||
**/
|
||
|
||
var protocols = [
|
||
'stun:',
|
||
'turn:'
|
||
];
|
||
|
||
module.exports = function(input) {
|
||
var url = (input || {}).url || input;
|
||
var protocol;
|
||
var parts;
|
||
var output = {};
|
||
|
||
// if we don't have a string url, then allow the input to passthrough
|
||
if (typeof url != 'string' && (! (url instanceof String))) {
|
||
return input;
|
||
}
|
||
|
||
// trim the url string, and convert to an array
|
||
url = url.trim();
|
||
|
||
// if the protocol is not known, then passthrough
|
||
protocol = protocols[protocols.indexOf(url.slice(0, 5))];
|
||
if (! protocol) {
|
||
return input;
|
||
}
|
||
|
||
// now let's attack the remaining url parts
|
||
url = url.slice(5);
|
||
parts = url.split('@');
|
||
|
||
output.username = input.username;
|
||
output.credential = input.credential;
|
||
// if we have an authentication part, then set the credentials
|
||
if (parts.length > 1) {
|
||
url = parts[1];
|
||
parts = parts[0].split(':');
|
||
|
||
// add the output credential and username
|
||
output.username = parts[0];
|
||
output.credential = (input || {}).credential || parts[1] || '';
|
||
}
|
||
|
||
output.url = protocol + url;
|
||
output.urls = [ output.url ];
|
||
|
||
return output;
|
||
};
|
||
|
||
},{}],23:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
/**
|
||
* Check if we're required to add a port number.
|
||
*
|
||
* @see https://url.spec.whatwg.org/#default-port
|
||
* @param {Number|String} port Port number we need to check
|
||
* @param {String} protocol Protocol we need to check against.
|
||
* @returns {Boolean} Is it a default port for the given protocol
|
||
* @api private
|
||
*/
|
||
module.exports = function required(port, protocol) {
|
||
protocol = protocol.split(':')[0];
|
||
port = +port;
|
||
|
||
if (!port) return false;
|
||
|
||
switch (protocol) {
|
||
case 'http':
|
||
case 'ws':
|
||
return port !== 80;
|
||
|
||
case 'https':
|
||
case 'wss':
|
||
return port !== 443;
|
||
|
||
case 'ftp':
|
||
return port !== 21;
|
||
|
||
case 'gopher':
|
||
return port !== 70;
|
||
|
||
case 'file':
|
||
return false;
|
||
}
|
||
|
||
return port !== 0;
|
||
};
|
||
|
||
},{}],24:[function(require,module,exports){
|
||
var grammar = module.exports = {
|
||
v: [{
|
||
name: 'version',
|
||
reg: /^(\d*)$/
|
||
}],
|
||
o: [{ //o=- 20518 0 IN IP4 203.0.113.1
|
||
// NB: sessionId will be a String in most cases because it is huge
|
||
name: 'origin',
|
||
reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
|
||
names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
|
||
format: "%s %s %d %s IP%d %s"
|
||
}],
|
||
// default parsing of these only (though some of these feel outdated)
|
||
s: [{ name: 'name' }],
|
||
i: [{ name: 'description' }],
|
||
u: [{ name: 'uri' }],
|
||
e: [{ name: 'email' }],
|
||
p: [{ name: 'phone' }],
|
||
z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly..
|
||
r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
|
||
//k: [{}], // outdated thing ignored
|
||
t: [{ //t=0 0
|
||
name: 'timing',
|
||
reg: /^(\d*) (\d*)/,
|
||
names: ['start', 'stop'],
|
||
format: "%d %d"
|
||
}],
|
||
c: [{ //c=IN IP4 10.47.197.26
|
||
name: 'connection',
|
||
reg: /^IN IP(\d) (\S*)/,
|
||
names: ['version', 'ip'],
|
||
format: "IN IP%d %s"
|
||
}],
|
||
b: [{ //b=AS:4000
|
||
push: 'bandwidth',
|
||
reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
|
||
names: ['type', 'limit'],
|
||
format: "%s:%s"
|
||
}],
|
||
m: [{ //m=video 51744 RTP/AVP 126 97 98 34 31
|
||
// NB: special - pushes to session
|
||
// TODO: rtp/fmtp should be filtered by the payloads found here?
|
||
reg: /^(\w*) (\d*) ([\w\/]*)(?: (.*))?/,
|
||
names: ['type', 'port', 'protocol', 'payloads'],
|
||
format: "%s %d %s %s"
|
||
}],
|
||
a: [
|
||
{ //a=rtpmap:110 opus/48000/2
|
||
push: 'rtp',
|
||
reg: /^rtpmap:(\d*) ([\w\-]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/,
|
||
names: ['payload', 'codec', 'rate', 'encoding'],
|
||
format: function (o) {
|
||
return (o.encoding) ?
|
||
"rtpmap:%d %s/%s/%s":
|
||
o.rate ?
|
||
"rtpmap:%d %s/%s":
|
||
"rtpmap:%d %s";
|
||
}
|
||
},
|
||
{
|
||
//a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
|
||
//a=fmtp:111 minptime=10; useinbandfec=1
|
||
push: 'fmtp',
|
||
reg: /^fmtp:(\d*) ([\S| ]*)/,
|
||
names: ['payload', 'config'],
|
||
format: "fmtp:%d %s"
|
||
},
|
||
{ //a=control:streamid=0
|
||
name: 'control',
|
||
reg: /^control:(.*)/,
|
||
format: "control:%s"
|
||
},
|
||
{ //a=rtcp:65179 IN IP4 193.84.77.194
|
||
name: 'rtcp',
|
||
reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
|
||
names: ['port', 'netType', 'ipVer', 'address'],
|
||
format: function (o) {
|
||
return (o.address != null) ?
|
||
"rtcp:%d %s IP%d %s":
|
||
"rtcp:%d";
|
||
}
|
||
},
|
||
{ //a=rtcp-fb:98 trr-int 100
|
||
push: 'rtcpFbTrrInt',
|
||
reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
|
||
names: ['payload', 'value'],
|
||
format: "rtcp-fb:%d trr-int %d"
|
||
},
|
||
{ //a=rtcp-fb:98 nack rpsi
|
||
push: 'rtcpFb',
|
||
reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
|
||
names: ['payload', 'type', 'subtype'],
|
||
format: function (o) {
|
||
return (o.subtype != null) ?
|
||
"rtcp-fb:%s %s %s":
|
||
"rtcp-fb:%s %s";
|
||
}
|
||
},
|
||
{ //a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
|
||
//a=extmap:1/recvonly URI-gps-string
|
||
push: 'ext',
|
||
reg: /^extmap:([\w_\/]*) (\S*)(?: (\S*))?/,
|
||
names: ['value', 'uri', 'config'], // value may include "/direction" suffix
|
||
format: function (o) {
|
||
return (o.config != null) ?
|
||
"extmap:%s %s %s":
|
||
"extmap:%s %s";
|
||
}
|
||
},
|
||
{
|
||
//a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
|
||
push: 'crypto',
|
||
reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
|
||
names: ['id', 'suite', 'config', 'sessionConfig'],
|
||
format: function (o) {
|
||
return (o.sessionConfig != null) ?
|
||
"crypto:%d %s %s %s":
|
||
"crypto:%d %s %s";
|
||
}
|
||
},
|
||
{ //a=setup:actpass
|
||
name: 'setup',
|
||
reg: /^setup:(\w*)/,
|
||
format: "setup:%s"
|
||
},
|
||
{ //a=mid:1
|
||
name: 'mid',
|
||
reg: /^mid:([^\s]*)/,
|
||
format: "mid:%s"
|
||
},
|
||
{ //a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
|
||
name: 'msid',
|
||
reg: /^msid:(.*)/,
|
||
format: "msid:%s"
|
||
},
|
||
{ //a=ptime:20
|
||
name: 'ptime',
|
||
reg: /^ptime:(\d*)/,
|
||
format: "ptime:%d"
|
||
},
|
||
{ //a=maxptime:60
|
||
name: 'maxptime',
|
||
reg: /^maxptime:(\d*)/,
|
||
format: "maxptime:%d"
|
||
},
|
||
{ //a=sendrecv
|
||
name: 'direction',
|
||
reg: /^(sendrecv|recvonly|sendonly|inactive)/
|
||
},
|
||
{ //a=ice-lite
|
||
name: 'icelite',
|
||
reg: /^(ice-lite)/
|
||
},
|
||
{ //a=ice-ufrag:F7gI
|
||
name: 'iceUfrag',
|
||
reg: /^ice-ufrag:(\S*)/,
|
||
format: "ice-ufrag:%s"
|
||
},
|
||
{ //a=ice-pwd:x9cml/YzichV2+XlhiMu8g
|
||
name: 'icePwd',
|
||
reg: /^ice-pwd:(\S*)/,
|
||
format: "ice-pwd:%s"
|
||
},
|
||
{ //a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
|
||
name: 'fingerprint',
|
||
reg: /^fingerprint:(\S*) (\S*)/,
|
||
names: ['type', 'hash'],
|
||
format: "fingerprint:%s %s"
|
||
},
|
||
{
|
||
//a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
|
||
//a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0
|
||
//a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0
|
||
//a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0
|
||
//a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0
|
||
push:'candidates',
|
||
reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?/,
|
||
names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation'],
|
||
format: function (o) {
|
||
var str = "candidate:%s %d %s %d %s %d typ %s";
|
||
|
||
str += (o.raddr != null) ? " raddr %s rport %d" : "%v%v";
|
||
|
||
// NB: candidate has three optional chunks, so %void middles one if it's missing
|
||
str += (o.tcptype != null) ? " tcptype %s" : "%v";
|
||
|
||
if (o.generation != null) {
|
||
str += " generation %d";
|
||
}
|
||
return str;
|
||
}
|
||
},
|
||
{ //a=end-of-candidates (keep after the candidates line for readability)
|
||
name: 'endOfCandidates',
|
||
reg: /^(end-of-candidates)/
|
||
},
|
||
{ //a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
|
||
name: 'remoteCandidates',
|
||
reg: /^remote-candidates:(.*)/,
|
||
format: "remote-candidates:%s"
|
||
},
|
||
{ //a=ice-options:google-ice
|
||
name: 'iceOptions',
|
||
reg: /^ice-options:(\S*)/,
|
||
format: "ice-options:%s"
|
||
},
|
||
{ //a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
|
||
push: "ssrcs",
|
||
reg: /^ssrc:(\d*) ([\w_]*):(.*)/,
|
||
names: ['id', 'attribute', 'value'],
|
||
format: "ssrc:%d %s:%s"
|
||
},
|
||
{ //a=ssrc-group:FEC 1 2
|
||
push: "ssrcGroups",
|
||
reg: /^ssrc-group:(\w*) (.*)/,
|
||
names: ['semantics', 'ssrcs'],
|
||
format: "ssrc-group:%s %s"
|
||
},
|
||
{ //a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
|
||
name: "msidSemantic",
|
||
reg: /^msid-semantic:\s?(\w*) (\S*)/,
|
||
names: ['semantic', 'token'],
|
||
format: "msid-semantic: %s %s" // space after ":" is not accidental
|
||
},
|
||
{ //a=group:BUNDLE audio video
|
||
push: 'groups',
|
||
reg: /^group:(\w*) (.*)/,
|
||
names: ['type', 'mids'],
|
||
format: "group:%s %s"
|
||
},
|
||
{ //a=rtcp-mux
|
||
name: 'rtcpMux',
|
||
reg: /^(rtcp-mux)/
|
||
},
|
||
{ //a=rtcp-rsize
|
||
name: 'rtcpRsize',
|
||
reg: /^(rtcp-rsize)/
|
||
},
|
||
{ // any a= that we don't understand is kepts verbatim on media.invalid
|
||
push: 'invalid',
|
||
names: ["value"]
|
||
}
|
||
]
|
||
};
|
||
|
||
// set sensible defaults to avoid polluting the grammar with boring details
|
||
Object.keys(grammar).forEach(function (key) {
|
||
var objs = grammar[key];
|
||
objs.forEach(function (obj) {
|
||
if (!obj.reg) {
|
||
obj.reg = /(.*)/;
|
||
}
|
||
if (!obj.format) {
|
||
obj.format = "%s";
|
||
}
|
||
});
|
||
});
|
||
|
||
},{}],25:[function(require,module,exports){
|
||
var parser = require('./parser');
|
||
var writer = require('./writer');
|
||
|
||
exports.write = writer;
|
||
exports.parse = parser.parse;
|
||
exports.parseFmtpConfig = parser.parseFmtpConfig;
|
||
exports.parsePayloads = parser.parsePayloads;
|
||
exports.parseRemoteCandidates = parser.parseRemoteCandidates;
|
||
|
||
},{"./parser":26,"./writer":27}],26:[function(require,module,exports){
|
||
var toIntIfInt = function (v) {
|
||
return String(Number(v)) === v ? Number(v) : v;
|
||
};
|
||
|
||
var attachProperties = function (match, location, names, rawName) {
|
||
if (rawName && !names) {
|
||
location[rawName] = toIntIfInt(match[1]);
|
||
}
|
||
else {
|
||
for (var i = 0; i < names.length; i += 1) {
|
||
if (match[i+1] != null) {
|
||
location[names[i]] = toIntIfInt(match[i+1]);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
var parseReg = function (obj, location, content) {
|
||
var needsBlank = obj.name && obj.names;
|
||
if (obj.push && !location[obj.push]) {
|
||
location[obj.push] = [];
|
||
}
|
||
else if (needsBlank && !location[obj.name]) {
|
||
location[obj.name] = {};
|
||
}
|
||
var keyLocation = obj.push ?
|
||
{} : // blank object that will be pushed
|
||
needsBlank ? location[obj.name] : location; // otherwise, named location or root
|
||
|
||
attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
|
||
|
||
if (obj.push) {
|
||
location[obj.push].push(keyLocation);
|
||
}
|
||
};
|
||
|
||
var grammar = require('./grammar');
|
||
var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
|
||
|
||
exports.parse = function (sdp) {
|
||
var session = {}
|
||
, media = []
|
||
, location = session; // points at where properties go under (one of the above)
|
||
|
||
// parse lines we understand
|
||
sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
|
||
var type = l[0];
|
||
var content = l.slice(2);
|
||
if (type === 'm') {
|
||
media.push({rtp: [], fmtp: []});
|
||
location = media[media.length-1]; // point at latest media line
|
||
}
|
||
|
||
for (var j = 0; j < (grammar[type] || []).length; j += 1) {
|
||
var obj = grammar[type][j];
|
||
if (obj.reg.test(content)) {
|
||
return parseReg(obj, location, content);
|
||
}
|
||
}
|
||
});
|
||
|
||
session.media = media; // link it up
|
||
return session;
|
||
};
|
||
|
||
var fmtpReducer = function (acc, expr) {
|
||
var s = expr.split('=');
|
||
if (s.length === 2) {
|
||
acc[s[0]] = toIntIfInt(s[1]);
|
||
}
|
||
return acc;
|
||
};
|
||
|
||
exports.parseFmtpConfig = function (str) {
|
||
return str.split(/\;\s?/).reduce(fmtpReducer, {});
|
||
};
|
||
|
||
exports.parsePayloads = function (str) {
|
||
return str.split(' ').map(Number);
|
||
};
|
||
|
||
exports.parseRemoteCandidates = function (str) {
|
||
var candidates = [];
|
||
var parts = str.split(' ').map(toIntIfInt);
|
||
for (var i = 0; i < parts.length; i += 3) {
|
||
candidates.push({
|
||
component: parts[i],
|
||
ip: parts[i + 1],
|
||
port: parts[i + 2]
|
||
});
|
||
}
|
||
return candidates;
|
||
};
|
||
|
||
},{"./grammar":24}],27:[function(require,module,exports){
|
||
var grammar = require('./grammar');
|
||
|
||
// customized util.format - discards excess arguments and can void middle ones
|
||
var formatRegExp = /%[sdv%]/g;
|
||
var format = function (formatStr) {
|
||
var i = 1;
|
||
var args = arguments;
|
||
var len = args.length;
|
||
return formatStr.replace(formatRegExp, function (x) {
|
||
if (i >= len) {
|
||
return x; // missing argument
|
||
}
|
||
var arg = args[i];
|
||
i += 1;
|
||
switch (x) {
|
||
case '%%':
|
||
return '%';
|
||
case '%s':
|
||
return String(arg);
|
||
case '%d':
|
||
return Number(arg);
|
||
case '%v':
|
||
return '';
|
||
}
|
||
});
|
||
// NB: we discard excess arguments - they are typically undefined from makeLine
|
||
};
|
||
|
||
var makeLine = function (type, obj, location) {
|
||
var str = obj.format instanceof Function ?
|
||
(obj.format(obj.push ? location : location[obj.name])) :
|
||
obj.format;
|
||
|
||
var args = [type + '=' + str];
|
||
if (obj.names) {
|
||
for (var i = 0; i < obj.names.length; i += 1) {
|
||
var n = obj.names[i];
|
||
if (obj.name) {
|
||
args.push(location[obj.name][n]);
|
||
}
|
||
else { // for mLine and push attributes
|
||
args.push(location[obj.names[i]]);
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
args.push(location[obj.name]);
|
||
}
|
||
return format.apply(null, args);
|
||
};
|
||
|
||
// RFC specified order
|
||
// TODO: extend this with all the rest
|
||
var defaultOuterOrder = [
|
||
'v', 'o', 's', 'i',
|
||
'u', 'e', 'p', 'c',
|
||
'b', 't', 'r', 'z', 'a'
|
||
];
|
||
var defaultInnerOrder = ['i', 'c', 'b', 'a'];
|
||
|
||
|
||
module.exports = function (session, opts) {
|
||
opts = opts || {};
|
||
// ensure certain properties exist
|
||
if (session.version == null) {
|
||
session.version = 0; // "v=0" must be there (only defined version atm)
|
||
}
|
||
if (session.name == null) {
|
||
session.name = " "; // "s= " must be there if no meaningful name set
|
||
}
|
||
session.media.forEach(function (mLine) {
|
||
if (mLine.payloads == null) {
|
||
mLine.payloads = "";
|
||
}
|
||
});
|
||
|
||
var outerOrder = opts.outerOrder || defaultOuterOrder;
|
||
var innerOrder = opts.innerOrder || defaultInnerOrder;
|
||
var sdp = [];
|
||
|
||
// loop through outerOrder for matching properties on session
|
||
outerOrder.forEach(function (type) {
|
||
grammar[type].forEach(function (obj) {
|
||
if (obj.name in session && session[obj.name] != null) {
|
||
sdp.push(makeLine(type, obj, session));
|
||
}
|
||
else if (obj.push in session && session[obj.push] != null) {
|
||
session[obj.push].forEach(function (el) {
|
||
sdp.push(makeLine(type, obj, el));
|
||
});
|
||
}
|
||
});
|
||
});
|
||
|
||
// then for each media line, follow the innerOrder
|
||
session.media.forEach(function (mLine) {
|
||
sdp.push(makeLine('m', grammar.m[0], mLine));
|
||
|
||
innerOrder.forEach(function (type) {
|
||
grammar[type].forEach(function (obj) {
|
||
if (obj.name in mLine && mLine[obj.name] != null) {
|
||
sdp.push(makeLine(type, obj, mLine));
|
||
}
|
||
else if (obj.push in mLine && mLine[obj.push] != null) {
|
||
mLine[obj.push].forEach(function (el) {
|
||
sdp.push(makeLine(type, obj, el));
|
||
});
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
return sdp.join('\r\n') + '\r\n';
|
||
};
|
||
|
||
},{"./grammar":24}],28:[function(require,module,exports){
|
||
/* Copyright @ 2015 Atlassian Pty Ltd
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
module.exports = function arrayEquals(array) {
|
||
// if the other array is a falsy value, return
|
||
if (!array)
|
||
return false;
|
||
|
||
// compare lengths - can save a lot of time
|
||
if (this.length != array.length)
|
||
return false;
|
||
|
||
for (var i = 0, l = this.length; i < l; i++) {
|
||
// Check if we have nested arrays
|
||
if (this[i] instanceof Array && array[i] instanceof Array) {
|
||
// recurse into the nested arrays
|
||
if (!arrayEquals.apply(this[i], [array[i]]))
|
||
return false;
|
||
} else if (this[i] != array[i]) {
|
||
// Warning - two different object instances will never be equal:
|
||
// {x:20} != {x:20}
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
};
|
||
|
||
|
||
},{}],29:[function(require,module,exports){
|
||
/* Copyright @ 2015 Atlassian Pty Ltd
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
exports.Interop = require('./interop');
|
||
|
||
},{"./interop":30}],30:[function(require,module,exports){
|
||
/* Copyright @ 2015 Atlassian Pty Ltd
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
/* global RTCSessionDescription */
|
||
/* global RTCIceCandidate */
|
||
/* jshint -W097 */
|
||
"use strict";
|
||
|
||
var transform = require('./transform');
|
||
var arrayEquals = require('./array-equals');
|
||
|
||
function Interop() {
|
||
|
||
/**
|
||
* This map holds the most recent Unified Plan offer/answer SDP that was
|
||
* converted to Plan B, with the SDP type ('offer' or 'answer') as keys and
|
||
* the SDP string as values.
|
||
*
|
||
* @type {{}}
|
||
*/
|
||
this.cache = {
|
||
mlB2UMap : {},
|
||
mlU2BMap : {}
|
||
};
|
||
}
|
||
|
||
module.exports = Interop;
|
||
|
||
/**
|
||
* Changes the candidate args to match with the related Unified Plan
|
||
*/
|
||
Interop.prototype.candidateToUnifiedPlan = function(candidate) {
|
||
var cand = new RTCIceCandidate(candidate);
|
||
|
||
cand.sdpMLineIndex = this.cache.mlB2UMap[cand.sdpMLineIndex];
|
||
/* TODO: change sdpMid to (audio|video)-SSRC */
|
||
|
||
return cand;
|
||
};
|
||
|
||
/**
|
||
* Changes the candidate args to match with the related Plan B
|
||
*/
|
||
Interop.prototype.candidateToPlanB = function(candidate) {
|
||
var cand = new RTCIceCandidate(candidate);
|
||
|
||
if (cand.sdpMid.indexOf('audio') === 0) {
|
||
cand.sdpMid = 'audio';
|
||
} else if (cand.sdpMid.indexOf('video') === 0) {
|
||
cand.sdpMid = 'video';
|
||
} else {
|
||
throw new Error('candidate with ' + cand.sdpMid + ' not allowed');
|
||
}
|
||
|
||
cand.sdpMLineIndex = this.cache.mlU2BMap[cand.sdpMLineIndex];
|
||
|
||
return cand;
|
||
};
|
||
|
||
/**
|
||
* Returns the index of the first m-line with the given media type and with a
|
||
* direction which allows sending, in the last Unified Plan description with
|
||
* type "answer" converted to Plan B. Returns {null} if there is no saved
|
||
* answer, or if none of its m-lines with the given type allow sending.
|
||
* @param type the media type ("audio" or "video").
|
||
* @returns {*}
|
||
*/
|
||
Interop.prototype.getFirstSendingIndexFromAnswer = function(type) {
|
||
if (!this.cache.answer) {
|
||
return null;
|
||
}
|
||
|
||
var session = transform.parse(this.cache.answer);
|
||
if (session && session.media && Array.isArray(session.media)){
|
||
for (var i = 0; i < session.media.length; i++) {
|
||
if (session.media[i].type == type &&
|
||
(!session.media[i].direction /* default to sendrecv */ ||
|
||
session.media[i].direction === 'sendrecv' ||
|
||
session.media[i].direction === 'sendonly')){
|
||
return i;
|
||
}
|
||
}
|
||
}
|
||
|
||
return null;
|
||
};
|
||
|
||
/**
|
||
* This method transforms a Unified Plan SDP to an equivalent Plan B SDP. A
|
||
* PeerConnection wrapper transforms the SDP to Plan B before passing it to the
|
||
* application.
|
||
*
|
||
* @param desc
|
||
* @returns {*}
|
||
*/
|
||
Interop.prototype.toPlanB = function(desc) {
|
||
var self = this;
|
||
//#region Preliminary input validation.
|
||
|
||
if (typeof desc !== 'object' || desc === null ||
|
||
typeof desc.sdp !== 'string') {
|
||
console.warn('An empty description was passed as an argument.');
|
||
return desc;
|
||
}
|
||
|
||
// Objectify the SDP for easier manipulation.
|
||
var session = transform.parse(desc.sdp);
|
||
|
||
// If the SDP contains no media, there's nothing to transform.
|
||
if (typeof session.media === 'undefined' ||
|
||
!Array.isArray(session.media) || session.media.length === 0) {
|
||
console.warn('The description has no media.');
|
||
return desc;
|
||
}
|
||
|
||
// Try some heuristics to "make sure" this is a Unified Plan SDP. Plan B
|
||
// SDP has a video, an audio and a data "channel" at most.
|
||
if (session.media.length <= 3 && session.media.every(function(m) {
|
||
return ['video', 'audio', 'data'].indexOf(m.mid) !== -1;
|
||
})) {
|
||
console.warn('This description does not look like Unified Plan.');
|
||
return desc;
|
||
}
|
||
|
||
//#endregion
|
||
|
||
// HACK https://bugzilla.mozilla.org/show_bug.cgi?id=1113443
|
||
var sdp = desc.sdp;
|
||
var rewrite = false;
|
||
for (var i = 0; i < session.media.length; i++) {
|
||
var uLine = session.media[i];
|
||
uLine.rtp.forEach(function(rtp) {
|
||
if (rtp.codec === 'NULL')
|
||
{
|
||
rewrite = true;
|
||
var offer = transform.parse(self.cache.offer);
|
||
rtp.codec = offer.media[i].rtp[0].codec;
|
||
}
|
||
});
|
||
}
|
||
if (rewrite) {
|
||
sdp = transform.write(session);
|
||
}
|
||
|
||
// Unified Plan SDP is our "precious". Cache it for later use in the Plan B
|
||
// -> Unified Plan transformation.
|
||
this.cache[desc.type] = sdp;
|
||
|
||
//#region Convert from Unified Plan to Plan B.
|
||
|
||
// We rebuild the session.media array.
|
||
var media = session.media;
|
||
session.media = [];
|
||
|
||
// Associative array that maps channel types to channel objects for fast
|
||
// access to channel objects by their type, e.g. type2bl['audio']->channel
|
||
// obj.
|
||
var type2bl = {};
|
||
|
||
// Used to build the group:BUNDLE value after the channels construction
|
||
// loop.
|
||
var types = [];
|
||
|
||
media.forEach(function(uLine) {
|
||
// rtcp-mux is required in the Plan B SDP.
|
||
if ((typeof uLine.rtcpMux !== 'string' ||
|
||
uLine.rtcpMux !== 'rtcp-mux') &&
|
||
uLine.direction !== 'inactive') {
|
||
throw new Error('Cannot convert to Plan B because m-lines ' +
|
||
'without the rtcp-mux attribute were found.');
|
||
}
|
||
|
||
// If we don't have a channel for this uLine.type OR the selected is
|
||
// inactive, then select this uLine as the channel basis.
|
||
if (typeof type2bl[uLine.type] === 'undefined' ||
|
||
type2bl[uLine.type].direction === 'inactive') {
|
||
type2bl[uLine.type] = uLine;
|
||
}
|
||
|
||
if (uLine.protocol != type2bl[uLine.type].protocol) {
|
||
throw new Error('Cannot convert to Plan B because m-lines ' +
|
||
'have different protocols and this library does not have ' +
|
||
'support for that');
|
||
}
|
||
|
||
if (uLine.payloads != type2bl[uLine.type].payloads) {
|
||
throw new Error('Cannot convert to Plan B because m-lines ' +
|
||
'have different payloads and this library does not have ' +
|
||
'support for that');
|
||
}
|
||
|
||
});
|
||
|
||
// Implode the Unified Plan m-lines/tracks into Plan B channels.
|
||
media.forEach(function(uLine) {
|
||
if (uLine.type === 'application') {
|
||
session.media.push(uLine);
|
||
types.push(uLine.mid);
|
||
return;
|
||
}
|
||
|
||
// Add sources to the channel and handle a=msid.
|
||
if (typeof uLine.sources === 'object') {
|
||
Object.keys(uLine.sources).forEach(function(ssrc) {
|
||
if (typeof type2bl[uLine.type].sources !== 'object')
|
||
type2bl[uLine.type].sources = {};
|
||
|
||
// Assign the sources to the channel.
|
||
type2bl[uLine.type].sources[ssrc] =
|
||
uLine.sources[ssrc];
|
||
|
||
if (typeof uLine.msid !== 'undefined') {
|
||
// In Plan B the msid is an SSRC attribute. Also, we don't
|
||
// care about the obsolete label and mslabel attributes.
|
||
//
|
||
// Note that it is not guaranteed that the uLine will
|
||
// have an msid. recvonly channels in particular don't have
|
||
// one.
|
||
type2bl[uLine.type].sources[ssrc].msid =
|
||
uLine.msid;
|
||
}
|
||
// NOTE ssrcs in ssrc groups will share msids, as
|
||
// draft-uberti-rtcweb-plan-00 mandates.
|
||
});
|
||
}
|
||
|
||
// Add ssrc groups to the channel.
|
||
if (typeof uLine.ssrcGroups !== 'undefined' &&
|
||
Array.isArray(uLine.ssrcGroups)) {
|
||
|
||
// Create the ssrcGroups array, if it's not defined.
|
||
if (typeof type2bl[uLine.type].ssrcGroups === 'undefined' ||
|
||
!Array.isArray(type2bl[uLine.type].ssrcGroups)) {
|
||
type2bl[uLine.type].ssrcGroups = [];
|
||
}
|
||
|
||
type2bl[uLine.type].ssrcGroups =
|
||
type2bl[uLine.type].ssrcGroups.concat(
|
||
uLine.ssrcGroups);
|
||
}
|
||
|
||
if (type2bl[uLine.type] === uLine) {
|
||
// Plan B mids are in ['audio', 'video', 'data']
|
||
uLine.mid = uLine.type;
|
||
|
||
// Plan B doesn't support/need the bundle-only attribute.
|
||
delete uLine.bundleOnly;
|
||
|
||
// In Plan B the msid is an SSRC attribute.
|
||
delete uLine.msid;
|
||
|
||
if (uLine.type == media[0].type) {
|
||
types.unshift(uLine.type);
|
||
// Add the channel to the new media array.
|
||
session.media.unshift(uLine);
|
||
} else {
|
||
types.push(uLine.type);
|
||
// Add the channel to the new media array.
|
||
session.media.push(uLine);
|
||
}
|
||
}
|
||
});
|
||
|
||
if (typeof session.groups !== 'undefined') {
|
||
// We regenerate the BUNDLE group with the new mids.
|
||
session.groups.some(function(group) {
|
||
if (group.type === 'BUNDLE') {
|
||
group.mids = types.join(' ');
|
||
return true;
|
||
}
|
||
});
|
||
}
|
||
|
||
// msid semantic
|
||
session.msidSemantic = {
|
||
semantic: 'WMS',
|
||
token: '*'
|
||
};
|
||
|
||
var resStr = transform.write(session);
|
||
|
||
return new RTCSessionDescription({
|
||
type: desc.type,
|
||
sdp: resStr
|
||
});
|
||
|
||
//#endregion
|
||
};
|
||
|
||
/* follow rules defined in RFC4145 */
|
||
function addSetupAttr(uLine) {
|
||
if (typeof uLine.setup === 'undefined') {
|
||
return;
|
||
}
|
||
|
||
if (uLine.setup === "active") {
|
||
uLine.setup = "passive";
|
||
} else if (uLine.setup === "passive") {
|
||
uLine.setup = "active";
|
||
}
|
||
}
|
||
|
||
/**
|
||
* This method transforms a Plan B SDP to an equivalent Unified Plan SDP. A
|
||
* PeerConnection wrapper transforms the SDP to Unified Plan before passing it
|
||
* to FF.
|
||
*
|
||
* @param desc
|
||
* @returns {*}
|
||
*/
|
||
Interop.prototype.toUnifiedPlan = function(desc) {
|
||
var self = this;
|
||
//#region Preliminary input validation.
|
||
|
||
if (typeof desc !== 'object' || desc === null ||
|
||
typeof desc.sdp !== 'string') {
|
||
console.warn('An empty description was passed as an argument.');
|
||
return desc;
|
||
}
|
||
|
||
var session = transform.parse(desc.sdp);
|
||
|
||
// If the SDP contains no media, there's nothing to transform.
|
||
if (typeof session.media === 'undefined' ||
|
||
!Array.isArray(session.media) || session.media.length === 0) {
|
||
console.warn('The description has no media.');
|
||
return desc;
|
||
}
|
||
|
||
// Try some heuristics to "make sure" this is a Plan B SDP. Plan B SDP has
|
||
// a video, an audio and a data "channel" at most.
|
||
if (session.media.length > 3 || !session.media.every(function(m) {
|
||
return ['video', 'audio', 'data'].indexOf(m.mid) !== -1;
|
||
})) {
|
||
console.warn('This description does not look like Plan B.');
|
||
return desc;
|
||
}
|
||
|
||
// Make sure this Plan B SDP can be converted to a Unified Plan SDP.
|
||
var mids = [];
|
||
session.media.forEach(function(m) {
|
||
mids.push(m.mid);
|
||
});
|
||
|
||
var hasBundle = false;
|
||
if (typeof session.groups !== 'undefined' &&
|
||
Array.isArray(session.groups)) {
|
||
hasBundle = session.groups.every(function(g) {
|
||
return g.type !== 'BUNDLE' ||
|
||
arrayEquals.apply(g.mids.sort(), [mids.sort()]);
|
||
});
|
||
}
|
||
|
||
if (!hasBundle) {
|
||
var mustBeBundle = false;
|
||
|
||
session.media.forEach(function(m) {
|
||
if (m.direction !== 'inactive') {
|
||
mustBeBundle = true;
|
||
}
|
||
});
|
||
|
||
if (mustBeBundle) {
|
||
throw new Error("Cannot convert to Unified Plan because m-lines that" +
|
||
" are not bundled were found.");
|
||
}
|
||
}
|
||
|
||
//#endregion
|
||
|
||
|
||
//#region Convert from Plan B to Unified Plan.
|
||
|
||
// Unfortunately, a Plan B offer/answer doesn't have enough information to
|
||
// rebuild an equivalent Unified Plan offer/answer.
|
||
//
|
||
// For example, if this is a local answer (in Unified Plan style) that we
|
||
// convert to Plan B prior to handing it over to the application (the
|
||
// PeerConnection wrapper called us, for instance, after a successful
|
||
// createAnswer), we want to remember the m-line at which we've seen the
|
||
// (local) SSRC. That's because when the application wants to do call the
|
||
// SLD method, forcing us to do the inverse transformation (from Plan B to
|
||
// Unified Plan), we need to know to which m-line to assign the (local)
|
||
// SSRC. We also need to know all the other m-lines that the original
|
||
// answer had and include them in the transformed answer as well.
|
||
//
|
||
// Another example is if this is a remote offer that we convert to Plan B
|
||
// prior to giving it to the application, we want to remember the mid at
|
||
// which we've seen the (remote) SSRC.
|
||
//
|
||
// In the iteration that follows, we use the cached Unified Plan (if it
|
||
// exists) to assign mids to ssrcs.
|
||
|
||
var type;
|
||
if (desc.type === 'answer') {
|
||
type = 'offer';
|
||
} else if (desc.type === 'offer') {
|
||
type = 'answer';
|
||
} else {
|
||
throw new Error("Type '" + desc.type + "' not supported.");
|
||
}
|
||
|
||
var cached;
|
||
if (typeof this.cache[type] !== 'undefined') {
|
||
cached = transform.parse(this.cache[type]);
|
||
}
|
||
|
||
var recvonlySsrcs = {
|
||
audio: {},
|
||
video: {}
|
||
};
|
||
|
||
// A helper map that sends mids to m-line objects. We use it later to
|
||
// rebuild the Unified Plan style session.media array.
|
||
var mid2ul = {};
|
||
var bIdx = 0;
|
||
var uIdx = 0;
|
||
|
||
var sources2ul = {};
|
||
|
||
var candidates;
|
||
var iceUfrag;
|
||
var icePwd;
|
||
var fingerprint;
|
||
var payloads = {};
|
||
var rtcpFb = {};
|
||
var rtp = {};
|
||
|
||
session.media.forEach(function(bLine) {
|
||
if ((typeof bLine.rtcpMux !== 'string' ||
|
||
bLine.rtcpMux !== 'rtcp-mux') &&
|
||
bLine.direction !== 'inactive') {
|
||
throw new Error("Cannot convert to Unified Plan because m-lines " +
|
||
"without the rtcp-mux attribute were found.");
|
||
}
|
||
|
||
if (bLine.type === 'application') {
|
||
mid2ul[bLine.mid] = bLine;
|
||
return;
|
||
}
|
||
|
||
// With rtcp-mux and bundle all the channels should have the same ICE
|
||
// stuff.
|
||
var sources = bLine.sources;
|
||
var ssrcGroups = bLine.ssrcGroups;
|
||
var port = bLine.port;
|
||
|
||
/* Chrome adds different candidates even using bundle, so we concat the candidates list */
|
||
if (typeof bLine.candidates != 'undefined') {
|
||
if (typeof candidates != 'undefined') {
|
||
candidates = candidates.concat(bLine.candidates);
|
||
} else {
|
||
candidates = bLine.candidates;
|
||
}
|
||
}
|
||
|
||
if ((typeof iceUfrag != 'undefined') && (typeof bLine.iceUfrag != 'undefined') && (iceUfrag != bLine.iceUfrag)) {
|
||
throw new Error("Only BUNDLE supported, iceUfrag must be the same for all m-lines.\n" +
|
||
"\tLast iceUfrag: " + iceUfrag + "\n" +
|
||
"\tNew iceUfrag: " + bLine.iceUfrag
|
||
);
|
||
}
|
||
|
||
if (typeof bLine.iceUfrag != 'undefined') {
|
||
iceUfrag = bLine.iceUfrag;
|
||
}
|
||
|
||
if ((typeof icePwd != 'undefined') && (typeof bLine.icePwd != 'undefined') && (icePwd != bLine.icePwd)) {
|
||
throw new Error("Only BUNDLE supported, icePwd must be the same for all m-lines.\n" +
|
||
"\tLast icePwd: " + icePwd + "\n" +
|
||
"\tNew icePwd: " + bLine.icePwd
|
||
);
|
||
}
|
||
|
||
if (typeof bLine.icePwd != 'undefined') {
|
||
icePwd = bLine.icePwd;
|
||
}
|
||
|
||
if ((typeof fingerprint != 'undefined') && (typeof bLine.fingerprint != 'undefined') &&
|
||
(fingerprint.type != bLine.fingerprint.type || fingerprint.hash != bLine.fingerprint.hash)) {
|
||
throw new Error("Only BUNDLE supported, fingerprint must be the same for all m-lines.\n" +
|
||
"\tLast fingerprint: " + JSON.stringify(fingerprint) + "\n" +
|
||
"\tNew fingerprint: " + JSON.stringify(bLine.fingerprint)
|
||
);
|
||
}
|
||
|
||
if (typeof bLine.fingerprint != 'undefined') {
|
||
fingerprint = bLine.fingerprint;
|
||
}
|
||
|
||
payloads[bLine.type] = bLine.payloads;
|
||
rtcpFb[bLine.type] = bLine.rtcpFb;
|
||
rtp[bLine.type] = bLine.rtp;
|
||
|
||
// inverted ssrc group map
|
||
var ssrc2group = {};
|
||
if (typeof ssrcGroups !== 'undefined' && Array.isArray(ssrcGroups)) {
|
||
ssrcGroups.forEach(function (ssrcGroup) {
|
||
// XXX This might brake if an SSRC is in more than one group
|
||
// for some reason.
|
||
if (typeof ssrcGroup.ssrcs !== 'undefined' &&
|
||
Array.isArray(ssrcGroup.ssrcs)) {
|
||
ssrcGroup.ssrcs.forEach(function (ssrc) {
|
||
if (typeof ssrc2group[ssrc] === 'undefined') {
|
||
ssrc2group[ssrc] = [];
|
||
}
|
||
|
||
ssrc2group[ssrc].push(ssrcGroup);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
// ssrc to m-line index.
|
||
var ssrc2ml = {};
|
||
|
||
if (typeof sources === 'object') {
|
||
|
||
// We'll use the "bLine" object as a prototype for each new "mLine"
|
||
// that we create, but first we need to clean it up a bit.
|
||
delete bLine.sources;
|
||
delete bLine.ssrcGroups;
|
||
delete bLine.candidates;
|
||
delete bLine.iceUfrag;
|
||
delete bLine.icePwd;
|
||
delete bLine.fingerprint;
|
||
delete bLine.port;
|
||
delete bLine.mid;
|
||
|
||
// Explode the Plan B channel sources with one m-line per source.
|
||
Object.keys(sources).forEach(function(ssrc) {
|
||
|
||
// The (unified) m-line for this SSRC. We either create it from
|
||
// scratch or, if it's a grouped SSRC, we re-use a related
|
||
// mline. In other words, if the source is grouped with another
|
||
// source, put the two together in the same m-line.
|
||
var uLine;
|
||
|
||
// We assume here that we are the answerer in the O/A, so any
|
||
// offers which we translate come from the remote side, while
|
||
// answers are local. So the check below is to make that we
|
||
// handle receive-only SSRCs in a special way only if they come
|
||
// from the remote side.
|
||
if (desc.type==='offer') {
|
||
// We want to detect SSRCs which are used by a remote peer
|
||
// in an m-line with direction=recvonly (i.e. they are
|
||
// being used for RTCP only).
|
||
// This information would have gotten lost if the remote
|
||
// peer used Unified Plan and their local description was
|
||
// translated to Plan B. So we use the lack of an MSID
|
||
// attribute to deduce a "receive only" SSRC.
|
||
if (!sources[ssrc].msid) {
|
||
recvonlySsrcs[bLine.type][ssrc] = sources[ssrc];
|
||
// Receive-only SSRCs must not create new m-lines. We
|
||
// will assign them to an existing m-line later.
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (typeof ssrc2group[ssrc] !== 'undefined' &&
|
||
Array.isArray(ssrc2group[ssrc])) {
|
||
ssrc2group[ssrc].some(function (ssrcGroup) {
|
||
// ssrcGroup.ssrcs *is* an Array, no need to check
|
||
// again here.
|
||
return ssrcGroup.ssrcs.some(function (related) {
|
||
if (typeof ssrc2ml[related] === 'object') {
|
||
uLine = ssrc2ml[related];
|
||
return true;
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
if (typeof uLine === 'object') {
|
||
// the m-line already exists. Just add the source.
|
||
uLine.sources[ssrc] = sources[ssrc];
|
||
delete sources[ssrc].msid;
|
||
} else {
|
||
// Use the "bLine" as a prototype for the "uLine".
|
||
uLine = Object.create(bLine);
|
||
ssrc2ml[ssrc] = uLine;
|
||
|
||
if (typeof sources[ssrc].msid !== 'undefined') {
|
||
// Assign the msid of the source to the m-line. Note
|
||
// that it is not guaranteed that the source will have
|
||
// msid. In particular "recvonly" sources don't have an
|
||
// msid. Note that "recvonly" is a term only defined
|
||
// for m-lines.
|
||
uLine.msid = sources[ssrc].msid;
|
||
delete sources[ssrc].msid;
|
||
}
|
||
|
||
// We assign one SSRC per media line.
|
||
uLine.sources = {};
|
||
uLine.sources[ssrc] = sources[ssrc];
|
||
uLine.ssrcGroups = ssrc2group[ssrc];
|
||
|
||
// Use the cached Unified Plan SDP (if it exists) to assign
|
||
// SSRCs to mids.
|
||
if (typeof cached !== 'undefined' &&
|
||
typeof cached.media !== 'undefined' &&
|
||
Array.isArray(cached.media)) {
|
||
|
||
cached.media.forEach(function (m) {
|
||
if (typeof m.sources === 'object') {
|
||
Object.keys(m.sources).forEach(function (s) {
|
||
if (s === ssrc) {
|
||
uLine.mid = m.mid;
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
if (typeof uLine.mid === 'undefined') {
|
||
|
||
// If this is an SSRC that we see for the first time
|
||
// assign it a new mid. This is typically the case when
|
||
// this method is called to transform a remote
|
||
// description for the first time or when there is a
|
||
// new SSRC in the remote description because a new
|
||
// peer has joined the conference. Local SSRCs should
|
||
// have already been added to the map in the toPlanB
|
||
// method.
|
||
//
|
||
// Because FF generates answers in Unified Plan style,
|
||
// we MUST already have a cached answer with all the
|
||
// local SSRCs mapped to some m-line/mid.
|
||
|
||
uLine.mid = [bLine.type, '-', ssrc].join('');
|
||
}
|
||
|
||
// Include the candidates in the 1st media line.
|
||
uLine.candidates = candidates;
|
||
uLine.iceUfrag = iceUfrag;
|
||
uLine.icePwd = icePwd;
|
||
uLine.fingerprint = fingerprint;
|
||
uLine.port = port;
|
||
|
||
mid2ul[uLine.mid] = uLine;
|
||
sources2ul[uIdx] = uLine.sources;
|
||
|
||
self.cache.mlU2BMap[uIdx] = bIdx;
|
||
if (typeof self.cache.mlB2UMap[bIdx] === 'undefined') {
|
||
self.cache.mlB2UMap[bIdx] = uIdx;
|
||
}
|
||
uIdx++;
|
||
}
|
||
});
|
||
} else {
|
||
var uLine = bLine;
|
||
|
||
uLine.candidates = candidates;
|
||
uLine.iceUfrag = iceUfrag;
|
||
uLine.icePwd = icePwd;
|
||
uLine.fingerprint = fingerprint;
|
||
uLine.port = port;
|
||
|
||
mid2ul[uLine.mid] = uLine;
|
||
|
||
self.cache.mlU2BMap[uIdx] = bIdx;
|
||
if (typeof self.cache.mlB2UMap[bIdx] === 'undefined') {
|
||
self.cache.mlB2UMap[bIdx] = uIdx;
|
||
}
|
||
}
|
||
|
||
bIdx++;
|
||
});
|
||
|
||
// Rebuild the media array in the right order and add the missing mLines
|
||
// (missing from the Plan B SDP).
|
||
session.media = [];
|
||
mids = []; // reuse
|
||
|
||
if (desc.type === 'answer') {
|
||
|
||
// The media lines in the answer must match the media lines in the
|
||
// offer. The order is important too. Here we assume that Firefox is
|
||
// the answerer, so we merely have to use the reconstructed (unified)
|
||
// answer to update the cached (unified) answer accordingly.
|
||
//
|
||
// In the general case, one would have to use the cached (unified)
|
||
// offer to find the m-lines that are missing from the reconstructed
|
||
// answer, potentially grabbing them from the cached (unified) answer.
|
||
// One has to be careful with this approach because inactive m-lines do
|
||
// not always have an mid, making it tricky (impossible?) to find where
|
||
// exactly and which m-lines are missing from the reconstructed answer.
|
||
|
||
for (var i = 0; i < cached.media.length; i++) {
|
||
var uLine = cached.media[i];
|
||
|
||
delete uLine.msid;
|
||
delete uLine.sources;
|
||
delete uLine.ssrcGroups;
|
||
|
||
if (typeof sources2ul[i] === 'undefined') {
|
||
if (!uLine.direction
|
||
|| uLine.direction === 'sendrecv')
|
||
uLine.direction = 'recvonly';
|
||
else if (uLine.direction === 'sendonly')
|
||
uLine.direction = 'inactive';
|
||
} else {
|
||
if (!uLine.direction
|
||
|| uLine.direction === 'sendrecv')
|
||
uLine.direction = 'sendrecv';
|
||
else if (uLine.direction === 'recvonly')
|
||
uLine.direction = 'sendonly';
|
||
}
|
||
|
||
uLine.sources = sources2ul[i];
|
||
uLine.candidates = candidates;
|
||
uLine.iceUfrag = iceUfrag;
|
||
uLine.icePwd = icePwd;
|
||
uLine.fingerprint = fingerprint;
|
||
|
||
uLine.rtp = rtp[uLine.type];
|
||
uLine.payloads = payloads[uLine.type];
|
||
uLine.rtcpFb = rtcpFb[uLine.type];
|
||
|
||
session.media.push(uLine);
|
||
|
||
if (typeof uLine.mid === 'string') {
|
||
// inactive lines don't/may not have an mid.
|
||
mids.push(uLine.mid);
|
||
}
|
||
}
|
||
} else {
|
||
|
||
// SDP offer/answer (and the JSEP spec) forbids removing an m-section
|
||
// under any circumstances. If we are no longer interested in sending a
|
||
// track, we just remove the msid and ssrc attributes and set it to
|
||
// either a=recvonly (as the reofferer, we must use recvonly if the
|
||
// other side was previously sending on the m-section, but we can also
|
||
// leave the possibility open if it wasn't previously in use), or
|
||
// a=inactive.
|
||
|
||
if (typeof cached !== 'undefined' &&
|
||
typeof cached.media !== 'undefined' &&
|
||
Array.isArray(cached.media)) {
|
||
cached.media.forEach(function(uLine) {
|
||
mids.push(uLine.mid);
|
||
if (typeof mid2ul[uLine.mid] !== 'undefined') {
|
||
session.media.push(mid2ul[uLine.mid]);
|
||
} else {
|
||
delete uLine.msid;
|
||
delete uLine.sources;
|
||
delete uLine.ssrcGroups;
|
||
|
||
if (!uLine.direction
|
||
|| uLine.direction === 'sendrecv') {
|
||
uLine.direction = 'sendonly';
|
||
}
|
||
if (!uLine.direction
|
||
|| uLine.direction === 'recvonly') {
|
||
uLine.direction = 'inactive';
|
||
}
|
||
|
||
addSetupAttr (uLine);
|
||
session.media.push(uLine);
|
||
}
|
||
});
|
||
}
|
||
|
||
// Add all the remaining (new) m-lines of the transformed SDP.
|
||
Object.keys(mid2ul).forEach(function(mid) {
|
||
if (mids.indexOf(mid) === -1) {
|
||
mids.push(mid);
|
||
if (mid2ul[mid].direction === 'recvonly') {
|
||
// This is a remote recvonly channel. Add its SSRC to the
|
||
// appropriate sendrecv or sendonly channel.
|
||
// TODO(gp) what if we don't have sendrecv/sendonly
|
||
// channel?
|
||
|
||
var done = false;
|
||
|
||
session.media.some(function (uLine) {
|
||
if ((uLine.direction === 'sendrecv' ||
|
||
uLine.direction === 'sendonly') &&
|
||
uLine.type === mid2ul[mid].type) {
|
||
// mid2ul[mid] shouldn't have any ssrc-groups
|
||
Object.keys(mid2ul[mid].sources).forEach(
|
||
function (ssrc) {
|
||
uLine.sources[ssrc] =
|
||
mid2ul[mid].sources[ssrc];
|
||
});
|
||
|
||
done = true;
|
||
return true;
|
||
}
|
||
});
|
||
|
||
if (!done) {
|
||
session.media.push(mid2ul[mid]);
|
||
}
|
||
} else {
|
||
session.media.push(mid2ul[mid]);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
// After we have constructed the Plan Unified m-lines we can figure out
|
||
// where (in which m-line) to place the 'recvonly SSRCs'.
|
||
// Note: we assume here that we are the answerer in the O/A, so any offers
|
||
// which we translate come from the remote side, while answers are local
|
||
// (and so our last local description is cached as an 'answer').
|
||
["audio", "video"].forEach(function (type) {
|
||
if (!session || !session.media || !Array.isArray(session.media))
|
||
return;
|
||
|
||
var idx = null;
|
||
if (Object.keys(recvonlySsrcs[type]).length > 0) {
|
||
idx = self.getFirstSendingIndexFromAnswer(type);
|
||
if (idx === null){
|
||
// If this is the first offer we receive, we don't have a
|
||
// cached answer. Assume that we will be sending media using
|
||
// the first m-line for each media type.
|
||
|
||
for (var i = 0; i < session.media.length; i++) {
|
||
if (session.media[i].type === type) {
|
||
idx = i;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (idx && session.media.length > idx) {
|
||
var mLine = session.media[idx];
|
||
Object.keys(recvonlySsrcs[type]).forEach(function(ssrc) {
|
||
if (mLine.sources && mLine.sources[ssrc]) {
|
||
console.warn("Replacing an existing SSRC.");
|
||
}
|
||
if (!mLine.sources) {
|
||
mLine.sources = {};
|
||
}
|
||
|
||
mLine.sources[ssrc] = recvonlySsrcs[type][ssrc];
|
||
});
|
||
}
|
||
});
|
||
|
||
if (typeof session.groups !== 'undefined') {
|
||
// We regenerate the BUNDLE group (since we regenerated the mids)
|
||
session.groups.some(function(group) {
|
||
if (group.type === 'BUNDLE') {
|
||
group.mids = mids.join(' ');
|
||
return true;
|
||
}
|
||
});
|
||
}
|
||
|
||
// msid semantic
|
||
session.msidSemantic = {
|
||
semantic: 'WMS',
|
||
token: '*'
|
||
};
|
||
|
||
var resStr = transform.write(session);
|
||
|
||
// Cache the transformed SDP (Unified Plan) for later re-use in this
|
||
// function.
|
||
this.cache[desc.type] = resStr;
|
||
|
||
return new RTCSessionDescription({
|
||
type: desc.type,
|
||
sdp: resStr
|
||
});
|
||
|
||
//#endregion
|
||
};
|
||
|
||
},{"./array-equals":28,"./transform":31}],31:[function(require,module,exports){
|
||
/* Copyright @ 2015 Atlassian Pty Ltd
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
var transform = require('sdp-transform');
|
||
|
||
exports.write = function(session, opts) {
|
||
|
||
if (typeof session !== 'undefined' &&
|
||
typeof session.media !== 'undefined' &&
|
||
Array.isArray(session.media)) {
|
||
|
||
session.media.forEach(function (mLine) {
|
||
// expand sources to ssrcs
|
||
if (typeof mLine.sources !== 'undefined' &&
|
||
Object.keys(mLine.sources).length !== 0) {
|
||
mLine.ssrcs = [];
|
||
Object.keys(mLine.sources).forEach(function (ssrc) {
|
||
var source = mLine.sources[ssrc];
|
||
Object.keys(source).forEach(function (attribute) {
|
||
mLine.ssrcs.push({
|
||
id: ssrc,
|
||
attribute: attribute,
|
||
value: source[attribute]
|
||
});
|
||
});
|
||
});
|
||
delete mLine.sources;
|
||
}
|
||
|
||
// join ssrcs in ssrc groups
|
||
if (typeof mLine.ssrcGroups !== 'undefined' &&
|
||
Array.isArray(mLine.ssrcGroups)) {
|
||
mLine.ssrcGroups.forEach(function (ssrcGroup) {
|
||
if (typeof ssrcGroup.ssrcs !== 'undefined' &&
|
||
Array.isArray(ssrcGroup.ssrcs)) {
|
||
ssrcGroup.ssrcs = ssrcGroup.ssrcs.join(' ');
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
// join group mids
|
||
if (typeof session !== 'undefined' &&
|
||
typeof session.groups !== 'undefined' && Array.isArray(session.groups)) {
|
||
|
||
session.groups.forEach(function (g) {
|
||
if (typeof g.mids !== 'undefined' && Array.isArray(g.mids)) {
|
||
g.mids = g.mids.join(' ');
|
||
}
|
||
});
|
||
}
|
||
|
||
return transform.write(session, opts);
|
||
};
|
||
|
||
exports.parse = function(sdp) {
|
||
var session = transform.parse(sdp);
|
||
|
||
if (typeof session !== 'undefined' && typeof session.media !== 'undefined' &&
|
||
Array.isArray(session.media)) {
|
||
|
||
session.media.forEach(function (mLine) {
|
||
// group sources attributes by ssrc
|
||
if (typeof mLine.ssrcs !== 'undefined' && Array.isArray(mLine.ssrcs)) {
|
||
mLine.sources = {};
|
||
mLine.ssrcs.forEach(function (ssrc) {
|
||
if (!mLine.sources[ssrc.id])
|
||
mLine.sources[ssrc.id] = {};
|
||
mLine.sources[ssrc.id][ssrc.attribute] = ssrc.value;
|
||
});
|
||
|
||
delete mLine.ssrcs;
|
||
}
|
||
|
||
// split ssrcs in ssrc groups
|
||
if (typeof mLine.ssrcGroups !== 'undefined' &&
|
||
Array.isArray(mLine.ssrcGroups)) {
|
||
mLine.ssrcGroups.forEach(function (ssrcGroup) {
|
||
if (typeof ssrcGroup.ssrcs === 'string') {
|
||
ssrcGroup.ssrcs = ssrcGroup.ssrcs.split(' ');
|
||
}
|
||
});
|
||
}
|
||
});
|
||
}
|
||
// split group mids
|
||
if (typeof session !== 'undefined' &&
|
||
typeof session.groups !== 'undefined' && Array.isArray(session.groups)) {
|
||
|
||
session.groups.forEach(function (g) {
|
||
if (typeof g.mids === 'string') {
|
||
g.mids = g.mids.split(' ');
|
||
}
|
||
});
|
||
}
|
||
|
||
return session;
|
||
};
|
||
|
||
|
||
},{"sdp-transform":25}],32:[function(require,module,exports){
|
||
/* eslint-env node */
|
||
'use strict';
|
||
|
||
// SDP helpers.
|
||
var SDPUtils = {};
|
||
|
||
// Generate an alphanumeric identifier for cname or mids.
|
||
// TODO: use UUIDs instead? https://gist.github.com/jed/982883
|
||
SDPUtils.generateIdentifier = function() {
|
||
return Math.random().toString(36).substr(2, 10);
|
||
};
|
||
|
||
// The RTCP CNAME used by all peerconnections from the same JS.
|
||
SDPUtils.localCName = SDPUtils.generateIdentifier();
|
||
|
||
// Splits SDP into lines, dealing with both CRLF and LF.
|
||
SDPUtils.splitLines = function(blob) {
|
||
return blob.trim().split('\n').map(function(line) {
|
||
return line.trim();
|
||
});
|
||
};
|
||
// Splits SDP into sessionpart and mediasections. Ensures CRLF.
|
||
SDPUtils.splitSections = function(blob) {
|
||
var parts = blob.split('\nm=');
|
||
return parts.map(function(part, index) {
|
||
return (index > 0 ? 'm=' + part : part).trim() + '\r\n';
|
||
});
|
||
};
|
||
|
||
// Returns lines that start with a certain prefix.
|
||
SDPUtils.matchPrefix = function(blob, prefix) {
|
||
return SDPUtils.splitLines(blob).filter(function(line) {
|
||
return line.indexOf(prefix) === 0;
|
||
});
|
||
};
|
||
|
||
// Parses an ICE candidate line. Sample input:
|
||
// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8
|
||
// rport 55996"
|
||
SDPUtils.parseCandidate = function(line) {
|
||
var parts;
|
||
// Parse both variants.
|
||
if (line.indexOf('a=candidate:') === 0) {
|
||
parts = line.substring(12).split(' ');
|
||
} else {
|
||
parts = line.substring(10).split(' ');
|
||
}
|
||
|
||
var candidate = {
|
||
foundation: parts[0],
|
||
component: parts[1],
|
||
protocol: parts[2].toLowerCase(),
|
||
priority: parseInt(parts[3], 10),
|
||
ip: parts[4],
|
||
port: parseInt(parts[5], 10),
|
||
// skip parts[6] == 'typ'
|
||
type: parts[7]
|
||
};
|
||
|
||
for (var i = 8; i < parts.length; i += 2) {
|
||
switch (parts[i]) {
|
||
case 'raddr':
|
||
candidate.relatedAddress = parts[i + 1];
|
||
break;
|
||
case 'rport':
|
||
candidate.relatedPort = parseInt(parts[i + 1], 10);
|
||
break;
|
||
case 'tcptype':
|
||
candidate.tcpType = parts[i + 1];
|
||
break;
|
||
default: // extension handling, in particular ufrag
|
||
candidate[parts[i]] = parts[i + 1];
|
||
break;
|
||
}
|
||
}
|
||
return candidate;
|
||
};
|
||
|
||
// Translates a candidate object into SDP candidate attribute.
|
||
SDPUtils.writeCandidate = function(candidate) {
|
||
var sdp = [];
|
||
sdp.push(candidate.foundation);
|
||
sdp.push(candidate.component);
|
||
sdp.push(candidate.protocol.toUpperCase());
|
||
sdp.push(candidate.priority);
|
||
sdp.push(candidate.ip);
|
||
sdp.push(candidate.port);
|
||
|
||
var type = candidate.type;
|
||
sdp.push('typ');
|
||
sdp.push(type);
|
||
if (type !== 'host' && candidate.relatedAddress &&
|
||
candidate.relatedPort) {
|
||
sdp.push('raddr');
|
||
sdp.push(candidate.relatedAddress); // was: relAddr
|
||
sdp.push('rport');
|
||
sdp.push(candidate.relatedPort); // was: relPort
|
||
}
|
||
if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {
|
||
sdp.push('tcptype');
|
||
sdp.push(candidate.tcpType);
|
||
}
|
||
return 'candidate:' + sdp.join(' ');
|
||
};
|
||
|
||
// Parses an ice-options line, returns an array of option tags.
|
||
// a=ice-options:foo bar
|
||
SDPUtils.parseIceOptions = function(line) {
|
||
return line.substr(14).split(' ');
|
||
}
|
||
|
||
// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input:
|
||
// a=rtpmap:111 opus/48000/2
|
||
SDPUtils.parseRtpMap = function(line) {
|
||
var parts = line.substr(9).split(' ');
|
||
var parsed = {
|
||
payloadType: parseInt(parts.shift(), 10) // was: id
|
||
};
|
||
|
||
parts = parts[0].split('/');
|
||
|
||
parsed.name = parts[0];
|
||
parsed.clockRate = parseInt(parts[1], 10); // was: clockrate
|
||
// was: channels
|
||
parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1;
|
||
return parsed;
|
||
};
|
||
|
||
// Generate an a=rtpmap line from RTCRtpCodecCapability or
|
||
// RTCRtpCodecParameters.
|
||
SDPUtils.writeRtpMap = function(codec) {
|
||
var pt = codec.payloadType;
|
||
if (codec.preferredPayloadType !== undefined) {
|
||
pt = codec.preferredPayloadType;
|
||
}
|
||
return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +
|
||
(codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n';
|
||
};
|
||
|
||
// Parses an a=extmap line (headerextension from RFC 5285). Sample input:
|
||
// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
|
||
// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset
|
||
SDPUtils.parseExtmap = function(line) {
|
||
var parts = line.substr(9).split(' ');
|
||
return {
|
||
id: parseInt(parts[0], 10),
|
||
direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv',
|
||
uri: parts[1]
|
||
};
|
||
};
|
||
|
||
// Generates a=extmap line from RTCRtpHeaderExtensionParameters or
|
||
// RTCRtpHeaderExtension.
|
||
SDPUtils.writeExtmap = function(headerExtension) {
|
||
return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) +
|
||
(headerExtension.direction && headerExtension.direction !== 'sendrecv'
|
||
? '/' + headerExtension.direction
|
||
: '') +
|
||
' ' + headerExtension.uri + '\r\n';
|
||
};
|
||
|
||
// Parses an ftmp line, returns dictionary. Sample input:
|
||
// a=fmtp:96 vbr=on;cng=on
|
||
// Also deals with vbr=on; cng=on
|
||
SDPUtils.parseFmtp = function(line) {
|
||
var parsed = {};
|
||
var kv;
|
||
var parts = line.substr(line.indexOf(' ') + 1).split(';');
|
||
for (var j = 0; j < parts.length; j++) {
|
||
kv = parts[j].trim().split('=');
|
||
parsed[kv[0].trim()] = kv[1];
|
||
}
|
||
return parsed;
|
||
};
|
||
|
||
// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters.
|
||
SDPUtils.writeFmtp = function(codec) {
|
||
var line = '';
|
||
var pt = codec.payloadType;
|
||
if (codec.preferredPayloadType !== undefined) {
|
||
pt = codec.preferredPayloadType;
|
||
}
|
||
if (codec.parameters && Object.keys(codec.parameters).length) {
|
||
var params = [];
|
||
Object.keys(codec.parameters).forEach(function(param) {
|
||
params.push(param + '=' + codec.parameters[param]);
|
||
});
|
||
line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n';
|
||
}
|
||
return line;
|
||
};
|
||
|
||
// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:
|
||
// a=rtcp-fb:98 nack rpsi
|
||
SDPUtils.parseRtcpFb = function(line) {
|
||
var parts = line.substr(line.indexOf(' ') + 1).split(' ');
|
||
return {
|
||
type: parts.shift(),
|
||
parameter: parts.join(' ')
|
||
};
|
||
};
|
||
// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.
|
||
SDPUtils.writeRtcpFb = function(codec) {
|
||
var lines = '';
|
||
var pt = codec.payloadType;
|
||
if (codec.preferredPayloadType !== undefined) {
|
||
pt = codec.preferredPayloadType;
|
||
}
|
||
if (codec.rtcpFeedback && codec.rtcpFeedback.length) {
|
||
// FIXME: special handling for trr-int?
|
||
codec.rtcpFeedback.forEach(function(fb) {
|
||
lines += 'a=rtcp-fb:' + pt + ' ' + fb.type +
|
||
(fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') +
|
||
'\r\n';
|
||
});
|
||
}
|
||
return lines;
|
||
};
|
||
|
||
// Parses an RFC 5576 ssrc media attribute. Sample input:
|
||
// a=ssrc:3735928559 cname:something
|
||
SDPUtils.parseSsrcMedia = function(line) {
|
||
var sp = line.indexOf(' ');
|
||
var parts = {
|
||
ssrc: parseInt(line.substr(7, sp - 7), 10)
|
||
};
|
||
var colon = line.indexOf(':', sp);
|
||
if (colon > -1) {
|
||
parts.attribute = line.substr(sp + 1, colon - sp - 1);
|
||
parts.value = line.substr(colon + 1);
|
||
} else {
|
||
parts.attribute = line.substr(sp + 1);
|
||
}
|
||
return parts;
|
||
};
|
||
|
||
// Extracts the MID (RFC 5888) from a media section.
|
||
// returns the MID or undefined if no mid line was found.
|
||
SDPUtils.getMid = function(mediaSection) {
|
||
var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0];
|
||
if (mid) {
|
||
return mid.substr(6);
|
||
}
|
||
}
|
||
|
||
SDPUtils.parseFingerprint = function(line) {
|
||
var parts = line.substr(14).split(' ');
|
||
return {
|
||
algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge.
|
||
value: parts[1]
|
||
};
|
||
};
|
||
|
||
// Extracts DTLS parameters from SDP media section or sessionpart.
|
||
// FIXME: for consistency with other functions this should only
|
||
// get the fingerprint line as input. See also getIceParameters.
|
||
SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {
|
||
var lines = SDPUtils.matchPrefix(mediaSection + sessionpart,
|
||
'a=fingerprint:');
|
||
// Note: a=setup line is ignored since we use the 'auto' role.
|
||
// Note2: 'algorithm' is not case sensitive except in Edge.
|
||
return {
|
||
role: 'auto',
|
||
fingerprints: lines.map(SDPUtils.parseFingerprint)
|
||
};
|
||
};
|
||
|
||
// Serializes DTLS parameters to SDP.
|
||
SDPUtils.writeDtlsParameters = function(params, setupType) {
|
||
var sdp = 'a=setup:' + setupType + '\r\n';
|
||
params.fingerprints.forEach(function(fp) {
|
||
sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n';
|
||
});
|
||
return sdp;
|
||
};
|
||
// Parses ICE information from SDP media section or sessionpart.
|
||
// FIXME: for consistency with other functions this should only
|
||
// get the ice-ufrag and ice-pwd lines as input.
|
||
SDPUtils.getIceParameters = function(mediaSection, sessionpart) {
|
||
var lines = SDPUtils.splitLines(mediaSection);
|
||
// Search in session part, too.
|
||
lines = lines.concat(SDPUtils.splitLines(sessionpart));
|
||
var iceParameters = {
|
||
usernameFragment: lines.filter(function(line) {
|
||
return line.indexOf('a=ice-ufrag:') === 0;
|
||
})[0].substr(12),
|
||
password: lines.filter(function(line) {
|
||
return line.indexOf('a=ice-pwd:') === 0;
|
||
})[0].substr(10)
|
||
};
|
||
return iceParameters;
|
||
};
|
||
|
||
// Serializes ICE parameters to SDP.
|
||
SDPUtils.writeIceParameters = function(params) {
|
||
return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' +
|
||
'a=ice-pwd:' + params.password + '\r\n';
|
||
};
|
||
|
||
// Parses the SDP media section and returns RTCRtpParameters.
|
||
SDPUtils.parseRtpParameters = function(mediaSection) {
|
||
var description = {
|
||
codecs: [],
|
||
headerExtensions: [],
|
||
fecMechanisms: [],
|
||
rtcp: []
|
||
};
|
||
var lines = SDPUtils.splitLines(mediaSection);
|
||
var mline = lines[0].split(' ');
|
||
for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..]
|
||
var pt = mline[i];
|
||
var rtpmapline = SDPUtils.matchPrefix(
|
||
mediaSection, 'a=rtpmap:' + pt + ' ')[0];
|
||
if (rtpmapline) {
|
||
var codec = SDPUtils.parseRtpMap(rtpmapline);
|
||
var fmtps = SDPUtils.matchPrefix(
|
||
mediaSection, 'a=fmtp:' + pt + ' ');
|
||
// Only the first a=fmtp:<pt> is considered.
|
||
codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};
|
||
codec.rtcpFeedback = SDPUtils.matchPrefix(
|
||
mediaSection, 'a=rtcp-fb:' + pt + ' ')
|
||
.map(SDPUtils.parseRtcpFb);
|
||
description.codecs.push(codec);
|
||
// parse FEC mechanisms from rtpmap lines.
|
||
switch (codec.name.toUpperCase()) {
|
||
case 'RED':
|
||
case 'ULPFEC':
|
||
description.fecMechanisms.push(codec.name.toUpperCase());
|
||
break;
|
||
default: // only RED and ULPFEC are recognized as FEC mechanisms.
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) {
|
||
description.headerExtensions.push(SDPUtils.parseExtmap(line));
|
||
});
|
||
// FIXME: parse rtcp.
|
||
return description;
|
||
};
|
||
|
||
// Generates parts of the SDP media section describing the capabilities /
|
||
// parameters.
|
||
SDPUtils.writeRtpDescription = function(kind, caps) {
|
||
var sdp = '';
|
||
|
||
// Build the mline.
|
||
sdp += 'm=' + kind + ' ';
|
||
sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.
|
||
sdp += ' UDP/TLS/RTP/SAVPF ';
|
||
sdp += caps.codecs.map(function(codec) {
|
||
if (codec.preferredPayloadType !== undefined) {
|
||
return codec.preferredPayloadType;
|
||
}
|
||
return codec.payloadType;
|
||
}).join(' ') + '\r\n';
|
||
|
||
sdp += 'c=IN IP4 0.0.0.0\r\n';
|
||
sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n';
|
||
|
||
// Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.
|
||
caps.codecs.forEach(function(codec) {
|
||
sdp += SDPUtils.writeRtpMap(codec);
|
||
sdp += SDPUtils.writeFmtp(codec);
|
||
sdp += SDPUtils.writeRtcpFb(codec);
|
||
});
|
||
var maxptime = 0;
|
||
caps.codecs.forEach(function(codec) {
|
||
if (codec.maxptime > maxptime) {
|
||
maxptime = codec.maxptime;
|
||
}
|
||
});
|
||
if (maxptime > 0) {
|
||
sdp += 'a=maxptime:' + maxptime + '\r\n';
|
||
}
|
||
sdp += 'a=rtcp-mux\r\n';
|
||
|
||
caps.headerExtensions.forEach(function(extension) {
|
||
sdp += SDPUtils.writeExtmap(extension);
|
||
});
|
||
// FIXME: write fecMechanisms.
|
||
return sdp;
|
||
};
|
||
|
||
// Parses the SDP media section and returns an array of
|
||
// RTCRtpEncodingParameters.
|
||
SDPUtils.parseRtpEncodingParameters = function(mediaSection) {
|
||
var encodingParameters = [];
|
||
var description = SDPUtils.parseRtpParameters(mediaSection);
|
||
var hasRed = description.fecMechanisms.indexOf('RED') !== -1;
|
||
var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;
|
||
|
||
// filter a=ssrc:... cname:, ignore PlanB-msid
|
||
var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
|
||
.map(function(line) {
|
||
return SDPUtils.parseSsrcMedia(line);
|
||
})
|
||
.filter(function(parts) {
|
||
return parts.attribute === 'cname';
|
||
});
|
||
var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;
|
||
var secondarySsrc;
|
||
|
||
var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')
|
||
.map(function(line) {
|
||
var parts = line.split(' ');
|
||
parts.shift();
|
||
return parts.map(function(part) {
|
||
return parseInt(part, 10);
|
||
});
|
||
});
|
||
if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {
|
||
secondarySsrc = flows[0][1];
|
||
}
|
||
|
||
description.codecs.forEach(function(codec) {
|
||
if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {
|
||
var encParam = {
|
||
ssrc: primarySsrc,
|
||
codecPayloadType: parseInt(codec.parameters.apt, 10),
|
||
rtx: {
|
||
ssrc: secondarySsrc
|
||
}
|
||
};
|
||
encodingParameters.push(encParam);
|
||
if (hasRed) {
|
||
encParam = JSON.parse(JSON.stringify(encParam));
|
||
encParam.fec = {
|
||
ssrc: secondarySsrc,
|
||
mechanism: hasUlpfec ? 'red+ulpfec' : 'red'
|
||
};
|
||
encodingParameters.push(encParam);
|
||
}
|
||
}
|
||
});
|
||
if (encodingParameters.length === 0 && primarySsrc) {
|
||
encodingParameters.push({
|
||
ssrc: primarySsrc
|
||
});
|
||
}
|
||
|
||
// we support both b=AS and b=TIAS but interpret AS as TIAS.
|
||
var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');
|
||
if (bandwidth.length) {
|
||
if (bandwidth[0].indexOf('b=TIAS:') === 0) {
|
||
bandwidth = parseInt(bandwidth[0].substr(7), 10);
|
||
} else if (bandwidth[0].indexOf('b=AS:') === 0) {
|
||
bandwidth = parseInt(bandwidth[0].substr(5), 10);
|
||
}
|
||
encodingParameters.forEach(function(params) {
|
||
params.maxBitrate = bandwidth;
|
||
});
|
||
}
|
||
return encodingParameters;
|
||
};
|
||
|
||
// parses http://draft.ortc.org/#rtcrtcpparameters*
|
||
SDPUtils.parseRtcpParameters = function(mediaSection) {
|
||
var rtcpParameters = {};
|
||
|
||
var cname;
|
||
// Gets the first SSRC. Note that with RTX there might be multiple
|
||
// SSRCs.
|
||
var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
|
||
.map(function(line) {
|
||
return SDPUtils.parseSsrcMedia(line);
|
||
})
|
||
.filter(function(obj) {
|
||
return obj.attribute === 'cname';
|
||
})[0];
|
||
if (remoteSsrc) {
|
||
rtcpParameters.cname = remoteSsrc.value;
|
||
rtcpParameters.ssrc = remoteSsrc.ssrc;
|
||
}
|
||
|
||
// Edge uses the compound attribute instead of reducedSize
|
||
// compound is !reducedSize
|
||
var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize');
|
||
rtcpParameters.reducedSize = rsize.length > 0;
|
||
rtcpParameters.compound = rsize.length === 0;
|
||
|
||
// parses the rtcp-mux attrіbute.
|
||
// Note that Edge does not support unmuxed RTCP.
|
||
var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux');
|
||
rtcpParameters.mux = mux.length > 0;
|
||
|
||
return rtcpParameters;
|
||
};
|
||
|
||
// parses either a=msid: or a=ssrc:... msid lines and returns
|
||
// the id of the MediaStream and MediaStreamTrack.
|
||
SDPUtils.parseMsid = function(mediaSection) {
|
||
var parts;
|
||
var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:');
|
||
if (spec.length === 1) {
|
||
parts = spec[0].substr(7).split(' ');
|
||
return {stream: parts[0], track: parts[1]};
|
||
}
|
||
var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
|
||
.map(function(line) {
|
||
return SDPUtils.parseSsrcMedia(line);
|
||
})
|
||
.filter(function(parts) {
|
||
return parts.attribute === 'msid';
|
||
});
|
||
if (planB.length > 0) {
|
||
parts = planB[0].value.split(' ');
|
||
return {stream: parts[0], track: parts[1]};
|
||
}
|
||
};
|
||
|
||
SDPUtils.writeSessionBoilerplate = function() {
|
||
// FIXME: sess-id should be an NTP timestamp.
|
||
return 'v=0\r\n' +
|
||
'o=thisisadapterortc 8169639915646943137 2 IN IP4 127.0.0.1\r\n' +
|
||
's=-\r\n' +
|
||
't=0 0\r\n';
|
||
};
|
||
|
||
SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) {
|
||
var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps);
|
||
|
||
// Map ICE parameters (ufrag, pwd) to SDP.
|
||
sdp += SDPUtils.writeIceParameters(
|
||
transceiver.iceGatherer.getLocalParameters());
|
||
|
||
// Map DTLS parameters to SDP.
|
||
sdp += SDPUtils.writeDtlsParameters(
|
||
transceiver.dtlsTransport.getLocalParameters(),
|
||
type === 'offer' ? 'actpass' : 'active');
|
||
|
||
sdp += 'a=mid:' + transceiver.mid + '\r\n';
|
||
|
||
if (transceiver.direction) {
|
||
sdp += 'a=' + transceiver.direction + '\r\n';
|
||
} else if (transceiver.rtpSender && transceiver.rtpReceiver) {
|
||
sdp += 'a=sendrecv\r\n';
|
||
} else if (transceiver.rtpSender) {
|
||
sdp += 'a=sendonly\r\n';
|
||
} else if (transceiver.rtpReceiver) {
|
||
sdp += 'a=recvonly\r\n';
|
||
} else {
|
||
sdp += 'a=inactive\r\n';
|
||
}
|
||
|
||
if (transceiver.rtpSender) {
|
||
// spec.
|
||
var msid = 'msid:' + stream.id + ' ' +
|
||
transceiver.rtpSender.track.id + '\r\n';
|
||
sdp += 'a=' + msid;
|
||
|
||
// for Chrome.
|
||
sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
|
||
' ' + msid;
|
||
if (transceiver.sendEncodingParameters[0].rtx) {
|
||
sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +
|
||
' ' + msid;
|
||
sdp += 'a=ssrc-group:FID ' +
|
||
transceiver.sendEncodingParameters[0].ssrc + ' ' +
|
||
transceiver.sendEncodingParameters[0].rtx.ssrc +
|
||
'\r\n';
|
||
}
|
||
}
|
||
// FIXME: this should be written by writeRtpDescription.
|
||
sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
|
||
' cname:' + SDPUtils.localCName + '\r\n';
|
||
if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) {
|
||
sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +
|
||
' cname:' + SDPUtils.localCName + '\r\n';
|
||
}
|
||
return sdp;
|
||
};
|
||
|
||
// Gets the direction from the mediaSection or the sessionpart.
|
||
SDPUtils.getDirection = function(mediaSection, sessionpart) {
|
||
// Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.
|
||
var lines = SDPUtils.splitLines(mediaSection);
|
||
for (var i = 0; i < lines.length; i++) {
|
||
switch (lines[i]) {
|
||
case 'a=sendrecv':
|
||
case 'a=sendonly':
|
||
case 'a=recvonly':
|
||
case 'a=inactive':
|
||
return lines[i].substr(2);
|
||
default:
|
||
// FIXME: What should happen here?
|
||
}
|
||
}
|
||
if (sessionpart) {
|
||
return SDPUtils.getDirection(sessionpart);
|
||
}
|
||
return 'sendrecv';
|
||
};
|
||
|
||
SDPUtils.getKind = function(mediaSection) {
|
||
var lines = SDPUtils.splitLines(mediaSection);
|
||
var mline = lines[0].split(' ');
|
||
return mline[0].substr(2);
|
||
};
|
||
|
||
SDPUtils.isRejected = function(mediaSection) {
|
||
return mediaSection.split(' ', 2)[1] === '0';
|
||
};
|
||
|
||
// Expose public methods.
|
||
module.exports = SDPUtils;
|
||
|
||
},{}],33:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
var transportList = require('./transport-list');
|
||
|
||
module.exports = require('./main')(transportList);
|
||
|
||
// TODO can't get rid of this until all servers do
|
||
if ('_sockjs_onload' in global) {
|
||
setTimeout(global._sockjs_onload, 1);
|
||
}
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"./main":46,"./transport-list":48}],34:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, Event = require('./event')
|
||
;
|
||
|
||
function CloseEvent() {
|
||
Event.call(this);
|
||
this.initEvent('close', false, false);
|
||
this.wasClean = false;
|
||
this.code = 0;
|
||
this.reason = '';
|
||
}
|
||
|
||
inherits(CloseEvent, Event);
|
||
|
||
module.exports = CloseEvent;
|
||
|
||
},{"./event":36,"inherits":7}],35:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, EventTarget = require('./eventtarget')
|
||
;
|
||
|
||
function EventEmitter() {
|
||
EventTarget.call(this);
|
||
}
|
||
|
||
inherits(EventEmitter, EventTarget);
|
||
|
||
EventEmitter.prototype.removeAllListeners = function(type) {
|
||
if (type) {
|
||
delete this._listeners[type];
|
||
} else {
|
||
this._listeners = {};
|
||
}
|
||
};
|
||
|
||
EventEmitter.prototype.once = function(type, listener) {
|
||
var self = this
|
||
, fired = false;
|
||
|
||
function g() {
|
||
self.removeListener(type, g);
|
||
|
||
if (!fired) {
|
||
fired = true;
|
||
listener.apply(this, arguments);
|
||
}
|
||
}
|
||
|
||
this.on(type, g);
|
||
};
|
||
|
||
EventEmitter.prototype.emit = function() {
|
||
var type = arguments[0];
|
||
var listeners = this._listeners[type];
|
||
if (!listeners) {
|
||
return;
|
||
}
|
||
// equivalent of Array.prototype.slice.call(arguments, 1);
|
||
var l = arguments.length;
|
||
var args = new Array(l - 1);
|
||
for (var ai = 1; ai < l; ai++) {
|
||
args[ai - 1] = arguments[ai];
|
||
}
|
||
for (var i = 0; i < listeners.length; i++) {
|
||
listeners[i].apply(this, args);
|
||
}
|
||
};
|
||
|
||
EventEmitter.prototype.on = EventEmitter.prototype.addListener = EventTarget.prototype.addEventListener;
|
||
EventEmitter.prototype.removeListener = EventTarget.prototype.removeEventListener;
|
||
|
||
module.exports.EventEmitter = EventEmitter;
|
||
|
||
},{"./eventtarget":37,"inherits":7}],36:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
function Event(eventType) {
|
||
this.type = eventType;
|
||
}
|
||
|
||
Event.prototype.initEvent = function(eventType, canBubble, cancelable) {
|
||
this.type = eventType;
|
||
this.bubbles = canBubble;
|
||
this.cancelable = cancelable;
|
||
this.timeStamp = +new Date();
|
||
return this;
|
||
};
|
||
|
||
Event.prototype.stopPropagation = function() {};
|
||
Event.prototype.preventDefault = function() {};
|
||
|
||
Event.CAPTURING_PHASE = 1;
|
||
Event.AT_TARGET = 2;
|
||
Event.BUBBLING_PHASE = 3;
|
||
|
||
module.exports = Event;
|
||
|
||
},{}],37:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
/* Simplified implementation of DOM2 EventTarget.
|
||
* http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget
|
||
*/
|
||
|
||
function EventTarget() {
|
||
this._listeners = {};
|
||
}
|
||
|
||
EventTarget.prototype.addEventListener = function(eventType, listener) {
|
||
if (!(eventType in this._listeners)) {
|
||
this._listeners[eventType] = [];
|
||
}
|
||
var arr = this._listeners[eventType];
|
||
// #4
|
||
if (arr.indexOf(listener) === -1) {
|
||
// Make a copy so as not to interfere with a current dispatchEvent.
|
||
arr = arr.concat([listener]);
|
||
}
|
||
this._listeners[eventType] = arr;
|
||
};
|
||
|
||
EventTarget.prototype.removeEventListener = function(eventType, listener) {
|
||
var arr = this._listeners[eventType];
|
||
if (!arr) {
|
||
return;
|
||
}
|
||
var idx = arr.indexOf(listener);
|
||
if (idx !== -1) {
|
||
if (arr.length > 1) {
|
||
// Make a copy so as not to interfere with a current dispatchEvent.
|
||
this._listeners[eventType] = arr.slice(0, idx).concat(arr.slice(idx + 1));
|
||
} else {
|
||
delete this._listeners[eventType];
|
||
}
|
||
return;
|
||
}
|
||
};
|
||
|
||
EventTarget.prototype.dispatchEvent = function() {
|
||
var event = arguments[0];
|
||
var t = event.type;
|
||
// equivalent of Array.prototype.slice.call(arguments, 0);
|
||
var args = arguments.length === 1 ? [event] : Array.apply(null, arguments);
|
||
// TODO: This doesn't match the real behavior; per spec, onfoo get
|
||
// their place in line from the /first/ time they're set from
|
||
// non-null. Although WebKit bumps it to the end every time it's
|
||
// set.
|
||
if (this['on' + t]) {
|
||
this['on' + t].apply(this, args);
|
||
}
|
||
if (t in this._listeners) {
|
||
// Grab a reference to the listeners list. removeEventListener may alter the list.
|
||
var listeners = this._listeners[t];
|
||
for (var i = 0; i < listeners.length; i++) {
|
||
listeners[i].apply(this, args);
|
||
}
|
||
}
|
||
};
|
||
|
||
module.exports = EventTarget;
|
||
|
||
},{}],38:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, Event = require('./event')
|
||
;
|
||
|
||
function TransportMessageEvent(data) {
|
||
Event.call(this);
|
||
this.initEvent('message', false, false);
|
||
this.data = data;
|
||
}
|
||
|
||
inherits(TransportMessageEvent, Event);
|
||
|
||
module.exports = TransportMessageEvent;
|
||
|
||
},{"./event":36,"inherits":7}],39:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var JSON3 = require('json3')
|
||
, iframeUtils = require('./utils/iframe')
|
||
;
|
||
|
||
function FacadeJS(transport) {
|
||
this._transport = transport;
|
||
transport.on('message', this._transportMessage.bind(this));
|
||
transport.on('close', this._transportClose.bind(this));
|
||
}
|
||
|
||
FacadeJS.prototype._transportClose = function(code, reason) {
|
||
iframeUtils.postMessage('c', JSON3.stringify([code, reason]));
|
||
};
|
||
FacadeJS.prototype._transportMessage = function(frame) {
|
||
iframeUtils.postMessage('t', frame);
|
||
};
|
||
FacadeJS.prototype._send = function(data) {
|
||
this._transport.send(data);
|
||
};
|
||
FacadeJS.prototype._close = function() {
|
||
this._transport.close();
|
||
this._transport.removeAllListeners();
|
||
};
|
||
|
||
module.exports = FacadeJS;
|
||
|
||
},{"./utils/iframe":79,"json3":8}],40:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var urlUtils = require('./utils/url')
|
||
, eventUtils = require('./utils/event')
|
||
, JSON3 = require('json3')
|
||
, FacadeJS = require('./facade')
|
||
, InfoIframeReceiver = require('./info-iframe-receiver')
|
||
, iframeUtils = require('./utils/iframe')
|
||
, loc = require('./location')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:iframe-bootstrap');
|
||
}
|
||
|
||
module.exports = function(SockJS, availableTransports) {
|
||
var transportMap = {};
|
||
availableTransports.forEach(function(at) {
|
||
if (at.facadeTransport) {
|
||
transportMap[at.facadeTransport.transportName] = at.facadeTransport;
|
||
}
|
||
});
|
||
|
||
// hard-coded for the info iframe
|
||
// TODO see if we can make this more dynamic
|
||
transportMap[InfoIframeReceiver.transportName] = InfoIframeReceiver;
|
||
var parentOrigin;
|
||
|
||
/* eslint-disable camelcase */
|
||
SockJS.bootstrap_iframe = function() {
|
||
/* eslint-enable camelcase */
|
||
var facade;
|
||
iframeUtils.currentWindowId = loc.hash.slice(1);
|
||
var onMessage = function(e) {
|
||
if (e.source !== parent) {
|
||
return;
|
||
}
|
||
if (typeof parentOrigin === 'undefined') {
|
||
parentOrigin = e.origin;
|
||
}
|
||
if (e.origin !== parentOrigin) {
|
||
return;
|
||
}
|
||
|
||
var iframeMessage;
|
||
try {
|
||
iframeMessage = JSON3.parse(e.data);
|
||
} catch (ignored) {
|
||
debug('bad json', e.data);
|
||
return;
|
||
}
|
||
|
||
if (iframeMessage.windowId !== iframeUtils.currentWindowId) {
|
||
return;
|
||
}
|
||
switch (iframeMessage.type) {
|
||
case 's':
|
||
var p;
|
||
try {
|
||
p = JSON3.parse(iframeMessage.data);
|
||
} catch (ignored) {
|
||
debug('bad json', iframeMessage.data);
|
||
break;
|
||
}
|
||
var version = p[0];
|
||
var transport = p[1];
|
||
var transUrl = p[2];
|
||
var baseUrl = p[3];
|
||
debug(version, transport, transUrl, baseUrl);
|
||
// change this to semver logic
|
||
if (version !== SockJS.version) {
|
||
throw new Error('Incompatible SockJS! Main site uses:' +
|
||
' "' + version + '", the iframe:' +
|
||
' "' + SockJS.version + '".');
|
||
}
|
||
|
||
if (!urlUtils.isOriginEqual(transUrl, loc.href) ||
|
||
!urlUtils.isOriginEqual(baseUrl, loc.href)) {
|
||
throw new Error('Can\'t connect to different domain from within an ' +
|
||
'iframe. (' + loc.href + ', ' + transUrl + ', ' + baseUrl + ')');
|
||
}
|
||
facade = new FacadeJS(new transportMap[transport](transUrl, baseUrl));
|
||
break;
|
||
case 'm':
|
||
facade._send(iframeMessage.data);
|
||
break;
|
||
case 'c':
|
||
if (facade) {
|
||
facade._close();
|
||
}
|
||
facade = null;
|
||
break;
|
||
}
|
||
};
|
||
|
||
eventUtils.attachEvent('message', onMessage);
|
||
|
||
// Start
|
||
iframeUtils.postMessage('s');
|
||
};
|
||
};
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"./facade":39,"./info-iframe-receiver":42,"./location":45,"./utils/event":78,"./utils/iframe":79,"./utils/url":84,"_process":114,"debug":1,"json3":8}],41:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var EventEmitter = require('events').EventEmitter
|
||
, inherits = require('inherits')
|
||
, JSON3 = require('json3')
|
||
, objectUtils = require('./utils/object')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:info-ajax');
|
||
}
|
||
|
||
function InfoAjax(url, AjaxObject) {
|
||
EventEmitter.call(this);
|
||
|
||
var self = this;
|
||
var t0 = +new Date();
|
||
this.xo = new AjaxObject('GET', url);
|
||
|
||
this.xo.once('finish', function(status, text) {
|
||
var info, rtt;
|
||
if (status === 200) {
|
||
rtt = (+new Date()) - t0;
|
||
if (text) {
|
||
try {
|
||
info = JSON3.parse(text);
|
||
} catch (e) {
|
||
debug('bad json', text);
|
||
}
|
||
}
|
||
|
||
if (!objectUtils.isObject(info)) {
|
||
info = {};
|
||
}
|
||
}
|
||
self.emit('finish', info, rtt);
|
||
self.removeAllListeners();
|
||
});
|
||
}
|
||
|
||
inherits(InfoAjax, EventEmitter);
|
||
|
||
InfoAjax.prototype.close = function() {
|
||
this.removeAllListeners();
|
||
this.xo.close();
|
||
};
|
||
|
||
module.exports = InfoAjax;
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"./utils/object":81,"_process":114,"debug":1,"events":35,"inherits":7,"json3":8}],42:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, EventEmitter = require('events').EventEmitter
|
||
, JSON3 = require('json3')
|
||
, XHRLocalObject = require('./transport/sender/xhr-local')
|
||
, InfoAjax = require('./info-ajax')
|
||
;
|
||
|
||
function InfoReceiverIframe(transUrl) {
|
||
var self = this;
|
||
EventEmitter.call(this);
|
||
|
||
this.ir = new InfoAjax(transUrl, XHRLocalObject);
|
||
this.ir.once('finish', function(info, rtt) {
|
||
self.ir = null;
|
||
self.emit('message', JSON3.stringify([info, rtt]));
|
||
});
|
||
}
|
||
|
||
inherits(InfoReceiverIframe, EventEmitter);
|
||
|
||
InfoReceiverIframe.transportName = 'iframe-info-receiver';
|
||
|
||
InfoReceiverIframe.prototype.close = function() {
|
||
if (this.ir) {
|
||
this.ir.close();
|
||
this.ir = null;
|
||
}
|
||
this.removeAllListeners();
|
||
};
|
||
|
||
module.exports = InfoReceiverIframe;
|
||
|
||
},{"./info-ajax":41,"./transport/sender/xhr-local":69,"events":35,"inherits":7,"json3":8}],43:[function(require,module,exports){
|
||
(function (process,global){
|
||
'use strict';
|
||
|
||
var EventEmitter = require('events').EventEmitter
|
||
, inherits = require('inherits')
|
||
, JSON3 = require('json3')
|
||
, utils = require('./utils/event')
|
||
, IframeTransport = require('./transport/iframe')
|
||
, InfoReceiverIframe = require('./info-iframe-receiver')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:info-iframe');
|
||
}
|
||
|
||
function InfoIframe(baseUrl, url) {
|
||
var self = this;
|
||
EventEmitter.call(this);
|
||
|
||
var go = function() {
|
||
var ifr = self.ifr = new IframeTransport(InfoReceiverIframe.transportName, url, baseUrl);
|
||
|
||
ifr.once('message', function(msg) {
|
||
if (msg) {
|
||
var d;
|
||
try {
|
||
d = JSON3.parse(msg);
|
||
} catch (e) {
|
||
debug('bad json', msg);
|
||
self.emit('finish');
|
||
self.close();
|
||
return;
|
||
}
|
||
|
||
var info = d[0], rtt = d[1];
|
||
self.emit('finish', info, rtt);
|
||
}
|
||
self.close();
|
||
});
|
||
|
||
ifr.once('close', function() {
|
||
self.emit('finish');
|
||
self.close();
|
||
});
|
||
};
|
||
|
||
// TODO this seems the same as the 'needBody' from transports
|
||
if (!global.document.body) {
|
||
utils.attachEvent('load', go);
|
||
} else {
|
||
go();
|
||
}
|
||
}
|
||
|
||
inherits(InfoIframe, EventEmitter);
|
||
|
||
InfoIframe.enabled = function() {
|
||
return IframeTransport.enabled();
|
||
};
|
||
|
||
InfoIframe.prototype.close = function() {
|
||
if (this.ifr) {
|
||
this.ifr.close();
|
||
}
|
||
this.removeAllListeners();
|
||
this.ifr = null;
|
||
};
|
||
|
||
module.exports = InfoIframe;
|
||
|
||
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"./info-iframe-receiver":42,"./transport/iframe":54,"./utils/event":78,"_process":114,"debug":1,"events":35,"inherits":7,"json3":8}],44:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var EventEmitter = require('events').EventEmitter
|
||
, inherits = require('inherits')
|
||
, urlUtils = require('./utils/url')
|
||
, XDR = require('./transport/sender/xdr')
|
||
, XHRCors = require('./transport/sender/xhr-cors')
|
||
, XHRLocal = require('./transport/sender/xhr-local')
|
||
, XHRFake = require('./transport/sender/xhr-fake')
|
||
, InfoIframe = require('./info-iframe')
|
||
, InfoAjax = require('./info-ajax')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:info-receiver');
|
||
}
|
||
|
||
function InfoReceiver(baseUrl, urlInfo) {
|
||
debug(baseUrl);
|
||
var self = this;
|
||
EventEmitter.call(this);
|
||
|
||
setTimeout(function() {
|
||
self.doXhr(baseUrl, urlInfo);
|
||
}, 0);
|
||
}
|
||
|
||
inherits(InfoReceiver, EventEmitter);
|
||
|
||
// TODO this is currently ignoring the list of available transports and the whitelist
|
||
|
||
InfoReceiver._getReceiver = function(baseUrl, url, urlInfo) {
|
||
// determine method of CORS support (if needed)
|
||
if (urlInfo.sameOrigin) {
|
||
return new InfoAjax(url, XHRLocal);
|
||
}
|
||
if (XHRCors.enabled) {
|
||
return new InfoAjax(url, XHRCors);
|
||
}
|
||
if (XDR.enabled && urlInfo.sameScheme) {
|
||
return new InfoAjax(url, XDR);
|
||
}
|
||
if (InfoIframe.enabled()) {
|
||
return new InfoIframe(baseUrl, url);
|
||
}
|
||
return new InfoAjax(url, XHRFake);
|
||
};
|
||
|
||
InfoReceiver.prototype.doXhr = function(baseUrl, urlInfo) {
|
||
var self = this
|
||
, url = urlUtils.addPath(baseUrl, '/info')
|
||
;
|
||
debug('doXhr', url);
|
||
|
||
this.xo = InfoReceiver._getReceiver(baseUrl, url, urlInfo);
|
||
|
||
this.timeoutRef = setTimeout(function() {
|
||
debug('timeout');
|
||
self._cleanup(false);
|
||
self.emit('finish');
|
||
}, InfoReceiver.timeout);
|
||
|
||
this.xo.once('finish', function(info, rtt) {
|
||
debug('finish', info, rtt);
|
||
self._cleanup(true);
|
||
self.emit('finish', info, rtt);
|
||
});
|
||
};
|
||
|
||
InfoReceiver.prototype._cleanup = function(wasClean) {
|
||
debug('_cleanup');
|
||
clearTimeout(this.timeoutRef);
|
||
this.timeoutRef = null;
|
||
if (!wasClean && this.xo) {
|
||
this.xo.close();
|
||
}
|
||
this.xo = null;
|
||
};
|
||
|
||
InfoReceiver.prototype.close = function() {
|
||
debug('close');
|
||
this.removeAllListeners();
|
||
this._cleanup(false);
|
||
};
|
||
|
||
InfoReceiver.timeout = 8000;
|
||
|
||
module.exports = InfoReceiver;
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"./info-ajax":41,"./info-iframe":43,"./transport/sender/xdr":66,"./transport/sender/xhr-cors":67,"./transport/sender/xhr-fake":68,"./transport/sender/xhr-local":69,"./utils/url":84,"_process":114,"debug":1,"events":35,"inherits":7}],45:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
module.exports = global.location || {
|
||
origin: 'http://localhost:80'
|
||
, protocol: 'http'
|
||
, host: 'localhost'
|
||
, port: 80
|
||
, href: 'http://localhost/'
|
||
, hash: ''
|
||
};
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{}],46:[function(require,module,exports){
|
||
(function (process,global){
|
||
'use strict';
|
||
|
||
require('./shims');
|
||
|
||
var URL = require('url-parse')
|
||
, inherits = require('inherits')
|
||
, JSON3 = require('json3')
|
||
, random = require('./utils/random')
|
||
, escape = require('./utils/escape')
|
||
, urlUtils = require('./utils/url')
|
||
, eventUtils = require('./utils/event')
|
||
, transport = require('./utils/transport')
|
||
, objectUtils = require('./utils/object')
|
||
, browser = require('./utils/browser')
|
||
, log = require('./utils/log')
|
||
, Event = require('./event/event')
|
||
, EventTarget = require('./event/eventtarget')
|
||
, loc = require('./location')
|
||
, CloseEvent = require('./event/close')
|
||
, TransportMessageEvent = require('./event/trans-message')
|
||
, InfoReceiver = require('./info-receiver')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:main');
|
||
}
|
||
|
||
var transports;
|
||
|
||
// follow constructor steps defined at http://dev.w3.org/html5/websockets/#the-websocket-interface
|
||
function SockJS(url, protocols, options) {
|
||
if (!(this instanceof SockJS)) {
|
||
return new SockJS(url, protocols, options);
|
||
}
|
||
if (arguments.length < 1) {
|
||
throw new TypeError("Failed to construct 'SockJS: 1 argument required, but only 0 present");
|
||
}
|
||
EventTarget.call(this);
|
||
|
||
this.readyState = SockJS.CONNECTING;
|
||
this.extensions = '';
|
||
this.protocol = '';
|
||
|
||
// non-standard extension
|
||
options = options || {};
|
||
if (options.protocols_whitelist) {
|
||
log.warn("'protocols_whitelist' is DEPRECATED. Use 'transports' instead.");
|
||
}
|
||
this._transportsWhitelist = options.transports;
|
||
this._transportOptions = options.transportOptions || {};
|
||
|
||
var sessionId = options.sessionId || 8;
|
||
if (typeof sessionId === 'function') {
|
||
this._generateSessionId = sessionId;
|
||
} else if (typeof sessionId === 'number') {
|
||
this._generateSessionId = function() {
|
||
return random.string(sessionId);
|
||
};
|
||
} else {
|
||
throw new TypeError('If sessionId is used in the options, it needs to be a number or a function.');
|
||
}
|
||
|
||
this._server = options.server || random.numberString(1000);
|
||
|
||
// Step 1 of WS spec - parse and validate the url. Issue #8
|
||
var parsedUrl = new URL(url);
|
||
if (!parsedUrl.host || !parsedUrl.protocol) {
|
||
throw new SyntaxError("The URL '" + url + "' is invalid");
|
||
} else if (parsedUrl.hash) {
|
||
throw new SyntaxError('The URL must not contain a fragment');
|
||
} else if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
|
||
throw new SyntaxError("The URL's scheme must be either 'http:' or 'https:'. '" + parsedUrl.protocol + "' is not allowed.");
|
||
}
|
||
|
||
var secure = parsedUrl.protocol === 'https:';
|
||
// Step 2 - don't allow secure origin with an insecure protocol
|
||
if (loc.protocol === 'https' && !secure) {
|
||
throw new Error('SecurityError: An insecure SockJS connection may not be initiated from a page loaded over HTTPS');
|
||
}
|
||
|
||
// Step 3 - check port access - no need here
|
||
// Step 4 - parse protocols argument
|
||
if (!protocols) {
|
||
protocols = [];
|
||
} else if (!Array.isArray(protocols)) {
|
||
protocols = [protocols];
|
||
}
|
||
|
||
// Step 5 - check protocols argument
|
||
var sortedProtocols = protocols.sort();
|
||
sortedProtocols.forEach(function(proto, i) {
|
||
if (!proto) {
|
||
throw new SyntaxError("The protocols entry '" + proto + "' is invalid.");
|
||
}
|
||
if (i < (sortedProtocols.length - 1) && proto === sortedProtocols[i + 1]) {
|
||
throw new SyntaxError("The protocols entry '" + proto + "' is duplicated.");
|
||
}
|
||
});
|
||
|
||
// Step 6 - convert origin
|
||
var o = urlUtils.getOrigin(loc.href);
|
||
this._origin = o ? o.toLowerCase() : null;
|
||
|
||
// remove the trailing slash
|
||
parsedUrl.set('pathname', parsedUrl.pathname.replace(/\/+$/, ''));
|
||
|
||
// store the sanitized url
|
||
this.url = parsedUrl.href;
|
||
debug('using url', this.url);
|
||
|
||
// Step 7 - start connection in background
|
||
// obtain server info
|
||
// http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-26
|
||
this._urlInfo = {
|
||
nullOrigin: !browser.hasDomain()
|
||
, sameOrigin: urlUtils.isOriginEqual(this.url, loc.href)
|
||
, sameScheme: urlUtils.isSchemeEqual(this.url, loc.href)
|
||
};
|
||
|
||
this._ir = new InfoReceiver(this.url, this._urlInfo);
|
||
this._ir.once('finish', this._receiveInfo.bind(this));
|
||
}
|
||
|
||
inherits(SockJS, EventTarget);
|
||
|
||
function userSetCode(code) {
|
||
return code === 1000 || (code >= 3000 && code <= 4999);
|
||
}
|
||
|
||
SockJS.prototype.close = function(code, reason) {
|
||
// Step 1
|
||
if (code && !userSetCode(code)) {
|
||
throw new Error('InvalidAccessError: Invalid code');
|
||
}
|
||
// Step 2.4 states the max is 123 bytes, but we are just checking length
|
||
if (reason && reason.length > 123) {
|
||
throw new SyntaxError('reason argument has an invalid length');
|
||
}
|
||
|
||
// Step 3.1
|
||
if (this.readyState === SockJS.CLOSING || this.readyState === SockJS.CLOSED) {
|
||
return;
|
||
}
|
||
|
||
// TODO look at docs to determine how to set this
|
||
var wasClean = true;
|
||
this._close(code || 1000, reason || 'Normal closure', wasClean);
|
||
};
|
||
|
||
SockJS.prototype.send = function(data) {
|
||
// #13 - convert anything non-string to string
|
||
// TODO this currently turns objects into [object Object]
|
||
if (typeof data !== 'string') {
|
||
data = '' + data;
|
||
}
|
||
if (this.readyState === SockJS.CONNECTING) {
|
||
throw new Error('InvalidStateError: The connection has not been established yet');
|
||
}
|
||
if (this.readyState !== SockJS.OPEN) {
|
||
return;
|
||
}
|
||
this._transport.send(escape.quote(data));
|
||
};
|
||
|
||
SockJS.version = require('./version');
|
||
|
||
SockJS.CONNECTING = 0;
|
||
SockJS.OPEN = 1;
|
||
SockJS.CLOSING = 2;
|
||
SockJS.CLOSED = 3;
|
||
|
||
SockJS.prototype._receiveInfo = function(info, rtt) {
|
||
debug('_receiveInfo', rtt);
|
||
this._ir = null;
|
||
if (!info) {
|
||
this._close(1002, 'Cannot connect to server');
|
||
return;
|
||
}
|
||
|
||
// establish a round-trip timeout (RTO) based on the
|
||
// round-trip time (RTT)
|
||
this._rto = this.countRTO(rtt);
|
||
// allow server to override url used for the actual transport
|
||
this._transUrl = info.base_url ? info.base_url : this.url;
|
||
info = objectUtils.extend(info, this._urlInfo);
|
||
debug('info', info);
|
||
// determine list of desired and supported transports
|
||
var enabledTransports = transports.filterToEnabled(this._transportsWhitelist, info);
|
||
this._transports = enabledTransports.main;
|
||
debug(this._transports.length + ' enabled transports');
|
||
|
||
this._connect();
|
||
};
|
||
|
||
SockJS.prototype._connect = function() {
|
||
for (var Transport = this._transports.shift(); Transport; Transport = this._transports.shift()) {
|
||
debug('attempt', Transport.transportName);
|
||
if (Transport.needBody) {
|
||
if (!global.document.body ||
|
||
(typeof global.document.readyState !== 'undefined' &&
|
||
global.document.readyState !== 'complete' &&
|
||
global.document.readyState !== 'interactive')) {
|
||
debug('waiting for body');
|
||
this._transports.unshift(Transport);
|
||
eventUtils.attachEvent('load', this._connect.bind(this));
|
||
return;
|
||
}
|
||
}
|
||
|
||
// calculate timeout based on RTO and round trips. Default to 5s
|
||
var timeoutMs = (this._rto * Transport.roundTrips) || 5000;
|
||
this._transportTimeoutId = setTimeout(this._transportTimeout.bind(this), timeoutMs);
|
||
debug('using timeout', timeoutMs);
|
||
|
||
var transportUrl = urlUtils.addPath(this._transUrl, '/' + this._server + '/' + this._generateSessionId());
|
||
var options = this._transportOptions[Transport.transportName];
|
||
debug('transport url', transportUrl);
|
||
var transportObj = new Transport(transportUrl, this._transUrl, options);
|
||
transportObj.on('message', this._transportMessage.bind(this));
|
||
transportObj.once('close', this._transportClose.bind(this));
|
||
transportObj.transportName = Transport.transportName;
|
||
this._transport = transportObj;
|
||
|
||
return;
|
||
}
|
||
this._close(2000, 'All transports failed', false);
|
||
};
|
||
|
||
SockJS.prototype._transportTimeout = function() {
|
||
debug('_transportTimeout');
|
||
if (this.readyState === SockJS.CONNECTING) {
|
||
this._transportClose(2007, 'Transport timed out');
|
||
}
|
||
};
|
||
|
||
SockJS.prototype._transportMessage = function(msg) {
|
||
debug('_transportMessage', msg);
|
||
var self = this
|
||
, type = msg.slice(0, 1)
|
||
, content = msg.slice(1)
|
||
, payload
|
||
;
|
||
|
||
// first check for messages that don't need a payload
|
||
switch (type) {
|
||
case 'o':
|
||
this._open();
|
||
return;
|
||
case 'h':
|
||
this.dispatchEvent(new Event('heartbeat'));
|
||
debug('heartbeat', this.transport);
|
||
return;
|
||
}
|
||
|
||
if (content) {
|
||
try {
|
||
payload = JSON3.parse(content);
|
||
} catch (e) {
|
||
debug('bad json', content);
|
||
}
|
||
}
|
||
|
||
if (typeof payload === 'undefined') {
|
||
debug('empty payload', content);
|
||
return;
|
||
}
|
||
|
||
switch (type) {
|
||
case 'a':
|
||
if (Array.isArray(payload)) {
|
||
payload.forEach(function(p) {
|
||
debug('message', self.transport, p);
|
||
self.dispatchEvent(new TransportMessageEvent(p));
|
||
});
|
||
}
|
||
break;
|
||
case 'm':
|
||
debug('message', this.transport, payload);
|
||
this.dispatchEvent(new TransportMessageEvent(payload));
|
||
break;
|
||
case 'c':
|
||
if (Array.isArray(payload) && payload.length === 2) {
|
||
this._close(payload[0], payload[1], true);
|
||
}
|
||
break;
|
||
}
|
||
};
|
||
|
||
SockJS.prototype._transportClose = function(code, reason) {
|
||
debug('_transportClose', this.transport, code, reason);
|
||
if (this._transport) {
|
||
this._transport.removeAllListeners();
|
||
this._transport = null;
|
||
this.transport = null;
|
||
}
|
||
|
||
if (!userSetCode(code) && code !== 2000 && this.readyState === SockJS.CONNECTING) {
|
||
this._connect();
|
||
return;
|
||
}
|
||
|
||
this._close(code, reason);
|
||
};
|
||
|
||
SockJS.prototype._open = function() {
|
||
debug('_open', this._transport.transportName, this.readyState);
|
||
if (this.readyState === SockJS.CONNECTING) {
|
||
if (this._transportTimeoutId) {
|
||
clearTimeout(this._transportTimeoutId);
|
||
this._transportTimeoutId = null;
|
||
}
|
||
this.readyState = SockJS.OPEN;
|
||
this.transport = this._transport.transportName;
|
||
this.dispatchEvent(new Event('open'));
|
||
debug('connected', this.transport);
|
||
} else {
|
||
// The server might have been restarted, and lost track of our
|
||
// connection.
|
||
this._close(1006, 'Server lost session');
|
||
}
|
||
};
|
||
|
||
SockJS.prototype._close = function(code, reason, wasClean) {
|
||
debug('_close', this.transport, code, reason, wasClean, this.readyState);
|
||
var forceFail = false;
|
||
|
||
if (this._ir) {
|
||
forceFail = true;
|
||
this._ir.close();
|
||
this._ir = null;
|
||
}
|
||
if (this._transport) {
|
||
this._transport.close();
|
||
this._transport = null;
|
||
this.transport = null;
|
||
}
|
||
|
||
if (this.readyState === SockJS.CLOSED) {
|
||
throw new Error('InvalidStateError: SockJS has already been closed');
|
||
}
|
||
|
||
this.readyState = SockJS.CLOSING;
|
||
setTimeout(function() {
|
||
this.readyState = SockJS.CLOSED;
|
||
|
||
if (forceFail) {
|
||
this.dispatchEvent(new Event('error'));
|
||
}
|
||
|
||
var e = new CloseEvent('close');
|
||
e.wasClean = wasClean || false;
|
||
e.code = code || 1000;
|
||
e.reason = reason;
|
||
|
||
this.dispatchEvent(e);
|
||
this.onmessage = this.onclose = this.onerror = null;
|
||
debug('disconnected');
|
||
}.bind(this), 0);
|
||
};
|
||
|
||
// See: http://www.erg.abdn.ac.uk/~gerrit/dccp/notes/ccid2/rto_estimator/
|
||
// and RFC 2988.
|
||
SockJS.prototype.countRTO = function(rtt) {
|
||
// In a local environment, when using IE8/9 and the `jsonp-polling`
|
||
// transport the time needed to establish a connection (the time that pass
|
||
// from the opening of the transport to the call of `_dispatchOpen`) is
|
||
// around 200msec (the lower bound used in the article above) and this
|
||
// causes spurious timeouts. For this reason we calculate a value slightly
|
||
// larger than that used in the article.
|
||
if (rtt > 100) {
|
||
return 4 * rtt; // rto > 400msec
|
||
}
|
||
return 300 + rtt; // 300msec < rto <= 400msec
|
||
};
|
||
|
||
module.exports = function(availableTransports) {
|
||
transports = transport(availableTransports);
|
||
require('./iframe-bootstrap')(SockJS, availableTransports);
|
||
return SockJS;
|
||
};
|
||
|
||
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"./event/close":34,"./event/event":36,"./event/eventtarget":37,"./event/trans-message":38,"./iframe-bootstrap":40,"./info-receiver":44,"./location":45,"./shims":47,"./utils/browser":76,"./utils/escape":77,"./utils/event":78,"./utils/log":80,"./utils/object":81,"./utils/random":82,"./utils/transport":83,"./utils/url":84,"./version":85,"_process":114,"debug":1,"inherits":7,"json3":8,"url-parse":87}],47:[function(require,module,exports){
|
||
/* eslint-disable */
|
||
/* jscs: disable */
|
||
'use strict';
|
||
|
||
// pulled specific shims from https://github.com/es-shims/es5-shim
|
||
|
||
var ArrayPrototype = Array.prototype;
|
||
var ObjectPrototype = Object.prototype;
|
||
var FunctionPrototype = Function.prototype;
|
||
var StringPrototype = String.prototype;
|
||
var array_slice = ArrayPrototype.slice;
|
||
|
||
var _toString = ObjectPrototype.toString;
|
||
var isFunction = function (val) {
|
||
return ObjectPrototype.toString.call(val) === '[object Function]';
|
||
};
|
||
var isArray = function isArray(obj) {
|
||
return _toString.call(obj) === '[object Array]';
|
||
};
|
||
var isString = function isString(obj) {
|
||
return _toString.call(obj) === '[object String]';
|
||
};
|
||
|
||
var supportsDescriptors = Object.defineProperty && (function () {
|
||
try {
|
||
Object.defineProperty({}, 'x', {});
|
||
return true;
|
||
} catch (e) { /* this is ES3 */
|
||
return false;
|
||
}
|
||
}());
|
||
|
||
// Define configurable, writable and non-enumerable props
|
||
// if they don't exist.
|
||
var defineProperty;
|
||
if (supportsDescriptors) {
|
||
defineProperty = function (object, name, method, forceAssign) {
|
||
if (!forceAssign && (name in object)) { return; }
|
||
Object.defineProperty(object, name, {
|
||
configurable: true,
|
||
enumerable: false,
|
||
writable: true,
|
||
value: method
|
||
});
|
||
};
|
||
} else {
|
||
defineProperty = function (object, name, method, forceAssign) {
|
||
if (!forceAssign && (name in object)) { return; }
|
||
object[name] = method;
|
||
};
|
||
}
|
||
var defineProperties = function (object, map, forceAssign) {
|
||
for (var name in map) {
|
||
if (ObjectPrototype.hasOwnProperty.call(map, name)) {
|
||
defineProperty(object, name, map[name], forceAssign);
|
||
}
|
||
}
|
||
};
|
||
|
||
var toObject = function (o) {
|
||
if (o == null) { // this matches both null and undefined
|
||
throw new TypeError("can't convert " + o + ' to object');
|
||
}
|
||
return Object(o);
|
||
};
|
||
|
||
//
|
||
// Util
|
||
// ======
|
||
//
|
||
|
||
// ES5 9.4
|
||
// http://es5.github.com/#x9.4
|
||
// http://jsperf.com/to-integer
|
||
|
||
function toInteger(num) {
|
||
var n = +num;
|
||
if (n !== n) { // isNaN
|
||
n = 0;
|
||
} else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
|
||
n = (n > 0 || -1) * Math.floor(Math.abs(n));
|
||
}
|
||
return n;
|
||
}
|
||
|
||
function ToUint32(x) {
|
||
return x >>> 0;
|
||
}
|
||
|
||
//
|
||
// Function
|
||
// ========
|
||
//
|
||
|
||
// ES-5 15.3.4.5
|
||
// http://es5.github.com/#x15.3.4.5
|
||
|
||
function Empty() {}
|
||
|
||
defineProperties(FunctionPrototype, {
|
||
bind: function bind(that) { // .length is 1
|
||
// 1. Let Target be the this value.
|
||
var target = this;
|
||
// 2. If IsCallable(Target) is false, throw a TypeError exception.
|
||
if (!isFunction(target)) {
|
||
throw new TypeError('Function.prototype.bind called on incompatible ' + target);
|
||
}
|
||
// 3. Let A be a new (possibly empty) internal list of all of the
|
||
// argument values provided after thisArg (arg1, arg2 etc), in order.
|
||
// XXX slicedArgs will stand in for "A" if used
|
||
var args = array_slice.call(arguments, 1); // for normal call
|
||
// 4. Let F be a new native ECMAScript object.
|
||
// 11. Set the [[Prototype]] internal property of F to the standard
|
||
// built-in Function prototype object as specified in 15.3.3.1.
|
||
// 12. Set the [[Call]] internal property of F as described in
|
||
// 15.3.4.5.1.
|
||
// 13. Set the [[Construct]] internal property of F as described in
|
||
// 15.3.4.5.2.
|
||
// 14. Set the [[HasInstance]] internal property of F as described in
|
||
// 15.3.4.5.3.
|
||
var binder = function () {
|
||
|
||
if (this instanceof bound) {
|
||
// 15.3.4.5.2 [[Construct]]
|
||
// When the [[Construct]] internal method of a function object,
|
||
// F that was created using the bind function is called with a
|
||
// list of arguments ExtraArgs, the following steps are taken:
|
||
// 1. Let target be the value of F's [[TargetFunction]]
|
||
// internal property.
|
||
// 2. If target has no [[Construct]] internal method, a
|
||
// TypeError exception is thrown.
|
||
// 3. Let boundArgs be the value of F's [[BoundArgs]] internal
|
||
// property.
|
||
// 4. Let args be a new list containing the same values as the
|
||
// list boundArgs in the same order followed by the same
|
||
// values as the list ExtraArgs in the same order.
|
||
// 5. Return the result of calling the [[Construct]] internal
|
||
// method of target providing args as the arguments.
|
||
|
||
var result = target.apply(
|
||
this,
|
||
args.concat(array_slice.call(arguments))
|
||
);
|
||
if (Object(result) === result) {
|
||
return result;
|
||
}
|
||
return this;
|
||
|
||
} else {
|
||
// 15.3.4.5.1 [[Call]]
|
||
// When the [[Call]] internal method of a function object, F,
|
||
// which was created using the bind function is called with a
|
||
// this value and a list of arguments ExtraArgs, the following
|
||
// steps are taken:
|
||
// 1. Let boundArgs be the value of F's [[BoundArgs]] internal
|
||
// property.
|
||
// 2. Let boundThis be the value of F's [[BoundThis]] internal
|
||
// property.
|
||
// 3. Let target be the value of F's [[TargetFunction]] internal
|
||
// property.
|
||
// 4. Let args be a new list containing the same values as the
|
||
// list boundArgs in the same order followed by the same
|
||
// values as the list ExtraArgs in the same order.
|
||
// 5. Return the result of calling the [[Call]] internal method
|
||
// of target providing boundThis as the this value and
|
||
// providing args as the arguments.
|
||
|
||
// equiv: target.call(this, ...boundArgs, ...args)
|
||
return target.apply(
|
||
that,
|
||
args.concat(array_slice.call(arguments))
|
||
);
|
||
|
||
}
|
||
|
||
};
|
||
|
||
// 15. If the [[Class]] internal property of Target is "Function", then
|
||
// a. Let L be the length property of Target minus the length of A.
|
||
// b. Set the length own property of F to either 0 or L, whichever is
|
||
// larger.
|
||
// 16. Else set the length own property of F to 0.
|
||
|
||
var boundLength = Math.max(0, target.length - args.length);
|
||
|
||
// 17. Set the attributes of the length own property of F to the values
|
||
// specified in 15.3.5.1.
|
||
var boundArgs = [];
|
||
for (var i = 0; i < boundLength; i++) {
|
||
boundArgs.push('$' + i);
|
||
}
|
||
|
||
// XXX Build a dynamic function with desired amount of arguments is the only
|
||
// way to set the length property of a function.
|
||
// In environments where Content Security Policies enabled (Chrome extensions,
|
||
// for ex.) all use of eval or Function costructor throws an exception.
|
||
// However in all of these environments Function.prototype.bind exists
|
||
// and so this code will never be executed.
|
||
var bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder);
|
||
|
||
if (target.prototype) {
|
||
Empty.prototype = target.prototype;
|
||
bound.prototype = new Empty();
|
||
// Clean up dangling references.
|
||
Empty.prototype = null;
|
||
}
|
||
|
||
// TODO
|
||
// 18. Set the [[Extensible]] internal property of F to true.
|
||
|
||
// TODO
|
||
// 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
|
||
// 20. Call the [[DefineOwnProperty]] internal method of F with
|
||
// arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
|
||
// thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
|
||
// false.
|
||
// 21. Call the [[DefineOwnProperty]] internal method of F with
|
||
// arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
|
||
// [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
|
||
// and false.
|
||
|
||
// TODO
|
||
// NOTE Function objects created using Function.prototype.bind do not
|
||
// have a prototype property or the [[Code]], [[FormalParameters]], and
|
||
// [[Scope]] internal properties.
|
||
// XXX can't delete prototype in pure-js.
|
||
|
||
// 22. Return F.
|
||
return bound;
|
||
}
|
||
});
|
||
|
||
//
|
||
// Array
|
||
// =====
|
||
//
|
||
|
||
// ES5 15.4.3.2
|
||
// http://es5.github.com/#x15.4.3.2
|
||
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
|
||
defineProperties(Array, { isArray: isArray });
|
||
|
||
|
||
var boxedString = Object('a');
|
||
var splitString = boxedString[0] !== 'a' || !(0 in boxedString);
|
||
|
||
var properlyBoxesContext = function properlyBoxed(method) {
|
||
// Check node 0.6.21 bug where third parameter is not boxed
|
||
var properlyBoxesNonStrict = true;
|
||
var properlyBoxesStrict = true;
|
||
if (method) {
|
||
method.call('foo', function (_, __, context) {
|
||
if (typeof context !== 'object') { properlyBoxesNonStrict = false; }
|
||
});
|
||
|
||
method.call([1], function () {
|
||
'use strict';
|
||
properlyBoxesStrict = typeof this === 'string';
|
||
}, 'x');
|
||
}
|
||
return !!method && properlyBoxesNonStrict && properlyBoxesStrict;
|
||
};
|
||
|
||
defineProperties(ArrayPrototype, {
|
||
forEach: function forEach(fun /*, thisp*/) {
|
||
var object = toObject(this),
|
||
self = splitString && isString(this) ? this.split('') : object,
|
||
thisp = arguments[1],
|
||
i = -1,
|
||
length = self.length >>> 0;
|
||
|
||
// If no callback function or if callback is not a callable function
|
||
if (!isFunction(fun)) {
|
||
throw new TypeError(); // TODO message
|
||
}
|
||
|
||
while (++i < length) {
|
||
if (i in self) {
|
||
// Invoke the callback function with call, passing arguments:
|
||
// context, property value, property key, thisArg object
|
||
// context
|
||
fun.call(thisp, self[i], i, object);
|
||
}
|
||
}
|
||
}
|
||
}, !properlyBoxesContext(ArrayPrototype.forEach));
|
||
|
||
// ES5 15.4.4.14
|
||
// http://es5.github.com/#x15.4.4.14
|
||
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
|
||
var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1;
|
||
defineProperties(ArrayPrototype, {
|
||
indexOf: function indexOf(sought /*, fromIndex */ ) {
|
||
var self = splitString && isString(this) ? this.split('') : toObject(this),
|
||
length = self.length >>> 0;
|
||
|
||
if (!length) {
|
||
return -1;
|
||
}
|
||
|
||
var i = 0;
|
||
if (arguments.length > 1) {
|
||
i = toInteger(arguments[1]);
|
||
}
|
||
|
||
// handle negative indices
|
||
i = i >= 0 ? i : Math.max(0, length + i);
|
||
for (; i < length; i++) {
|
||
if (i in self && self[i] === sought) {
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
}, hasFirefox2IndexOfBug);
|
||
|
||
//
|
||
// String
|
||
// ======
|
||
//
|
||
|
||
// ES5 15.5.4.14
|
||
// http://es5.github.com/#x15.5.4.14
|
||
|
||
// [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers]
|
||
// Many browsers do not split properly with regular expressions or they
|
||
// do not perform the split correctly under obscure conditions.
|
||
// See http://blog.stevenlevithan.com/archives/cross-browser-split
|
||
// I've tested in many browsers and this seems to cover the deviant ones:
|
||
// 'ab'.split(/(?:ab)*/) should be ["", ""], not [""]
|
||
// '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""]
|
||
// 'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not
|
||
// [undefined, "t", undefined, "e", ...]
|
||
// ''.split(/.?/) should be [], not [""]
|
||
// '.'.split(/()()/) should be ["."], not ["", "", "."]
|
||
|
||
var string_split = StringPrototype.split;
|
||
if (
|
||
'ab'.split(/(?:ab)*/).length !== 2 ||
|
||
'.'.split(/(.?)(.?)/).length !== 4 ||
|
||
'tesst'.split(/(s)*/)[1] === 't' ||
|
||
'test'.split(/(?:)/, -1).length !== 4 ||
|
||
''.split(/.?/).length ||
|
||
'.'.split(/()()/).length > 1
|
||
) {
|
||
(function () {
|
||
var compliantExecNpcg = /()??/.exec('')[1] === void 0; // NPCG: nonparticipating capturing group
|
||
|
||
StringPrototype.split = function (separator, limit) {
|
||
var string = this;
|
||
if (separator === void 0 && limit === 0) {
|
||
return [];
|
||
}
|
||
|
||
// If `separator` is not a regex, use native split
|
||
if (_toString.call(separator) !== '[object RegExp]') {
|
||
return string_split.call(this, separator, limit);
|
||
}
|
||
|
||
var output = [],
|
||
flags = (separator.ignoreCase ? 'i' : '') +
|
||
(separator.multiline ? 'm' : '') +
|
||
(separator.extended ? 'x' : '') + // Proposed for ES6
|
||
(separator.sticky ? 'y' : ''), // Firefox 3+
|
||
lastLastIndex = 0,
|
||
// Make `global` and avoid `lastIndex` issues by working with a copy
|
||
separator2, match, lastIndex, lastLength;
|
||
separator = new RegExp(separator.source, flags + 'g');
|
||
string += ''; // Type-convert
|
||
if (!compliantExecNpcg) {
|
||
// Doesn't need flags gy, but they don't hurt
|
||
separator2 = new RegExp('^' + separator.source + '$(?!\\s)', flags);
|
||
}
|
||
/* Values for `limit`, per the spec:
|
||
* If undefined: 4294967295 // Math.pow(2, 32) - 1
|
||
* If 0, Infinity, or NaN: 0
|
||
* If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
|
||
* If negative number: 4294967296 - Math.floor(Math.abs(limit))
|
||
* If other: Type-convert, then use the above rules
|
||
*/
|
||
limit = limit === void 0 ?
|
||
-1 >>> 0 : // Math.pow(2, 32) - 1
|
||
ToUint32(limit);
|
||
while (match = separator.exec(string)) {
|
||
// `separator.lastIndex` is not reliable cross-browser
|
||
lastIndex = match.index + match[0].length;
|
||
if (lastIndex > lastLastIndex) {
|
||
output.push(string.slice(lastLastIndex, match.index));
|
||
// Fix browsers whose `exec` methods don't consistently return `undefined` for
|
||
// nonparticipating capturing groups
|
||
if (!compliantExecNpcg && match.length > 1) {
|
||
match[0].replace(separator2, function () {
|
||
for (var i = 1; i < arguments.length - 2; i++) {
|
||
if (arguments[i] === void 0) {
|
||
match[i] = void 0;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
if (match.length > 1 && match.index < string.length) {
|
||
ArrayPrototype.push.apply(output, match.slice(1));
|
||
}
|
||
lastLength = match[0].length;
|
||
lastLastIndex = lastIndex;
|
||
if (output.length >= limit) {
|
||
break;
|
||
}
|
||
}
|
||
if (separator.lastIndex === match.index) {
|
||
separator.lastIndex++; // Avoid an infinite loop
|
||
}
|
||
}
|
||
if (lastLastIndex === string.length) {
|
||
if (lastLength || !separator.test('')) {
|
||
output.push('');
|
||
}
|
||
} else {
|
||
output.push(string.slice(lastLastIndex));
|
||
}
|
||
return output.length > limit ? output.slice(0, limit) : output;
|
||
};
|
||
}());
|
||
|
||
// [bugfix, chrome]
|
||
// If separator is undefined, then the result array contains just one String,
|
||
// which is the this value (converted to a String). If limit is not undefined,
|
||
// then the output array is truncated so that it contains no more than limit
|
||
// elements.
|
||
// "0".split(undefined, 0) -> []
|
||
} else if ('0'.split(void 0, 0).length) {
|
||
StringPrototype.split = function split(separator, limit) {
|
||
if (separator === void 0 && limit === 0) { return []; }
|
||
return string_split.call(this, separator, limit);
|
||
};
|
||
}
|
||
|
||
// ES5 15.5.4.20
|
||
// whitespace from: http://es5.github.io/#x15.5.4.20
|
||
var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' +
|
||
'\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' +
|
||
'\u2029\uFEFF';
|
||
var zeroWidth = '\u200b';
|
||
var wsRegexChars = '[' + ws + ']';
|
||
var trimBeginRegexp = new RegExp('^' + wsRegexChars + wsRegexChars + '*');
|
||
var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + '*$');
|
||
var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim());
|
||
defineProperties(StringPrototype, {
|
||
// http://blog.stevenlevithan.com/archives/faster-trim-javascript
|
||
// http://perfectionkills.com/whitespace-deviations/
|
||
trim: function trim() {
|
||
if (this === void 0 || this === null) {
|
||
throw new TypeError("can't convert " + this + ' to object');
|
||
}
|
||
return String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, '');
|
||
}
|
||
}, hasTrimWhitespaceBug);
|
||
|
||
// ECMA-262, 3rd B.2.3
|
||
// Not an ECMAScript standard, although ECMAScript 3rd Edition has a
|
||
// non-normative section suggesting uniform semantics and it should be
|
||
// normalized across all browsers
|
||
// [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE
|
||
var string_substr = StringPrototype.substr;
|
||
var hasNegativeSubstrBug = ''.substr && '0b'.substr(-1) !== 'b';
|
||
defineProperties(StringPrototype, {
|
||
substr: function substr(start, length) {
|
||
return string_substr.call(
|
||
this,
|
||
start < 0 ? ((start = this.length + start) < 0 ? 0 : start) : start,
|
||
length
|
||
);
|
||
}
|
||
}, hasNegativeSubstrBug);
|
||
|
||
},{}],48:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
module.exports = [
|
||
// streaming transports
|
||
require('./transport/websocket')
|
||
, require('./transport/xhr-streaming')
|
||
, require('./transport/xdr-streaming')
|
||
, require('./transport/eventsource')
|
||
, require('./transport/lib/iframe-wrap')(require('./transport/eventsource'))
|
||
|
||
// polling transports
|
||
, require('./transport/htmlfile')
|
||
, require('./transport/lib/iframe-wrap')(require('./transport/htmlfile'))
|
||
, require('./transport/xhr-polling')
|
||
, require('./transport/xdr-polling')
|
||
, require('./transport/lib/iframe-wrap')(require('./transport/xhr-polling'))
|
||
, require('./transport/jsonp-polling')
|
||
];
|
||
|
||
},{"./transport/eventsource":52,"./transport/htmlfile":53,"./transport/jsonp-polling":55,"./transport/lib/iframe-wrap":58,"./transport/websocket":70,"./transport/xdr-polling":71,"./transport/xdr-streaming":72,"./transport/xhr-polling":73,"./transport/xhr-streaming":74}],49:[function(require,module,exports){
|
||
(function (process,global){
|
||
'use strict';
|
||
|
||
var EventEmitter = require('events').EventEmitter
|
||
, inherits = require('inherits')
|
||
, utils = require('../../utils/event')
|
||
, urlUtils = require('../../utils/url')
|
||
, XHR = global.XMLHttpRequest
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:browser:xhr');
|
||
}
|
||
|
||
function AbstractXHRObject(method, url, payload, opts) {
|
||
debug(method, url);
|
||
var self = this;
|
||
EventEmitter.call(this);
|
||
|
||
setTimeout(function () {
|
||
self._start(method, url, payload, opts);
|
||
}, 0);
|
||
}
|
||
|
||
inherits(AbstractXHRObject, EventEmitter);
|
||
|
||
AbstractXHRObject.prototype._start = function(method, url, payload, opts) {
|
||
var self = this;
|
||
|
||
try {
|
||
this.xhr = new XHR();
|
||
} catch (x) {
|
||
// intentionally empty
|
||
}
|
||
|
||
if (!this.xhr) {
|
||
debug('no xhr');
|
||
this.emit('finish', 0, 'no xhr support');
|
||
this._cleanup();
|
||
return;
|
||
}
|
||
|
||
// several browsers cache POSTs
|
||
url = urlUtils.addQuery(url, 't=' + (+new Date()));
|
||
|
||
// Explorer tends to keep connection open, even after the
|
||
// tab gets closed: http://bugs.jquery.com/ticket/5280
|
||
this.unloadRef = utils.unloadAdd(function() {
|
||
debug('unload cleanup');
|
||
self._cleanup(true);
|
||
});
|
||
try {
|
||
this.xhr.open(method, url, true);
|
||
if (this.timeout && 'timeout' in this.xhr) {
|
||
this.xhr.timeout = this.timeout;
|
||
this.xhr.ontimeout = function() {
|
||
debug('xhr timeout');
|
||
self.emit('finish', 0, '');
|
||
self._cleanup(false);
|
||
};
|
||
}
|
||
} catch (e) {
|
||
debug('exception', e);
|
||
// IE raises an exception on wrong port.
|
||
this.emit('finish', 0, '');
|
||
this._cleanup(false);
|
||
return;
|
||
}
|
||
|
||
if ((!opts || !opts.noCredentials) && AbstractXHRObject.supportsCORS) {
|
||
debug('withCredentials');
|
||
// Mozilla docs says https://developer.mozilla.org/en/XMLHttpRequest :
|
||
// "This never affects same-site requests."
|
||
|
||
this.xhr.withCredentials = 'true';
|
||
}
|
||
if (opts && opts.headers) {
|
||
for (var key in opts.headers) {
|
||
this.xhr.setRequestHeader(key, opts.headers[key]);
|
||
}
|
||
}
|
||
|
||
this.xhr.onreadystatechange = function() {
|
||
if (self.xhr) {
|
||
var x = self.xhr;
|
||
var text, status;
|
||
debug('readyState', x.readyState);
|
||
switch (x.readyState) {
|
||
case 3:
|
||
// IE doesn't like peeking into responseText or status
|
||
// on Microsoft.XMLHTTP and readystate=3
|
||
try {
|
||
status = x.status;
|
||
text = x.responseText;
|
||
} catch (e) {
|
||
// intentionally empty
|
||
}
|
||
debug('status', status);
|
||
// IE returns 1223 for 204: http://bugs.jquery.com/ticket/1450
|
||
if (status === 1223) {
|
||
status = 204;
|
||
}
|
||
|
||
// IE does return readystate == 3 for 404 answers.
|
||
if (status === 200 && text && text.length > 0) {
|
||
debug('chunk');
|
||
self.emit('chunk', status, text);
|
||
}
|
||
break;
|
||
case 4:
|
||
status = x.status;
|
||
debug('status', status);
|
||
// IE returns 1223 for 204: http://bugs.jquery.com/ticket/1450
|
||
if (status === 1223) {
|
||
status = 204;
|
||
}
|
||
// IE returns this for a bad port
|
||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa383770(v=vs.85).aspx
|
||
if (status === 12005 || status === 12029) {
|
||
status = 0;
|
||
}
|
||
|
||
debug('finish', status, x.responseText);
|
||
self.emit('finish', status, x.responseText);
|
||
self._cleanup(false);
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
|
||
try {
|
||
self.xhr.send(payload);
|
||
} catch (e) {
|
||
self.emit('finish', 0, '');
|
||
self._cleanup(false);
|
||
}
|
||
};
|
||
|
||
AbstractXHRObject.prototype._cleanup = function(abort) {
|
||
debug('cleanup');
|
||
if (!this.xhr) {
|
||
return;
|
||
}
|
||
this.removeAllListeners();
|
||
utils.unloadDel(this.unloadRef);
|
||
|
||
// IE needs this field to be a function
|
||
this.xhr.onreadystatechange = function() {};
|
||
if (this.xhr.ontimeout) {
|
||
this.xhr.ontimeout = null;
|
||
}
|
||
|
||
if (abort) {
|
||
try {
|
||
this.xhr.abort();
|
||
} catch (x) {
|
||
// intentionally empty
|
||
}
|
||
}
|
||
this.unloadRef = this.xhr = null;
|
||
};
|
||
|
||
AbstractXHRObject.prototype.close = function() {
|
||
debug('close');
|
||
this._cleanup(true);
|
||
};
|
||
|
||
AbstractXHRObject.enabled = !!XHR;
|
||
// override XMLHttpRequest for IE6/7
|
||
// obfuscate to avoid firewalls
|
||
var axo = ['Active'].concat('Object').join('X');
|
||
if (!AbstractXHRObject.enabled && (axo in global)) {
|
||
debug('overriding xmlhttprequest');
|
||
XHR = function() {
|
||
try {
|
||
return new global[axo]('Microsoft.XMLHTTP');
|
||
} catch (e) {
|
||
return null;
|
||
}
|
||
};
|
||
AbstractXHRObject.enabled = !!new XHR();
|
||
}
|
||
|
||
var cors = false;
|
||
try {
|
||
cors = 'withCredentials' in new XHR();
|
||
} catch (ignored) {
|
||
// intentionally empty
|
||
}
|
||
|
||
AbstractXHRObject.supportsCORS = cors;
|
||
|
||
module.exports = AbstractXHRObject;
|
||
|
||
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"../../utils/event":78,"../../utils/url":84,"_process":114,"debug":1,"events":35,"inherits":7}],50:[function(require,module,exports){
|
||
(function (global){
|
||
module.exports = global.EventSource;
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{}],51:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
var Driver = global.WebSocket || global.MozWebSocket;
|
||
if (Driver) {
|
||
module.exports = function WebSocketBrowserDriver(url) {
|
||
return new Driver(url);
|
||
};
|
||
}
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{}],52:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, AjaxBasedTransport = require('./lib/ajax-based')
|
||
, EventSourceReceiver = require('./receiver/eventsource')
|
||
, XHRCorsObject = require('./sender/xhr-cors')
|
||
, EventSourceDriver = require('eventsource')
|
||
;
|
||
|
||
function EventSourceTransport(transUrl) {
|
||
if (!EventSourceTransport.enabled()) {
|
||
throw new Error('Transport created when disabled');
|
||
}
|
||
|
||
AjaxBasedTransport.call(this, transUrl, '/eventsource', EventSourceReceiver, XHRCorsObject);
|
||
}
|
||
|
||
inherits(EventSourceTransport, AjaxBasedTransport);
|
||
|
||
EventSourceTransport.enabled = function() {
|
||
return !!EventSourceDriver;
|
||
};
|
||
|
||
EventSourceTransport.transportName = 'eventsource';
|
||
EventSourceTransport.roundTrips = 2;
|
||
|
||
module.exports = EventSourceTransport;
|
||
|
||
},{"./lib/ajax-based":56,"./receiver/eventsource":61,"./sender/xhr-cors":67,"eventsource":50,"inherits":7}],53:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, HtmlfileReceiver = require('./receiver/htmlfile')
|
||
, XHRLocalObject = require('./sender/xhr-local')
|
||
, AjaxBasedTransport = require('./lib/ajax-based')
|
||
;
|
||
|
||
function HtmlFileTransport(transUrl) {
|
||
if (!HtmlfileReceiver.enabled) {
|
||
throw new Error('Transport created when disabled');
|
||
}
|
||
AjaxBasedTransport.call(this, transUrl, '/htmlfile', HtmlfileReceiver, XHRLocalObject);
|
||
}
|
||
|
||
inherits(HtmlFileTransport, AjaxBasedTransport);
|
||
|
||
HtmlFileTransport.enabled = function(info) {
|
||
return HtmlfileReceiver.enabled && info.sameOrigin;
|
||
};
|
||
|
||
HtmlFileTransport.transportName = 'htmlfile';
|
||
HtmlFileTransport.roundTrips = 2;
|
||
|
||
module.exports = HtmlFileTransport;
|
||
|
||
},{"./lib/ajax-based":56,"./receiver/htmlfile":62,"./sender/xhr-local":69,"inherits":7}],54:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
// Few cool transports do work only for same-origin. In order to make
|
||
// them work cross-domain we shall use iframe, served from the
|
||
// remote domain. New browsers have capabilities to communicate with
|
||
// cross domain iframe using postMessage(). In IE it was implemented
|
||
// from IE 8+, but of course, IE got some details wrong:
|
||
// http://msdn.microsoft.com/en-us/library/cc197015(v=VS.85).aspx
|
||
// http://stevesouders.com/misc/test-postmessage.php
|
||
|
||
var inherits = require('inherits')
|
||
, JSON3 = require('json3')
|
||
, EventEmitter = require('events').EventEmitter
|
||
, version = require('../version')
|
||
, urlUtils = require('../utils/url')
|
||
, iframeUtils = require('../utils/iframe')
|
||
, eventUtils = require('../utils/event')
|
||
, random = require('../utils/random')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:transport:iframe');
|
||
}
|
||
|
||
function IframeTransport(transport, transUrl, baseUrl) {
|
||
if (!IframeTransport.enabled()) {
|
||
throw new Error('Transport created when disabled');
|
||
}
|
||
EventEmitter.call(this);
|
||
|
||
var self = this;
|
||
this.origin = urlUtils.getOrigin(baseUrl);
|
||
this.baseUrl = baseUrl;
|
||
this.transUrl = transUrl;
|
||
this.transport = transport;
|
||
this.windowId = random.string(8);
|
||
|
||
var iframeUrl = urlUtils.addPath(baseUrl, '/iframe.html') + '#' + this.windowId;
|
||
debug(transport, transUrl, iframeUrl);
|
||
|
||
this.iframeObj = iframeUtils.createIframe(iframeUrl, function(r) {
|
||
debug('err callback');
|
||
self.emit('close', 1006, 'Unable to load an iframe (' + r + ')');
|
||
self.close();
|
||
});
|
||
|
||
this.onmessageCallback = this._message.bind(this);
|
||
eventUtils.attachEvent('message', this.onmessageCallback);
|
||
}
|
||
|
||
inherits(IframeTransport, EventEmitter);
|
||
|
||
IframeTransport.prototype.close = function() {
|
||
debug('close');
|
||
this.removeAllListeners();
|
||
if (this.iframeObj) {
|
||
eventUtils.detachEvent('message', this.onmessageCallback);
|
||
try {
|
||
// When the iframe is not loaded, IE raises an exception
|
||
// on 'contentWindow'.
|
||
this.postMessage('c');
|
||
} catch (x) {
|
||
// intentionally empty
|
||
}
|
||
this.iframeObj.cleanup();
|
||
this.iframeObj = null;
|
||
this.onmessageCallback = this.iframeObj = null;
|
||
}
|
||
};
|
||
|
||
IframeTransport.prototype._message = function(e) {
|
||
debug('message', e.data);
|
||
if (!urlUtils.isOriginEqual(e.origin, this.origin)) {
|
||
debug('not same origin', e.origin, this.origin);
|
||
return;
|
||
}
|
||
|
||
var iframeMessage;
|
||
try {
|
||
iframeMessage = JSON3.parse(e.data);
|
||
} catch (ignored) {
|
||
debug('bad json', e.data);
|
||
return;
|
||
}
|
||
|
||
if (iframeMessage.windowId !== this.windowId) {
|
||
debug('mismatched window id', iframeMessage.windowId, this.windowId);
|
||
return;
|
||
}
|
||
|
||
switch (iframeMessage.type) {
|
||
case 's':
|
||
this.iframeObj.loaded();
|
||
// window global dependency
|
||
this.postMessage('s', JSON3.stringify([
|
||
version
|
||
, this.transport
|
||
, this.transUrl
|
||
, this.baseUrl
|
||
]));
|
||
break;
|
||
case 't':
|
||
this.emit('message', iframeMessage.data);
|
||
break;
|
||
case 'c':
|
||
var cdata;
|
||
try {
|
||
cdata = JSON3.parse(iframeMessage.data);
|
||
} catch (ignored) {
|
||
debug('bad json', iframeMessage.data);
|
||
return;
|
||
}
|
||
this.emit('close', cdata[0], cdata[1]);
|
||
this.close();
|
||
break;
|
||
}
|
||
};
|
||
|
||
IframeTransport.prototype.postMessage = function(type, data) {
|
||
debug('postMessage', type, data);
|
||
this.iframeObj.post(JSON3.stringify({
|
||
windowId: this.windowId
|
||
, type: type
|
||
, data: data || ''
|
||
}), this.origin);
|
||
};
|
||
|
||
IframeTransport.prototype.send = function(message) {
|
||
debug('send', message);
|
||
this.postMessage('m', message);
|
||
};
|
||
|
||
IframeTransport.enabled = function() {
|
||
return iframeUtils.iframeEnabled;
|
||
};
|
||
|
||
IframeTransport.transportName = 'iframe';
|
||
IframeTransport.roundTrips = 2;
|
||
|
||
module.exports = IframeTransport;
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"../utils/event":78,"../utils/iframe":79,"../utils/random":82,"../utils/url":84,"../version":85,"_process":114,"debug":1,"events":35,"inherits":7,"json3":8}],55:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
// The simplest and most robust transport, using the well-know cross
|
||
// domain hack - JSONP. This transport is quite inefficient - one
|
||
// message could use up to one http request. But at least it works almost
|
||
// everywhere.
|
||
// Known limitations:
|
||
// o you will get a spinning cursor
|
||
// o for Konqueror a dumb timer is needed to detect errors
|
||
|
||
var inherits = require('inherits')
|
||
, SenderReceiver = require('./lib/sender-receiver')
|
||
, JsonpReceiver = require('./receiver/jsonp')
|
||
, jsonpSender = require('./sender/jsonp')
|
||
;
|
||
|
||
function JsonPTransport(transUrl) {
|
||
if (!JsonPTransport.enabled()) {
|
||
throw new Error('Transport created when disabled');
|
||
}
|
||
SenderReceiver.call(this, transUrl, '/jsonp', jsonpSender, JsonpReceiver);
|
||
}
|
||
|
||
inherits(JsonPTransport, SenderReceiver);
|
||
|
||
JsonPTransport.enabled = function() {
|
||
return !!global.document;
|
||
};
|
||
|
||
JsonPTransport.transportName = 'jsonp-polling';
|
||
JsonPTransport.roundTrips = 1;
|
||
JsonPTransport.needBody = true;
|
||
|
||
module.exports = JsonPTransport;
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"./lib/sender-receiver":60,"./receiver/jsonp":63,"./sender/jsonp":65,"inherits":7}],56:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, urlUtils = require('../../utils/url')
|
||
, SenderReceiver = require('./sender-receiver')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:ajax-based');
|
||
}
|
||
|
||
function createAjaxSender(AjaxObject) {
|
||
return function(url, payload, callback) {
|
||
debug('create ajax sender', url, payload);
|
||
var opt = {};
|
||
if (typeof payload === 'string') {
|
||
opt.headers = {'Content-type': 'text/plain'};
|
||
}
|
||
var ajaxUrl = urlUtils.addPath(url, '/xhr_send');
|
||
var xo = new AjaxObject('POST', ajaxUrl, payload, opt);
|
||
xo.once('finish', function(status) {
|
||
debug('finish', status);
|
||
xo = null;
|
||
|
||
if (status !== 200 && status !== 204) {
|
||
return callback(new Error('http status ' + status));
|
||
}
|
||
callback();
|
||
});
|
||
return function() {
|
||
debug('abort');
|
||
xo.close();
|
||
xo = null;
|
||
|
||
var err = new Error('Aborted');
|
||
err.code = 1000;
|
||
callback(err);
|
||
};
|
||
};
|
||
}
|
||
|
||
function AjaxBasedTransport(transUrl, urlSuffix, Receiver, AjaxObject) {
|
||
SenderReceiver.call(this, transUrl, urlSuffix, createAjaxSender(AjaxObject), Receiver, AjaxObject);
|
||
}
|
||
|
||
inherits(AjaxBasedTransport, SenderReceiver);
|
||
|
||
module.exports = AjaxBasedTransport;
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"../../utils/url":84,"./sender-receiver":60,"_process":114,"debug":1,"inherits":7}],57:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, EventEmitter = require('events').EventEmitter
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:buffered-sender');
|
||
}
|
||
|
||
function BufferedSender(url, sender) {
|
||
debug(url);
|
||
EventEmitter.call(this);
|
||
this.sendBuffer = [];
|
||
this.sender = sender;
|
||
this.url = url;
|
||
}
|
||
|
||
inherits(BufferedSender, EventEmitter);
|
||
|
||
BufferedSender.prototype.send = function(message) {
|
||
debug('send', message);
|
||
this.sendBuffer.push(message);
|
||
if (!this.sendStop) {
|
||
this.sendSchedule();
|
||
}
|
||
};
|
||
|
||
// For polling transports in a situation when in the message callback,
|
||
// new message is being send. If the sending connection was started
|
||
// before receiving one, it is possible to saturate the network and
|
||
// timeout due to the lack of receiving socket. To avoid that we delay
|
||
// sending messages by some small time, in order to let receiving
|
||
// connection be started beforehand. This is only a halfmeasure and
|
||
// does not fix the big problem, but it does make the tests go more
|
||
// stable on slow networks.
|
||
BufferedSender.prototype.sendScheduleWait = function() {
|
||
debug('sendScheduleWait');
|
||
var self = this;
|
||
var tref;
|
||
this.sendStop = function() {
|
||
debug('sendStop');
|
||
self.sendStop = null;
|
||
clearTimeout(tref);
|
||
};
|
||
tref = setTimeout(function() {
|
||
debug('timeout');
|
||
self.sendStop = null;
|
||
self.sendSchedule();
|
||
}, 25);
|
||
};
|
||
|
||
BufferedSender.prototype.sendSchedule = function() {
|
||
debug('sendSchedule', this.sendBuffer.length);
|
||
var self = this;
|
||
if (this.sendBuffer.length > 0) {
|
||
var payload = '[' + this.sendBuffer.join(',') + ']';
|
||
this.sendStop = this.sender(this.url, payload, function(err) {
|
||
self.sendStop = null;
|
||
if (err) {
|
||
debug('error', err);
|
||
self.emit('close', err.code || 1006, 'Sending error: ' + err);
|
||
self._cleanup();
|
||
} else {
|
||
self.sendScheduleWait();
|
||
}
|
||
});
|
||
this.sendBuffer = [];
|
||
}
|
||
};
|
||
|
||
BufferedSender.prototype._cleanup = function() {
|
||
debug('_cleanup');
|
||
this.removeAllListeners();
|
||
};
|
||
|
||
BufferedSender.prototype.stop = function() {
|
||
debug('stop');
|
||
this._cleanup();
|
||
if (this.sendStop) {
|
||
this.sendStop();
|
||
this.sendStop = null;
|
||
}
|
||
};
|
||
|
||
module.exports = BufferedSender;
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"_process":114,"debug":1,"events":35,"inherits":7}],58:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, IframeTransport = require('../iframe')
|
||
, objectUtils = require('../../utils/object')
|
||
;
|
||
|
||
module.exports = function(transport) {
|
||
|
||
function IframeWrapTransport(transUrl, baseUrl) {
|
||
IframeTransport.call(this, transport.transportName, transUrl, baseUrl);
|
||
}
|
||
|
||
inherits(IframeWrapTransport, IframeTransport);
|
||
|
||
IframeWrapTransport.enabled = function(url, info) {
|
||
if (!global.document) {
|
||
return false;
|
||
}
|
||
|
||
var iframeInfo = objectUtils.extend({}, info);
|
||
iframeInfo.sameOrigin = true;
|
||
return transport.enabled(iframeInfo) && IframeTransport.enabled();
|
||
};
|
||
|
||
IframeWrapTransport.transportName = 'iframe-' + transport.transportName;
|
||
IframeWrapTransport.needBody = true;
|
||
IframeWrapTransport.roundTrips = IframeTransport.roundTrips + transport.roundTrips - 1; // html, javascript (2) + transport - no CORS (1)
|
||
|
||
IframeWrapTransport.facadeTransport = transport;
|
||
|
||
return IframeWrapTransport;
|
||
};
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"../../utils/object":81,"../iframe":54,"inherits":7}],59:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, EventEmitter = require('events').EventEmitter
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:polling');
|
||
}
|
||
|
||
function Polling(Receiver, receiveUrl, AjaxObject) {
|
||
debug(receiveUrl);
|
||
EventEmitter.call(this);
|
||
this.Receiver = Receiver;
|
||
this.receiveUrl = receiveUrl;
|
||
this.AjaxObject = AjaxObject;
|
||
this._scheduleReceiver();
|
||
}
|
||
|
||
inherits(Polling, EventEmitter);
|
||
|
||
Polling.prototype._scheduleReceiver = function() {
|
||
debug('_scheduleReceiver');
|
||
var self = this;
|
||
var poll = this.poll = new this.Receiver(this.receiveUrl, this.AjaxObject);
|
||
|
||
poll.on('message', function(msg) {
|
||
debug('message', msg);
|
||
self.emit('message', msg);
|
||
});
|
||
|
||
poll.once('close', function(code, reason) {
|
||
debug('close', code, reason, self.pollIsClosing);
|
||
self.poll = poll = null;
|
||
|
||
if (!self.pollIsClosing) {
|
||
if (reason === 'network') {
|
||
self._scheduleReceiver();
|
||
} else {
|
||
self.emit('close', code || 1006, reason);
|
||
self.removeAllListeners();
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
Polling.prototype.abort = function() {
|
||
debug('abort');
|
||
this.removeAllListeners();
|
||
this.pollIsClosing = true;
|
||
if (this.poll) {
|
||
this.poll.abort();
|
||
}
|
||
};
|
||
|
||
module.exports = Polling;
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"_process":114,"debug":1,"events":35,"inherits":7}],60:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, urlUtils = require('../../utils/url')
|
||
, BufferedSender = require('./buffered-sender')
|
||
, Polling = require('./polling')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:sender-receiver');
|
||
}
|
||
|
||
function SenderReceiver(transUrl, urlSuffix, senderFunc, Receiver, AjaxObject) {
|
||
var pollUrl = urlUtils.addPath(transUrl, urlSuffix);
|
||
debug(pollUrl);
|
||
var self = this;
|
||
BufferedSender.call(this, transUrl, senderFunc);
|
||
|
||
this.poll = new Polling(Receiver, pollUrl, AjaxObject);
|
||
this.poll.on('message', function(msg) {
|
||
debug('poll message', msg);
|
||
self.emit('message', msg);
|
||
});
|
||
this.poll.once('close', function(code, reason) {
|
||
debug('poll close', code, reason);
|
||
self.poll = null;
|
||
self.emit('close', code, reason);
|
||
self.close();
|
||
});
|
||
}
|
||
|
||
inherits(SenderReceiver, BufferedSender);
|
||
|
||
SenderReceiver.prototype.close = function() {
|
||
debug('close');
|
||
this.removeAllListeners();
|
||
if (this.poll) {
|
||
this.poll.abort();
|
||
this.poll = null;
|
||
}
|
||
this.stop();
|
||
};
|
||
|
||
module.exports = SenderReceiver;
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"../../utils/url":84,"./buffered-sender":57,"./polling":59,"_process":114,"debug":1,"inherits":7}],61:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, EventEmitter = require('events').EventEmitter
|
||
, EventSourceDriver = require('eventsource')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:receiver:eventsource');
|
||
}
|
||
|
||
function EventSourceReceiver(url) {
|
||
debug(url);
|
||
EventEmitter.call(this);
|
||
|
||
var self = this;
|
||
var es = this.es = new EventSourceDriver(url);
|
||
es.onmessage = function(e) {
|
||
debug('message', e.data);
|
||
self.emit('message', decodeURI(e.data));
|
||
};
|
||
es.onerror = function(e) {
|
||
debug('error', es.readyState, e);
|
||
// ES on reconnection has readyState = 0 or 1.
|
||
// on network error it's CLOSED = 2
|
||
var reason = (es.readyState !== 2 ? 'network' : 'permanent');
|
||
self._cleanup();
|
||
self._close(reason);
|
||
};
|
||
}
|
||
|
||
inherits(EventSourceReceiver, EventEmitter);
|
||
|
||
EventSourceReceiver.prototype.abort = function() {
|
||
debug('abort');
|
||
this._cleanup();
|
||
this._close('user');
|
||
};
|
||
|
||
EventSourceReceiver.prototype._cleanup = function() {
|
||
debug('cleanup');
|
||
var es = this.es;
|
||
if (es) {
|
||
es.onmessage = es.onerror = null;
|
||
es.close();
|
||
this.es = null;
|
||
}
|
||
};
|
||
|
||
EventSourceReceiver.prototype._close = function(reason) {
|
||
debug('close', reason);
|
||
var self = this;
|
||
// Safari and chrome < 15 crash if we close window before
|
||
// waiting for ES cleanup. See:
|
||
// https://code.google.com/p/chromium/issues/detail?id=89155
|
||
setTimeout(function() {
|
||
self.emit('close', null, reason);
|
||
self.removeAllListeners();
|
||
}, 200);
|
||
};
|
||
|
||
module.exports = EventSourceReceiver;
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"_process":114,"debug":1,"events":35,"eventsource":50,"inherits":7}],62:[function(require,module,exports){
|
||
(function (process,global){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, iframeUtils = require('../../utils/iframe')
|
||
, urlUtils = require('../../utils/url')
|
||
, EventEmitter = require('events').EventEmitter
|
||
, random = require('../../utils/random')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:receiver:htmlfile');
|
||
}
|
||
|
||
function HtmlfileReceiver(url) {
|
||
debug(url);
|
||
EventEmitter.call(this);
|
||
var self = this;
|
||
iframeUtils.polluteGlobalNamespace();
|
||
|
||
this.id = 'a' + random.string(6);
|
||
url = urlUtils.addQuery(url, 'c=' + decodeURIComponent(iframeUtils.WPrefix + '.' + this.id));
|
||
|
||
debug('using htmlfile', HtmlfileReceiver.htmlfileEnabled);
|
||
var constructFunc = HtmlfileReceiver.htmlfileEnabled ?
|
||
iframeUtils.createHtmlfile : iframeUtils.createIframe;
|
||
|
||
global[iframeUtils.WPrefix][this.id] = {
|
||
start: function() {
|
||
debug('start');
|
||
self.iframeObj.loaded();
|
||
}
|
||
, message: function(data) {
|
||
debug('message', data);
|
||
self.emit('message', data);
|
||
}
|
||
, stop: function() {
|
||
debug('stop');
|
||
self._cleanup();
|
||
self._close('network');
|
||
}
|
||
};
|
||
this.iframeObj = constructFunc(url, function() {
|
||
debug('callback');
|
||
self._cleanup();
|
||
self._close('permanent');
|
||
});
|
||
}
|
||
|
||
inherits(HtmlfileReceiver, EventEmitter);
|
||
|
||
HtmlfileReceiver.prototype.abort = function() {
|
||
debug('abort');
|
||
this._cleanup();
|
||
this._close('user');
|
||
};
|
||
|
||
HtmlfileReceiver.prototype._cleanup = function() {
|
||
debug('_cleanup');
|
||
if (this.iframeObj) {
|
||
this.iframeObj.cleanup();
|
||
this.iframeObj = null;
|
||
}
|
||
delete global[iframeUtils.WPrefix][this.id];
|
||
};
|
||
|
||
HtmlfileReceiver.prototype._close = function(reason) {
|
||
debug('_close', reason);
|
||
this.emit('close', null, reason);
|
||
this.removeAllListeners();
|
||
};
|
||
|
||
HtmlfileReceiver.htmlfileEnabled = false;
|
||
|
||
// obfuscate to avoid firewalls
|
||
var axo = ['Active'].concat('Object').join('X');
|
||
if (axo in global) {
|
||
try {
|
||
HtmlfileReceiver.htmlfileEnabled = !!new global[axo]('htmlfile');
|
||
} catch (x) {
|
||
// intentionally empty
|
||
}
|
||
}
|
||
|
||
HtmlfileReceiver.enabled = HtmlfileReceiver.htmlfileEnabled || iframeUtils.iframeEnabled;
|
||
|
||
module.exports = HtmlfileReceiver;
|
||
|
||
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"../../utils/iframe":79,"../../utils/random":82,"../../utils/url":84,"_process":114,"debug":1,"events":35,"inherits":7}],63:[function(require,module,exports){
|
||
(function (process,global){
|
||
'use strict';
|
||
|
||
var utils = require('../../utils/iframe')
|
||
, random = require('../../utils/random')
|
||
, browser = require('../../utils/browser')
|
||
, urlUtils = require('../../utils/url')
|
||
, inherits = require('inherits')
|
||
, EventEmitter = require('events').EventEmitter
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:receiver:jsonp');
|
||
}
|
||
|
||
function JsonpReceiver(url) {
|
||
debug(url);
|
||
var self = this;
|
||
EventEmitter.call(this);
|
||
|
||
utils.polluteGlobalNamespace();
|
||
|
||
this.id = 'a' + random.string(6);
|
||
var urlWithId = urlUtils.addQuery(url, 'c=' + encodeURIComponent(utils.WPrefix + '.' + this.id));
|
||
|
||
global[utils.WPrefix][this.id] = this._callback.bind(this);
|
||
this._createScript(urlWithId);
|
||
|
||
// Fallback mostly for Konqueror - stupid timer, 35 seconds shall be plenty.
|
||
this.timeoutId = setTimeout(function() {
|
||
debug('timeout');
|
||
self._abort(new Error('JSONP script loaded abnormally (timeout)'));
|
||
}, JsonpReceiver.timeout);
|
||
}
|
||
|
||
inherits(JsonpReceiver, EventEmitter);
|
||
|
||
JsonpReceiver.prototype.abort = function() {
|
||
debug('abort');
|
||
if (global[utils.WPrefix][this.id]) {
|
||
var err = new Error('JSONP user aborted read');
|
||
err.code = 1000;
|
||
this._abort(err);
|
||
}
|
||
};
|
||
|
||
JsonpReceiver.timeout = 35000;
|
||
JsonpReceiver.scriptErrorTimeout = 1000;
|
||
|
||
JsonpReceiver.prototype._callback = function(data) {
|
||
debug('_callback', data);
|
||
this._cleanup();
|
||
|
||
if (this.aborting) {
|
||
return;
|
||
}
|
||
|
||
if (data) {
|
||
debug('message', data);
|
||
this.emit('message', data);
|
||
}
|
||
this.emit('close', null, 'network');
|
||
this.removeAllListeners();
|
||
};
|
||
|
||
JsonpReceiver.prototype._abort = function(err) {
|
||
debug('_abort', err);
|
||
this._cleanup();
|
||
this.aborting = true;
|
||
this.emit('close', err.code, err.message);
|
||
this.removeAllListeners();
|
||
};
|
||
|
||
JsonpReceiver.prototype._cleanup = function() {
|
||
debug('_cleanup');
|
||
clearTimeout(this.timeoutId);
|
||
if (this.script2) {
|
||
this.script2.parentNode.removeChild(this.script2);
|
||
this.script2 = null;
|
||
}
|
||
if (this.script) {
|
||
var script = this.script;
|
||
// Unfortunately, you can't really abort script loading of
|
||
// the script.
|
||
script.parentNode.removeChild(script);
|
||
script.onreadystatechange = script.onerror =
|
||
script.onload = script.onclick = null;
|
||
this.script = null;
|
||
}
|
||
delete global[utils.WPrefix][this.id];
|
||
};
|
||
|
||
JsonpReceiver.prototype._scriptError = function() {
|
||
debug('_scriptError');
|
||
var self = this;
|
||
if (this.errorTimer) {
|
||
return;
|
||
}
|
||
|
||
this.errorTimer = setTimeout(function() {
|
||
if (!self.loadedOkay) {
|
||
self._abort(new Error('JSONP script loaded abnormally (onerror)'));
|
||
}
|
||
}, JsonpReceiver.scriptErrorTimeout);
|
||
};
|
||
|
||
JsonpReceiver.prototype._createScript = function(url) {
|
||
debug('_createScript', url);
|
||
var self = this;
|
||
var script = this.script = global.document.createElement('script');
|
||
var script2; // Opera synchronous load trick.
|
||
|
||
script.id = 'a' + random.string(8);
|
||
script.src = url;
|
||
script.type = 'text/javascript';
|
||
script.charset = 'UTF-8';
|
||
script.onerror = this._scriptError.bind(this);
|
||
script.onload = function() {
|
||
debug('onload');
|
||
self._abort(new Error('JSONP script loaded abnormally (onload)'));
|
||
};
|
||
|
||
// IE9 fires 'error' event after onreadystatechange or before, in random order.
|
||
// Use loadedOkay to determine if actually errored
|
||
script.onreadystatechange = function() {
|
||
debug('onreadystatechange', script.readyState);
|
||
if (/loaded|closed/.test(script.readyState)) {
|
||
if (script && script.htmlFor && script.onclick) {
|
||
self.loadedOkay = true;
|
||
try {
|
||
// In IE, actually execute the script.
|
||
script.onclick();
|
||
} catch (x) {
|
||
// intentionally empty
|
||
}
|
||
}
|
||
if (script) {
|
||
self._abort(new Error('JSONP script loaded abnormally (onreadystatechange)'));
|
||
}
|
||
}
|
||
};
|
||
// IE: event/htmlFor/onclick trick.
|
||
// One can't rely on proper order for onreadystatechange. In order to
|
||
// make sure, set a 'htmlFor' and 'event' properties, so that
|
||
// script code will be installed as 'onclick' handler for the
|
||
// script object. Later, onreadystatechange, manually execute this
|
||
// code. FF and Chrome doesn't work with 'event' and 'htmlFor'
|
||
// set. For reference see:
|
||
// http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
|
||
// Also, read on that about script ordering:
|
||
// http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
|
||
if (typeof script.async === 'undefined' && global.document.attachEvent) {
|
||
// According to mozilla docs, in recent browsers script.async defaults
|
||
// to 'true', so we may use it to detect a good browser:
|
||
// https://developer.mozilla.org/en/HTML/Element/script
|
||
if (!browser.isOpera()) {
|
||
// Naively assume we're in IE
|
||
try {
|
||
script.htmlFor = script.id;
|
||
script.event = 'onclick';
|
||
} catch (x) {
|
||
// intentionally empty
|
||
}
|
||
script.async = true;
|
||
} else {
|
||
// Opera, second sync script hack
|
||
script2 = this.script2 = global.document.createElement('script');
|
||
script2.text = "try{var a = document.getElementById('" + script.id + "'); if(a)a.onerror();}catch(x){};";
|
||
script.async = script2.async = false;
|
||
}
|
||
}
|
||
if (typeof script.async !== 'undefined') {
|
||
script.async = true;
|
||
}
|
||
|
||
var head = global.document.getElementsByTagName('head')[0];
|
||
head.insertBefore(script, head.firstChild);
|
||
if (script2) {
|
||
head.insertBefore(script2, head.firstChild);
|
||
}
|
||
};
|
||
|
||
module.exports = JsonpReceiver;
|
||
|
||
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"../../utils/browser":76,"../../utils/iframe":79,"../../utils/random":82,"../../utils/url":84,"_process":114,"debug":1,"events":35,"inherits":7}],64:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, EventEmitter = require('events').EventEmitter
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:receiver:xhr');
|
||
}
|
||
|
||
function XhrReceiver(url, AjaxObject) {
|
||
debug(url);
|
||
EventEmitter.call(this);
|
||
var self = this;
|
||
|
||
this.bufferPosition = 0;
|
||
|
||
this.xo = new AjaxObject('POST', url, null);
|
||
this.xo.on('chunk', this._chunkHandler.bind(this));
|
||
this.xo.once('finish', function(status, text) {
|
||
debug('finish', status, text);
|
||
self._chunkHandler(status, text);
|
||
self.xo = null;
|
||
var reason = status === 200 ? 'network' : 'permanent';
|
||
debug('close', reason);
|
||
self.emit('close', null, reason);
|
||
self._cleanup();
|
||
});
|
||
}
|
||
|
||
inherits(XhrReceiver, EventEmitter);
|
||
|
||
XhrReceiver.prototype._chunkHandler = function(status, text) {
|
||
debug('_chunkHandler', status);
|
||
if (status !== 200 || !text) {
|
||
return;
|
||
}
|
||
|
||
for (var idx = -1; ; this.bufferPosition += idx + 1) {
|
||
var buf = text.slice(this.bufferPosition);
|
||
idx = buf.indexOf('\n');
|
||
if (idx === -1) {
|
||
break;
|
||
}
|
||
var msg = buf.slice(0, idx);
|
||
if (msg) {
|
||
debug('message', msg);
|
||
this.emit('message', msg);
|
||
}
|
||
}
|
||
};
|
||
|
||
XhrReceiver.prototype._cleanup = function() {
|
||
debug('_cleanup');
|
||
this.removeAllListeners();
|
||
};
|
||
|
||
XhrReceiver.prototype.abort = function() {
|
||
debug('abort');
|
||
if (this.xo) {
|
||
this.xo.close();
|
||
debug('close');
|
||
this.emit('close', null, 'user');
|
||
this.xo = null;
|
||
}
|
||
this._cleanup();
|
||
};
|
||
|
||
module.exports = XhrReceiver;
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"_process":114,"debug":1,"events":35,"inherits":7}],65:[function(require,module,exports){
|
||
(function (process,global){
|
||
'use strict';
|
||
|
||
var random = require('../../utils/random')
|
||
, urlUtils = require('../../utils/url')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:sender:jsonp');
|
||
}
|
||
|
||
var form, area;
|
||
|
||
function createIframe(id) {
|
||
debug('createIframe', id);
|
||
try {
|
||
// ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
|
||
return global.document.createElement('<iframe name="' + id + '">');
|
||
} catch (x) {
|
||
var iframe = global.document.createElement('iframe');
|
||
iframe.name = id;
|
||
return iframe;
|
||
}
|
||
}
|
||
|
||
function createForm() {
|
||
debug('createForm');
|
||
form = global.document.createElement('form');
|
||
form.style.display = 'none';
|
||
form.style.position = 'absolute';
|
||
form.method = 'POST';
|
||
form.enctype = 'application/x-www-form-urlencoded';
|
||
form.acceptCharset = 'UTF-8';
|
||
|
||
area = global.document.createElement('textarea');
|
||
area.name = 'd';
|
||
form.appendChild(area);
|
||
|
||
global.document.body.appendChild(form);
|
||
}
|
||
|
||
module.exports = function(url, payload, callback) {
|
||
debug(url, payload);
|
||
if (!form) {
|
||
createForm();
|
||
}
|
||
var id = 'a' + random.string(8);
|
||
form.target = id;
|
||
form.action = urlUtils.addQuery(urlUtils.addPath(url, '/jsonp_send'), 'i=' + id);
|
||
|
||
var iframe = createIframe(id);
|
||
iframe.id = id;
|
||
iframe.style.display = 'none';
|
||
form.appendChild(iframe);
|
||
|
||
try {
|
||
area.value = payload;
|
||
} catch (e) {
|
||
// seriously broken browsers get here
|
||
}
|
||
form.submit();
|
||
|
||
var completed = function(err) {
|
||
debug('completed', id, err);
|
||
if (!iframe.onerror) {
|
||
return;
|
||
}
|
||
iframe.onreadystatechange = iframe.onerror = iframe.onload = null;
|
||
// Opera mini doesn't like if we GC iframe
|
||
// immediately, thus this timeout.
|
||
setTimeout(function() {
|
||
debug('cleaning up', id);
|
||
iframe.parentNode.removeChild(iframe);
|
||
iframe = null;
|
||
}, 500);
|
||
area.value = '';
|
||
// It is not possible to detect if the iframe succeeded or
|
||
// failed to submit our form.
|
||
callback(err);
|
||
};
|
||
iframe.onerror = function() {
|
||
debug('onerror', id);
|
||
completed();
|
||
};
|
||
iframe.onload = function() {
|
||
debug('onload', id);
|
||
completed();
|
||
};
|
||
iframe.onreadystatechange = function(e) {
|
||
debug('onreadystatechange', id, iframe.readyState, e);
|
||
if (iframe.readyState === 'complete') {
|
||
completed();
|
||
}
|
||
};
|
||
return function() {
|
||
debug('aborted', id);
|
||
completed(new Error('Aborted'));
|
||
};
|
||
};
|
||
|
||
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"../../utils/random":82,"../../utils/url":84,"_process":114,"debug":1}],66:[function(require,module,exports){
|
||
(function (process,global){
|
||
'use strict';
|
||
|
||
var EventEmitter = require('events').EventEmitter
|
||
, inherits = require('inherits')
|
||
, eventUtils = require('../../utils/event')
|
||
, browser = require('../../utils/browser')
|
||
, urlUtils = require('../../utils/url')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:sender:xdr');
|
||
}
|
||
|
||
// References:
|
||
// http://ajaxian.com/archives/100-line-ajax-wrapper
|
||
// http://msdn.microsoft.com/en-us/library/cc288060(v=VS.85).aspx
|
||
|
||
function XDRObject(method, url, payload) {
|
||
debug(method, url);
|
||
var self = this;
|
||
EventEmitter.call(this);
|
||
|
||
setTimeout(function() {
|
||
self._start(method, url, payload);
|
||
}, 0);
|
||
}
|
||
|
||
inherits(XDRObject, EventEmitter);
|
||
|
||
XDRObject.prototype._start = function(method, url, payload) {
|
||
debug('_start');
|
||
var self = this;
|
||
var xdr = new global.XDomainRequest();
|
||
// IE caches even POSTs
|
||
url = urlUtils.addQuery(url, 't=' + (+new Date()));
|
||
|
||
xdr.onerror = function() {
|
||
debug('onerror');
|
||
self._error();
|
||
};
|
||
xdr.ontimeout = function() {
|
||
debug('ontimeout');
|
||
self._error();
|
||
};
|
||
xdr.onprogress = function() {
|
||
debug('progress', xdr.responseText);
|
||
self.emit('chunk', 200, xdr.responseText);
|
||
};
|
||
xdr.onload = function() {
|
||
debug('load');
|
||
self.emit('finish', 200, xdr.responseText);
|
||
self._cleanup(false);
|
||
};
|
||
this.xdr = xdr;
|
||
this.unloadRef = eventUtils.unloadAdd(function() {
|
||
self._cleanup(true);
|
||
});
|
||
try {
|
||
// Fails with AccessDenied if port number is bogus
|
||
this.xdr.open(method, url);
|
||
if (this.timeout) {
|
||
this.xdr.timeout = this.timeout;
|
||
}
|
||
this.xdr.send(payload);
|
||
} catch (x) {
|
||
this._error();
|
||
}
|
||
};
|
||
|
||
XDRObject.prototype._error = function() {
|
||
this.emit('finish', 0, '');
|
||
this._cleanup(false);
|
||
};
|
||
|
||
XDRObject.prototype._cleanup = function(abort) {
|
||
debug('cleanup', abort);
|
||
if (!this.xdr) {
|
||
return;
|
||
}
|
||
this.removeAllListeners();
|
||
eventUtils.unloadDel(this.unloadRef);
|
||
|
||
this.xdr.ontimeout = this.xdr.onerror = this.xdr.onprogress = this.xdr.onload = null;
|
||
if (abort) {
|
||
try {
|
||
this.xdr.abort();
|
||
} catch (x) {
|
||
// intentionally empty
|
||
}
|
||
}
|
||
this.unloadRef = this.xdr = null;
|
||
};
|
||
|
||
XDRObject.prototype.close = function() {
|
||
debug('close');
|
||
this._cleanup(true);
|
||
};
|
||
|
||
// IE 8/9 if the request target uses the same scheme - #79
|
||
XDRObject.enabled = !!(global.XDomainRequest && browser.hasDomain());
|
||
|
||
module.exports = XDRObject;
|
||
|
||
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"../../utils/browser":76,"../../utils/event":78,"../../utils/url":84,"_process":114,"debug":1,"events":35,"inherits":7}],67:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, XhrDriver = require('../driver/xhr')
|
||
;
|
||
|
||
function XHRCorsObject(method, url, payload, opts) {
|
||
XhrDriver.call(this, method, url, payload, opts);
|
||
}
|
||
|
||
inherits(XHRCorsObject, XhrDriver);
|
||
|
||
XHRCorsObject.enabled = XhrDriver.enabled && XhrDriver.supportsCORS;
|
||
|
||
module.exports = XHRCorsObject;
|
||
|
||
},{"../driver/xhr":49,"inherits":7}],68:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var EventEmitter = require('events').EventEmitter
|
||
, inherits = require('inherits')
|
||
;
|
||
|
||
function XHRFake(/* method, url, payload, opts */) {
|
||
var self = this;
|
||
EventEmitter.call(this);
|
||
|
||
this.to = setTimeout(function() {
|
||
self.emit('finish', 200, '{}');
|
||
}, XHRFake.timeout);
|
||
}
|
||
|
||
inherits(XHRFake, EventEmitter);
|
||
|
||
XHRFake.prototype.close = function() {
|
||
clearTimeout(this.to);
|
||
};
|
||
|
||
XHRFake.timeout = 2000;
|
||
|
||
module.exports = XHRFake;
|
||
|
||
},{"events":35,"inherits":7}],69:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, XhrDriver = require('../driver/xhr')
|
||
;
|
||
|
||
function XHRLocalObject(method, url, payload /*, opts */) {
|
||
XhrDriver.call(this, method, url, payload, {
|
||
noCredentials: true
|
||
});
|
||
}
|
||
|
||
inherits(XHRLocalObject, XhrDriver);
|
||
|
||
XHRLocalObject.enabled = XhrDriver.enabled;
|
||
|
||
module.exports = XHRLocalObject;
|
||
|
||
},{"../driver/xhr":49,"inherits":7}],70:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var utils = require('../utils/event')
|
||
, urlUtils = require('../utils/url')
|
||
, inherits = require('inherits')
|
||
, EventEmitter = require('events').EventEmitter
|
||
, WebsocketDriver = require('./driver/websocket')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:websocket');
|
||
}
|
||
|
||
function WebSocketTransport(transUrl, ignore, options) {
|
||
if (!WebSocketTransport.enabled()) {
|
||
throw new Error('Transport created when disabled');
|
||
}
|
||
|
||
EventEmitter.call(this);
|
||
debug('constructor', transUrl);
|
||
|
||
var self = this;
|
||
var url = urlUtils.addPath(transUrl, '/websocket');
|
||
if (url.slice(0, 5) === 'https') {
|
||
url = 'wss' + url.slice(5);
|
||
} else {
|
||
url = 'ws' + url.slice(4);
|
||
}
|
||
this.url = url;
|
||
|
||
this.ws = new WebsocketDriver(this.url, [], options);
|
||
this.ws.onmessage = function(e) {
|
||
debug('message event', e.data);
|
||
self.emit('message', e.data);
|
||
};
|
||
// Firefox has an interesting bug. If a websocket connection is
|
||
// created after onunload, it stays alive even when user
|
||
// navigates away from the page. In such situation let's lie -
|
||
// let's not open the ws connection at all. See:
|
||
// https://github.com/sockjs/sockjs-client/issues/28
|
||
// https://bugzilla.mozilla.org/show_bug.cgi?id=696085
|
||
this.unloadRef = utils.unloadAdd(function() {
|
||
debug('unload');
|
||
self.ws.close();
|
||
});
|
||
this.ws.onclose = function(e) {
|
||
debug('close event', e.code, e.reason);
|
||
self.emit('close', e.code, e.reason);
|
||
self._cleanup();
|
||
};
|
||
this.ws.onerror = function(e) {
|
||
debug('error event', e);
|
||
self.emit('close', 1006, 'WebSocket connection broken');
|
||
self._cleanup();
|
||
};
|
||
}
|
||
|
||
inherits(WebSocketTransport, EventEmitter);
|
||
|
||
WebSocketTransport.prototype.send = function(data) {
|
||
var msg = '[' + data + ']';
|
||
debug('send', msg);
|
||
this.ws.send(msg);
|
||
};
|
||
|
||
WebSocketTransport.prototype.close = function() {
|
||
debug('close');
|
||
if (this.ws) {
|
||
this.ws.close();
|
||
}
|
||
this._cleanup();
|
||
};
|
||
|
||
WebSocketTransport.prototype._cleanup = function() {
|
||
debug('_cleanup');
|
||
var ws = this.ws;
|
||
if (ws) {
|
||
ws.onmessage = ws.onclose = ws.onerror = null;
|
||
}
|
||
utils.unloadDel(this.unloadRef);
|
||
this.unloadRef = this.ws = null;
|
||
this.removeAllListeners();
|
||
};
|
||
|
||
WebSocketTransport.enabled = function() {
|
||
debug('enabled');
|
||
return !!WebsocketDriver;
|
||
};
|
||
WebSocketTransport.transportName = 'websocket';
|
||
|
||
// In theory, ws should require 1 round trip. But in chrome, this is
|
||
// not very stable over SSL. Most likely a ws connection requires a
|
||
// separate SSL connection, in which case 2 round trips are an
|
||
// absolute minumum.
|
||
WebSocketTransport.roundTrips = 2;
|
||
|
||
module.exports = WebSocketTransport;
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"../utils/event":78,"../utils/url":84,"./driver/websocket":51,"_process":114,"debug":1,"events":35,"inherits":7}],71:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, AjaxBasedTransport = require('./lib/ajax-based')
|
||
, XdrStreamingTransport = require('./xdr-streaming')
|
||
, XhrReceiver = require('./receiver/xhr')
|
||
, XDRObject = require('./sender/xdr')
|
||
;
|
||
|
||
function XdrPollingTransport(transUrl) {
|
||
if (!XDRObject.enabled) {
|
||
throw new Error('Transport created when disabled');
|
||
}
|
||
AjaxBasedTransport.call(this, transUrl, '/xhr', XhrReceiver, XDRObject);
|
||
}
|
||
|
||
inherits(XdrPollingTransport, AjaxBasedTransport);
|
||
|
||
XdrPollingTransport.enabled = XdrStreamingTransport.enabled;
|
||
XdrPollingTransport.transportName = 'xdr-polling';
|
||
XdrPollingTransport.roundTrips = 2; // preflight, ajax
|
||
|
||
module.exports = XdrPollingTransport;
|
||
|
||
},{"./lib/ajax-based":56,"./receiver/xhr":64,"./sender/xdr":66,"./xdr-streaming":72,"inherits":7}],72:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, AjaxBasedTransport = require('./lib/ajax-based')
|
||
, XhrReceiver = require('./receiver/xhr')
|
||
, XDRObject = require('./sender/xdr')
|
||
;
|
||
|
||
// According to:
|
||
// http://stackoverflow.com/questions/1641507/detect-browser-support-for-cross-domain-xmlhttprequests
|
||
// http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/
|
||
|
||
function XdrStreamingTransport(transUrl) {
|
||
if (!XDRObject.enabled) {
|
||
throw new Error('Transport created when disabled');
|
||
}
|
||
AjaxBasedTransport.call(this, transUrl, '/xhr_streaming', XhrReceiver, XDRObject);
|
||
}
|
||
|
||
inherits(XdrStreamingTransport, AjaxBasedTransport);
|
||
|
||
XdrStreamingTransport.enabled = function(info) {
|
||
if (info.cookie_needed || info.nullOrigin) {
|
||
return false;
|
||
}
|
||
return XDRObject.enabled && info.sameScheme;
|
||
};
|
||
|
||
XdrStreamingTransport.transportName = 'xdr-streaming';
|
||
XdrStreamingTransport.roundTrips = 2; // preflight, ajax
|
||
|
||
module.exports = XdrStreamingTransport;
|
||
|
||
},{"./lib/ajax-based":56,"./receiver/xhr":64,"./sender/xdr":66,"inherits":7}],73:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, AjaxBasedTransport = require('./lib/ajax-based')
|
||
, XhrReceiver = require('./receiver/xhr')
|
||
, XHRCorsObject = require('./sender/xhr-cors')
|
||
, XHRLocalObject = require('./sender/xhr-local')
|
||
;
|
||
|
||
function XhrPollingTransport(transUrl) {
|
||
if (!XHRLocalObject.enabled && !XHRCorsObject.enabled) {
|
||
throw new Error('Transport created when disabled');
|
||
}
|
||
AjaxBasedTransport.call(this, transUrl, '/xhr', XhrReceiver, XHRCorsObject);
|
||
}
|
||
|
||
inherits(XhrPollingTransport, AjaxBasedTransport);
|
||
|
||
XhrPollingTransport.enabled = function(info) {
|
||
if (info.nullOrigin) {
|
||
return false;
|
||
}
|
||
|
||
if (XHRLocalObject.enabled && info.sameOrigin) {
|
||
return true;
|
||
}
|
||
return XHRCorsObject.enabled;
|
||
};
|
||
|
||
XhrPollingTransport.transportName = 'xhr-polling';
|
||
XhrPollingTransport.roundTrips = 2; // preflight, ajax
|
||
|
||
module.exports = XhrPollingTransport;
|
||
|
||
},{"./lib/ajax-based":56,"./receiver/xhr":64,"./sender/xhr-cors":67,"./sender/xhr-local":69,"inherits":7}],74:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
var inherits = require('inherits')
|
||
, AjaxBasedTransport = require('./lib/ajax-based')
|
||
, XhrReceiver = require('./receiver/xhr')
|
||
, XHRCorsObject = require('./sender/xhr-cors')
|
||
, XHRLocalObject = require('./sender/xhr-local')
|
||
, browser = require('../utils/browser')
|
||
;
|
||
|
||
function XhrStreamingTransport(transUrl) {
|
||
if (!XHRLocalObject.enabled && !XHRCorsObject.enabled) {
|
||
throw new Error('Transport created when disabled');
|
||
}
|
||
AjaxBasedTransport.call(this, transUrl, '/xhr_streaming', XhrReceiver, XHRCorsObject);
|
||
}
|
||
|
||
inherits(XhrStreamingTransport, AjaxBasedTransport);
|
||
|
||
XhrStreamingTransport.enabled = function(info) {
|
||
if (info.nullOrigin) {
|
||
return false;
|
||
}
|
||
// Opera doesn't support xhr-streaming #60
|
||
// But it might be able to #92
|
||
if (browser.isOpera()) {
|
||
return false;
|
||
}
|
||
|
||
return XHRCorsObject.enabled;
|
||
};
|
||
|
||
XhrStreamingTransport.transportName = 'xhr-streaming';
|
||
XhrStreamingTransport.roundTrips = 2; // preflight, ajax
|
||
|
||
// Safari gets confused when a streaming ajax request is started
|
||
// before onload. This causes the load indicator to spin indefinetely.
|
||
// Only require body when used in a browser
|
||
XhrStreamingTransport.needBody = !!global.document;
|
||
|
||
module.exports = XhrStreamingTransport;
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"../utils/browser":76,"./lib/ajax-based":56,"./receiver/xhr":64,"./sender/xhr-cors":67,"./sender/xhr-local":69,"inherits":7}],75:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
if (global.crypto && global.crypto.getRandomValues) {
|
||
module.exports.randomBytes = function(length) {
|
||
var bytes = new Uint8Array(length);
|
||
global.crypto.getRandomValues(bytes);
|
||
return bytes;
|
||
};
|
||
} else {
|
||
module.exports.randomBytes = function(length) {
|
||
var bytes = new Array(length);
|
||
for (var i = 0; i < length; i++) {
|
||
bytes[i] = Math.floor(Math.random() * 256);
|
||
}
|
||
return bytes;
|
||
};
|
||
}
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{}],76:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
module.exports = {
|
||
isOpera: function() {
|
||
return global.navigator &&
|
||
/opera/i.test(global.navigator.userAgent);
|
||
}
|
||
|
||
, isKonqueror: function() {
|
||
return global.navigator &&
|
||
/konqueror/i.test(global.navigator.userAgent);
|
||
}
|
||
|
||
// #187 wrap document.domain in try/catch because of WP8 from file:///
|
||
, hasDomain: function () {
|
||
// non-browser client always has a domain
|
||
if (!global.document) {
|
||
return true;
|
||
}
|
||
|
||
try {
|
||
return !!global.document.domain;
|
||
} catch (e) {
|
||
return false;
|
||
}
|
||
}
|
||
};
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{}],77:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var JSON3 = require('json3');
|
||
|
||
// Some extra characters that Chrome gets wrong, and substitutes with
|
||
// something else on the wire.
|
||
var extraEscapable = /[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f80-\u0f83\u0f93\u0f9d\u0fa2\u0fa7\u0fac\u0fb9\u1939-\u193a\u1a17\u1b6b\u1cda-\u1cdb\u1dc0-\u1dcf\u1dfc\u1dfe\u1f71\u1f73\u1f75\u1f77\u1f79\u1f7b\u1f7d\u1fbb\u1fbe\u1fc9\u1fcb\u1fd3\u1fdb\u1fe3\u1feb\u1fee-\u1fef\u1ff9\u1ffb\u1ffd\u2000-\u2001\u20d0-\u20d1\u20d4-\u20d7\u20e7-\u20e9\u2126\u212a-\u212b\u2329-\u232a\u2adc\u302b-\u302c\uaab2-\uaab3\uf900-\ufa0d\ufa10\ufa12\ufa15-\ufa1e\ufa20\ufa22\ufa25-\ufa26\ufa2a-\ufa2d\ufa30-\ufa6d\ufa70-\ufad9\ufb1d\ufb1f\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4e\ufff0-\uffff]/g
|
||
, extraLookup;
|
||
|
||
// This may be quite slow, so let's delay until user actually uses bad
|
||
// characters.
|
||
var unrollLookup = function(escapable) {
|
||
var i;
|
||
var unrolled = {};
|
||
var c = [];
|
||
for (i = 0; i < 65536; i++) {
|
||
c.push( String.fromCharCode(i) );
|
||
}
|
||
escapable.lastIndex = 0;
|
||
c.join('').replace(escapable, function(a) {
|
||
unrolled[ a ] = '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||
return '';
|
||
});
|
||
escapable.lastIndex = 0;
|
||
return unrolled;
|
||
};
|
||
|
||
// Quote string, also taking care of unicode characters that browsers
|
||
// often break. Especially, take care of unicode surrogates:
|
||
// http://en.wikipedia.org/wiki/Mapping_of_Unicode_characters#Surrogates
|
||
module.exports = {
|
||
quote: function(string) {
|
||
var quoted = JSON3.stringify(string);
|
||
|
||
// In most cases this should be very fast and good enough.
|
||
extraEscapable.lastIndex = 0;
|
||
if (!extraEscapable.test(quoted)) {
|
||
return quoted;
|
||
}
|
||
|
||
if (!extraLookup) {
|
||
extraLookup = unrollLookup(extraEscapable);
|
||
}
|
||
|
||
return quoted.replace(extraEscapable, function(a) {
|
||
return extraLookup[a];
|
||
});
|
||
}
|
||
};
|
||
|
||
},{"json3":8}],78:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
var random = require('./random');
|
||
|
||
var onUnload = {}
|
||
, afterUnload = false
|
||
// detect google chrome packaged apps because they don't allow the 'unload' event
|
||
, isChromePackagedApp = global.chrome && global.chrome.app && global.chrome.app.runtime
|
||
;
|
||
|
||
module.exports = {
|
||
attachEvent: function(event, listener) {
|
||
if (typeof global.addEventListener !== 'undefined') {
|
||
global.addEventListener(event, listener, false);
|
||
} else if (global.document && global.attachEvent) {
|
||
// IE quirks.
|
||
// According to: http://stevesouders.com/misc/test-postmessage.php
|
||
// the message gets delivered only to 'document', not 'window'.
|
||
global.document.attachEvent('on' + event, listener);
|
||
// I get 'window' for ie8.
|
||
global.attachEvent('on' + event, listener);
|
||
}
|
||
}
|
||
|
||
, detachEvent: function(event, listener) {
|
||
if (typeof global.addEventListener !== 'undefined') {
|
||
global.removeEventListener(event, listener, false);
|
||
} else if (global.document && global.detachEvent) {
|
||
global.document.detachEvent('on' + event, listener);
|
||
global.detachEvent('on' + event, listener);
|
||
}
|
||
}
|
||
|
||
, unloadAdd: function(listener) {
|
||
if (isChromePackagedApp) {
|
||
return null;
|
||
}
|
||
|
||
var ref = random.string(8);
|
||
onUnload[ref] = listener;
|
||
if (afterUnload) {
|
||
setTimeout(this.triggerUnloadCallbacks, 0);
|
||
}
|
||
return ref;
|
||
}
|
||
|
||
, unloadDel: function(ref) {
|
||
if (ref in onUnload) {
|
||
delete onUnload[ref];
|
||
}
|
||
}
|
||
|
||
, triggerUnloadCallbacks: function() {
|
||
for (var ref in onUnload) {
|
||
onUnload[ref]();
|
||
delete onUnload[ref];
|
||
}
|
||
}
|
||
};
|
||
|
||
var unloadTriggered = function() {
|
||
if (afterUnload) {
|
||
return;
|
||
}
|
||
afterUnload = true;
|
||
module.exports.triggerUnloadCallbacks();
|
||
};
|
||
|
||
// 'unload' alone is not reliable in opera within an iframe, but we
|
||
// can't use `beforeunload` as IE fires it on javascript: links.
|
||
if (!isChromePackagedApp) {
|
||
module.exports.attachEvent('unload', unloadTriggered);
|
||
}
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"./random":82}],79:[function(require,module,exports){
|
||
(function (process,global){
|
||
'use strict';
|
||
|
||
var eventUtils = require('./event')
|
||
, JSON3 = require('json3')
|
||
, browser = require('./browser')
|
||
;
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:utils:iframe');
|
||
}
|
||
|
||
module.exports = {
|
||
WPrefix: '_jp'
|
||
, currentWindowId: null
|
||
|
||
, polluteGlobalNamespace: function() {
|
||
if (!(module.exports.WPrefix in global)) {
|
||
global[module.exports.WPrefix] = {};
|
||
}
|
||
}
|
||
|
||
, postMessage: function(type, data) {
|
||
if (global.parent !== global) {
|
||
global.parent.postMessage(JSON3.stringify({
|
||
windowId: module.exports.currentWindowId
|
||
, type: type
|
||
, data: data || ''
|
||
}), '*');
|
||
} else {
|
||
debug('Cannot postMessage, no parent window.', type, data);
|
||
}
|
||
}
|
||
|
||
, createIframe: function(iframeUrl, errorCallback) {
|
||
var iframe = global.document.createElement('iframe');
|
||
var tref, unloadRef;
|
||
var unattach = function() {
|
||
debug('unattach');
|
||
clearTimeout(tref);
|
||
// Explorer had problems with that.
|
||
try {
|
||
iframe.onload = null;
|
||
} catch (x) {
|
||
// intentionally empty
|
||
}
|
||
iframe.onerror = null;
|
||
};
|
||
var cleanup = function() {
|
||
debug('cleanup');
|
||
if (iframe) {
|
||
unattach();
|
||
// This timeout makes chrome fire onbeforeunload event
|
||
// within iframe. Without the timeout it goes straight to
|
||
// onunload.
|
||
setTimeout(function() {
|
||
if (iframe) {
|
||
iframe.parentNode.removeChild(iframe);
|
||
}
|
||
iframe = null;
|
||
}, 0);
|
||
eventUtils.unloadDel(unloadRef);
|
||
}
|
||
};
|
||
var onerror = function(err) {
|
||
debug('onerror', err);
|
||
if (iframe) {
|
||
cleanup();
|
||
errorCallback(err);
|
||
}
|
||
};
|
||
var post = function(msg, origin) {
|
||
debug('post', msg, origin);
|
||
try {
|
||
// When the iframe is not loaded, IE raises an exception
|
||
// on 'contentWindow'.
|
||
setTimeout(function() {
|
||
if (iframe && iframe.contentWindow) {
|
||
iframe.contentWindow.postMessage(msg, origin);
|
||
}
|
||
}, 0);
|
||
} catch (x) {
|
||
// intentionally empty
|
||
}
|
||
};
|
||
|
||
iframe.src = iframeUrl;
|
||
iframe.style.display = 'none';
|
||
iframe.style.position = 'absolute';
|
||
iframe.onerror = function() {
|
||
onerror('onerror');
|
||
};
|
||
iframe.onload = function() {
|
||
debug('onload');
|
||
// `onload` is triggered before scripts on the iframe are
|
||
// executed. Give it few seconds to actually load stuff.
|
||
clearTimeout(tref);
|
||
tref = setTimeout(function() {
|
||
onerror('onload timeout');
|
||
}, 2000);
|
||
};
|
||
global.document.body.appendChild(iframe);
|
||
tref = setTimeout(function() {
|
||
onerror('timeout');
|
||
}, 15000);
|
||
unloadRef = eventUtils.unloadAdd(cleanup);
|
||
return {
|
||
post: post
|
||
, cleanup: cleanup
|
||
, loaded: unattach
|
||
};
|
||
}
|
||
|
||
/* jshint undef: false, newcap: false */
|
||
/* eslint no-undef: 0, new-cap: 0 */
|
||
, createHtmlfile: function(iframeUrl, errorCallback) {
|
||
var axo = ['Active'].concat('Object').join('X');
|
||
var doc = new global[axo]('htmlfile');
|
||
var tref, unloadRef;
|
||
var iframe;
|
||
var unattach = function() {
|
||
clearTimeout(tref);
|
||
iframe.onerror = null;
|
||
};
|
||
var cleanup = function() {
|
||
if (doc) {
|
||
unattach();
|
||
eventUtils.unloadDel(unloadRef);
|
||
iframe.parentNode.removeChild(iframe);
|
||
iframe = doc = null;
|
||
CollectGarbage();
|
||
}
|
||
};
|
||
var onerror = function(r) {
|
||
debug('onerror', r);
|
||
if (doc) {
|
||
cleanup();
|
||
errorCallback(r);
|
||
}
|
||
};
|
||
var post = function(msg, origin) {
|
||
try {
|
||
// When the iframe is not loaded, IE raises an exception
|
||
// on 'contentWindow'.
|
||
setTimeout(function() {
|
||
if (iframe && iframe.contentWindow) {
|
||
iframe.contentWindow.postMessage(msg, origin);
|
||
}
|
||
}, 0);
|
||
} catch (x) {
|
||
// intentionally empty
|
||
}
|
||
};
|
||
|
||
doc.open();
|
||
doc.write('<html><s' + 'cript>' +
|
||
'document.domain="' + global.document.domain + '";' +
|
||
'</s' + 'cript></html>');
|
||
doc.close();
|
||
doc.parentWindow[module.exports.WPrefix] = global[module.exports.WPrefix];
|
||
var c = doc.createElement('div');
|
||
doc.body.appendChild(c);
|
||
iframe = doc.createElement('iframe');
|
||
c.appendChild(iframe);
|
||
iframe.src = iframeUrl;
|
||
iframe.onerror = function() {
|
||
onerror('onerror');
|
||
};
|
||
tref = setTimeout(function() {
|
||
onerror('timeout');
|
||
}, 15000);
|
||
unloadRef = eventUtils.unloadAdd(cleanup);
|
||
return {
|
||
post: post
|
||
, cleanup: cleanup
|
||
, loaded: unattach
|
||
};
|
||
}
|
||
};
|
||
|
||
module.exports.iframeEnabled = false;
|
||
if (global.document) {
|
||
// postMessage misbehaves in konqueror 4.6.5 - the messages are delivered with
|
||
// huge delay, or not at all.
|
||
module.exports.iframeEnabled = (typeof global.postMessage === 'function' ||
|
||
typeof global.postMessage === 'object') && (!browser.isKonqueror());
|
||
}
|
||
|
||
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"./browser":76,"./event":78,"_process":114,"debug":1,"json3":8}],80:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
var logObject = {};
|
||
['log', 'debug', 'warn'].forEach(function (level) {
|
||
var levelExists;
|
||
|
||
try {
|
||
levelExists = global.console && global.console[level] && global.console[level].apply;
|
||
} catch(e) {
|
||
// do nothing
|
||
}
|
||
|
||
logObject[level] = levelExists ? function () {
|
||
return global.console[level].apply(global.console, arguments);
|
||
} : (level === 'log' ? function () {} : logObject.log);
|
||
});
|
||
|
||
module.exports = logObject;
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{}],81:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
module.exports = {
|
||
isObject: function(obj) {
|
||
var type = typeof obj;
|
||
return type === 'function' || type === 'object' && !!obj;
|
||
}
|
||
|
||
, extend: function(obj) {
|
||
if (!this.isObject(obj)) {
|
||
return obj;
|
||
}
|
||
var source, prop;
|
||
for (var i = 1, length = arguments.length; i < length; i++) {
|
||
source = arguments[i];
|
||
for (prop in source) {
|
||
if (Object.prototype.hasOwnProperty.call(source, prop)) {
|
||
obj[prop] = source[prop];
|
||
}
|
||
}
|
||
}
|
||
return obj;
|
||
}
|
||
};
|
||
|
||
},{}],82:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
/* global crypto:true */
|
||
var crypto = require('crypto');
|
||
|
||
// This string has length 32, a power of 2, so the modulus doesn't introduce a
|
||
// bias.
|
||
var _randomStringChars = 'abcdefghijklmnopqrstuvwxyz012345';
|
||
module.exports = {
|
||
string: function(length) {
|
||
var max = _randomStringChars.length;
|
||
var bytes = crypto.randomBytes(length);
|
||
var ret = [];
|
||
for (var i = 0; i < length; i++) {
|
||
ret.push(_randomStringChars.substr(bytes[i] % max, 1));
|
||
}
|
||
return ret.join('');
|
||
}
|
||
|
||
, number: function(max) {
|
||
return Math.floor(Math.random() * max);
|
||
}
|
||
|
||
, numberString: function(max) {
|
||
var t = ('' + (max - 1)).length;
|
||
var p = new Array(t + 1).join('0');
|
||
return (p + this.number(max)).slice(-t);
|
||
}
|
||
};
|
||
|
||
},{"crypto":75}],83:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:utils:transport');
|
||
}
|
||
|
||
module.exports = function(availableTransports) {
|
||
return {
|
||
filterToEnabled: function(transportsWhitelist, info) {
|
||
var transports = {
|
||
main: []
|
||
, facade: []
|
||
};
|
||
if (!transportsWhitelist) {
|
||
transportsWhitelist = [];
|
||
} else if (typeof transportsWhitelist === 'string') {
|
||
transportsWhitelist = [transportsWhitelist];
|
||
}
|
||
|
||
availableTransports.forEach(function(trans) {
|
||
if (!trans) {
|
||
return;
|
||
}
|
||
|
||
if (trans.transportName === 'websocket' && info.websocket === false) {
|
||
debug('disabled from server', 'websocket');
|
||
return;
|
||
}
|
||
|
||
if (transportsWhitelist.length &&
|
||
transportsWhitelist.indexOf(trans.transportName) === -1) {
|
||
debug('not in whitelist', trans.transportName);
|
||
return;
|
||
}
|
||
|
||
if (trans.enabled(info)) {
|
||
debug('enabled', trans.transportName);
|
||
transports.main.push(trans);
|
||
if (trans.facadeTransport) {
|
||
transports.facade.push(trans.facadeTransport);
|
||
}
|
||
} else {
|
||
debug('disabled', trans.transportName);
|
||
}
|
||
});
|
||
return transports;
|
||
}
|
||
};
|
||
};
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"_process":114,"debug":1}],84:[function(require,module,exports){
|
||
(function (process){
|
||
'use strict';
|
||
|
||
var URL = require('url-parse');
|
||
|
||
var debug = function() {};
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
debug = require('debug')('sockjs-client:utils:url');
|
||
}
|
||
|
||
module.exports = {
|
||
getOrigin: function(url) {
|
||
if (!url) {
|
||
return null;
|
||
}
|
||
|
||
var p = new URL(url);
|
||
if (p.protocol === 'file:') {
|
||
return null;
|
||
}
|
||
|
||
var port = p.port;
|
||
if (!port) {
|
||
port = (p.protocol === 'https:') ? '443' : '80';
|
||
}
|
||
|
||
return p.protocol + '//' + p.hostname + ':' + port;
|
||
}
|
||
|
||
, isOriginEqual: function(a, b) {
|
||
var res = this.getOrigin(a) === this.getOrigin(b);
|
||
debug('same', a, b, res);
|
||
return res;
|
||
}
|
||
|
||
, isSchemeEqual: function(a, b) {
|
||
return (a.split(':')[0] === b.split(':')[0]);
|
||
}
|
||
|
||
, addPath: function (url, path) {
|
||
var qs = url.split('?');
|
||
return qs[0] + path + (qs[1] ? '?' + qs[1] : '');
|
||
}
|
||
|
||
, addQuery: function (url, q) {
|
||
return url + (url.indexOf('?') === -1 ? ('?' + q) : ('&' + q));
|
||
}
|
||
};
|
||
|
||
}).call(this,require('_process'))
|
||
|
||
},{"_process":114,"debug":1,"url-parse":87}],85:[function(require,module,exports){
|
||
module.exports = '1.1.1';
|
||
|
||
},{}],86:[function(require,module,exports){
|
||
/**
|
||
* UAParser.js v0.7.12
|
||
* Lightweight JavaScript-based User-Agent string parser
|
||
* https://github.com/faisalman/ua-parser-js
|
||
*
|
||
* Copyright © 2012-2016 Faisal Salman <fyzlman@gmail.com>
|
||
* Dual licensed under GPLv2 & MIT
|
||
*/
|
||
|
||
(function (window, undefined) {
|
||
|
||
'use strict';
|
||
|
||
//////////////
|
||
// Constants
|
||
/////////////
|
||
|
||
|
||
var LIBVERSION = '0.7.12',
|
||
EMPTY = '',
|
||
UNKNOWN = '?',
|
||
FUNC_TYPE = 'function',
|
||
UNDEF_TYPE = 'undefined',
|
||
OBJ_TYPE = 'object',
|
||
STR_TYPE = 'string',
|
||
MAJOR = 'major', // deprecated
|
||
MODEL = 'model',
|
||
NAME = 'name',
|
||
TYPE = 'type',
|
||
VENDOR = 'vendor',
|
||
VERSION = 'version',
|
||
ARCHITECTURE= 'architecture',
|
||
CONSOLE = 'console',
|
||
MOBILE = 'mobile',
|
||
TABLET = 'tablet',
|
||
SMARTTV = 'smarttv',
|
||
WEARABLE = 'wearable',
|
||
EMBEDDED = 'embedded';
|
||
|
||
|
||
///////////
|
||
// Helper
|
||
//////////
|
||
|
||
|
||
var util = {
|
||
extend : function (regexes, extensions) {
|
||
var margedRegexes = {};
|
||
for (var i in regexes) {
|
||
if (extensions[i] && extensions[i].length % 2 === 0) {
|
||
margedRegexes[i] = extensions[i].concat(regexes[i]);
|
||
} else {
|
||
margedRegexes[i] = regexes[i];
|
||
}
|
||
}
|
||
return margedRegexes;
|
||
},
|
||
has : function (str1, str2) {
|
||
if (typeof str1 === "string") {
|
||
return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1;
|
||
} else {
|
||
return false;
|
||
}
|
||
},
|
||
lowerize : function (str) {
|
||
return str.toLowerCase();
|
||
},
|
||
major : function (version) {
|
||
return typeof(version) === STR_TYPE ? version.replace(/[^\d\.]/g,'').split(".")[0] : undefined;
|
||
},
|
||
trim : function (str) {
|
||
return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
||
}
|
||
};
|
||
|
||
|
||
///////////////
|
||
// Map helper
|
||
//////////////
|
||
|
||
|
||
var mapper = {
|
||
|
||
rgx : function () {
|
||
|
||
var result, i = 0, j, k, p, q, matches, match, args = arguments;
|
||
|
||
// loop through all regexes maps
|
||
while (i < args.length && !matches) {
|
||
|
||
var regex = args[i], // even sequence (0,2,4,..)
|
||
props = args[i + 1]; // odd sequence (1,3,5,..)
|
||
|
||
// construct object barebones
|
||
if (typeof result === UNDEF_TYPE) {
|
||
result = {};
|
||
for (p in props) {
|
||
if (props.hasOwnProperty(p)){
|
||
q = props[p];
|
||
if (typeof q === OBJ_TYPE) {
|
||
result[q[0]] = undefined;
|
||
} else {
|
||
result[q] = undefined;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// try matching uastring with regexes
|
||
j = k = 0;
|
||
while (j < regex.length && !matches) {
|
||
matches = regex[j++].exec(this.getUA());
|
||
if (!!matches) {
|
||
for (p = 0; p < props.length; p++) {
|
||
match = matches[++k];
|
||
q = props[p];
|
||
// check if given property is actually array
|
||
if (typeof q === OBJ_TYPE && q.length > 0) {
|
||
if (q.length == 2) {
|
||
if (typeof q[1] == FUNC_TYPE) {
|
||
// assign modified match
|
||
result[q[0]] = q[1].call(this, match);
|
||
} else {
|
||
// assign given value, ignore regex match
|
||
result[q[0]] = q[1];
|
||
}
|
||
} else if (q.length == 3) {
|
||
// check whether function or regex
|
||
if (typeof q[1] === FUNC_TYPE && !(q[1].exec && q[1].test)) {
|
||
// call function (usually string mapper)
|
||
result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
|
||
} else {
|
||
// sanitize match using given regex
|
||
result[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
|
||
}
|
||
} else if (q.length == 4) {
|
||
result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
|
||
}
|
||
} else {
|
||
result[q] = match ? match : undefined;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
i += 2;
|
||
}
|
||
return result;
|
||
},
|
||
|
||
str : function (str, map) {
|
||
|
||
for (var i in map) {
|
||
// check if array
|
||
if (typeof map[i] === OBJ_TYPE && map[i].length > 0) {
|
||
for (var j = 0; j < map[i].length; j++) {
|
||
if (util.has(map[i][j], str)) {
|
||
return (i === UNKNOWN) ? undefined : i;
|
||
}
|
||
}
|
||
} else if (util.has(map[i], str)) {
|
||
return (i === UNKNOWN) ? undefined : i;
|
||
}
|
||
}
|
||
return str;
|
||
}
|
||
};
|
||
|
||
|
||
///////////////
|
||
// String map
|
||
//////////////
|
||
|
||
|
||
var maps = {
|
||
|
||
browser : {
|
||
oldsafari : {
|
||
version : {
|
||
'1.0' : '/8',
|
||
'1.2' : '/1',
|
||
'1.3' : '/3',
|
||
'2.0' : '/412',
|
||
'2.0.2' : '/416',
|
||
'2.0.3' : '/417',
|
||
'2.0.4' : '/419',
|
||
'?' : '/'
|
||
}
|
||
}
|
||
},
|
||
|
||
device : {
|
||
amazon : {
|
||
model : {
|
||
'Fire Phone' : ['SD', 'KF']
|
||
}
|
||
},
|
||
sprint : {
|
||
model : {
|
||
'Evo Shift 4G' : '7373KT'
|
||
},
|
||
vendor : {
|
||
'HTC' : 'APA',
|
||
'Sprint' : 'Sprint'
|
||
}
|
||
}
|
||
},
|
||
|
||
os : {
|
||
windows : {
|
||
version : {
|
||
'ME' : '4.90',
|
||
'NT 3.11' : 'NT3.51',
|
||
'NT 4.0' : 'NT4.0',
|
||
'2000' : 'NT 5.0',
|
||
'XP' : ['NT 5.1', 'NT 5.2'],
|
||
'Vista' : 'NT 6.0',
|
||
'7' : 'NT 6.1',
|
||
'8' : 'NT 6.2',
|
||
'8.1' : 'NT 6.3',
|
||
'10' : ['NT 6.4', 'NT 10.0'],
|
||
'RT' : 'ARM'
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
//////////////
|
||
// Regex map
|
||
/////////////
|
||
|
||
|
||
var regexes = {
|
||
|
||
browser : [[
|
||
|
||
// Presto based
|
||
/(opera\smini)\/([\w\.-]+)/i, // Opera Mini
|
||
/(opera\s[mobiletab]+).+version\/([\w\.-]+)/i, // Opera Mobi/Tablet
|
||
/(opera).+version\/([\w\.]+)/i, // Opera > 9.80
|
||
/(opera)[\/\s]+([\w\.]+)/i // Opera < 9.80
|
||
], [NAME, VERSION], [
|
||
|
||
/(opios)[\/\s]+([\w\.]+)/i // Opera mini on iphone >= 8.0
|
||
], [[NAME, 'Opera Mini'], VERSION], [
|
||
|
||
/\s(opr)\/([\w\.]+)/i // Opera Webkit
|
||
], [[NAME, 'Opera'], VERSION], [
|
||
|
||
// Mixed
|
||
/(kindle)\/([\w\.]+)/i, // Kindle
|
||
/(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i,
|
||
// Lunascape/Maxthon/Netfront/Jasmine/Blazer
|
||
|
||
// Trident based
|
||
/(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i,
|
||
// Avant/IEMobile/SlimBrowser/Baidu
|
||
/(?:ms|\()(ie)\s([\w\.]+)/i, // Internet Explorer
|
||
|
||
// Webkit/KHTML based
|
||
/(rekonq)\/([\w\.]+)*/i, // Rekonq
|
||
/(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs)\/([\w\.-]+)/i
|
||
// Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS
|
||
], [NAME, VERSION], [
|
||
|
||
/(trident).+rv[:\s]([\w\.]+).+like\sgecko/i // IE11
|
||
], [[NAME, 'IE'], VERSION], [
|
||
|
||
/(edge)\/((\d+)?[\w\.]+)/i // Microsoft Edge
|
||
], [NAME, VERSION], [
|
||
|
||
/(yabrowser)\/([\w\.]+)/i // Yandex
|
||
], [[NAME, 'Yandex'], VERSION], [
|
||
|
||
/(comodo_dragon)\/([\w\.]+)/i // Comodo Dragon
|
||
], [[NAME, /_/g, ' '], VERSION], [
|
||
|
||
/(micromessenger)\/([\w\.]+)/i // WeChat
|
||
], [[NAME, 'WeChat'], VERSION], [
|
||
|
||
/xiaomi\/miuibrowser\/([\w\.]+)/i // MIUI Browser
|
||
], [VERSION, [NAME, 'MIUI Browser']], [
|
||
|
||
/\swv\).+(chrome)\/([\w\.]+)/i // Chrome WebView
|
||
], [[NAME, /(.+)/, '$1 WebView'], VERSION], [
|
||
|
||
/android.+samsungbrowser\/([\w\.]+)/i,
|
||
/android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)*/i // Android Browser
|
||
], [VERSION, [NAME, 'Android Browser']], [
|
||
|
||
/(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i,
|
||
// Chrome/OmniWeb/Arora/Tizen/Nokia
|
||
/(qqbrowser)[\/\s]?([\w\.]+)/i
|
||
// QQBrowser
|
||
], [NAME, VERSION], [
|
||
|
||
/(uc\s?browser)[\/\s]?([\w\.]+)/i,
|
||
/ucweb.+(ucbrowser)[\/\s]?([\w\.]+)/i,
|
||
/juc.+(ucweb)[\/\s]?([\w\.]+)/i
|
||
// UCBrowser
|
||
], [[NAME, 'UCBrowser'], VERSION], [
|
||
|
||
/(dolfin)\/([\w\.]+)/i // Dolphin
|
||
], [[NAME, 'Dolphin'], VERSION], [
|
||
|
||
/((?:android.+)crmo|crios)\/([\w\.]+)/i // Chrome for Android/iOS
|
||
], [[NAME, 'Chrome'], VERSION], [
|
||
|
||
/;fbav\/([\w\.]+);/i // Facebook App for iOS
|
||
], [VERSION, [NAME, 'Facebook']], [
|
||
|
||
/fxios\/([\w\.-]+)/i // Firefox for iOS
|
||
], [VERSION, [NAME, 'Firefox']], [
|
||
|
||
/version\/([\w\.]+).+?mobile\/\w+\s(safari)/i // Mobile Safari
|
||
], [VERSION, [NAME, 'Mobile Safari']], [
|
||
|
||
/version\/([\w\.]+).+?(mobile\s?safari|safari)/i // Safari & Safari Mobile
|
||
], [VERSION, NAME], [
|
||
|
||
/webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i // Safari < 3.0
|
||
], [NAME, [VERSION, mapper.str, maps.browser.oldsafari.version]], [
|
||
|
||
/(konqueror)\/([\w\.]+)/i, // Konqueror
|
||
/(webkit|khtml)\/([\w\.]+)/i
|
||
], [NAME, VERSION], [
|
||
|
||
// Gecko based
|
||
/(navigator|netscape)\/([\w\.-]+)/i // Netscape
|
||
], [[NAME, 'Netscape'], VERSION], [
|
||
/(swiftfox)/i, // Swiftfox
|
||
/(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i,
|
||
// IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
|
||
/(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i,
|
||
// Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
|
||
/(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla
|
||
|
||
// Other
|
||
/(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir)[\/\s]?([\w\.]+)/i,
|
||
// Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir
|
||
/(links)\s\(([\w\.]+)/i, // Links
|
||
/(gobrowser)\/?([\w\.]+)*/i, // GoBrowser
|
||
/(ice\s?browser)\/v?([\w\._]+)/i, // ICE Browser
|
||
/(mosaic)[\/\s]([\w\.]+)/i // Mosaic
|
||
], [NAME, VERSION]
|
||
|
||
/* /////////////////////
|
||
// Media players BEGIN
|
||
////////////////////////
|
||
|
||
, [
|
||
|
||
/(apple(?:coremedia|))\/((\d+)[\w\._]+)/i, // Generic Apple CoreMedia
|
||
/(coremedia) v((\d+)[\w\._]+)/i
|
||
], [NAME, VERSION], [
|
||
|
||
/(aqualung|lyssna|bsplayer)\/((\d+)?[\w\.-]+)/i // Aqualung/Lyssna/BSPlayer
|
||
], [NAME, VERSION], [
|
||
|
||
/(ares|ossproxy)\s((\d+)[\w\.-]+)/i // Ares/OSSProxy
|
||
], [NAME, VERSION], [
|
||
|
||
/(audacious|audimusicstream|amarok|bass|core|dalvik|gnomemplayer|music on console|nsplayer|psp-internetradioplayer|videos)\/((\d+)[\w\.-]+)/i,
|
||
// Audacious/AudiMusicStream/Amarok/BASS/OpenCORE/Dalvik/GnomeMplayer/MoC
|
||
// NSPlayer/PSP-InternetRadioPlayer/Videos
|
||
/(clementine|music player daemon)\s((\d+)[\w\.-]+)/i, // Clementine/MPD
|
||
/(lg player|nexplayer)\s((\d+)[\d\.]+)/i,
|
||
/player\/(nexplayer|lg player)\s((\d+)[\w\.-]+)/i // NexPlayer/LG Player
|
||
], [NAME, VERSION], [
|
||
/(nexplayer)\s((\d+)[\w\.-]+)/i // Nexplayer
|
||
], [NAME, VERSION], [
|
||
|
||
/(flrp)\/((\d+)[\w\.-]+)/i // Flip Player
|
||
], [[NAME, 'Flip Player'], VERSION], [
|
||
|
||
/(fstream|nativehost|queryseekspider|ia-archiver|facebookexternalhit)/i
|
||
// FStream/NativeHost/QuerySeekSpider/IA Archiver/facebookexternalhit
|
||
], [NAME], [
|
||
|
||
/(gstreamer) souphttpsrc (?:\([^\)]+\)){0,1} libsoup\/((\d+)[\w\.-]+)/i
|
||
// Gstreamer
|
||
], [NAME, VERSION], [
|
||
|
||
/(htc streaming player)\s[\w_]+\s\/\s((\d+)[\d\.]+)/i, // HTC Streaming Player
|
||
/(java|python-urllib|python-requests|wget|libcurl)\/((\d+)[\w\.-_]+)/i,
|
||
// Java/urllib/requests/wget/cURL
|
||
/(lavf)((\d+)[\d\.]+)/i // Lavf (FFMPEG)
|
||
], [NAME, VERSION], [
|
||
|
||
/(htc_one_s)\/((\d+)[\d\.]+)/i // HTC One S
|
||
], [[NAME, /_/g, ' '], VERSION], [
|
||
|
||
/(mplayer)(?:\s|\/)(?:(?:sherpya-){0,1}svn)(?:-|\s)(r\d+(?:-\d+[\w\.-]+){0,1})/i
|
||
// MPlayer SVN
|
||
], [NAME, VERSION], [
|
||
|
||
/(mplayer)(?:\s|\/|[unkow-]+)((\d+)[\w\.-]+)/i // MPlayer
|
||
], [NAME, VERSION], [
|
||
|
||
/(mplayer)/i, // MPlayer (no other info)
|
||
/(yourmuze)/i, // YourMuze
|
||
/(media player classic|nero showtime)/i // Media Player Classic/Nero ShowTime
|
||
], [NAME], [
|
||
|
||
/(nero (?:home|scout))\/((\d+)[\w\.-]+)/i // Nero Home/Nero Scout
|
||
], [NAME, VERSION], [
|
||
|
||
/(nokia\d+)\/((\d+)[\w\.-]+)/i // Nokia
|
||
], [NAME, VERSION], [
|
||
|
||
/\s(songbird)\/((\d+)[\w\.-]+)/i // Songbird/Philips-Songbird
|
||
], [NAME, VERSION], [
|
||
|
||
/(winamp)3 version ((\d+)[\w\.-]+)/i, // Winamp
|
||
/(winamp)\s((\d+)[\w\.-]+)/i,
|
||
/(winamp)mpeg\/((\d+)[\w\.-]+)/i
|
||
], [NAME, VERSION], [
|
||
|
||
/(ocms-bot|tapinradio|tunein radio|unknown|winamp|inlight radio)/i // OCMS-bot/tap in radio/tunein/unknown/winamp (no other info)
|
||
// inlight radio
|
||
], [NAME], [
|
||
|
||
/(quicktime|rma|radioapp|radioclientapplication|soundtap|totem|stagefright|streamium)\/((\d+)[\w\.-]+)/i
|
||
// QuickTime/RealMedia/RadioApp/RadioClientApplication/
|
||
// SoundTap/Totem/Stagefright/Streamium
|
||
], [NAME, VERSION], [
|
||
|
||
/(smp)((\d+)[\d\.]+)/i // SMP
|
||
], [NAME, VERSION], [
|
||
|
||
/(vlc) media player - version ((\d+)[\w\.]+)/i, // VLC Videolan
|
||
/(vlc)\/((\d+)[\w\.-]+)/i,
|
||
/(xbmc|gvfs|xine|xmms|irapp)\/((\d+)[\w\.-]+)/i, // XBMC/gvfs/Xine/XMMS/irapp
|
||
/(foobar2000)\/((\d+)[\d\.]+)/i, // Foobar2000
|
||
/(itunes)\/((\d+)[\d\.]+)/i // iTunes
|
||
], [NAME, VERSION], [
|
||
|
||
/(wmplayer)\/((\d+)[\w\.-]+)/i, // Windows Media Player
|
||
/(windows-media-player)\/((\d+)[\w\.-]+)/i
|
||
], [[NAME, /-/g, ' '], VERSION], [
|
||
|
||
/windows\/((\d+)[\w\.-]+) upnp\/[\d\.]+ dlnadoc\/[\d\.]+ (home media server)/i
|
||
// Windows Media Server
|
||
], [VERSION, [NAME, 'Windows']], [
|
||
|
||
/(com\.riseupradioalarm)\/((\d+)[\d\.]*)/i // RiseUP Radio Alarm
|
||
], [NAME, VERSION], [
|
||
|
||
/(rad.io)\s((\d+)[\d\.]+)/i, // Rad.io
|
||
/(radio.(?:de|at|fr))\s((\d+)[\d\.]+)/i
|
||
], [[NAME, 'rad.io'], VERSION]
|
||
|
||
//////////////////////
|
||
// Media players END
|
||
////////////////////*/
|
||
|
||
],
|
||
|
||
cpu : [[
|
||
|
||
/(?:(amd|x(?:(?:86|64)[_-])?|wow|win)64)[;\)]/i // AMD64
|
||
], [[ARCHITECTURE, 'amd64']], [
|
||
|
||
/(ia32(?=;))/i // IA32 (quicktime)
|
||
], [[ARCHITECTURE, util.lowerize]], [
|
||
|
||
/((?:i[346]|x)86)[;\)]/i // IA32
|
||
], [[ARCHITECTURE, 'ia32']], [
|
||
|
||
// PocketPC mistakenly identified as PowerPC
|
||
/windows\s(ce|mobile);\sppc;/i
|
||
], [[ARCHITECTURE, 'arm']], [
|
||
|
||
/((?:ppc|powerpc)(?:64)?)(?:\smac|;|\))/i // PowerPC
|
||
], [[ARCHITECTURE, /ower/, '', util.lowerize]], [
|
||
|
||
/(sun4\w)[;\)]/i // SPARC
|
||
], [[ARCHITECTURE, 'sparc']], [
|
||
|
||
/((?:avr32|ia64(?=;))|68k(?=\))|arm(?:64|(?=v\d+;))|(?=atmel\s)avr|(?:irix|mips|sparc)(?:64)?(?=;)|pa-risc)/i
|
||
// IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC
|
||
], [[ARCHITECTURE, util.lowerize]]
|
||
],
|
||
|
||
device : [[
|
||
|
||
/\((ipad|playbook);[\w\s\);-]+(rim|apple)/i // iPad/PlayBook
|
||
], [MODEL, VENDOR, [TYPE, TABLET]], [
|
||
|
||
/applecoremedia\/[\w\.]+ \((ipad)/ // iPad
|
||
], [MODEL, [VENDOR, 'Apple'], [TYPE, TABLET]], [
|
||
|
||
/(apple\s{0,1}tv)/i // Apple TV
|
||
], [[MODEL, 'Apple TV'], [VENDOR, 'Apple']], [
|
||
|
||
/(archos)\s(gamepad2?)/i, // Archos
|
||
/(hp).+(touchpad)/i, // HP TouchPad
|
||
/(hp).+(tablet)/i, // HP Tablet
|
||
/(kindle)\/([\w\.]+)/i, // Kindle
|
||
/\s(nook)[\w\s]+build\/(\w+)/i, // Nook
|
||
/(dell)\s(strea[kpr\s\d]*[\dko])/i // Dell Streak
|
||
], [VENDOR, MODEL, [TYPE, TABLET]], [
|
||
|
||
/(kf[A-z]+)\sbuild\/[\w\.]+.*silk\//i // Kindle Fire HD
|
||
], [MODEL, [VENDOR, 'Amazon'], [TYPE, TABLET]], [
|
||
/(sd|kf)[0349hijorstuw]+\sbuild\/[\w\.]+.*silk\//i // Fire Phone
|
||
], [[MODEL, mapper.str, maps.device.amazon.model], [VENDOR, 'Amazon'], [TYPE, MOBILE]], [
|
||
|
||
/\((ip[honed|\s\w*]+);.+(apple)/i // iPod/iPhone
|
||
], [MODEL, VENDOR, [TYPE, MOBILE]], [
|
||
/\((ip[honed|\s\w*]+);/i // iPod/iPhone
|
||
], [MODEL, [VENDOR, 'Apple'], [TYPE, MOBILE]], [
|
||
|
||
/(blackberry)[\s-]?(\w+)/i, // BlackBerry
|
||
/(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|huawei|meizu|motorola|polytron)[\s_-]?([\w-]+)*/i,
|
||
// BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Huawei/Meizu/Motorola/Polytron
|
||
/(hp)\s([\w\s]+\w)/i, // HP iPAQ
|
||
/(asus)-?(\w+)/i // Asus
|
||
], [VENDOR, MODEL, [TYPE, MOBILE]], [
|
||
/\(bb10;\s(\w+)/i // BlackBerry 10
|
||
], [MODEL, [VENDOR, 'BlackBerry'], [TYPE, MOBILE]], [
|
||
// Asus Tablets
|
||
/android.+(transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+|nexus 7|padfone)/i
|
||
], [MODEL, [VENDOR, 'Asus'], [TYPE, TABLET]], [
|
||
|
||
/(sony)\s(tablet\s[ps])\sbuild\//i, // Sony
|
||
/(sony)?(?:sgp.+)\sbuild\//i
|
||
], [[VENDOR, 'Sony'], [MODEL, 'Xperia Tablet'], [TYPE, TABLET]], [
|
||
/(?:sony)?(?:(?:(?:c|d)\d{4})|(?:so[-l].+))\sbuild\//i
|
||
], [[VENDOR, 'Sony'], [MODEL, 'Xperia Phone'], [TYPE, MOBILE]], [
|
||
|
||
/\s(ouya)\s/i, // Ouya
|
||
/(nintendo)\s([wids3u]+)/i // Nintendo
|
||
], [VENDOR, MODEL, [TYPE, CONSOLE]], [
|
||
|
||
/android.+;\s(shield)\sbuild/i // Nvidia
|
||
], [MODEL, [VENDOR, 'Nvidia'], [TYPE, CONSOLE]], [
|
||
|
||
/(playstation\s[34portablevi]+)/i // Playstation
|
||
], [MODEL, [VENDOR, 'Sony'], [TYPE, CONSOLE]], [
|
||
|
||
/(sprint\s(\w+))/i // Sprint Phones
|
||
], [[VENDOR, mapper.str, maps.device.sprint.vendor], [MODEL, mapper.str, maps.device.sprint.model], [TYPE, MOBILE]], [
|
||
|
||
/(lenovo)\s?(S(?:5000|6000)+(?:[-][\w+]))/i // Lenovo tablets
|
||
], [VENDOR, MODEL, [TYPE, TABLET]], [
|
||
|
||
/(htc)[;_\s-]+([\w\s]+(?=\))|\w+)*/i, // HTC
|
||
/(zte)-(\w+)*/i, // ZTE
|
||
/(alcatel|geeksphone|huawei|lenovo|nexian|panasonic|(?=;\s)sony)[_\s-]?([\w-]+)*/i
|
||
// Alcatel/GeeksPhone/Huawei/Lenovo/Nexian/Panasonic/Sony
|
||
], [VENDOR, [MODEL, /_/g, ' '], [TYPE, MOBILE]], [
|
||
|
||
/(nexus\s9)/i // HTC Nexus 9
|
||
], [MODEL, [VENDOR, 'HTC'], [TYPE, TABLET]], [
|
||
|
||
/(nexus\s6p)/i // Huawei Nexus 6P
|
||
], [MODEL, [VENDOR, 'Huawei'], [TYPE, MOBILE]], [
|
||
|
||
/(microsoft);\s(lumia[\s\w]+)/i // Microsoft Lumia
|
||
], [VENDOR, MODEL, [TYPE, MOBILE]], [
|
||
|
||
/[\s\(;](xbox(?:\sone)?)[\s\);]/i // Microsoft Xbox
|
||
], [MODEL, [VENDOR, 'Microsoft'], [TYPE, CONSOLE]], [
|
||
/(kin\.[onetw]{3})/i // Microsoft Kin
|
||
], [[MODEL, /\./g, ' '], [VENDOR, 'Microsoft'], [TYPE, MOBILE]], [
|
||
|
||
// Motorola
|
||
/\s(milestone|droid(?:[2-4x]|\s(?:bionic|x2|pro|razr))?(:?\s4g)?)[\w\s]+build\//i,
|
||
/mot[\s-]?(\w+)*/i,
|
||
/(XT\d{3,4}) build\//i,
|
||
/(nexus\s6)/i
|
||
], [MODEL, [VENDOR, 'Motorola'], [TYPE, MOBILE]], [
|
||
/android.+\s(mz60\d|xoom[\s2]{0,2})\sbuild\//i
|
||
], [MODEL, [VENDOR, 'Motorola'], [TYPE, TABLET]], [
|
||
|
||
/hbbtv\/\d+\.\d+\.\d+\s+\([\w\s]*;\s*(\w[^;]*);([^;]*)/i // HbbTV devices
|
||
], [[VENDOR, util.trim], [MODEL, util.trim], [TYPE, SMARTTV]], [
|
||
|
||
/hbbtv.+maple;(\d+)/i
|
||
], [[MODEL, /^/, 'SmartTV'], [VENDOR, 'Samsung'], [TYPE, SMARTTV]], [
|
||
|
||
/\(dtv[\);].+(aquos)/i // Sharp
|
||
], [MODEL, [VENDOR, 'Sharp'], [TYPE, SMARTTV]], [
|
||
|
||
/android.+((sch-i[89]0\d|shw-m380s|gt-p\d{4}|gt-n\d+|sgh-t8[56]9|nexus 10))/i,
|
||
/((SM-T\w+))/i
|
||
], [[VENDOR, 'Samsung'], MODEL, [TYPE, TABLET]], [ // Samsung
|
||
/smart-tv.+(samsung)/i
|
||
], [VENDOR, [TYPE, SMARTTV], MODEL], [
|
||
/((s[cgp]h-\w+|gt-\w+|galaxy\snexus|sm-\w[\w\d]+))/i,
|
||
/(sam[sung]*)[\s-]*(\w+-?[\w-]*)*/i,
|
||
/sec-((sgh\w+))/i
|
||
], [[VENDOR, 'Samsung'], MODEL, [TYPE, MOBILE]], [
|
||
|
||
/sie-(\w+)*/i // Siemens
|
||
], [MODEL, [VENDOR, 'Siemens'], [TYPE, MOBILE]], [
|
||
|
||
/(maemo|nokia).*(n900|lumia\s\d+)/i, // Nokia
|
||
/(nokia)[\s_-]?([\w-]+)*/i
|
||
], [[VENDOR, 'Nokia'], MODEL, [TYPE, MOBILE]], [
|
||
|
||
/android\s3\.[\s\w;-]{10}(a\d{3})/i // Acer
|
||
], [MODEL, [VENDOR, 'Acer'], [TYPE, TABLET]], [
|
||
|
||
/android\s3\.[\s\w;-]{10}(lg?)-([06cv9]{3,4})/i // LG Tablet
|
||
], [[VENDOR, 'LG'], MODEL, [TYPE, TABLET]], [
|
||
/(lg) netcast\.tv/i // LG SmartTV
|
||
], [VENDOR, MODEL, [TYPE, SMARTTV]], [
|
||
/(nexus\s[45])/i, // LG
|
||
/lg[e;\s\/-]+(\w+)*/i
|
||
], [MODEL, [VENDOR, 'LG'], [TYPE, MOBILE]], [
|
||
|
||
/android.+(ideatab[a-z0-9\-\s]+)/i // Lenovo
|
||
], [MODEL, [VENDOR, 'Lenovo'], [TYPE, TABLET]], [
|
||
|
||
/linux;.+((jolla));/i // Jolla
|
||
], [VENDOR, MODEL, [TYPE, MOBILE]], [
|
||
|
||
/((pebble))app\/[\d\.]+\s/i // Pebble
|
||
], [VENDOR, MODEL, [TYPE, WEARABLE]], [
|
||
|
||
/android.+;\s(glass)\s\d/i // Google Glass
|
||
], [MODEL, [VENDOR, 'Google'], [TYPE, WEARABLE]], [
|
||
|
||
/android.+(\w+)\s+build\/hm\1/i, // Xiaomi Hongmi 'numeric' models
|
||
/android.+(hm[\s\-_]*note?[\s_]*(?:\d\w)?)\s+build/i, // Xiaomi Hongmi
|
||
/android.+(mi[\s\-_]*(?:one|one[\s_]plus|note lte)?[\s_]*(?:\d\w)?)\s+build/i // Xiaomi Mi
|
||
], [[MODEL, /_/g, ' '], [VENDOR, 'Xiaomi'], [TYPE, MOBILE]], [
|
||
|
||
/android.+a000(1)\s+build/i // OnePlus
|
||
], [MODEL, [VENDOR, 'OnePlus'], [TYPE, MOBILE]], [
|
||
|
||
/\s(tablet)[;\/]/i, // Unidentifiable Tablet
|
||
/\s(mobile)(?:[;\/]|\ssafari)/i // Unidentifiable Mobile
|
||
], [[TYPE, util.lowerize], VENDOR, MODEL]
|
||
|
||
/*//////////////////////////
|
||
// TODO: move to string map
|
||
////////////////////////////
|
||
|
||
/(C6603)/i // Sony Xperia Z C6603
|
||
], [[MODEL, 'Xperia Z C6603'], [VENDOR, 'Sony'], [TYPE, MOBILE]], [
|
||
/(C6903)/i // Sony Xperia Z 1
|
||
], [[MODEL, 'Xperia Z 1'], [VENDOR, 'Sony'], [TYPE, MOBILE]], [
|
||
|
||
/(SM-G900[F|H])/i // Samsung Galaxy S5
|
||
], [[MODEL, 'Galaxy S5'], [VENDOR, 'Samsung'], [TYPE, MOBILE]], [
|
||
/(SM-G7102)/i // Samsung Galaxy Grand 2
|
||
], [[MODEL, 'Galaxy Grand 2'], [VENDOR, 'Samsung'], [TYPE, MOBILE]], [
|
||
/(SM-G530H)/i // Samsung Galaxy Grand Prime
|
||
], [[MODEL, 'Galaxy Grand Prime'], [VENDOR, 'Samsung'], [TYPE, MOBILE]], [
|
||
/(SM-G313HZ)/i // Samsung Galaxy V
|
||
], [[MODEL, 'Galaxy V'], [VENDOR, 'Samsung'], [TYPE, MOBILE]], [
|
||
/(SM-T805)/i // Samsung Galaxy Tab S 10.5
|
||
], [[MODEL, 'Galaxy Tab S 10.5'], [VENDOR, 'Samsung'], [TYPE, TABLET]], [
|
||
/(SM-G800F)/i // Samsung Galaxy S5 Mini
|
||
], [[MODEL, 'Galaxy S5 Mini'], [VENDOR, 'Samsung'], [TYPE, MOBILE]], [
|
||
/(SM-T311)/i // Samsung Galaxy Tab 3 8.0
|
||
], [[MODEL, 'Galaxy Tab 3 8.0'], [VENDOR, 'Samsung'], [TYPE, TABLET]], [
|
||
|
||
/(R1001)/i // Oppo R1001
|
||
], [MODEL, [VENDOR, 'OPPO'], [TYPE, MOBILE]], [
|
||
/(X9006)/i // Oppo Find 7a
|
||
], [[MODEL, 'Find 7a'], [VENDOR, 'Oppo'], [TYPE, MOBILE]], [
|
||
/(R2001)/i // Oppo YOYO R2001
|
||
], [[MODEL, 'Yoyo R2001'], [VENDOR, 'Oppo'], [TYPE, MOBILE]], [
|
||
/(R815)/i // Oppo Clover R815
|
||
], [[MODEL, 'Clover R815'], [VENDOR, 'Oppo'], [TYPE, MOBILE]], [
|
||
/(U707)/i // Oppo Find Way S
|
||
], [[MODEL, 'Find Way S'], [VENDOR, 'Oppo'], [TYPE, MOBILE]], [
|
||
|
||
/(T3C)/i // Advan Vandroid T3C
|
||
], [MODEL, [VENDOR, 'Advan'], [TYPE, TABLET]], [
|
||
/(ADVAN T1J\+)/i // Advan Vandroid T1J+
|
||
], [[MODEL, 'Vandroid T1J+'], [VENDOR, 'Advan'], [TYPE, TABLET]], [
|
||
/(ADVAN S4A)/i // Advan Vandroid S4A
|
||
], [[MODEL, 'Vandroid S4A'], [VENDOR, 'Advan'], [TYPE, MOBILE]], [
|
||
|
||
/(V972M)/i // ZTE V972M
|
||
], [MODEL, [VENDOR, 'ZTE'], [TYPE, MOBILE]], [
|
||
|
||
/(i-mobile)\s(IQ\s[\d\.]+)/i // i-mobile IQ
|
||
], [VENDOR, MODEL, [TYPE, MOBILE]], [
|
||
/(IQ6.3)/i // i-mobile IQ IQ 6.3
|
||
], [[MODEL, 'IQ 6.3'], [VENDOR, 'i-mobile'], [TYPE, MOBILE]], [
|
||
/(i-mobile)\s(i-style\s[\d\.]+)/i // i-mobile i-STYLE
|
||
], [VENDOR, MODEL, [TYPE, MOBILE]], [
|
||
/(i-STYLE2.1)/i // i-mobile i-STYLE 2.1
|
||
], [[MODEL, 'i-STYLE 2.1'], [VENDOR, 'i-mobile'], [TYPE, MOBILE]], [
|
||
|
||
/(mobiistar touch LAI 512)/i // mobiistar touch LAI 512
|
||
], [[MODEL, 'Touch LAI 512'], [VENDOR, 'mobiistar'], [TYPE, MOBILE]], [
|
||
|
||
/////////////
|
||
// END TODO
|
||
///////////*/
|
||
|
||
],
|
||
|
||
engine : [[
|
||
|
||
/windows.+\sedge\/([\w\.]+)/i // EdgeHTML
|
||
], [VERSION, [NAME, 'EdgeHTML']], [
|
||
|
||
/(presto)\/([\w\.]+)/i, // Presto
|
||
/(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m
|
||
/(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links
|
||
/(icab)[\/\s]([23]\.[\d\.]+)/i // iCab
|
||
], [NAME, VERSION], [
|
||
|
||
/rv\:([\w\.]+).*(gecko)/i // Gecko
|
||
], [VERSION, NAME]
|
||
],
|
||
|
||
os : [[
|
||
|
||
// Windows based
|
||
/microsoft\s(windows)\s(vista|xp)/i // Windows (iTunes)
|
||
], [NAME, VERSION], [
|
||
/(windows)\snt\s6\.2;\s(arm)/i, // Windows RT
|
||
/(windows\sphone(?:\sos)*)[\s\/]?([\d\.\s]+\w)*/i, // Windows Phone
|
||
/(windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i
|
||
], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [
|
||
/(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
|
||
], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [
|
||
|
||
// Mobile/Embedded OS
|
||
/\((bb)(10);/i // BlackBerry 10
|
||
], [[NAME, 'BlackBerry'], VERSION], [
|
||
/(blackberry)\w*\/?([\w\.]+)*/i, // Blackberry
|
||
/(tizen)[\/\s]([\w\.]+)/i, // Tizen
|
||
/(android|webos|palm\sos|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i,
|
||
// Android/WebOS/Palm/QNX/Bada/RIM/MeeGo/Contiki
|
||
/linux;.+(sailfish);/i // Sailfish OS
|
||
], [NAME, VERSION], [
|
||
/(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i // Symbian
|
||
], [[NAME, 'Symbian'], VERSION], [
|
||
/\((series40);/i // Series 40
|
||
], [NAME], [
|
||
/mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS
|
||
], [[NAME, 'Firefox OS'], VERSION], [
|
||
|
||
// Console
|
||
/(nintendo|playstation)\s([wids34portablevu]+)/i, // Nintendo/Playstation
|
||
|
||
// GNU/Linux based
|
||
/(mint)[\/\s\(]?(\w+)*/i, // Mint
|
||
/(mageia|vectorlinux)[;\s]/i, // Mageia/VectorLinux
|
||
/(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|(?=\s)arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?(?!chrom)([\w\.-]+)*/i,
|
||
// Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware
|
||
// Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus
|
||
/(hurd|linux)\s?([\w\.]+)*/i, // Hurd/Linux
|
||
/(gnu)\s?([\w\.]+)*/i // GNU
|
||
], [NAME, VERSION], [
|
||
|
||
/(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS
|
||
], [[NAME, 'Chromium OS'], VERSION],[
|
||
|
||
// Solaris
|
||
/(sunos)\s?([\w\.]+\d)*/i // Solaris
|
||
], [[NAME, 'Solaris'], VERSION], [
|
||
|
||
// BSD based
|
||
/\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
|
||
], [NAME, VERSION],[
|
||
|
||
/(haiku)\s(\w+)/i // Haiku
|
||
], [NAME, VERSION],[
|
||
|
||
/(ip[honead]+)(?:.*os\s([\w]+)*\slike\smac|;\sopera)/i // iOS
|
||
], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [
|
||
|
||
/(mac\sos\sx)\s?([\w\s\.]+\w)*/i,
|
||
/(macintosh|mac(?=_powerpc)\s)/i // Mac OS
|
||
], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [
|
||
|
||
// Other
|
||
/((?:open)?solaris)[\/\s-]?([\w\.]+)*/i, // Solaris
|
||
/(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, // AIX
|
||
/(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i,
|
||
// Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS/OpenVMS
|
||
/(unix)\s?([\w\.]+)*/i // UNIX
|
||
], [NAME, VERSION]
|
||
]
|
||
};
|
||
|
||
|
||
/////////////////
|
||
// Constructor
|
||
////////////////
|
||
|
||
|
||
var UAParser = function (uastring, extensions) {
|
||
|
||
if (!(this instanceof UAParser)) {
|
||
return new UAParser(uastring, extensions).getResult();
|
||
}
|
||
|
||
var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY);
|
||
var rgxmap = extensions ? util.extend(regexes, extensions) : regexes;
|
||
|
||
this.getBrowser = function () {
|
||
var browser = mapper.rgx.apply(this, rgxmap.browser);
|
||
browser.major = util.major(browser.version);
|
||
return browser;
|
||
};
|
||
this.getCPU = function () {
|
||
return mapper.rgx.apply(this, rgxmap.cpu);
|
||
};
|
||
this.getDevice = function () {
|
||
return mapper.rgx.apply(this, rgxmap.device);
|
||
};
|
||
this.getEngine = function () {
|
||
return mapper.rgx.apply(this, rgxmap.engine);
|
||
};
|
||
this.getOS = function () {
|
||
return mapper.rgx.apply(this, rgxmap.os);
|
||
};
|
||
this.getResult = function() {
|
||
return {
|
||
ua : this.getUA(),
|
||
browser : this.getBrowser(),
|
||
engine : this.getEngine(),
|
||
os : this.getOS(),
|
||
device : this.getDevice(),
|
||
cpu : this.getCPU()
|
||
};
|
||
};
|
||
this.getUA = function () {
|
||
return ua;
|
||
};
|
||
this.setUA = function (uastring) {
|
||
ua = uastring;
|
||
return this;
|
||
};
|
||
return this;
|
||
};
|
||
|
||
UAParser.VERSION = LIBVERSION;
|
||
UAParser.BROWSER = {
|
||
NAME : NAME,
|
||
MAJOR : MAJOR, // deprecated
|
||
VERSION : VERSION
|
||
};
|
||
UAParser.CPU = {
|
||
ARCHITECTURE : ARCHITECTURE
|
||
};
|
||
UAParser.DEVICE = {
|
||
MODEL : MODEL,
|
||
VENDOR : VENDOR,
|
||
TYPE : TYPE,
|
||
CONSOLE : CONSOLE,
|
||
MOBILE : MOBILE,
|
||
SMARTTV : SMARTTV,
|
||
TABLET : TABLET,
|
||
WEARABLE: WEARABLE,
|
||
EMBEDDED: EMBEDDED
|
||
};
|
||
UAParser.ENGINE = {
|
||
NAME : NAME,
|
||
VERSION : VERSION
|
||
};
|
||
UAParser.OS = {
|
||
NAME : NAME,
|
||
VERSION : VERSION
|
||
};
|
||
|
||
|
||
///////////
|
||
// Export
|
||
//////////
|
||
|
||
|
||
// check js environment
|
||
if (typeof(exports) !== UNDEF_TYPE) {
|
||
// nodejs env
|
||
if (typeof module !== UNDEF_TYPE && module.exports) {
|
||
exports = module.exports = UAParser;
|
||
}
|
||
exports.UAParser = UAParser;
|
||
} else {
|
||
// requirejs env (optional)
|
||
if (typeof(define) === FUNC_TYPE && define.amd) {
|
||
define(function () {
|
||
return UAParser;
|
||
});
|
||
} else {
|
||
// browser env
|
||
window.UAParser = UAParser;
|
||
}
|
||
}
|
||
|
||
// jQuery/Zepto specific (optional)
|
||
// Note:
|
||
// In AMD env the global scope should be kept clean, but jQuery is an exception.
|
||
// jQuery always exports to global scope, unless jQuery.noConflict(true) is used,
|
||
// and we should catch that.
|
||
var $ = window.jQuery || window.Zepto;
|
||
if (typeof $ !== UNDEF_TYPE) {
|
||
var parser = new UAParser();
|
||
$.ua = parser.getResult();
|
||
$.ua.get = function() {
|
||
return parser.getUA();
|
||
};
|
||
$.ua.set = function (uastring) {
|
||
parser.setUA(uastring);
|
||
var result = parser.getResult();
|
||
for (var prop in result) {
|
||
$.ua[prop] = result[prop];
|
||
}
|
||
};
|
||
}
|
||
|
||
})(typeof window === 'object' ? window : this);
|
||
|
||
},{}],87:[function(require,module,exports){
|
||
(function (global){
|
||
'use strict';
|
||
|
||
var required = require('requires-port')
|
||
, qs = require('querystringify')
|
||
, protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i
|
||
, slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//;
|
||
|
||
/**
|
||
* These are the parse rules for the URL parser, it informs the parser
|
||
* about:
|
||
*
|
||
* 0. The char it Needs to parse, if it's a string it should be done using
|
||
* indexOf, RegExp using exec and NaN means set as current value.
|
||
* 1. The property we should set when parsing this value.
|
||
* 2. Indication if it's backwards or forward parsing, when set as number it's
|
||
* the value of extra chars that should be split off.
|
||
* 3. Inherit from location if non existing in the parser.
|
||
* 4. `toLowerCase` the resulting value.
|
||
*/
|
||
var rules = [
|
||
['#', 'hash'], // Extract from the back.
|
||
['?', 'query'], // Extract from the back.
|
||
['/', 'pathname'], // Extract from the back.
|
||
['@', 'auth', 1], // Extract from the front.
|
||
[NaN, 'host', undefined, 1, 1], // Set left over value.
|
||
[/:(\d+)$/, 'port', undefined, 1], // RegExp the back.
|
||
[NaN, 'hostname', undefined, 1, 1] // Set left over.
|
||
];
|
||
|
||
/**
|
||
* These properties should not be copied or inherited from. This is only needed
|
||
* for all non blob URL's as a blob URL does not include a hash, only the
|
||
* origin.
|
||
*
|
||
* @type {Object}
|
||
* @private
|
||
*/
|
||
var ignore = { hash: 1, query: 1 };
|
||
|
||
/**
|
||
* The location object differs when your code is loaded through a normal page,
|
||
* Worker or through a worker using a blob. And with the blobble begins the
|
||
* trouble as the location object will contain the URL of the blob, not the
|
||
* location of the page where our code is loaded in. The actual origin is
|
||
* encoded in the `pathname` so we can thankfully generate a good "default"
|
||
* location from it so we can generate proper relative URL's again.
|
||
*
|
||
* @param {Object|String} loc Optional default location object.
|
||
* @returns {Object} lolcation object.
|
||
* @api public
|
||
*/
|
||
function lolcation(loc) {
|
||
loc = loc || global.location || {};
|
||
|
||
var finaldestination = {}
|
||
, type = typeof loc
|
||
, key;
|
||
|
||
if ('blob:' === loc.protocol) {
|
||
finaldestination = new URL(unescape(loc.pathname), {});
|
||
} else if ('string' === type) {
|
||
finaldestination = new URL(loc, {});
|
||
for (key in ignore) delete finaldestination[key];
|
||
} else if ('object' === type) {
|
||
for (key in loc) {
|
||
if (key in ignore) continue;
|
||
finaldestination[key] = loc[key];
|
||
}
|
||
|
||
if (finaldestination.slashes === undefined) {
|
||
finaldestination.slashes = slashes.test(loc.href);
|
||
}
|
||
}
|
||
|
||
return finaldestination;
|
||
}
|
||
|
||
/**
|
||
* @typedef ProtocolExtract
|
||
* @type Object
|
||
* @property {String} protocol Protocol matched in the URL, in lowercase.
|
||
* @property {Boolean} slashes `true` if protocol is followed by "//", else `false`.
|
||
* @property {String} rest Rest of the URL that is not part of the protocol.
|
||
*/
|
||
|
||
/**
|
||
* Extract protocol information from a URL with/without double slash ("//").
|
||
*
|
||
* @param {String} address URL we want to extract from.
|
||
* @return {ProtocolExtract} Extracted information.
|
||
* @api private
|
||
*/
|
||
function extractProtocol(address) {
|
||
var match = protocolre.exec(address);
|
||
|
||
return {
|
||
protocol: match[1] ? match[1].toLowerCase() : '',
|
||
slashes: !!match[2],
|
||
rest: match[3]
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Resolve a relative URL pathname against a base URL pathname.
|
||
*
|
||
* @param {String} relative Pathname of the relative URL.
|
||
* @param {String} base Pathname of the base URL.
|
||
* @return {String} Resolved pathname.
|
||
* @api private
|
||
*/
|
||
function resolve(relative, base) {
|
||
var path = (base || '/').split('/').slice(0, -1).concat(relative.split('/'))
|
||
, i = path.length
|
||
, last = path[i - 1]
|
||
, unshift = false
|
||
, up = 0;
|
||
|
||
while (i--) {
|
||
if (path[i] === '.') {
|
||
path.splice(i, 1);
|
||
} else if (path[i] === '..') {
|
||
path.splice(i, 1);
|
||
up++;
|
||
} else if (up) {
|
||
if (i === 0) unshift = true;
|
||
path.splice(i, 1);
|
||
up--;
|
||
}
|
||
}
|
||
|
||
if (unshift) path.unshift('');
|
||
if (last === '.' || last === '..') path.push('');
|
||
|
||
return path.join('/');
|
||
}
|
||
|
||
/**
|
||
* The actual URL instance. Instead of returning an object we've opted-in to
|
||
* create an actual constructor as it's much more memory efficient and
|
||
* faster and it pleases my OCD.
|
||
*
|
||
* @constructor
|
||
* @param {String} address URL we want to parse.
|
||
* @param {Object|String} location Location defaults for relative paths.
|
||
* @param {Boolean|Function} parser Parser for the query string.
|
||
* @api public
|
||
*/
|
||
function URL(address, location, parser) {
|
||
if (!(this instanceof URL)) {
|
||
return new URL(address, location, parser);
|
||
}
|
||
|
||
var relative, extracted, parse, instruction, index, key
|
||
, instructions = rules.slice()
|
||
, type = typeof location
|
||
, url = this
|
||
, i = 0;
|
||
|
||
//
|
||
// The following if statements allows this module two have compatibility with
|
||
// 2 different API:
|
||
//
|
||
// 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments
|
||
// where the boolean indicates that the query string should also be parsed.
|
||
//
|
||
// 2. The `URL` interface of the browser which accepts a URL, object as
|
||
// arguments. The supplied object will be used as default values / fall-back
|
||
// for relative paths.
|
||
//
|
||
if ('object' !== type && 'string' !== type) {
|
||
parser = location;
|
||
location = null;
|
||
}
|
||
|
||
if (parser && 'function' !== typeof parser) parser = qs.parse;
|
||
|
||
location = lolcation(location);
|
||
|
||
//
|
||
// Extract protocol information before running the instructions.
|
||
//
|
||
extracted = extractProtocol(address || '');
|
||
relative = !extracted.protocol && !extracted.slashes;
|
||
url.slashes = extracted.slashes || relative && location.slashes;
|
||
url.protocol = extracted.protocol || location.protocol || '';
|
||
address = extracted.rest;
|
||
|
||
//
|
||
// When the authority component is absent the URL starts with a path
|
||
// component.
|
||
//
|
||
if (!extracted.slashes) instructions[2] = [/(.*)/, 'pathname'];
|
||
|
||
for (; i < instructions.length; i++) {
|
||
instruction = instructions[i];
|
||
parse = instruction[0];
|
||
key = instruction[1];
|
||
|
||
if (parse !== parse) {
|
||
url[key] = address;
|
||
} else if ('string' === typeof parse) {
|
||
if (~(index = address.indexOf(parse))) {
|
||
if ('number' === typeof instruction[2]) {
|
||
url[key] = address.slice(0, index);
|
||
address = address.slice(index + instruction[2]);
|
||
} else {
|
||
url[key] = address.slice(index);
|
||
address = address.slice(0, index);
|
||
}
|
||
}
|
||
} else if ((index = parse.exec(address))) {
|
||
url[key] = index[1];
|
||
address = address.slice(0, index.index);
|
||
}
|
||
|
||
url[key] = url[key] || (
|
||
relative && instruction[3] ? location[key] || '' : ''
|
||
);
|
||
|
||
//
|
||
// Hostname, host and protocol should be lowercased so they can be used to
|
||
// create a proper `origin`.
|
||
//
|
||
if (instruction[4]) url[key] = url[key].toLowerCase();
|
||
}
|
||
|
||
//
|
||
// Also parse the supplied query string in to an object. If we're supplied
|
||
// with a custom parser as function use that instead of the default build-in
|
||
// parser.
|
||
//
|
||
if (parser) url.query = parser(url.query);
|
||
|
||
//
|
||
// If the URL is relative, resolve the pathname against the base URL.
|
||
//
|
||
if (
|
||
relative
|
||
&& location.slashes
|
||
&& url.pathname.charAt(0) !== '/'
|
||
&& (url.pathname !== '' || location.pathname !== '')
|
||
) {
|
||
url.pathname = resolve(url.pathname, location.pathname);
|
||
}
|
||
|
||
//
|
||
// We should not add port numbers if they are already the default port number
|
||
// for a given protocol. As the host also contains the port number we're going
|
||
// override it with the hostname which contains no port number.
|
||
//
|
||
if (!required(url.port, url.protocol)) {
|
||
url.host = url.hostname;
|
||
url.port = '';
|
||
}
|
||
|
||
//
|
||
// Parse down the `auth` for the username and password.
|
||
//
|
||
url.username = url.password = '';
|
||
if (url.auth) {
|
||
instruction = url.auth.split(':');
|
||
url.username = instruction[0] || '';
|
||
url.password = instruction[1] || '';
|
||
}
|
||
|
||
url.origin = url.protocol && url.host && url.protocol !== 'file:'
|
||
? url.protocol +'//'+ url.host
|
||
: 'null';
|
||
|
||
//
|
||
// The href is just the compiled result.
|
||
//
|
||
url.href = url.toString();
|
||
}
|
||
|
||
/**
|
||
* This is convenience method for changing properties in the URL instance to
|
||
* insure that they all propagate correctly.
|
||
*
|
||
* @param {String} part Property we need to adjust.
|
||
* @param {Mixed} value The newly assigned value.
|
||
* @param {Boolean|Function} fn When setting the query, it will be the function
|
||
* used to parse the query.
|
||
* When setting the protocol, double slash will be
|
||
* removed from the final url if it is true.
|
||
* @returns {URL}
|
||
* @api public
|
||
*/
|
||
function set(part, value, fn) {
|
||
var url = this;
|
||
|
||
switch (part) {
|
||
case 'query':
|
||
if ('string' === typeof value && value.length) {
|
||
value = (fn || qs.parse)(value);
|
||
}
|
||
|
||
url[part] = value;
|
||
break;
|
||
|
||
case 'port':
|
||
url[part] = value;
|
||
|
||
if (!required(value, url.protocol)) {
|
||
url.host = url.hostname;
|
||
url[part] = '';
|
||
} else if (value) {
|
||
url.host = url.hostname +':'+ value;
|
||
}
|
||
|
||
break;
|
||
|
||
case 'hostname':
|
||
url[part] = value;
|
||
|
||
if (url.port) value += ':'+ url.port;
|
||
url.host = value;
|
||
break;
|
||
|
||
case 'host':
|
||
url[part] = value;
|
||
|
||
if (/:\d+$/.test(value)) {
|
||
value = value.split(':');
|
||
url.port = value.pop();
|
||
url.hostname = value.join(':');
|
||
} else {
|
||
url.hostname = value;
|
||
url.port = '';
|
||
}
|
||
|
||
break;
|
||
|
||
case 'protocol':
|
||
url.protocol = value.toLowerCase();
|
||
url.slashes = !fn;
|
||
break;
|
||
|
||
case 'pathname':
|
||
url.pathname = value.length && value.charAt(0) !== '/' ? '/' + value : value;
|
||
|
||
break;
|
||
|
||
default:
|
||
url[part] = value;
|
||
}
|
||
|
||
for (var i = 0; i < rules.length; i++) {
|
||
var ins = rules[i];
|
||
|
||
if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase();
|
||
}
|
||
|
||
url.origin = url.protocol && url.host && url.protocol !== 'file:'
|
||
? url.protocol +'//'+ url.host
|
||
: 'null';
|
||
|
||
url.href = url.toString();
|
||
|
||
return url;
|
||
}
|
||
|
||
/**
|
||
* Transform the properties back in to a valid and full URL string.
|
||
*
|
||
* @param {Function} stringify Optional query stringify function.
|
||
* @returns {String}
|
||
* @api public
|
||
*/
|
||
function toString(stringify) {
|
||
if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify;
|
||
|
||
var query
|
||
, url = this
|
||
, protocol = url.protocol;
|
||
|
||
if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':';
|
||
|
||
var result = protocol + (url.slashes ? '//' : '');
|
||
|
||
if (url.username) {
|
||
result += url.username;
|
||
if (url.password) result += ':'+ url.password;
|
||
result += '@';
|
||
}
|
||
|
||
result += url.host + url.pathname;
|
||
|
||
query = 'object' === typeof url.query ? stringify(url.query) : url.query;
|
||
if (query) result += '?' !== query.charAt(0) ? '?'+ query : query;
|
||
|
||
if (url.hash) result += url.hash;
|
||
|
||
return result;
|
||
}
|
||
|
||
URL.prototype = { set: set, toString: toString };
|
||
|
||
//
|
||
// Expose the URL parser and some additional properties that might be useful for
|
||
// others or testing.
|
||
//
|
||
URL.extractProtocol = extractProtocol;
|
||
URL.location = lolcation;
|
||
URL.qs = qs;
|
||
|
||
module.exports = URL;
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{"querystringify":88,"requires-port":23}],88:[function(require,module,exports){
|
||
'use strict';
|
||
|
||
var has = Object.prototype.hasOwnProperty;
|
||
|
||
/**
|
||
* Decode a URI encoded string.
|
||
*
|
||
* @param {String} input The URI encoded string.
|
||
* @returns {String} The decoded string.
|
||
* @api private
|
||
*/
|
||
function decode(input) {
|
||
return decodeURIComponent(input.replace(/\+/g, ' '));
|
||
}
|
||
|
||
/**
|
||
* Simple query string parser.
|
||
*
|
||
* @param {String} query The query string that needs to be parsed.
|
||
* @returns {Object}
|
||
* @api public
|
||
*/
|
||
function querystring(query) {
|
||
var parser = /([^=?&]+)=?([^&]*)/g
|
||
, result = {}
|
||
, part;
|
||
|
||
//
|
||
// Little nifty parsing hack, leverage the fact that RegExp.exec increments
|
||
// the lastIndex property so we can continue executing this loop until we've
|
||
// parsed all results.
|
||
//
|
||
for (;
|
||
part = parser.exec(query);
|
||
result[decode(part[1])] = decode(part[2])
|
||
);
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Transform a query string to an object.
|
||
*
|
||
* @param {Object} obj Object that should be transformed.
|
||
* @param {String} prefix Optional prefix.
|
||
* @returns {String}
|
||
* @api public
|
||
*/
|
||
function querystringify(obj, prefix) {
|
||
prefix = prefix || '';
|
||
|
||
var pairs = [];
|
||
|
||
//
|
||
// Optionally prefix with a '?' if needed
|
||
//
|
||
if ('string' !== typeof prefix) prefix = '?';
|
||
|
||
for (var key in obj) {
|
||
if (has.call(obj, key)) {
|
||
pairs.push(encodeURIComponent(key) +'='+ encodeURIComponent(obj[key]));
|
||
}
|
||
}
|
||
|
||
return pairs.length ? prefix + pairs.join('&') : '';
|
||
}
|
||
|
||
//
|
||
// Expose the module.
|
||
//
|
||
exports.stringify = querystringify;
|
||
exports.parse = querystring;
|
||
|
||
},{}],89:[function(require,module,exports){
|
||
(function (global){
|
||
|
||
var rng;
|
||
|
||
var crypto = global.crypto || global.msCrypto; // for IE 11
|
||
if (crypto && crypto.getRandomValues) {
|
||
// WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
|
||
// Moderately fast, high quality
|
||
var _rnds8 = new Uint8Array(16);
|
||
rng = function whatwgRNG() {
|
||
crypto.getRandomValues(_rnds8);
|
||
return _rnds8;
|
||
};
|
||
}
|
||
|
||
if (!rng) {
|
||
// Math.random()-based (RNG)
|
||
//
|
||
// If all else fails, use Math.random(). It's fast, but is of unspecified
|
||
// quality.
|
||
var _rnds = new Array(16);
|
||
rng = function() {
|
||
for (var i = 0, r; i < 16; i++) {
|
||
if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
|
||
_rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
|
||
}
|
||
|
||
return _rnds;
|
||
};
|
||
}
|
||
|
||
module.exports = rng;
|
||
|
||
|
||
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
||
},{}],90:[function(require,module,exports){
|
||
// uuid.js
|
||
//
|
||
// Copyright (c) 2010-2012 Robert Kieffer
|
||
// MIT License - http://opensource.org/licenses/mit-license.php
|
||
|
||
// Unique ID creation requires a high quality random # generator. We feature
|
||
// detect to determine the best RNG source, normalizing to a function that
|
||
// returns 128-bits of randomness, since that's what's usually required
|
||
var _rng = require('./rng');
|
||
|
||
// Maps for number <-> hex string conversion
|
||
var _byteToHex = [];
|
||
var _hexToByte = {};
|
||
for (var i = 0; i < 256; i++) {
|
||
_byteToHex[i] = (i + 0x100).toString(16).substr(1);
|
||
_hexToByte[_byteToHex[i]] = i;
|
||
}
|
||
|
||
// **`parse()` - Parse a UUID into it's component bytes**
|
||
function parse(s, buf, offset) {
|
||
var i = (buf && offset) || 0, ii = 0;
|
||
|
||
buf = buf || [];
|
||
s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
|
||
if (ii < 16) { // Don't overflow!
|
||
buf[i + ii++] = _hexToByte[oct];
|
||
}
|
||
});
|
||
|
||
// Zero out remaining bytes if string was short
|
||
while (ii < 16) {
|
||
buf[i + ii++] = 0;
|
||
}
|
||
|
||
return buf;
|
||
}
|
||
|
||
// **`unparse()` - Convert UUID byte array (ala parse()) into a string**
|
||
function unparse(buf, offset) {
|
||
var i = offset || 0, bth = _byteToHex;
|
||
return bth[buf[i++]] + bth[buf[i++]] +
|
||
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
||
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
||
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
||
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
||
bth[buf[i++]] + bth[buf[i++]] +
|
||
bth[buf[i++]] + bth[buf[i++]] +
|
||
bth[buf[i++]] + bth[buf[i++]];
|
||
}
|
||
|
||
// **`v1()` - Generate time-based UUID**
|
||
//
|
||
// Inspired by https://github.com/LiosK/UUID.js
|
||
// and http://docs.python.org/library/uuid.html
|
||
|
||
// random #'s we need to init node and clockseq
|
||
var _seedBytes = _rng();
|
||
|
||
// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
|
||
var _nodeId = [
|
||
_seedBytes[0] | 0x01,
|
||
_seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
|
||
];
|
||
|
||
// Per 4.2.2, randomize (14 bit) clockseq
|
||
var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
|
||
|
||
// Previous uuid creation time
|
||
var _lastMSecs = 0, _lastNSecs = 0;
|
||
|
||
// See https://github.com/broofa/node-uuid for API details
|
||
function v1(options, buf, offset) {
|
||
var i = buf && offset || 0;
|
||
var b = buf || [];
|
||
|
||
options = options || {};
|
||
|
||
var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;
|
||
|
||
// UUID timestamps are 100 nano-second units since the Gregorian epoch,
|
||
// (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
|
||
// time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
|
||
// (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
|
||
var msecs = options.msecs !== undefined ? options.msecs : new Date().getTime();
|
||
|
||
// Per 4.2.1.2, use count of uuid's generated during the current clock
|
||
// cycle to simulate higher resolution clock
|
||
var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1;
|
||
|
||
// Time since last uuid creation (in msecs)
|
||
var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
|
||
|
||
// Per 4.2.1.2, Bump clockseq on clock regression
|
||
if (dt < 0 && options.clockseq === undefined) {
|
||
clockseq = clockseq + 1 & 0x3fff;
|
||
}
|
||
|
||
// Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
|
||
// time interval
|
||
if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
|
||
nsecs = 0;
|
||
}
|
||
|
||
// Per 4.2.1.2 Throw error if too many uuids are requested
|
||
if (nsecs >= 10000) {
|
||
throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
|
||
}
|
||
|
||
_lastMSecs = msecs;
|
||
_lastNSecs = nsecs;
|
||
_clockseq = clockseq;
|
||
|
||
// Per 4.1.4 - Convert from unix epoch to Gregorian epoch
|
||
msecs += 12219292800000;
|
||
|
||
// `time_low`
|
||
var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
|
||
b[i++] = tl >>> 24 & 0xff;
|
||
b[i++] = tl >>> 16 & 0xff;
|
||
b[i++] = tl >>> 8 & 0xff;
|
||
b[i++] = tl & 0xff;
|
||
|
||
// `time_mid`
|
||
var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
|
||
b[i++] = tmh >>> 8 & 0xff;
|
||
b[i++] = tmh & 0xff;
|
||
|
||
// `time_high_and_version`
|
||
b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
|
||
b[i++] = tmh >>> 16 & 0xff;
|
||
|
||
// `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
|
||
b[i++] = clockseq >>> 8 | 0x80;
|
||
|
||
// `clock_seq_low`
|
||
b[i++] = clockseq & 0xff;
|
||
|
||
// `node`
|
||
var node = options.node || _nodeId;
|
||
for (var n = 0; n < 6; n++) {
|
||
b[i + n] = node[n];
|
||
}
|
||
|
||
return buf ? buf : unparse(b);
|
||
}
|
||
|
||
// **`v4()` - Generate random UUID**
|
||
|
||
// See https://github.com/broofa/node-uuid for API details
|
||
function v4(options, buf, offset) {
|
||
// Deprecated - 'format' argument, as supported in v1.2
|
||
var i = buf && offset || 0;
|
||
|
||
if (typeof(options) == 'string') {
|
||
buf = options == 'binary' ? new Array(16) : null;
|
||
options = null;
|
||
}
|
||
options = options || {};
|
||
|
||
var rnds = options.random || (options.rng || _rng)();
|
||
|
||
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
||
rnds[6] = (rnds[6] & 0x0f) | 0x40;
|
||
rnds[8] = (rnds[8] & 0x3f) | 0x80;
|
||
|
||
// Copy bytes to buffer, if provided
|
||
if (buf) {
|
||
for (var ii = 0; ii < 16; ii++) {
|
||
buf[i + ii] = rnds[ii];
|
||
}
|
||
}
|
||
|
||
return buf || unparse(rnds);
|
||
}
|
||
|
||
// Export public API
|
||
var uuid = v4;
|
||
uuid.v1 = v1;
|
||
uuid.v4 = v4;
|
||
uuid.parse = parse;
|
||
uuid.unparse = unparse;
|
||
|
||
module.exports = uuid;
|
||
|
||
},{"./rng":89}],91:[function(require,module,exports){
|
||
/*
|
||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||
*
|
||
* Use of this source code is governed by a BSD-style license
|
||
* that can be found in the LICENSE file in the root of the source
|
||
* tree.
|
||
*/
|
||
/* eslint-env node */
|
||
|
||
'use strict';
|
||
|
||
// Shimming starts here.
|
||
(function() {
|
||
// Utils.
|
||
var utils = require('./utils');
|
||
var logging = utils.log;
|
||
var browserDetails = utils.browserDetails;
|
||
// Export to the adapter global object visible in the browser.
|
||
module.exports.browserDetails = browserDetails;
|
||
module.exports.extractVersion = utils.extractVersion;
|
||
module.exports.disableLog = utils.disableLog;
|
||
|
||
// Uncomment the line below if you want logging to occur, including logging
|
||
// for the switch statement below. Can also be turned on in the browser via
|
||
// adapter.disableLog(false), but then logging from the switch statement below
|
||
// will not appear.
|
||
// require('./utils').disableLog(false);
|
||
|
||
// Browser shims.
|
||
var chromeShim = require('./chrome/chrome_shim') || null;
|
||
var edgeShim = require('./edge/edge_shim') || null;
|
||
var firefoxShim = require('./firefox/firefox_shim') || null;
|
||
var safariShim = require('./safari/safari_shim') || null;
|
||
|
||
// Shim browser if found.
|
||
switch (browserDetails.browser) {
|
||
case 'chrome':
|
||
if (!chromeShim || !chromeShim.shimPeerConnection) {
|
||
logging('Chrome shim is not included in this adapter release.');
|
||
return;
|
||
}
|
||
logging('adapter.js shimming chrome.');
|
||
// Export to the adapter global object visible in the browser.
|
||
module.exports.browserShim = chromeShim;
|
||
|
||
chromeShim.shimGetUserMedia();
|
||
chromeShim.shimMediaStream();
|
||
utils.shimCreateObjectURL();
|
||
chromeShim.shimSourceObject();
|
||
chromeShim.shimPeerConnection();
|
||
chromeShim.shimOnTrack();
|
||
chromeShim.shimGetSendersWithDtmf();
|
||
break;
|
||
case 'firefox':
|
||
if (!firefoxShim || !firefoxShim.shimPeerConnection) {
|
||
logging('Firefox shim is not included in this adapter release.');
|
||
return;
|
||
}
|
||
logging('adapter.js shimming firefox.');
|
||
// Export to the adapter global object visible in the browser.
|
||
module.exports.browserShim = firefoxShim;
|
||
|
||
firefoxShim.shimGetUserMedia();
|
||
utils.shimCreateObjectURL();
|
||
firefoxShim.shimSourceObject();
|
||
firefoxShim.shimPeerConnection();
|
||
firefoxShim.shimOnTrack();
|
||
break;
|
||
case 'edge':
|
||
if (!edgeShim || !edgeShim.shimPeerConnection) {
|
||
logging('MS edge shim is not included in this adapter release.');
|
||
return;
|
||
}
|
||
logging('adapter.js shimming edge.');
|
||
// Export to the adapter global object visible in the browser.
|
||
module.exports.browserShim = edgeShim;
|
||
|
||
edgeShim.shimGetUserMedia();
|
||
utils.shimCreateObjectURL();
|
||
edgeShim.shimPeerConnection();
|
||
edgeShim.shimReplaceTrack();
|
||
break;
|
||
case 'safari':
|
||
if (!safariShim) {
|
||
logging('Safari shim is not included in this adapter release.');
|
||
return;
|
||
}
|
||
logging('adapter.js shimming safari.');
|
||
// Export to the adapter global object visible in the browser.
|
||
module.exports.browserShim = safariShim;
|
||
|
||
safariShim.shimOnAddStream();
|
||
safariShim.shimGetUserMedia();
|
||
break;
|
||
default:
|
||
logging('Unsupported browser!');
|
||
}
|
||
})();
|
||
|
||
},{"./chrome/chrome_shim":92,"./edge/edge_shim":94,"./firefox/firefox_shim":97,"./safari/safari_shim":99,"./utils":100}],92:[function(require,module,exports){
|
||
|
||
/*
|
||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||
*
|
||
* Use of this source code is governed by a BSD-style license
|
||
* that can be found in the LICENSE file in the root of the source
|
||
* tree.
|
||
*/
|
||
/* eslint-env node */
|
||
'use strict';
|
||
var logging = require('../utils.js').log;
|
||
var browserDetails = require('../utils.js').browserDetails;
|
||
|
||
var chromeShim = {
|
||
shimMediaStream: function() {
|
||
window.MediaStream = window.MediaStream || window.webkitMediaStream;
|
||
},
|
||
|
||
shimOnTrack: function() {
|
||
if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in
|
||
window.RTCPeerConnection.prototype)) {
|
||
Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
|
||
get: function() {
|
||
return this._ontrack;
|
||
},
|
||
set: function(f) {
|
||
var self = this;
|
||
if (this._ontrack) {
|
||
this.removeEventListener('track', this._ontrack);
|
||
this.removeEventListener('addstream', this._ontrackpoly);
|
||
}
|
||
this.addEventListener('track', this._ontrack = f);
|
||
this.addEventListener('addstream', this._ontrackpoly = function(e) {
|
||
// onaddstream does not fire when a track is added to an existing
|
||
// stream. But stream.onaddtrack is implemented so we use that.
|
||
e.stream.addEventListener('addtrack', function(te) {
|
||
var event = new Event('track');
|
||
event.track = te.track;
|
||
event.receiver = {track: te.track};
|
||
event.streams = [e.stream];
|
||
self.dispatchEvent(event);
|
||
});
|
||
e.stream.getTracks().forEach(function(track) {
|
||
var event = new Event('track');
|
||
event.track = track;
|
||
event.receiver = {track: track};
|
||
event.streams = [e.stream];
|
||
this.dispatchEvent(event);
|
||
}.bind(this));
|
||
}.bind(this));
|
||
}
|
||
});
|
||
}
|
||
},
|
||
|
||
shimGetSendersWithDtmf: function() {
|
||
if (typeof window === 'object' && window.RTCPeerConnection &&
|
||
!('getSenders' in RTCPeerConnection.prototype) &&
|
||
'createDTMFSender' in RTCPeerConnection.prototype) {
|
||
RTCPeerConnection.prototype.getSenders = function() {
|
||
return this._senders;
|
||
};
|
||
var origAddStream = RTCPeerConnection.prototype.addStream;
|
||
var origRemoveStream = RTCPeerConnection.prototype.removeStream;
|
||
|
||
RTCPeerConnection.prototype.addStream = function(stream) {
|
||
var pc = this;
|
||
pc._senders = pc._senders || [];
|
||
origAddStream.apply(pc, [stream]);
|
||
stream.getTracks().forEach(function(track) {
|
||
pc._senders.push({
|
||
track: track,
|
||
get dtmf() {
|
||
if (this._dtmf === undefined) {
|
||
if (track.kind === 'audio') {
|
||
this._dtmf = pc.createDTMFSender(track);
|
||
} else {
|
||
this._dtmf = null;
|
||
}
|
||
}
|
||
return this._dtmf;
|
||
}
|
||
});
|
||
});
|
||
};
|
||
|
||
RTCPeerConnection.prototype.removeStream = function(stream) {
|
||
var pc = this;
|
||
pc._senders = pc._senders || [];
|
||
origRemoveStream.apply(pc, [stream]);
|
||
stream.getTracks().forEach(function(track) {
|
||
var sender = pc._senders.find(function(s) {
|
||
return s.track === track;
|
||
});
|
||
if (sender) {
|
||
pc._senders.splice(pc._senders.indexOf(sender), 1); // remove sender
|
||
}
|
||
});
|
||
};
|
||
}
|
||
},
|
||
|
||
shimSourceObject: function() {
|
||
if (typeof window === 'object') {
|
||
if (window.HTMLMediaElement &&
|
||
!('srcObject' in window.HTMLMediaElement.prototype)) {
|
||
// Shim the srcObject property, once, when HTMLMediaElement is found.
|
||
Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
|
||
get: function() {
|
||
return this._srcObject;
|
||
},
|
||
set: function(stream) {
|
||
var self = this;
|
||
// Use _srcObject as a private property for this shim
|
||
this._srcObject = stream;
|
||
if (this.src) {
|
||
URL.revokeObjectURL(this.src);
|
||
}
|
||
|
||
if (!stream) {
|
||
this.src = '';
|
||
return undefined;
|
||
}
|
||
this.src = URL.createObjectURL(stream);
|
||
// We need to recreate the blob url when a track is added or
|
||
// removed. Doing it manually since we want to avoid a recursion.
|
||
stream.addEventListener('addtrack', function() {
|
||
if (self.src) {
|
||
URL.revokeObjectURL(self.src);
|
||
}
|
||
self.src = URL.createObjectURL(stream);
|
||
});
|
||
stream.addEventListener('removetrack', function() {
|
||
if (self.src) {
|
||
URL.revokeObjectURL(self.src);
|
||
}
|
||
self.src = URL.createObjectURL(stream);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
}
|
||
},
|
||
|
||
shimPeerConnection: function() {
|
||
// The RTCPeerConnection object.
|
||
if (!window.RTCPeerConnection) {
|
||
window.RTCPeerConnection = function(pcConfig, pcConstraints) {
|
||
// Translate iceTransportPolicy to iceTransports,
|
||
// see https://code.google.com/p/webrtc/issues/detail?id=4869
|
||
// this was fixed in M56 along with unprefixing RTCPeerConnection.
|
||
logging('PeerConnection');
|
||
if (pcConfig && pcConfig.iceTransportPolicy) {
|
||
pcConfig.iceTransports = pcConfig.iceTransportPolicy;
|
||
}
|
||
|
||
return new webkitRTCPeerConnection(pcConfig, pcConstraints);
|
||
};
|
||
window.RTCPeerConnection.prototype = webkitRTCPeerConnection.prototype;
|
||
// wrap static methods. Currently just generateCertificate.
|
||
if (webkitRTCPeerConnection.generateCertificate) {
|
||
Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
|
||
get: function() {
|
||
return webkitRTCPeerConnection.generateCertificate;
|
||
}
|
||
});
|
||
}
|
||
} else {
|
||
// migrate from non-spec RTCIceServer.url to RTCIceServer.urls
|
||
var OrigPeerConnection = RTCPeerConnection;
|
||
window.RTCPeerConnection = function(pcConfig, pcConstraints) {
|
||
if (pcConfig && pcConfig.iceServers) {
|
||
var newIceServers = [];
|
||
for (var i = 0; i < pcConfig.iceServers.length; i++) {
|
||
var server = pcConfig.iceServers[i];
|
||
if (!server.hasOwnProperty('urls') &&
|
||
server.hasOwnProperty('url')) {
|
||
console.warn('RTCIceServer.url is deprecated! Use urls instead.');
|
||
server = JSON.parse(JSON.stringify(server));
|
||
server.urls = server.url;
|
||
newIceServers.push(server);
|
||
} else {
|
||
newIceServers.push(pcConfig.iceServers[i]);
|
||
}
|
||
}
|
||
pcConfig.iceServers = newIceServers;
|
||
}
|
||
return new OrigPeerConnection(pcConfig, pcConstraints);
|
||
};
|
||
window.RTCPeerConnection.prototype = OrigPeerConnection.prototype;
|
||
// wrap static methods. Currently just generateCertificate.
|
||
Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
|
||
get: function() {
|
||
return OrigPeerConnection.generateCertificate;
|
||
}
|
||
});
|
||
}
|
||
|
||
var origGetStats = RTCPeerConnection.prototype.getStats;
|
||
RTCPeerConnection.prototype.getStats = function(selector,
|
||
successCallback, errorCallback) {
|
||
var self = this;
|
||
var args = arguments;
|
||
|
||
// If selector is a function then we are in the old style stats so just
|
||
// pass back the original getStats format to avoid breaking old users.
|
||
if (arguments.length > 0 && typeof selector === 'function') {
|
||
return origGetStats.apply(this, arguments);
|
||
}
|
||
|
||
// When spec-style getStats is supported, return those when called with
|
||
// either no arguments or the selector argument is null.
|
||
if (origGetStats.length === 0 && (arguments.length === 0 ||
|
||
typeof arguments[0] !== 'function')) {
|
||
return origGetStats.apply(this, []);
|
||
}
|
||
|
||
var fixChromeStats_ = function(response) {
|
||
var standardReport = {};
|
||
var reports = response.result();
|
||
reports.forEach(function(report) {
|
||
var standardStats = {
|
||
id: report.id,
|
||
timestamp: report.timestamp,
|
||
type: {
|
||
localcandidate: 'local-candidate',
|
||
remotecandidate: 'remote-candidate'
|
||
}[report.type] || report.type
|
||
};
|
||
report.names().forEach(function(name) {
|
||
standardStats[name] = report.stat(name);
|
||
});
|
||
standardReport[standardStats.id] = standardStats;
|
||
});
|
||
|
||
return standardReport;
|
||
};
|
||
|
||
// shim getStats with maplike support
|
||
var makeMapStats = function(stats) {
|
||
return new Map(Object.keys(stats).map(function(key) {
|
||
return[key, stats[key]];
|
||
}));
|
||
};
|
||
|
||
if (arguments.length >= 2) {
|
||
var successCallbackWrapper_ = function(response) {
|
||
args[1](makeMapStats(fixChromeStats_(response)));
|
||
};
|
||
|
||
return origGetStats.apply(this, [successCallbackWrapper_,
|
||
arguments[0]]);
|
||
}
|
||
|
||
// promise-support
|
||
return new Promise(function(resolve, reject) {
|
||
origGetStats.apply(self, [
|
||
function(response) {
|
||
resolve(makeMapStats(fixChromeStats_(response)));
|
||
}, reject]);
|
||
}).then(successCallback, errorCallback);
|
||
};
|
||
|
||
// add promise support -- natively available in Chrome 51
|
||
if (browserDetails.version < 51) {
|
||
['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
|
||
.forEach(function(method) {
|
||
var nativeMethod = RTCPeerConnection.prototype[method];
|
||
RTCPeerConnection.prototype[method] = function() {
|
||
var args = arguments;
|
||
var self = this;
|
||
var promise = new Promise(function(resolve, reject) {
|
||
nativeMethod.apply(self, [args[0], resolve, reject]);
|
||
});
|
||
if (args.length < 2) {
|
||
return promise;
|
||
}
|
||
return promise.then(function() {
|
||
args[1].apply(null, []);
|
||
},
|
||
function(err) {
|
||
if (args.length >= 3) {
|
||
args[2].apply(null, [err]);
|
||
}
|
||
});
|
||
};
|
||
});
|
||
}
|
||
|
||
// promise support for createOffer and createAnswer. Available (without
|
||
// bugs) since M52: crbug/619289
|
||
if (browserDetails.version < 52) {
|
||
['createOffer', 'createAnswer'].forEach(function(method) {
|
||
var nativeMethod = RTCPeerConnection.prototype[method];
|
||
RTCPeerConnection.prototype[method] = function() {
|
||
var self = this;
|
||
if (arguments.length < 1 || (arguments.length === 1 &&
|
||
typeof arguments[0] === 'object')) {
|
||
var opts = arguments.length === 1 ? arguments[0] : undefined;
|
||
return new Promise(function(resolve, reject) {
|
||
nativeMethod.apply(self, [resolve, reject, opts]);
|
||
});
|
||
}
|
||
return nativeMethod.apply(this, arguments);
|
||
};
|
||
});
|
||
}
|
||
|
||
// shim implicit creation of RTCSessionDescription/RTCIceCandidate
|
||
['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
|
||
.forEach(function(method) {
|
||
var nativeMethod = RTCPeerConnection.prototype[method];
|
||
RTCPeerConnection.prototype[method] = function() {
|
||
arguments[0] = new ((method === 'addIceCandidate') ?
|
||
RTCIceCandidate : RTCSessionDescription)(arguments[0]);
|
||
return nativeMethod.apply(this, arguments);
|
||
};
|
||
});
|
||
|
||
// support for addIceCandidate(null or undefined)
|
||
var nativeAddIceCandidate =
|
||
RTCPeerConnection.prototype.addIceCandidate;
|
||
RTCPeerConnection.prototype.addIceCandidate = function() {
|
||
if (!arguments[0]) {
|
||
if (arguments[1]) {
|
||
arguments[1].apply(null);
|
||
}
|
||
return Promise.resolve();
|
||
}
|
||
return nativeAddIceCandidate.apply(this, arguments);
|
||
};
|
||
}
|
||
};
|
||
|
||
|
||
// Expose public methods.
|
||
module.exports = {
|
||
shimMediaStream: chromeShim.shimMediaStream,
|
||
shimOnTrack: chromeShim.shimOnTrack,
|
||
shimGetSendersWithDtmf: chromeShim.shimGetSendersWithDtmf,
|
||
shimSourceObject: chromeShim.shimSourceObject,
|
||
shimPeerConnection: chromeShim.shimPeerConnection,
|
||
shimGetUserMedia: require('./getusermedia')
|
||
};
|
||
|
||
},{"../utils.js":100,"./getusermedia":93}],93:[function(require,module,exports){
|
||
/*
|
||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||
*
|
||
* Use of this source code is governed by a BSD-style license
|
||
* that can be found in the LICENSE file in the root of the source
|
||
* tree.
|
||
*/
|
||
/* eslint-env node */
|
||
'use strict';
|
||
var logging = require('../utils.js').log;
|
||
var browserDetails = require('../utils.js').browserDetails;
|
||
|
||
// Expose public methods.
|
||
module.exports = function() {
|
||
var constraintsToChrome_ = function(c) {
|
||
if (typeof c !== 'object' || c.mandatory || c.optional) {
|
||
return c;
|
||
}
|
||
var cc = {};
|
||
Object.keys(c).forEach(function(key) {
|
||
if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
|
||
return;
|
||
}
|
||
var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]};
|
||
if (r.exact !== undefined && typeof r.exact === 'number') {
|
||
r.min = r.max = r.exact;
|
||
}
|
||
var oldname_ = function(prefix, name) {
|
||
if (prefix) {
|
||
return prefix + name.charAt(0).toUpperCase() + name.slice(1);
|
||
}
|
||
return (name === 'deviceId') ? 'sourceId' : name;
|
||
};
|
||
if (r.ideal !== undefined) {
|
||
cc.optional = cc.optional || [];
|
||
var oc = {};
|
||
if (typeof r.ideal === 'number') {
|
||
oc[oldname_('min', key)] = r.ideal;
|
||
cc.optional.push(oc);
|
||
oc = {};
|
||
oc[oldname_('max', key)] = r.ideal;
|
||
cc.optional.push(oc);
|
||
} else {
|
||
oc[oldname_('', key)] = r.ideal;
|
||
cc.optional.push(oc);
|
||
}
|
||
}
|
||
if (r.exact !== undefined && typeof r.exact !== 'number') {
|
||
cc.mandatory = cc.mandatory || {};
|
||
cc.mandatory[oldname_('', key)] = r.exact;
|
||
} else {
|
||
['min', 'max'].forEach(function(mix) {
|
||
if (r[mix] !== undefined) {
|
||
cc.mandatory = cc.mandatory || {};
|
||
cc.mandatory[oldname_(mix, key)] = r[mix];
|
||
}
|
||
});
|
||
}
|
||
});
|
||
if (c.advanced) {
|
||
cc.optional = (cc.optional || []).concat(c.advanced);
|
||
}
|
||
return cc;
|
||
};
|
||
|
||
var shimConstraints_ = function(constraints, func) {
|
||
constraints = JSON.parse(JSON.stringify(constraints));
|
||
if (constraints && constraints.audio) {
|
||
constraints.audio = constraintsToChrome_(constraints.audio);
|
||
}
|
||
if (constraints && typeof constraints.video === 'object') {
|
||
// Shim facingMode for mobile & surface pro.
|
||
var face = constraints.video.facingMode;
|
||
face = face && ((typeof face === 'object') ? face : {ideal: face});
|
||
var getSupportedFacingModeLies = browserDetails.version < 61;
|
||
|
||
if ((face && (face.exact === 'user' || face.exact === 'environment' ||
|
||
face.ideal === 'user' || face.ideal === 'environment')) &&
|
||
!(navigator.mediaDevices.getSupportedConstraints &&
|
||
navigator.mediaDevices.getSupportedConstraints().facingMode &&
|
||
!getSupportedFacingModeLies)) {
|
||
delete constraints.video.facingMode;
|
||
var matches;
|
||
if (face.exact === 'environment' || face.ideal === 'environment') {
|
||
matches = ['back', 'rear'];
|
||
} else if (face.exact === 'user' || face.ideal === 'user') {
|
||
matches = ['front'];
|
||
}
|
||
if (matches) {
|
||
// Look for matches in label, or use last cam for back (typical).
|
||
return navigator.mediaDevices.enumerateDevices()
|
||
.then(function(devices) {
|
||
devices = devices.filter(function(d) {
|
||
return d.kind === 'videoinput';
|
||
});
|
||
var dev = devices.find(function(d) {
|
||
return matches.some(function(match) {
|
||
return d.label.toLowerCase().indexOf(match) !== -1;
|
||
});
|
||
});
|
||
if (!dev && devices.length && matches.indexOf('back') !== -1) {
|
||
dev = devices[devices.length - 1]; // more likely the back cam
|
||
}
|
||
if (dev) {
|
||
constraints.video.deviceId = face.exact ? {exact: dev.deviceId} :
|
||
{ideal: dev.deviceId};
|
||
}
|
||
constraints.video = constraintsToChrome_(constraints.video);
|
||
logging('chrome: ' + JSON.stringify(constraints));
|
||
return func(constraints);
|
||
});
|
||
}
|
||
}
|
||
constraints.video = constraintsToChrome_(constraints.video);
|
||
}
|
||
logging('chrome: ' + JSON.stringify(constraints));
|
||
return func(constraints);
|
||
};
|
||
|
||
var shimError_ = function(e) {
|
||
return {
|
||
name: {
|
||
PermissionDeniedError: 'NotAllowedError',
|
||
ConstraintNotSatisfiedError: 'OverconstrainedError'
|
||
}[e.name] || e.name,
|
||
message: e.message,
|
||
constraint: e.constraintName,
|
||
toString: function() {
|
||
return this.name + (this.message && ': ') + this.message;
|
||
}
|
||
};
|
||
};
|
||
|
||
var getUserMedia_ = function(constraints, onSuccess, onError) {
|
||
shimConstraints_(constraints, function(c) {
|
||
navigator.webkitGetUserMedia(c, onSuccess, function(e) {
|
||
onError(shimError_(e));
|
||
});
|
||
});
|
||
};
|
||
|
||
navigator.getUserMedia = getUserMedia_;
|
||
|
||
// Returns the result of getUserMedia as a Promise.
|
||
var getUserMediaPromise_ = function(constraints) {
|
||
return new Promise(function(resolve, reject) {
|
||
navigator.getUserMedia(constraints, resolve, reject);
|
||
});
|
||
};
|
||
|
||
if (!navigator.mediaDevices) {
|
||
navigator.mediaDevices = {
|
||
getUserMedia: getUserMediaPromise_,
|
||
enumerateDevices: function() {
|
||
return new Promise(function(resolve) {
|
||
var kinds = {audio: 'audioinput', video: 'videoinput'};
|
||
return MediaStreamTrack.getSources(function(devices) {
|
||
resolve(devices.map(function(device) {
|
||
return {label: device.label,
|
||
kind: kinds[device.kind],
|
||
deviceId: device.id,
|
||
groupId: ''};
|
||
}));
|
||
});
|
||
});
|
||
},
|
||
getSupportedConstraints: function() {
|
||
return {
|
||
deviceId: true, echoCancellation: true, facingMode: true,
|
||
frameRate: true, height: true, width: true
|
||
};
|
||
}
|
||
};
|
||
}
|
||
|
||
// A shim for getUserMedia method on the mediaDevices object.
|
||
// TODO(KaptenJansson) remove once implemented in Chrome stable.
|
||
if (!navigator.mediaDevices.getUserMedia) {
|
||
navigator.mediaDevices.getUserMedia = function(constraints) {
|
||
return getUserMediaPromise_(constraints);
|
||
};
|
||
} else {
|
||
// Even though Chrome 45 has navigator.mediaDevices and a getUserMedia
|
||
// function which returns a Promise, it does not accept spec-style
|
||
// constraints.
|
||
var origGetUserMedia = navigator.mediaDevices.getUserMedia.
|
||
bind(navigator.mediaDevices);
|
||
navigator.mediaDevices.getUserMedia = function(cs) {
|
||
return shimConstraints_(cs, function(c) {
|
||
return origGetUserMedia(c).then(function(stream) {
|
||
if (c.audio && !stream.getAudioTracks().length ||
|
||
c.video && !stream.getVideoTracks().length) {
|
||
stream.getTracks().forEach(function(track) {
|
||
track.stop();
|
||
});
|
||
throw new DOMException('', 'NotFoundError');
|
||
}
|
||
return stream;
|
||
}, function(e) {
|
||
return Promise.reject(shimError_(e));
|
||
});
|
||
});
|
||
};
|
||
}
|
||
|
||
// Dummy devicechange event methods.
|
||
// TODO(KaptenJansson) remove once implemented in Chrome stable.
|
||
if (typeof navigator.mediaDevices.addEventListener === 'undefined') {
|
||
navigator.mediaDevices.addEventListener = function() {
|
||
logging('Dummy mediaDevices.addEventListener called.');
|
||
};
|
||
}
|
||
if (typeof navigator.mediaDevices.removeEventListener === 'undefined') {
|
||
navigator.mediaDevices.removeEventListener = function() {
|
||
logging('Dummy mediaDevices.removeEventListener called.');
|
||
};
|
||
}
|
||
};
|
||
|
||
},{"../utils.js":100}],94:[function(require,module,exports){
|
||
/*
|
||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||
*
|
||
* Use of this source code is governed by a BSD-style license
|
||
* that can be found in the LICENSE file in the root of the source
|
||
* tree.
|
||
*/
|
||
/* eslint-env node */
|
||
'use strict';
|
||
|
||
var browserDetails = require('../utils').browserDetails;
|
||
var shimRTCPeerConnection = require('./rtcpeerconnection_shim');
|
||
|
||
module.exports = {
|
||
shimGetUserMedia: require('./getusermedia'),
|
||
shimPeerConnection: function() {
|
||
if (window.RTCIceGatherer) {
|
||
// ORTC defines an RTCIceCandidate object but no constructor.
|
||
// Not implemented in Edge.
|
||
if (!window.RTCIceCandidate) {
|
||
window.RTCIceCandidate = function(args) {
|
||
return args;
|
||
};
|
||
}
|
||
// ORTC does not have a session description object but
|
||
// other browsers (i.e. Chrome) that will support both PC and ORTC
|
||
// in the future might have this defined already.
|
||
if (!window.RTCSessionDescription) {
|
||
window.RTCSessionDescription = function(args) {
|
||
return args;
|
||
};
|
||
}
|
||
// this adds an additional event listener to MediaStrackTrack that signals
|
||
// when a tracks enabled property was changed. Workaround for a bug in
|
||
// addStream, see below. No longer required in 15025+
|
||
if (browserDetails.version < 15025) {
|
||
var origMSTEnabled = Object.getOwnPropertyDescriptor(
|
||
MediaStreamTrack.prototype, 'enabled');
|
||
Object.defineProperty(MediaStreamTrack.prototype, 'enabled', {
|
||
set: function(value) {
|
||
origMSTEnabled.set.call(this, value);
|
||
var ev = new Event('enabled');
|
||
ev.enabled = value;
|
||
this.dispatchEvent(ev);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
window.RTCPeerConnection = shimRTCPeerConnection(browserDetails.version);
|
||
},
|
||
shimReplaceTrack: function() {
|
||
// ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614
|
||
if (window.RTCRtpSender && !('replaceTrack' in RTCRtpSender.prototype)) {
|
||
RTCRtpSender.prototype.replaceTrack = RTCRtpSender.prototype.setTrack;
|
||
}
|
||
}
|
||
};
|
||
|
||
},{"../utils":100,"./getusermedia":95,"./rtcpeerconnection_shim":96}],95:[function(require,module,exports){
|
||
/*
|
||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||
*
|
||
* Use of this source code is governed by a BSD-style license
|
||
* that can be found in the LICENSE file in the root of the source
|
||
* tree.
|
||
*/
|
||
/* eslint-env node */
|
||
'use strict';
|
||
|
||
// Expose public methods.
|
||
module.exports = function() {
|
||
var shimError_ = function(e) {
|
||
return {
|
||
name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name,
|
||
message: e.message,
|
||
constraint: e.constraint,
|
||
toString: function() {
|
||
return this.name;
|
||
}
|
||
};
|
||
};
|
||
|
||
// getUserMedia error shim.
|
||
var origGetUserMedia = navigator.mediaDevices.getUserMedia.
|
||
bind(navigator.mediaDevices);
|
||
navigator.mediaDevices.getUserMedia = function(c) {
|
||
return origGetUserMedia(c).catch(function(e) {
|
||
return Promise.reject(shimError_(e));
|
||
});
|
||
};
|
||
};
|
||
|
||
},{}],96:[function(require,module,exports){
|
||
/*
|
||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||
*
|
||
* Use of this source code is governed by a BSD-style license
|
||
* that can be found in the LICENSE file in the root of the source
|
||
* tree.
|
||
*/
|
||
/* eslint-env node */
|
||
'use strict';
|
||
|
||
var SDPUtils = require('sdp');
|
||
|
||
// sort tracks such that they follow an a-v-a-v...
|
||
// pattern.
|
||
function sortTracks(tracks) {
|
||
var audioTracks = tracks.filter(function(track) {
|
||
return track.kind === 'audio';
|
||
});
|
||
var videoTracks = tracks.filter(function(track) {
|
||
return track.kind === 'video';
|
||
});
|
||
tracks = [];
|
||
while (audioTracks.length || videoTracks.length) {
|
||
if (audioTracks.length) {
|
||
tracks.push(audioTracks.shift());
|
||
}
|
||
if (videoTracks.length) {
|
||
tracks.push(videoTracks.shift());
|
||
}
|
||
}
|
||
return tracks;
|
||
}
|
||
|
||
// Edge does not like
|
||
// 1) stun:
|
||
// 2) turn: that does not have all of turn:host:port?transport=udp
|
||
// 3) turn: with ipv6 addresses
|
||
// 4) turn: occurring muliple times
|
||
function filterIceServers(iceServers, edgeVersion) {
|
||
var hasTurn = false;
|
||
iceServers = JSON.parse(JSON.stringify(iceServers));
|
||
return iceServers.filter(function(server) {
|
||
if (server && (server.urls || server.url)) {
|
||
var urls = server.urls || server.url;
|
||
if (server.url && !server.urls) {
|
||
console.warn('RTCIceServer.url is deprecated! Use urls instead.');
|
||
}
|
||
var isString = typeof urls === 'string';
|
||
if (isString) {
|
||
urls = [urls];
|
||
}
|
||
urls = urls.filter(function(url) {
|
||
var validTurn = url.indexOf('turn:') === 0 &&
|
||
url.indexOf('transport=udp') !== -1 &&
|
||
url.indexOf('turn:[') === -1 &&
|
||
!hasTurn;
|
||
|
||
if (validTurn) {
|
||
hasTurn = true;
|
||
return true;
|
||
}
|
||
return url.indexOf('stun:') === 0 && edgeVersion >= 14393;
|
||
});
|
||
|
||
delete server.url;
|
||
server.urls = isString ? urls[0] : urls;
|
||
return !!urls.length;
|
||
}
|
||
return false;
|
||
});
|
||
}
|
||
|
||
module.exports = function(edgeVersion) {
|
||
var RTCPeerConnection = function(config) {
|
||
var self = this;
|
||
|
||
var _eventTarget = document.createDocumentFragment();
|
||
['addEventListener', 'removeEventListener', 'dispatchEvent']
|
||
.forEach(function(method) {
|
||
self[method] = _eventTarget[method].bind(_eventTarget);
|
||
});
|
||
|
||
this.onicecandidate = null;
|
||
this.onaddstream = null;
|
||
this.ontrack = null;
|
||
this.onremovestream = null;
|
||
this.onsignalingstatechange = null;
|
||
this.oniceconnectionstatechange = null;
|
||
this.onicegatheringstatechange = null;
|
||
this.onnegotiationneeded = null;
|
||
this.ondatachannel = null;
|
||
this.canTrickleIceCandidates = null;
|
||
|
||
this.localStreams = [];
|
||
this.remoteStreams = [];
|
||
this.getLocalStreams = function() {
|
||
return self.localStreams;
|
||
};
|
||
this.getRemoteStreams = function() {
|
||
return self.remoteStreams;
|
||
};
|
||
|
||
this.localDescription = new RTCSessionDescription({
|
||
type: '',
|
||
sdp: ''
|
||
});
|
||
this.remoteDescription = new RTCSessionDescription({
|
||
type: '',
|
||
sdp: ''
|
||
});
|
||
this.signalingState = 'stable';
|
||
this.iceConnectionState = 'new';
|
||
this.iceGatheringState = 'new';
|
||
|
||
this.iceOptions = {
|
||
gatherPolicy: 'all',
|
||
iceServers: []
|
||
};
|
||
if (config && config.iceTransportPolicy) {
|
||
switch (config.iceTransportPolicy) {
|
||
case 'all':
|
||
case 'relay':
|
||
this.iceOptions.gatherPolicy = config.iceTransportPolicy;
|
||
break;
|
||
default:
|
||
// don't set iceTransportPolicy.
|
||
break;
|
||
}
|
||
}
|
||
this.usingBundle = config && config.bundlePolicy === 'max-bundle';
|
||
|
||
if (config && config.iceServers) {
|
||
this.iceOptions.iceServers = filterIceServers(config.iceServers,
|
||
edgeVersion);
|
||
}
|
||
this._config = config || {};
|
||
|
||
// per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ...
|
||
// everything that is needed to describe a SDP m-line.
|
||
this.transceivers = [];
|
||
|
||
// since the iceGatherer is currently created in createOffer but we
|
||
// must not emit candidates until after setLocalDescription we buffer
|
||
// them in this array.
|
||
this._localIceCandidatesBuffer = [];
|
||
};
|
||
|
||
RTCPeerConnection.prototype._emitGatheringStateChange = function() {
|
||
var event = new Event('icegatheringstatechange');
|
||
this.dispatchEvent(event);
|
||
if (this.onicegatheringstatechange !== null) {
|
||
this.onicegatheringstatechange(event);
|
||
}
|
||
};
|
||
|
||
RTCPeerConnection.prototype._emitBufferedCandidates = function() {
|
||
var self = this;
|
||
var sections = SDPUtils.splitSections(self.localDescription.sdp);
|
||
// FIXME: need to apply ice candidates in a way which is async but
|
||
// in-order
|
||
this._localIceCandidatesBuffer.forEach(function(event) {
|
||
var end = !event.candidate || Object.keys(event.candidate).length === 0;
|
||
if (end) {
|
||
for (var j = 1; j < sections.length; j++) {
|
||
if (sections[j].indexOf('\r\na=end-of-candidates\r\n') === -1) {
|
||
sections[j] += 'a=end-of-candidates\r\n';
|
||
}
|
||
}
|
||
} else {
|
||
sections[event.candidate.sdpMLineIndex + 1] +=
|
||
'a=' + event.candidate.candidate + '\r\n';
|
||
}
|
||
self.localDescription.sdp = sections.join('');
|
||
self.dispatchEvent(event);
|
||
if (self.onicecandidate !== null) {
|
||
self.onicecandidate(event);
|
||
}
|
||
if (!event.candidate && self.iceGatheringState !== 'complete') {
|
||
var complete = self.transceivers.every(function(transceiver) {
|
||
return transceiver.iceGatherer &&
|
||
transceiver.iceGatherer.state === 'completed';
|
||
});
|
||
if (complete && self.iceGatheringStateChange !== 'complete') {
|
||
self.iceGatheringState = 'complete';
|
||
self._emitGatheringStateChange();
|
||
}
|
||
}
|
||
});
|
||
this._localIceCandidatesBuffer = [];
|
||
};
|
||
|
||
RTCPeerConnection.prototype.getConfiguration = function() {
|
||
return this._config;
|
||
};
|
||
|
||
RTCPeerConnection.prototype.addStream = function(stream) {
|
||
if (edgeVersion >= 15025) {
|
||
this.localStreams.push(stream);
|
||
} else {
|
||
// Clone is necessary for local demos mostly, attaching directly
|
||
// to two different senders does not work (build 10547).
|
||
// Fixed in 15025 (or earlier)
|
||
var clonedStream = stream.clone();
|
||
stream.getTracks().forEach(function(track, idx) {
|
||
var clonedTrack = clonedStream.getTracks()[idx];
|
||
track.addEventListener('enabled', function(event) {
|
||
clonedTrack.enabled = event.enabled;
|
||
});
|
||
});
|
||
this.localStreams.push(clonedStream);
|
||
}
|
||
this._maybeFireNegotiationNeeded();
|
||
};
|
||
|
||
RTCPeerConnection.prototype.removeStream = function(stream) {
|
||
var idx = this.localStreams.indexOf(stream);
|
||
if (idx > -1) {
|
||
this.localStreams.splice(idx, 1);
|
||
this._maybeFireNegotiationNeeded();
|
||
}
|
||
};
|
||
|
||
RTCPeerConnection.prototype.getSenders = function() {
|
||
return this.transceivers.filter(function(transceiver) {
|
||
return !!transceiver.rtpSender;
|
||
})
|
||
.map(function(transceiver) {
|
||
return transceiver.rtpSender;
|
||
});
|
||
};
|
||
|
||
RTCPeerConnection.prototype.getReceivers = function() {
|
||
return this.transceivers.filter(function(transceiver) {
|
||
return !!transceiver.rtpReceiver;
|
||
})
|
||
.map(function(transceiver) {
|
||
return transceiver.rtpReceiver;
|
||
});
|
||
};
|
||
|
||
// Determines the intersection of local and remote capabilities.
|
||
RTCPeerConnection.prototype._getCommonCapabilities = function(
|
||
localCapabilities, remoteCapabilities) {
|
||
var commonCapabilities = {
|
||
codecs: [],
|
||
headerExtensions: [],
|
||
fecMechanisms: []
|
||
};
|
||
|
||
var findCodecByPayloadType = function(pt, codecs) {
|
||
pt = parseInt(pt, 10);
|
||
for (var i = 0; i < codecs.length; i++) {
|
||
if (codecs[i].payloadType === pt ||
|
||
codecs[i].preferredPayloadType === pt) {
|
||
return codecs[i];
|
||
}
|
||
}
|
||
};
|
||
|
||
var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) {
|
||
var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs);
|
||
var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs);
|
||
return lCodec && rCodec &&
|
||
lCodec.name.toLowerCase() === rCodec.name.toLowerCase();
|
||
};
|
||
|
||
localCapabilities.codecs.forEach(function(lCodec) {
|
||
for (var i = 0; i < remoteCapabilities.codecs.length; i++) {
|
||
var rCodec = remoteCapabilities.codecs[i];
|
||
if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() &&
|
||
lCodec.clockRate === rCodec.clockRate) {
|
||
if (lCodec.name.toLowerCase() === 'rtx' &&
|
||
lCodec.parameters && rCodec.parameters.apt) {
|
||
// for RTX we need to find the local rtx that has a apt
|
||
// which points to the same local codec as the remote one.
|
||
if (!rtxCapabilityMatches(lCodec, rCodec,
|
||
localCapabilities.codecs, remoteCapabilities.codecs)) {
|
||
continue;
|
||
}
|
||
}
|
||
rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy
|
||
// number of channels is the highest common number of channels
|
||
rCodec.numChannels = Math.min(lCodec.numChannels,
|
||
rCodec.numChannels);
|
||
// push rCodec so we reply with offerer payload type
|
||
commonCapabilities.codecs.push(rCodec);
|
||
|
||
// determine common feedback mechanisms
|
||
rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) {
|
||
for (var j = 0; j < lCodec.rtcpFeedback.length; j++) {
|
||
if (lCodec.rtcpFeedback[j].type === fb.type &&
|
||
lCodec.rtcpFeedback[j].parameter === fb.parameter) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
});
|
||
// FIXME: also need to determine .parameters
|
||
// see https://github.com/openpeer/ortc/issues/569
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
|
||
localCapabilities.headerExtensions
|
||
.forEach(function(lHeaderExtension) {
|
||
for (var i = 0; i < remoteCapabilities.headerExtensions.length;
|
||
i++) {
|
||
var rHeaderExtension = remoteCapabilities.headerExtensions[i];
|
||
if (lHeaderExtension.uri === rHeaderExtension.uri) {
|
||
commonCapabilities.headerExtensions.push(rHeaderExtension);
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
|
||
// FIXME: fecMechanisms
|
||
return commonCapabilities;
|
||
};
|
||
|
||
// Create ICE gatherer, ICE transport and DTLS transport.
|
||
RTCPeerConnection.prototype._createIceAndDtlsTransports = function(mid,
|
||
sdpMLineIndex) {
|
||
var self = this;
|
||
var iceGatherer = new RTCIceGatherer(self.iceOptions);
|
||
var iceTransport = new RTCIceTransport(iceGatherer);
|
||
iceGatherer.onlocalcandidate = function(evt) {
|
||
var event = new Event('icecandidate');
|
||
event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex};
|
||
|
||
var cand = evt.candidate;
|
||
var end = !cand || Object.keys(cand).length === 0;
|
||
// Edge emits an empty object for RTCIceCandidateComplete‥
|
||
if (end) {
|
||
// polyfill since RTCIceGatherer.state is not implemented in
|
||
// Edge 10547 yet.
|
||
if (iceGatherer.state === undefined) {
|
||
iceGatherer.state = 'completed';
|
||
}
|
||
} else {
|
||
// RTCIceCandidate doesn't have a component, needs to be added
|
||
cand.component = iceTransport.component === 'RTCP' ? 2 : 1;
|
||
event.candidate.candidate = SDPUtils.writeCandidate(cand);
|
||
}
|
||
|
||
// update local description.
|
||
var sections = SDPUtils.splitSections(self.localDescription.sdp);
|
||
if (!end) {
|
||
sections[event.candidate.sdpMLineIndex + 1] +=
|
||
'a=' + event.candidate.candidate + '\r\n';
|
||
} else {
|
||
sections[event.candidate.sdpMLineIndex + 1] +=
|
||
'a=end-of-candidates\r\n';
|
||
}
|
||
self.localDescription.sdp = sections.join('');
|
||
var transceivers = self._pendingOffer ? self._pendingOffer :
|
||
self.transceivers;
|
||
var complete = transceivers.every(function(transceiver) {
|
||
return transceiver.iceGatherer &&
|
||
transceiver.iceGatherer.state === 'completed';
|
||
});
|
||
|
||
// Emit candidate if localDescription is set.
|
||
// Also emits null candidate when all gatherers are complete.
|
||
switch (self.iceGatheringState) {
|
||
case 'new':
|
||
if (!end) {
|
||
self._localIceCandidatesBuffer.push(event);
|
||
}
|
||
if (end && complete) {
|
||
self._localIceCandidatesBuffer.push(
|
||
new Event('icecandidate'));
|
||
}
|
||
break;
|
||
case 'gathering':
|
||
self._emitBufferedCandidates();
|
||
if (!end) {
|
||
self.dispatchEvent(event);
|
||
if (self.onicecandidate !== null) {
|
||
self.onicecandidate(event);
|
||
}
|
||
}
|
||
if (complete) {
|
||
self.dispatchEvent(new Event('icecandidate'));
|
||
if (self.onicecandidate !== null) {
|
||
self.onicecandidate(new Event('icecandidate'));
|
||
}
|
||
self.iceGatheringState = 'complete';
|
||
self._emitGatheringStateChange();
|
||
}
|
||
break;
|
||
case 'complete':
|
||
// should not happen... currently!
|
||
break;
|
||
default: // no-op.
|
||
break;
|
||
}
|
||
};
|
||
iceTransport.onicestatechange = function() {
|
||
self._updateConnectionState();
|
||
};
|
||
|
||
var dtlsTransport = new RTCDtlsTransport(iceTransport);
|
||
dtlsTransport.ondtlsstatechange = function() {
|
||
self._updateConnectionState();
|
||
};
|
||
dtlsTransport.onerror = function() {
|
||
// onerror does not set state to failed by itself.
|
||
dtlsTransport.state = 'failed';
|
||
self._updateConnectionState();
|
||
};
|
||
|
||
return {
|
||
iceGatherer: iceGatherer,
|
||
iceTransport: iceTransport,
|
||
dtlsTransport: dtlsTransport
|
||
};
|
||
};
|
||
|
||
// Destroy ICE gatherer, ICE transport and DTLS transport.
|
||
// Without triggering the callbacks.
|
||
RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function(
|
||
sdpMLineIndex) {
|
||
var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer;
|
||
if (iceGatherer) {
|
||
delete iceGatherer.onlocalcandidate;
|
||
delete this.transceivers[sdpMLineIndex].iceGatherer;
|
||
}
|
||
var iceTransport = this.transceivers[sdpMLineIndex].iceTransport;
|
||
if (iceTransport) {
|
||
delete iceTransport.onicestatechange;
|
||
delete this.transceivers[sdpMLineIndex].iceTransport;
|
||
}
|
||
var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport;
|
||
if (dtlsTransport) {
|
||
delete dtlsTransport.ondtlssttatechange;
|
||
delete dtlsTransport.onerror;
|
||
delete this.transceivers[sdpMLineIndex].dtlsTransport;
|
||
}
|
||
};
|
||
|
||
// Start the RTP Sender and Receiver for a transceiver.
|
||
RTCPeerConnection.prototype._transceive = function(transceiver,
|
||
send, recv) {
|
||
var params = this._getCommonCapabilities(transceiver.localCapabilities,
|
||
transceiver.remoteCapabilities);
|
||
if (send && transceiver.rtpSender) {
|
||
params.encodings = transceiver.sendEncodingParameters;
|
||
params.rtcp = {
|
||
cname: SDPUtils.localCName,
|
||
compound: transceiver.rtcpParameters.compound
|
||
};
|
||
if (transceiver.recvEncodingParameters.length) {
|
||
params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc;
|
||
}
|
||
transceiver.rtpSender.send(params);
|
||
}
|
||
if (recv && transceiver.rtpReceiver) {
|
||
// remove RTX field in Edge 14942
|
||
if (transceiver.kind === 'video'
|
||
&& transceiver.recvEncodingParameters
|
||
&& edgeVersion < 15019) {
|
||
transceiver.recvEncodingParameters.forEach(function(p) {
|
||
delete p.rtx;
|
||
});
|
||
}
|
||
params.encodings = transceiver.recvEncodingParameters;
|
||
params.rtcp = {
|
||
cname: transceiver.rtcpParameters.cname,
|
||
compound: transceiver.rtcpParameters.compound
|
||
};
|
||
if (transceiver.sendEncodingParameters.length) {
|
||
params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc;
|
||
}
|
||
transceiver.rtpReceiver.receive(params);
|
||
}
|
||
};
|
||
|
||
RTCPeerConnection.prototype.setLocalDescription = function(description) {
|
||
var self = this;
|
||
var sections;
|
||
var sessionpart;
|
||
if (description.type === 'offer') {
|
||
// FIXME: What was the purpose of this empty if statement?
|
||
// if (!this._pendingOffer) {
|
||
// } else {
|
||
if (this._pendingOffer) {
|
||
// VERY limited support for SDP munging. Limited to:
|
||
// * changing the order of codecs
|
||
sections = SDPUtils.splitSections(description.sdp);
|
||
sessionpart = sections.shift();
|
||
sections.forEach(function(mediaSection, sdpMLineIndex) {
|
||
var caps = SDPUtils.parseRtpParameters(mediaSection);
|
||
self._pendingOffer[sdpMLineIndex].localCapabilities = caps;
|
||
});
|
||
this.transceivers = this._pendingOffer;
|
||
delete this._pendingOffer;
|
||
}
|
||
} else if (description.type === 'answer') {
|
||
sections = SDPUtils.splitSections(self.remoteDescription.sdp);
|
||
sessionpart = sections.shift();
|
||
var isIceLite = SDPUtils.matchPrefix(sessionpart,
|
||
'a=ice-lite').length > 0;
|
||
sections.forEach(function(mediaSection, sdpMLineIndex) {
|
||
var transceiver = self.transceivers[sdpMLineIndex];
|
||
var iceGatherer = transceiver.iceGatherer;
|
||
var iceTransport = transceiver.iceTransport;
|
||
var dtlsTransport = transceiver.dtlsTransport;
|
||
var localCapabilities = transceiver.localCapabilities;
|
||
var remoteCapabilities = transceiver.remoteCapabilities;
|
||
|
||
var rejected = mediaSection.split('\n', 1)[0]
|
||
.split(' ', 2)[1] === '0';
|
||
|
||
if (!rejected && !transceiver.isDatachannel) {
|
||
var remoteIceParameters = SDPUtils.getIceParameters(
|
||
mediaSection, sessionpart);
|
||
var remoteDtlsParameters = SDPUtils.getDtlsParameters(
|
||
mediaSection, sessionpart);
|
||
if (isIceLite) {
|
||
remoteDtlsParameters.role = 'server';
|
||
}
|
||
|
||
if (!self.usingBundle || sdpMLineIndex === 0) {
|
||
iceTransport.start(iceGatherer, remoteIceParameters,
|
||
isIceLite ? 'controlling' : 'controlled');
|
||
dtlsTransport.start(remoteDtlsParameters);
|
||
}
|
||
|
||
// Calculate intersection of capabilities.
|
||
var params = self._getCommonCapabilities(localCapabilities,
|
||
remoteCapabilities);
|
||
|
||
// Start the RTCRtpSender. The RTCRtpReceiver for this
|
||
// transceiver has already been started in setRemoteDescription.
|
||
self._transceive(transceiver,
|
||
params.codecs.length > 0,
|
||
false);
|
||
}
|
||
});
|
||
}
|
||
|
||
this.localDescription = {
|
||
type: description.type,
|
||
sdp: description.sdp
|
||
};
|
||
switch (description.type) {
|
||
case 'offer':
|
||
this._updateSignalingState('have-local-offer');
|
||
break;
|
||
case 'answer':
|
||
this._updateSignalingState('stable');
|
||
break;
|
||
default:
|
||
throw new TypeError('unsupported type "' + description.type +
|
||
'"');
|
||
}
|
||
|
||
// If a success callback was provided, emit ICE candidates after it
|
||
// has been executed. Otherwise, emit callback after the Promise is
|
||
// resolved.
|
||
var hasCallback = arguments.length > 1 &&
|
||
typeof arguments[1] === 'function';
|
||
if (hasCallback) {
|
||
var cb = arguments[1];
|
||
window.setTimeout(function() {
|
||
cb();
|
||
if (self.iceGatheringState === 'new') {
|
||
self.iceGatheringState = 'gathering';
|
||
self._emitGatheringStateChange();
|
||
}
|
||
self._emitBufferedCandidates();
|
||
}, 0);
|
||
}
|
||
var p = Promise.resolve();
|
||
p.then(function() {
|
||
if (!hasCallback) {
|
||
if (self.iceGatheringState === 'new') {
|
||
self.iceGatheringState = 'gathering';
|
||
self._emitGatheringStateChange();
|
||
}
|
||
// Usually candidates will be emitted earlier.
|
||
window.setTimeout(self._emitBufferedCandidates.bind(self), 500);
|
||
}
|
||
});
|
||
return p;
|
||
};
|
||
|
||
RTCPeerConnection.prototype.setRemoteDescription = function(description) {
|
||
var self = this;
|
||
var streams = {};
|
||
var receiverList = [];
|
||
var sections = SDPUtils.splitSections(description.sdp);
|
||
var sessionpart = sections.shift();
|
||
var isIceLite = SDPUtils.matchPrefix(sessionpart,
|
||
'a=ice-lite').length > 0;
|
||
var usingBundle = SDPUtils.matchPrefix(sessionpart,
|
||
'a=group:BUNDLE ').length > 0;
|
||
var iceOptions = SDPUtils.matchPrefix(sessionpart,
|
||
'a=ice-options:')[0];
|
||
if (iceOptions) {
|
||
this.canTrickleIceCandidates = iceOptions.substr(14).split(' ')
|
||
.indexOf('trickle') >= 0;
|
||
} else {
|
||
this.canTrickleIceCandidates = false;
|
||
}
|
||
|
||
sections.forEach(function(mediaSection, sdpMLineIndex) {
|
||
var lines = SDPUtils.splitLines(mediaSection);
|
||
var mline = lines[0].substr(2).split(' ');
|
||
var kind = mline[0];
|
||
var rejected = mline[1] === '0';
|
||
var direction = SDPUtils.getDirection(mediaSection, sessionpart);
|
||
var remoteMsid = SDPUtils.parseMsid(mediaSection);
|
||
|
||
var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:');
|
||
if (mid.length) {
|
||
mid = mid[0].substr(6);
|
||
} else {
|
||
mid = SDPUtils.generateIdentifier();
|
||
}
|
||
|
||
// Reject datachannels which are not implemented yet.
|
||
if (kind === 'application' && mline[2] === 'DTLS/SCTP') {
|
||
self.transceivers[sdpMLineIndex] = {
|
||
mid: mid,
|
||
isDatachannel: true
|
||
};
|
||
return;
|
||
}
|
||
|
||
var transceiver;
|
||
var iceGatherer;
|
||
var iceTransport;
|
||
var dtlsTransport;
|
||
var rtpSender;
|
||
var rtpReceiver;
|
||
var sendEncodingParameters;
|
||
var recvEncodingParameters;
|
||
var localCapabilities;
|
||
|
||
var track;
|
||
// FIXME: ensure the mediaSection has rtcp-mux set.
|
||
var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection);
|
||
var remoteIceParameters;
|
||
var remoteDtlsParameters;
|
||
if (!rejected) {
|
||
remoteIceParameters = SDPUtils.getIceParameters(mediaSection,
|
||
sessionpart);
|
||
remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection,
|
||
sessionpart);
|
||
remoteDtlsParameters.role = 'client';
|
||
}
|
||
recvEncodingParameters =
|
||
SDPUtils.parseRtpEncodingParameters(mediaSection);
|
||
|
||
var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection);
|
||
|
||
var isComplete = SDPUtils.matchPrefix(mediaSection,
|
||
'a=end-of-candidates', sessionpart).length > 0;
|
||
var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:')
|
||
.map(function(cand) {
|
||
return SDPUtils.parseCandidate(cand);
|
||
})
|
||
.filter(function(cand) {
|
||
return cand.component === '1';
|
||
});
|
||
if (description.type === 'offer' && !rejected) {
|
||
var transports = usingBundle && sdpMLineIndex > 0 ? {
|
||
iceGatherer: self.transceivers[0].iceGatherer,
|
||
iceTransport: self.transceivers[0].iceTransport,
|
||
dtlsTransport: self.transceivers[0].dtlsTransport
|
||
} : self._createIceAndDtlsTransports(mid, sdpMLineIndex);
|
||
|
||
if (isComplete && (!usingBundle || sdpMLineIndex === 0)) {
|
||
transports.iceTransport.setRemoteCandidates(cands);
|
||
}
|
||
|
||
localCapabilities = RTCRtpReceiver.getCapabilities(kind);
|
||
|
||
// filter RTX until additional stuff needed for RTX is implemented
|
||
// in adapter.js
|
||
if (edgeVersion < 15019) {
|
||
localCapabilities.codecs = localCapabilities.codecs.filter(
|
||
function(codec) {
|
||
return codec.name !== 'rtx';
|
||
});
|
||
}
|
||
|
||
sendEncodingParameters = [{
|
||
ssrc: (2 * sdpMLineIndex + 2) * 1001
|
||
}];
|
||
|
||
if (direction === 'sendrecv' || direction === 'sendonly') {
|
||
rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport,
|
||
kind);
|
||
|
||
track = rtpReceiver.track;
|
||
// FIXME: does not work with Plan B.
|
||
if (remoteMsid) {
|
||
if (!streams[remoteMsid.stream]) {
|
||
streams[remoteMsid.stream] = new MediaStream();
|
||
Object.defineProperty(streams[remoteMsid.stream], 'id', {
|
||
get: function() {
|
||
return remoteMsid.stream;
|
||
}
|
||
});
|
||
}
|
||
Object.defineProperty(track, 'id', {
|
||
get: function() {
|
||
return remoteMsid.track;
|
||
}
|
||
});
|
||
streams[remoteMsid.stream].addTrack(track);
|
||
receiverList.push([track, rtpReceiver,
|
||
streams[remoteMsid.stream]]);
|
||
} else {
|
||
if (!streams.default) {
|
||
streams.default = new MediaStream();
|
||
}
|
||
streams.default.addTrack(track);
|
||
receiverList.push([track, rtpReceiver, streams.default]);
|
||
}
|
||
}
|
||
|
||
// FIXME: look at direction.
|
||
if (self.localStreams.length > 0 &&
|
||
self.localStreams[0].getTracks().length >= sdpMLineIndex) {
|
||
var localTrack;
|
||
if (kind === 'audio') {
|
||
localTrack = self.localStreams[0].getAudioTracks()[0];
|
||
} else if (kind === 'video') {
|
||
localTrack = self.localStreams[0].getVideoTracks()[0];
|
||
}
|
||
if (localTrack) {
|
||
// add RTX
|
||
if (edgeVersion >= 15019 && kind === 'video') {
|
||
sendEncodingParameters[0].rtx = {
|
||
ssrc: (2 * sdpMLineIndex + 2) * 1001 + 1
|
||
};
|
||
}
|
||
rtpSender = new RTCRtpSender(localTrack,
|
||
transports.dtlsTransport);
|
||
}
|
||
}
|
||
|
||
self.transceivers[sdpMLineIndex] = {
|
||
iceGatherer: transports.iceGatherer,
|
||
iceTransport: transports.iceTransport,
|
||
dtlsTransport: transports.dtlsTransport,
|
||
localCapabilities: localCapabilities,
|
||
remoteCapabilities: remoteCapabilities,
|
||
rtpSender: rtpSender,
|
||
rtpReceiver: rtpReceiver,
|
||
kind: kind,
|
||
mid: mid,
|
||
rtcpParameters: rtcpParameters,
|
||
sendEncodingParameters: sendEncodingParameters,
|
||
recvEncodingParameters: recvEncodingParameters
|
||
};
|
||
// Start the RTCRtpReceiver now. The RTPSender is started in
|
||
// setLocalDescription.
|
||
self._transceive(self.transceivers[sdpMLineIndex],
|
||
false,
|
||
direction === 'sendrecv' || direction === 'sendonly');
|
||
} else if (description.type === 'answer' && !rejected) {
|
||
if (usingBundle && sdpMLineIndex > 0) {
|
||
self._disposeIceAndDtlsTransports(sdpMLineIndex);
|
||
self.transceivers[sdpMLineIndex].iceGatherer =
|
||
self.transceivers[0].iceGatherer;
|
||
self.transceivers[sdpMLineIndex].iceTransport =
|
||
self.transceivers[0].iceTransport;
|
||
self.transceivers[sdpMLineIndex].dtlsTransport =
|
||
self.transceivers[0].dtlsTransport;
|
||
if (self.transceivers[sdpMLineIndex].rtpSender) {
|
||
self.transceivers[sdpMLineIndex].rtpSender.setTransport(
|
||
self.transceivers[0].dtlsTransport);
|
||
}
|
||
if (self.transceivers[sdpMLineIndex].rtpReceiver) {
|
||
self.transceivers[sdpMLineIndex].rtpReceiver.setTransport(
|
||
self.transceivers[0].dtlsTransport);
|
||
}
|
||
}
|
||
transceiver = self.transceivers[sdpMLineIndex];
|
||
iceGatherer = transceiver.iceGatherer;
|
||
iceTransport = transceiver.iceTransport;
|
||
dtlsTransport = transceiver.dtlsTransport;
|
||
rtpSender = transceiver.rtpSender;
|
||
rtpReceiver = transceiver.rtpReceiver;
|
||
sendEncodingParameters = transceiver.sendEncodingParameters;
|
||
localCapabilities = transceiver.localCapabilities;
|
||
|
||
self.transceivers[sdpMLineIndex].recvEncodingParameters =
|
||
recvEncodingParameters;
|
||
self.transceivers[sdpMLineIndex].remoteCapabilities =
|
||
remoteCapabilities;
|
||
self.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters;
|
||
|
||
if ((isIceLite || isComplete) && cands.length) {
|
||
iceTransport.setRemoteCandidates(cands);
|
||
}
|
||
if (!usingBundle || sdpMLineIndex === 0) {
|
||
iceTransport.start(iceGatherer, remoteIceParameters,
|
||
'controlling');
|
||
dtlsTransport.start(remoteDtlsParameters);
|
||
}
|
||
|
||
self._transceive(transceiver,
|
||
direction === 'sendrecv' || direction === 'recvonly',
|
||
direction === 'sendrecv' || direction === 'sendonly');
|
||
|
||
if (rtpReceiver &&
|
||
(direction === 'sendrecv' || direction === 'sendonly')) {
|
||
track = rtpReceiver.track;
|
||
receiverList.push([track, rtpReceiver]);
|
||
if (remoteMsid) {
|
||
if (!streams[remoteMsid.stream]) {
|
||
streams[remoteMsid.stream] = new MediaStream();
|
||
}
|
||
streams[remoteMsid.stream].addTrack(track);
|
||
} else {
|
||
if (!streams.default) {
|
||
streams.default = new MediaStream();
|
||
}
|
||
streams.default.addTrack(track);
|
||
}
|
||
} else {
|
||
// FIXME: actually the receiver should be created later.
|
||
delete transceiver.rtpReceiver;
|
||
}
|
||
}
|
||
});
|
||
this.usingBundle = usingBundle;
|
||
|
||
this.remoteDescription = {
|
||
type: description.type,
|
||
sdp: description.sdp
|
||
};
|
||
switch (description.type) {
|
||
case 'offer':
|
||
this._updateSignalingState('have-remote-offer');
|
||
break;
|
||
case 'answer':
|
||
this._updateSignalingState('stable');
|
||
break;
|
||
default:
|
||
throw new TypeError('unsupported type "' + description.type +
|
||
'"');
|
||
}
|
||
Object.keys(streams).forEach(function(sid) {
|
||
var stream = streams[sid];
|
||
if (stream.getTracks().length) {
|
||
self.remoteStreams.push(stream);
|
||
var event = new Event('addstream');
|
||
event.stream = stream;
|
||
self.dispatchEvent(event);
|
||
if (self.onaddstream !== null) {
|
||
window.setTimeout(function() {
|
||
self.onaddstream(event);
|
||
}, 0);
|
||
}
|
||
|
||
receiverList.forEach(function(item) {
|
||
var track = item[0];
|
||
var receiver = item[1];
|
||
if (stream.id !== item[2].id) {
|
||
return;
|
||
}
|
||
var trackEvent = new Event('track');
|
||
trackEvent.track = track;
|
||
trackEvent.receiver = receiver;
|
||
trackEvent.streams = [stream];
|
||
self.dispatchEvent(trackEvent);
|
||
if (self.ontrack !== null) {
|
||
window.setTimeout(function() {
|
||
self.ontrack(trackEvent);
|
||
}, 0);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
if (arguments.length > 1 && typeof arguments[1] === 'function') {
|
||
window.setTimeout(arguments[1], 0);
|
||
}
|
||
return Promise.resolve();
|
||
};
|
||
|
||
RTCPeerConnection.prototype.close = function() {
|
||
this.transceivers.forEach(function(transceiver) {
|
||
/* not yet
|
||
if (transceiver.iceGatherer) {
|
||
transceiver.iceGatherer.close();
|
||
}
|
||
*/
|
||
if (transceiver.iceTransport) {
|
||
transceiver.iceTransport.stop();
|
||
}
|
||
if (transceiver.dtlsTransport) {
|
||
transceiver.dtlsTransport.stop();
|
||
}
|
||
if (transceiver.rtpSender) {
|
||
transceiver.rtpSender.stop();
|
||
}
|
||
if (transceiver.rtpReceiver) {
|
||
transceiver.rtpReceiver.stop();
|
||
}
|
||
});
|
||
// FIXME: clean up tracks, local streams, remote streams, etc
|
||
this._updateSignalingState('closed');
|
||
};
|
||
|
||
// Update the signaling state.
|
||
RTCPeerConnection.prototype._updateSignalingState = function(newState) {
|
||
this.signalingState = newState;
|
||
var event = new Event('signalingstatechange');
|
||
this.dispatchEvent(event);
|
||
if (this.onsignalingstatechange !== null) {
|
||
this.onsignalingstatechange(event);
|
||
}
|
||
};
|
||
|
||
// Determine whether to fire the negotiationneeded event.
|
||
RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() {
|
||
// Fire away (for now).
|
||
var event = new Event('negotiationneeded');
|
||
this.dispatchEvent(event);
|
||
if (this.onnegotiationneeded !== null) {
|
||
this.onnegotiationneeded(event);
|
||
}
|
||
};
|
||
|
||
// Update the connection state.
|
||
RTCPeerConnection.prototype._updateConnectionState = function() {
|
||
var self = this;
|
||
var newState;
|
||
var states = {
|
||
'new': 0,
|
||
closed: 0,
|
||
connecting: 0,
|
||
checking: 0,
|
||
connected: 0,
|
||
completed: 0,
|
||
failed: 0
|
||
};
|
||
this.transceivers.forEach(function(transceiver) {
|
||
states[transceiver.iceTransport.state]++;
|
||
states[transceiver.dtlsTransport.state]++;
|
||
});
|
||
// ICETransport.completed and connected are the same for this purpose.
|
||
states.connected += states.completed;
|
||
|
||
newState = 'new';
|
||
if (states.failed > 0) {
|
||
newState = 'failed';
|
||
} else if (states.connecting > 0 || states.checking > 0) {
|
||
newState = 'connecting';
|
||
} else if (states.disconnected > 0) {
|
||
newState = 'disconnected';
|
||
} else if (states.new > 0) {
|
||
newState = 'new';
|
||
} else if (states.connected > 0 || states.completed > 0) {
|
||
newState = 'connected';
|
||
}
|
||
|
||
if (newState !== self.iceConnectionState) {
|
||
self.iceConnectionState = newState;
|
||
var event = new Event('iceconnectionstatechange');
|
||
this.dispatchEvent(event);
|
||
if (this.oniceconnectionstatechange !== null) {
|
||
this.oniceconnectionstatechange(event);
|
||
}
|
||
}
|
||
};
|
||
|
||
RTCPeerConnection.prototype.createOffer = function() {
|
||
var self = this;
|
||
if (this._pendingOffer) {
|
||
throw new Error('createOffer called while there is a pending offer.');
|
||
}
|
||
var offerOptions;
|
||
if (arguments.length === 1 && typeof arguments[0] !== 'function') {
|
||
offerOptions = arguments[0];
|
||
} else if (arguments.length === 3) {
|
||
offerOptions = arguments[2];
|
||
}
|
||
|
||
var tracks = [];
|
||
var numAudioTracks = 0;
|
||
var numVideoTracks = 0;
|
||
// Default to sendrecv.
|
||
if (this.localStreams.length) {
|
||
numAudioTracks = this.localStreams.reduce(function(numTracks, stream) {
|
||
return numTracks + stream.getAudioTracks().length;
|
||
}, 0);
|
||
numVideoTracks = this.localStreams.reduce(function(numTracks, stream) {
|
||
return numTracks + stream.getVideoTracks().length;
|
||
}, 0);
|
||
}
|
||
// Determine number of audio and video tracks we need to send/recv.
|
||
if (offerOptions) {
|
||
// Reject Chrome legacy constraints.
|
||
if (offerOptions.mandatory || offerOptions.optional) {
|
||
throw new TypeError(
|
||
'Legacy mandatory/optional constraints not supported.');
|
||
}
|
||
if (offerOptions.offerToReceiveAudio !== undefined) {
|
||
numAudioTracks = offerOptions.offerToReceiveAudio;
|
||
}
|
||
if (offerOptions.offerToReceiveVideo !== undefined) {
|
||
numVideoTracks = offerOptions.offerToReceiveVideo;
|
||
}
|
||
}
|
||
|
||
// Push local streams.
|
||
this.localStreams.forEach(function(localStream) {
|
||
localStream.getTracks().forEach(function(track) {
|
||
tracks.push({
|
||
kind: track.kind,
|
||
track: track,
|
||
stream: localStream,
|
||
wantReceive: track.kind === 'audio' ?
|
||
numAudioTracks > 0 : numVideoTracks > 0
|
||
});
|
||
if (track.kind === 'audio') {
|
||
numAudioTracks--;
|
||
} else if (track.kind === 'video') {
|
||
numVideoTracks--;
|
||
}
|
||
});
|
||
});
|
||
|
||
// Create M-lines for recvonly streams.
|
||
while (numAudioTracks > 0 || numVideoTracks > 0) {
|
||
if (numAudioTracks > 0) {
|
||
tracks.push({
|
||
kind: 'audio',
|
||
wantReceive: true
|
||
});
|
||
numAudioTracks--;
|
||
}
|
||
if (numVideoTracks > 0) {
|
||
tracks.push({
|
||
kind: 'video',
|
||
wantReceive: true
|
||
});
|
||
numVideoTracks--;
|
||
}
|
||
}
|
||
// reorder tracks
|
||
tracks = sortTracks(tracks);
|
||
|
||
var sdp = SDPUtils.writeSessionBoilerplate();
|
||
var transceivers = [];
|
||
tracks.forEach(function(mline, sdpMLineIndex) {
|
||
// For each track, create an ice gatherer, ice transport,
|
||
// dtls transport, potentially rtpsender and rtpreceiver.
|
||
var track = mline.track;
|
||
var kind = mline.kind;
|
||
var mid = SDPUtils.generateIdentifier();
|
||
|
||
var transports = self.usingBundle && sdpMLineIndex > 0 ? {
|
||
iceGatherer: transceivers[0].iceGatherer,
|
||
iceTransport: transceivers[0].iceTransport,
|
||
dtlsTransport: transceivers[0].dtlsTransport
|
||
} : self._createIceAndDtlsTransports(mid, sdpMLineIndex);
|
||
|
||
var localCapabilities = RTCRtpSender.getCapabilities(kind);
|
||
// filter RTX until additional stuff needed for RTX is implemented
|
||
// in adapter.js
|
||
if (edgeVersion < 15019) {
|
||
localCapabilities.codecs = localCapabilities.codecs.filter(
|
||
function(codec) {
|
||
return codec.name !== 'rtx';
|
||
});
|
||
}
|
||
localCapabilities.codecs.forEach(function(codec) {
|
||
// work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552
|
||
// by adding level-asymmetry-allowed=1
|
||
if (codec.name === 'H264' &&
|
||
codec.parameters['level-asymmetry-allowed'] === undefined) {
|
||
codec.parameters['level-asymmetry-allowed'] = '1';
|
||
}
|
||
});
|
||
|
||
var rtpSender;
|
||
var rtpReceiver;
|
||
|
||
// generate an ssrc now, to be used later in rtpSender.send
|
||
var sendEncodingParameters = [{
|
||
ssrc: (2 * sdpMLineIndex + 1) * 1001
|
||
}];
|
||
if (track) {
|
||
// add RTX
|
||
if (edgeVersion >= 15019 && kind === 'video') {
|
||
sendEncodingParameters[0].rtx = {
|
||
ssrc: (2 * sdpMLineIndex + 1) * 1001 + 1
|
||
};
|
||
}
|
||
rtpSender = new RTCRtpSender(track, transports.dtlsTransport);
|
||
}
|
||
|
||
if (mline.wantReceive) {
|
||
rtpReceiver = new RTCRtpReceiver(transports.dtlsTransport, kind);
|
||
}
|
||
|
||
transceivers[sdpMLineIndex] = {
|
||
iceGatherer: transports.iceGatherer,
|
||
iceTransport: transports.iceTransport,
|
||
dtlsTransport: transports.dtlsTransport,
|
||
localCapabilities: localCapabilities,
|
||
remoteCapabilities: null,
|
||
rtpSender: rtpSender,
|
||
rtpReceiver: rtpReceiver,
|
||
kind: kind,
|
||
mid: mid,
|
||
sendEncodingParameters: sendEncodingParameters,
|
||
recvEncodingParameters: null
|
||
};
|
||
});
|
||
|
||
// always offer BUNDLE and dispose on return if not supported.
|
||
if (this._config.bundlePolicy !== 'max-compat') {
|
||
sdp += 'a=group:BUNDLE ' + transceivers.map(function(t) {
|
||
return t.mid;
|
||
}).join(' ') + '\r\n';
|
||
}
|
||
sdp += 'a=ice-options:trickle\r\n';
|
||
|
||
tracks.forEach(function(mline, sdpMLineIndex) {
|
||
var transceiver = transceivers[sdpMLineIndex];
|
||
sdp += SDPUtils.writeMediaSection(transceiver,
|
||
transceiver.localCapabilities, 'offer', mline.stream);
|
||
sdp += 'a=rtcp-rsize\r\n';
|
||
});
|
||
|
||
this._pendingOffer = transceivers;
|
||
var desc = new RTCSessionDescription({
|
||
type: 'offer',
|
||
sdp: sdp
|
||
});
|
||
if (arguments.length && typeof arguments[0] === 'function') {
|
||
window.setTimeout(arguments[0], 0, desc);
|
||
}
|
||
return Promise.resolve(desc);
|
||
};
|
||
|
||
RTCPeerConnection.prototype.createAnswer = function() {
|
||
var self = this;
|
||
|
||
var sdp = SDPUtils.writeSessionBoilerplate();
|
||
if (this.usingBundle) {
|
||
sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) {
|
||
return t.mid;
|
||
}).join(' ') + '\r\n';
|
||
}
|
||
this.transceivers.forEach(function(transceiver) {
|
||
if (transceiver.isDatachannel) {
|
||
sdp += 'm=application 0 DTLS/SCTP 5000\r\n' +
|
||
'c=IN IP4 0.0.0.0\r\n' +
|
||
'a=mid:' + transceiver.mid + '\r\n';
|
||
return;
|
||
}
|
||
// Calculate intersection of capabilities.
|
||
var commonCapabilities = self._getCommonCapabilities(
|
||
transceiver.localCapabilities,
|
||
transceiver.remoteCapabilities);
|
||
|
||
var hasRtx = commonCapabilities.codecs.filter(function(c) {
|
||
return c.name.toLowerCase() === 'rtx';
|
||
}).length;
|
||
if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) {
|
||
delete transceiver.sendEncodingParameters[0].rtx;
|
||
}
|
||
|
||
sdp += SDPUtils.writeMediaSection(transceiver, commonCapabilities,
|
||
'answer', self.localStreams[0]);
|
||
if (transceiver.rtcpParameters &&
|
||
transceiver.rtcpParameters.reducedSize) {
|
||
sdp += 'a=rtcp-rsize\r\n';
|
||
}
|
||
});
|
||
|
||
var desc = new RTCSessionDescription({
|
||
type: 'answer',
|
||
sdp: sdp
|
||
});
|
||
if (arguments.length && typeof arguments[0] === 'function') {
|
||
window.setTimeout(arguments[0], 0, desc);
|
||
}
|
||
return Promise.resolve(desc);
|
||
};
|
||
|
||
RTCPeerConnection.prototype.addIceCandidate = function(candidate) {
|
||
if (!candidate) {
|
||
for (var j = 0; j < this.transceivers.length; j++) {
|
||
this.transceivers[j].iceTransport.addRemoteCandidate({});
|
||
if (this.usingBundle) {
|
||
return Promise.resolve();
|
||
}
|
||
}
|
||
} else {
|
||
var mLineIndex = candidate.sdpMLineIndex;
|
||
if (candidate.sdpMid) {
|
||
for (var i = 0; i < this.transceivers.length; i++) {
|
||
if (this.transceivers[i].mid === candidate.sdpMid) {
|
||
mLineIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
var transceiver = this.transceivers[mLineIndex];
|
||
if (transceiver) {
|
||
var cand = Object.keys(candidate.candidate).length > 0 ?
|
||
SDPUtils.parseCandidate(candidate.candidate) : {};
|
||
// Ignore Chrome's invalid candidates since Edge does not like them.
|
||
if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) {
|
||
return Promise.resolve();
|
||
}
|
||
// Ignore RTCP candidates, we assume RTCP-MUX.
|
||
if (cand.component !== '1') {
|
||
return Promise.resolve();
|
||
}
|
||
transceiver.iceTransport.addRemoteCandidate(cand);
|
||
|
||
// update the remoteDescription.
|
||
var sections = SDPUtils.splitSections(this.remoteDescription.sdp);
|
||
sections[mLineIndex + 1] += (cand.type ? candidate.candidate.trim()
|
||
: 'a=end-of-candidates') + '\r\n';
|
||
this.remoteDescription.sdp = sections.join('');
|
||
}
|
||
}
|
||
if (arguments.length > 1 && typeof arguments[1] === 'function') {
|
||
window.setTimeout(arguments[1], 0);
|
||
}
|
||
return Promise.resolve();
|
||
};
|
||
|
||
RTCPeerConnection.prototype.getStats = function() {
|
||
var promises = [];
|
||
this.transceivers.forEach(function(transceiver) {
|
||
['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport',
|
||
'dtlsTransport'].forEach(function(method) {
|
||
if (transceiver[method]) {
|
||
promises.push(transceiver[method].getStats());
|
||
}
|
||
});
|
||
});
|
||
var cb = arguments.length > 1 && typeof arguments[1] === 'function' &&
|
||
arguments[1];
|
||
var fixStatsType = function(stat) {
|
||
return {
|
||
inboundrtp: 'inbound-rtp',
|
||
outboundrtp: 'outbound-rtp',
|
||
candidatepair: 'candidate-pair',
|
||
localcandidate: 'local-candidate',
|
||
remotecandidate: 'remote-candidate'
|
||
}[stat.type] || stat.type;
|
||
};
|
||
return new Promise(function(resolve) {
|
||
// shim getStats with maplike support
|
||
var results = new Map();
|
||
Promise.all(promises).then(function(res) {
|
||
res.forEach(function(result) {
|
||
Object.keys(result).forEach(function(id) {
|
||
result[id].type = fixStatsType(result[id]);
|
||
results.set(id, result[id]);
|
||
});
|
||
});
|
||
if (cb) {
|
||
window.setTimeout(cb, 0, results);
|
||
}
|
||
resolve(results);
|
||
});
|
||
});
|
||
};
|
||
return RTCPeerConnection;
|
||
};
|
||
|
||
},{"sdp":32}],97:[function(require,module,exports){
|
||
/*
|
||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||
*
|
||
* Use of this source code is governed by a BSD-style license
|
||
* that can be found in the LICENSE file in the root of the source
|
||
* tree.
|
||
*/
|
||
/* eslint-env node */
|
||
'use strict';
|
||
|
||
var browserDetails = require('../utils').browserDetails;
|
||
|
||
var firefoxShim = {
|
||
shimOnTrack: function() {
|
||
if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in
|
||
window.RTCPeerConnection.prototype)) {
|
||
Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
|
||
get: function() {
|
||
return this._ontrack;
|
||
},
|
||
set: function(f) {
|
||
if (this._ontrack) {
|
||
this.removeEventListener('track', this._ontrack);
|
||
this.removeEventListener('addstream', this._ontrackpoly);
|
||
}
|
||
this.addEventListener('track', this._ontrack = f);
|
||
this.addEventListener('addstream', this._ontrackpoly = function(e) {
|
||
e.stream.getTracks().forEach(function(track) {
|
||
var event = new Event('track');
|
||
event.track = track;
|
||
event.receiver = {track: track};
|
||
event.streams = [e.stream];
|
||
this.dispatchEvent(event);
|
||
}.bind(this));
|
||
}.bind(this));
|
||
}
|
||
});
|
||
}
|
||
},
|
||
|
||
shimSourceObject: function() {
|
||
// Firefox has supported mozSrcObject since FF22, unprefixed in 42.
|
||
if (typeof window === 'object') {
|
||
if (window.HTMLMediaElement &&
|
||
!('srcObject' in window.HTMLMediaElement.prototype)) {
|
||
// Shim the srcObject property, once, when HTMLMediaElement is found.
|
||
Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', {
|
||
get: function() {
|
||
return this.mozSrcObject;
|
||
},
|
||
set: function(stream) {
|
||
this.mozSrcObject = stream;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
},
|
||
|
||
shimPeerConnection: function() {
|
||
if (typeof window !== 'object' || !(window.RTCPeerConnection ||
|
||
window.mozRTCPeerConnection)) {
|
||
return; // probably media.peerconnection.enabled=false in about:config
|
||
}
|
||
// The RTCPeerConnection object.
|
||
if (!window.RTCPeerConnection) {
|
||
window.RTCPeerConnection = function(pcConfig, pcConstraints) {
|
||
if (browserDetails.version < 38) {
|
||
// .urls is not supported in FF < 38.
|
||
// create RTCIceServers with a single url.
|
||
if (pcConfig && pcConfig.iceServers) {
|
||
var newIceServers = [];
|
||
for (var i = 0; i < pcConfig.iceServers.length; i++) {
|
||
var server = pcConfig.iceServers[i];
|
||
if (server.hasOwnProperty('urls')) {
|
||
for (var j = 0; j < server.urls.length; j++) {
|
||
var newServer = {
|
||
url: server.urls[j]
|
||
};
|
||
if (server.urls[j].indexOf('turn') === 0) {
|
||
newServer.username = server.username;
|
||
newServer.credential = server.credential;
|
||
}
|
||
newIceServers.push(newServer);
|
||
}
|
||
} else {
|
||
newIceServers.push(pcConfig.iceServers[i]);
|
||
}
|
||
}
|
||
pcConfig.iceServers = newIceServers;
|
||
}
|
||
}
|
||
return new mozRTCPeerConnection(pcConfig, pcConstraints);
|
||
};
|
||
window.RTCPeerConnection.prototype = mozRTCPeerConnection.prototype;
|
||
|
||
// wrap static methods. Currently just generateCertificate.
|
||
if (mozRTCPeerConnection.generateCertificate) {
|
||
Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
|
||
get: function() {
|
||
return mozRTCPeerConnection.generateCertificate;
|
||
}
|
||
});
|
||
}
|
||
|
||
window.RTCSessionDescription = mozRTCSessionDescription;
|
||
window.RTCIceCandidate = mozRTCIceCandidate;
|
||
}
|
||
|
||
// shim away need for obsolete RTCIceCandidate/RTCSessionDescription.
|
||
['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']
|
||
.forEach(function(method) {
|
||
var nativeMethod = RTCPeerConnection.prototype[method];
|
||
RTCPeerConnection.prototype[method] = function() {
|
||
arguments[0] = new ((method === 'addIceCandidate') ?
|
||
RTCIceCandidate : RTCSessionDescription)(arguments[0]);
|
||
return nativeMethod.apply(this, arguments);
|
||
};
|
||
});
|
||
|
||
// support for addIceCandidate(null or undefined)
|
||
var nativeAddIceCandidate =
|
||
RTCPeerConnection.prototype.addIceCandidate;
|
||
RTCPeerConnection.prototype.addIceCandidate = function() {
|
||
if (!arguments[0]) {
|
||
if (arguments[1]) {
|
||
arguments[1].apply(null);
|
||
}
|
||
return Promise.resolve();
|
||
}
|
||
return nativeAddIceCandidate.apply(this, arguments);
|
||
};
|
||
|
||
// shim getStats with maplike support
|
||
var makeMapStats = function(stats) {
|
||
var map = new Map();
|
||
Object.keys(stats).forEach(function(key) {
|
||
map.set(key, stats[key]);
|
||
map[key] = stats[key];
|
||
});
|
||
return map;
|
||
};
|
||
|
||
var modernStatsTypes = {
|
||
inboundrtp: 'inbound-rtp',
|
||
outboundrtp: 'outbound-rtp',
|
||
candidatepair: 'candidate-pair',
|
||
localcandidate: 'local-candidate',
|
||
remotecandidate: 'remote-candidate'
|
||
};
|
||
|
||
var nativeGetStats = RTCPeerConnection.prototype.getStats;
|
||
RTCPeerConnection.prototype.getStats = function(selector, onSucc, onErr) {
|
||
return nativeGetStats.apply(this, [selector || null])
|
||
.then(function(stats) {
|
||
if (browserDetails.version < 48) {
|
||
stats = makeMapStats(stats);
|
||
}
|
||
if (browserDetails.version < 53 && !onSucc) {
|
||
// Shim only promise getStats with spec-hyphens in type names
|
||
// Leave callback version alone; misc old uses of forEach before Map
|
||
try {
|
||
stats.forEach(function(stat) {
|
||
stat.type = modernStatsTypes[stat.type] || stat.type;
|
||
});
|
||
} catch (e) {
|
||
if (e.name !== 'TypeError') {
|
||
throw e;
|
||
}
|
||
// Avoid TypeError: "type" is read-only, in old versions. 34-43ish
|
||
stats.forEach(function(stat, i) {
|
||
stats.set(i, Object.assign({}, stat, {
|
||
type: modernStatsTypes[stat.type] || stat.type
|
||
}));
|
||
});
|
||
}
|
||
}
|
||
return stats;
|
||
})
|
||
.then(onSucc, onErr);
|
||
};
|
||
}
|
||
};
|
||
|
||
// Expose public methods.
|
||
module.exports = {
|
||
shimOnTrack: firefoxShim.shimOnTrack,
|
||
shimSourceObject: firefoxShim.shimSourceObject,
|
||
shimPeerConnection: firefoxShim.shimPeerConnection,
|
||
shimGetUserMedia: require('./getusermedia')
|
||
};
|
||
|
||
},{"../utils":100,"./getusermedia":98}],98:[function(require,module,exports){
|
||
/*
|
||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||
*
|
||
* Use of this source code is governed by a BSD-style license
|
||
* that can be found in the LICENSE file in the root of the source
|
||
* tree.
|
||
*/
|
||
/* eslint-env node */
|
||
'use strict';
|
||
|
||
var logging = require('../utils').log;
|
||
var browserDetails = require('../utils').browserDetails;
|
||
|
||
// Expose public methods.
|
||
module.exports = function() {
|
||
var shimError_ = function(e) {
|
||
return {
|
||
name: {
|
||
NotSupportedError: 'TypeError',
|
||
SecurityError: 'NotAllowedError',
|
||
PermissionDeniedError: 'NotAllowedError'
|
||
}[e.name] || e.name,
|
||
message: {
|
||
'The operation is insecure.': 'The request is not allowed by the ' +
|
||
'user agent or the platform in the current context.'
|
||
}[e.message] || e.message,
|
||
constraint: e.constraint,
|
||
toString: function() {
|
||
return this.name + (this.message && ': ') + this.message;
|
||
}
|
||
};
|
||
};
|
||
|
||
// getUserMedia constraints shim.
|
||
var getUserMedia_ = function(constraints, onSuccess, onError) {
|
||
var constraintsToFF37_ = function(c) {
|
||
if (typeof c !== 'object' || c.require) {
|
||
return c;
|
||
}
|
||
var require = [];
|
||
Object.keys(c).forEach(function(key) {
|
||
if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
|
||
return;
|
||
}
|
||
var r = c[key] = (typeof c[key] === 'object') ?
|
||
c[key] : {ideal: c[key]};
|
||
if (r.min !== undefined ||
|
||
r.max !== undefined || r.exact !== undefined) {
|
||
require.push(key);
|
||
}
|
||
if (r.exact !== undefined) {
|
||
if (typeof r.exact === 'number') {
|
||
r. min = r.max = r.exact;
|
||
} else {
|
||
c[key] = r.exact;
|
||
}
|
||
delete r.exact;
|
||
}
|
||
if (r.ideal !== undefined) {
|
||
c.advanced = c.advanced || [];
|
||
var oc = {};
|
||
if (typeof r.ideal === 'number') {
|
||
oc[key] = {min: r.ideal, max: r.ideal};
|
||
} else {
|
||
oc[key] = r.ideal;
|
||
}
|
||
c.advanced.push(oc);
|
||
delete r.ideal;
|
||
if (!Object.keys(r).length) {
|
||
delete c[key];
|
||
}
|
||
}
|
||
});
|
||
if (require.length) {
|
||
c.require = require;
|
||
}
|
||
return c;
|
||
};
|
||
constraints = JSON.parse(JSON.stringify(constraints));
|
||
if (browserDetails.version < 38) {
|
||
logging('spec: ' + JSON.stringify(constraints));
|
||
if (constraints.audio) {
|
||
constraints.audio = constraintsToFF37_(constraints.audio);
|
||
}
|
||
if (constraints.video) {
|
||
constraints.video = constraintsToFF37_(constraints.video);
|
||
}
|
||
logging('ff37: ' + JSON.stringify(constraints));
|
||
}
|
||
return navigator.mozGetUserMedia(constraints, onSuccess, function(e) {
|
||
onError(shimError_(e));
|
||
});
|
||
};
|
||
|
||
// Returns the result of getUserMedia as a Promise.
|
||
var getUserMediaPromise_ = function(constraints) {
|
||
return new Promise(function(resolve, reject) {
|
||
getUserMedia_(constraints, resolve, reject);
|
||
});
|
||
};
|
||
|
||
// Shim for mediaDevices on older versions.
|
||
if (!navigator.mediaDevices) {
|
||
navigator.mediaDevices = {getUserMedia: getUserMediaPromise_,
|
||
addEventListener: function() { },
|
||
removeEventListener: function() { }
|
||
};
|
||
}
|
||
navigator.mediaDevices.enumerateDevices =
|
||
navigator.mediaDevices.enumerateDevices || function() {
|
||
return new Promise(function(resolve) {
|
||
var infos = [
|
||
{kind: 'audioinput', deviceId: 'default', label: '', groupId: ''},
|
||
{kind: 'videoinput', deviceId: 'default', label: '', groupId: ''}
|
||
];
|
||
resolve(infos);
|
||
});
|
||
};
|
||
|
||
if (browserDetails.version < 41) {
|
||
// Work around http://bugzil.la/1169665
|
||
var orgEnumerateDevices =
|
||
navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices);
|
||
navigator.mediaDevices.enumerateDevices = function() {
|
||
return orgEnumerateDevices().then(undefined, function(e) {
|
||
if (e.name === 'NotFoundError') {
|
||
return [];
|
||
}
|
||
throw e;
|
||
});
|
||
};
|
||
}
|
||
if (browserDetails.version < 49) {
|
||
var origGetUserMedia = navigator.mediaDevices.getUserMedia.
|
||
bind(navigator.mediaDevices);
|
||
navigator.mediaDevices.getUserMedia = function(c) {
|
||
return origGetUserMedia(c).then(function(stream) {
|
||
// Work around https://bugzil.la/802326
|
||
if (c.audio && !stream.getAudioTracks().length ||
|
||
c.video && !stream.getVideoTracks().length) {
|
||
stream.getTracks().forEach(function(track) {
|
||
track.stop();
|
||
});
|
||
throw new DOMException('The object can not be found here.',
|
||
'NotFoundError');
|
||
}
|
||
return stream;
|
||
}, function(e) {
|
||
return Promise.reject(shimError_(e));
|
||
});
|
||
};
|
||
}
|
||
navigator.getUserMedia = function(constraints, onSuccess, onError) {
|
||
if (browserDetails.version < 44) {
|
||
return getUserMedia_(constraints, onSuccess, onError);
|
||
}
|
||
// Replace Firefox 44+'s deprecation warning with unprefixed version.
|
||
console.warn('navigator.getUserMedia has been replaced by ' +
|
||
'navigator.mediaDevices.getUserMedia');
|
||
navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
|
||
};
|
||
};
|
||
|
||
},{"../utils":100}],99:[function(require,module,exports){
|
||
/*
|
||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||
*
|
||
* Use of this source code is governed by a BSD-style license
|
||
* that can be found in the LICENSE file in the root of the source
|
||
* tree.
|
||
*/
|
||
'use strict';
|
||
var safariShim = {
|
||
// TODO: DrAlex, should be here, double check against LayoutTests
|
||
|
||
// TODO: once the back-end for the mac port is done, add.
|
||
// TODO: check for webkitGTK+
|
||
// shimPeerConnection: function() { },
|
||
|
||
shimOnAddStream: function() {
|
||
if (typeof window === 'object' && window.RTCPeerConnection &&
|
||
!('onaddstream' in window.RTCPeerConnection.prototype)) {
|
||
Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', {
|
||
get: function() {
|
||
return this._onaddstream;
|
||
},
|
||
set: function(f) {
|
||
if (this._onaddstream) {
|
||
this.removeEventListener('addstream', this._onaddstream);
|
||
this.removeEventListener('track', this._onaddstreampoly);
|
||
}
|
||
this.addEventListener('addstream', this._onaddstream = f);
|
||
this.addEventListener('track', this._onaddstreampoly = function(e) {
|
||
var stream = e.streams[0];
|
||
if (!this._streams) {
|
||
this._streams = [];
|
||
}
|
||
if (this._streams.indexOf(stream) >= 0) {
|
||
return;
|
||
}
|
||
this._streams.push(stream);
|
||
var event = new Event('addstream');
|
||
event.stream = e.streams[0];
|
||
this.dispatchEvent(event);
|
||
}.bind(this));
|
||
}
|
||
});
|
||
}
|
||
},
|
||
|
||
shimGetUserMedia: function() {
|
||
if (!navigator.getUserMedia) {
|
||
if (navigator.webkitGetUserMedia) {
|
||
navigator.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
|
||
} else if (navigator.mediaDevices &&
|
||
navigator.mediaDevices.getUserMedia) {
|
||
navigator.getUserMedia = function(constraints, cb, errcb) {
|
||
navigator.mediaDevices.getUserMedia(constraints)
|
||
.then(cb, errcb);
|
||
}.bind(navigator);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
// Expose public methods.
|
||
module.exports = {
|
||
shimOnAddStream: safariShim.shimOnAddStream,
|
||
shimGetUserMedia: safariShim.shimGetUserMedia
|
||
// TODO
|
||
// shimPeerConnection: safariShim.shimPeerConnection
|
||
};
|
||
|
||
},{}],100:[function(require,module,exports){
|
||
/*
|
||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||
*
|
||
* Use of this source code is governed by a BSD-style license
|
||
* that can be found in the LICENSE file in the root of the source
|
||
* tree.
|
||
*/
|
||
/* eslint-env node */
|
||
'use strict';
|
||
|
||
var logDisabled_ = true;
|
||
|
||
// Utility methods.
|
||
var utils = {
|
||
disableLog: function(bool) {
|
||
if (typeof bool !== 'boolean') {
|
||
return new Error('Argument type: ' + typeof bool +
|
||
'. Please use a boolean.');
|
||
}
|
||
logDisabled_ = bool;
|
||
return (bool) ? 'adapter.js logging disabled' :
|
||
'adapter.js logging enabled';
|
||
},
|
||
|
||
log: function() {
|
||
if (typeof window === 'object') {
|
||
if (logDisabled_) {
|
||
return;
|
||
}
|
||
if (typeof console !== 'undefined' && typeof console.log === 'function') {
|
||
console.log.apply(console, arguments);
|
||
}
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Extract browser version out of the provided user agent string.
|
||
*
|
||
* @param {!string} uastring userAgent string.
|
||
* @param {!string} expr Regular expression used as match criteria.
|
||
* @param {!number} pos position in the version string to be returned.
|
||
* @return {!number} browser version.
|
||
*/
|
||
extractVersion: function(uastring, expr, pos) {
|
||
var match = uastring.match(expr);
|
||
return match && match.length >= pos && parseInt(match[pos], 10);
|
||
},
|
||
|
||
/**
|
||
* Browser detector.
|
||
*
|
||
* @return {object} result containing browser and version
|
||
* properties.
|
||
*/
|
||
detectBrowser: function() {
|
||
// Returned result object.
|
||
var result = {};
|
||
result.browser = null;
|
||
result.version = null;
|
||
|
||
// Fail early if it's not a browser
|
||
if (typeof window === 'undefined' || !window.navigator) {
|
||
result.browser = 'Not a browser.';
|
||
return result;
|
||
}
|
||
|
||
// Firefox.
|
||
if (navigator.mozGetUserMedia) {
|
||
result.browser = 'firefox';
|
||
result.version = this.extractVersion(navigator.userAgent,
|
||
/Firefox\/(\d+)\./, 1);
|
||
} else if (navigator.webkitGetUserMedia) {
|
||
// Chrome, Chromium, Webview, Opera, all use the chrome shim for now
|
||
if (window.webkitRTCPeerConnection) {
|
||
result.browser = 'chrome';
|
||
result.version = this.extractVersion(navigator.userAgent,
|
||
/Chrom(e|ium)\/(\d+)\./, 2);
|
||
} else { // Safari (in an unpublished version) or unknown webkit-based.
|
||
if (navigator.userAgent.match(/Version\/(\d+).(\d+)/)) {
|
||
result.browser = 'safari';
|
||
result.version = this.extractVersion(navigator.userAgent,
|
||
/AppleWebKit\/(\d+)\./, 1);
|
||
} else { // unknown webkit-based browser.
|
||
result.browser = 'Unsupported webkit-based browser ' +
|
||
'with GUM support but no WebRTC support.';
|
||
return result;
|
||
}
|
||
}
|
||
} else if (navigator.mediaDevices &&
|
||
navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { // Edge.
|
||
result.browser = 'edge';
|
||
result.version = this.extractVersion(navigator.userAgent,
|
||
/Edge\/(\d+).(\d+)$/, 2);
|
||
} else if (navigator.mediaDevices &&
|
||
navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) {
|
||
// Safari, with webkitGetUserMedia removed.
|
||
result.browser = 'safari';
|
||
result.version = this.extractVersion(navigator.userAgent,
|
||
/AppleWebKit\/(\d+)\./, 1);
|
||
} else { // Default fallthrough: not supported.
|
||
result.browser = 'Not a supported browser.';
|
||
return result;
|
||
}
|
||
|
||
return result;
|
||
},
|
||
|
||
// shimCreateObjectURL must be called before shimSourceObject to avoid loop.
|
||
|
||
shimCreateObjectURL: function() {
|
||
if (!(typeof window === 'object' && window.HTMLMediaElement &&
|
||
'srcObject' in window.HTMLMediaElement.prototype)) {
|
||
// Only shim CreateObjectURL using srcObject if srcObject exists.
|
||
return undefined;
|
||
}
|
||
|
||
var nativeCreateObjectURL = URL.createObjectURL.bind(URL);
|
||
var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL);
|
||
var streams = new Map(), newId = 0;
|
||
|
||
URL.createObjectURL = function(stream) {
|
||
if ('getTracks' in stream) {
|
||
var url = 'polyblob:' + (++newId);
|
||
streams.set(url, stream);
|
||
console.log('URL.createObjectURL(stream) is deprecated! ' +
|
||
'Use elem.srcObject = stream instead!');
|
||
return url;
|
||
}
|
||
return nativeCreateObjectURL(stream);
|
||
};
|
||
URL.revokeObjectURL = function(url) {
|
||
nativeRevokeObjectURL(url);
|
||
streams.delete(url);
|
||
};
|
||
|
||
var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype,
|
||
'src');
|
||
Object.defineProperty(window.HTMLMediaElement.prototype, 'src', {
|
||
get: function() {
|
||
return dsc.get.apply(this);
|
||
},
|
||
set: function(url) {
|
||
this.srcObject = streams.get(url) || null;
|
||
return dsc.set.apply(this, [url]);
|
||
}
|
||
});
|
||
|
||
var nativeSetAttribute = HTMLMediaElement.prototype.setAttribute;
|
||
HTMLMediaElement.prototype.setAttribute = function() {
|
||
if (arguments.length === 2 &&
|
||
('' + arguments[0]).toLowerCase() === 'src') {
|
||
this.srcObject = streams.get(arguments[1]) || null;
|
||
}
|
||
return nativeSetAttribute.apply(this, arguments);
|
||
};
|
||
}
|
||
};
|
||
|
||
// Export.
|
||
module.exports = {
|
||
log: utils.log,
|
||
disableLog: utils.disableLog,
|
||
browserDetails: utils.detectBrowser(),
|
||
extractVersion: utils.extractVersion,
|
||
shimCreateObjectURL: utils.shimCreateObjectURL,
|
||
detectBrowser: utils.detectBrowser.bind(utils)
|
||
};
|
||
|
||
},{}],101:[function(require,module,exports){
|
||
/*
|
||
WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based
|
||
on @visionmedia's Emitter from UI Kit.
|
||
|
||
Why? I wanted it standalone.
|
||
|
||
I also wanted support for wildcard emitters like this:
|
||
|
||
emitter.on('*', function (eventName, other, event, payloads) {
|
||
|
||
});
|
||
|
||
emitter.on('somenamespace*', function (eventName, payloads) {
|
||
|
||
});
|
||
|
||
Please note that callbacks triggered by wildcard registered events also get
|
||
the event name as the first argument.
|
||
*/
|
||
|
||
module.exports = WildEmitter;
|
||
|
||
function WildEmitter() { }
|
||
|
||
WildEmitter.mixin = function (constructor) {
|
||
var prototype = constructor.prototype || constructor;
|
||
|
||
prototype.isWildEmitter= true;
|
||
|
||
// Listen on the given `event` with `fn`. Store a group name if present.
|
||
prototype.on = function (event, groupName, fn) {
|
||
this.callbacks = this.callbacks || {};
|
||
var hasGroup = (arguments.length === 3),
|
||
group = hasGroup ? arguments[1] : undefined,
|
||
func = hasGroup ? arguments[2] : arguments[1];
|
||
func._groupName = group;
|
||
(this.callbacks[event] = this.callbacks[event] || []).push(func);
|
||
return this;
|
||
};
|
||
|
||
// Adds an `event` listener that will be invoked a single
|
||
// time then automatically removed.
|
||
prototype.once = function (event, groupName, fn) {
|
||
var self = this,
|
||
hasGroup = (arguments.length === 3),
|
||
group = hasGroup ? arguments[1] : undefined,
|
||
func = hasGroup ? arguments[2] : arguments[1];
|
||
function on() {
|
||
self.off(event, on);
|
||
func.apply(this, arguments);
|
||
}
|
||
this.on(event, group, on);
|
||
return this;
|
||
};
|
||
|
||
// Unbinds an entire group
|
||
prototype.releaseGroup = function (groupName) {
|
||
this.callbacks = this.callbacks || {};
|
||
var item, i, len, handlers;
|
||
for (item in this.callbacks) {
|
||
handlers = this.callbacks[item];
|
||
for (i = 0, len = handlers.length; i < len; i++) {
|
||
if (handlers[i]._groupName === groupName) {
|
||
//console.log('removing');
|
||
// remove it and shorten the array we're looping through
|
||
handlers.splice(i, 1);
|
||
i--;
|
||
len--;
|
||
}
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
// Remove the given callback for `event` or all
|
||
// registered callbacks.
|
||
prototype.off = function (event, fn) {
|
||
this.callbacks = this.callbacks || {};
|
||
var callbacks = this.callbacks[event],
|
||
i;
|
||
|
||
if (!callbacks) return this;
|
||
|
||
// remove all handlers
|
||
if (arguments.length === 1) {
|
||
delete this.callbacks[event];
|
||
return this;
|
||
}
|
||
|
||
// remove specific handler
|
||
i = callbacks.indexOf(fn);
|
||
callbacks.splice(i, 1);
|
||
if (callbacks.length === 0) {
|
||
delete this.callbacks[event];
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/// Emit `event` with the given args.
|
||
// also calls any `*` handlers
|
||
prototype.emit = function (event) {
|
||
this.callbacks = this.callbacks || {};
|
||
var args = [].slice.call(arguments, 1),
|
||
callbacks = this.callbacks[event],
|
||
specialCallbacks = this.getWildcardCallbacks(event),
|
||
i,
|
||
len,
|
||
item,
|
||
listeners;
|
||
|
||
if (callbacks) {
|
||
listeners = callbacks.slice();
|
||
for (i = 0, len = listeners.length; i < len; ++i) {
|
||
if (!listeners[i]) {
|
||
break;
|
||
}
|
||
listeners[i].apply(this, args);
|
||
}
|
||
}
|
||
|
||
if (specialCallbacks) {
|
||
len = specialCallbacks.length;
|
||
listeners = specialCallbacks.slice();
|
||
for (i = 0, len = listeners.length; i < len; ++i) {
|
||
if (!listeners[i]) {
|
||
break;
|
||
}
|
||
listeners[i].apply(this, [event].concat(args));
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
// Helper for for finding special wildcard event handlers that match the event
|
||
prototype.getWildcardCallbacks = function (eventName) {
|
||
this.callbacks = this.callbacks || {};
|
||
var item,
|
||
split,
|
||
result = [];
|
||
|
||
for (item in this.callbacks) {
|
||
split = item.split('*');
|
||
if (item === '*' || (split.length === 2 && eventName.slice(0, split[0].length) === split[0])) {
|
||
result = result.concat(this.callbacks[item]);
|
||
}
|
||
}
|
||
return result;
|
||
};
|
||
|
||
};
|
||
|
||
WildEmitter.mixin(WildEmitter);
|
||
|
||
},{}],102:[function(require,module,exports){
|
||
/*!
|
||
* EventEmitter v4.2.9 - git.io/ee
|
||
* Oliver Caldwell
|
||
* MIT license
|
||
* @preserve
|
||
*/
|
||
|
||
(function () {
|
||
'use strict';
|
||
|
||
/**
|
||
* Class for managing events.
|
||
* Can be extended to provide event functionality in other classes.
|
||
*
|
||
* @class EventEmitter Manages event registering and emitting.
|
||
*/
|
||
function EventEmitter() {}
|
||
|
||
// Shortcuts to improve speed and size
|
||
var proto = EventEmitter.prototype;
|
||
var exports = this;
|
||
var originalGlobalValue = exports.EventEmitter;
|
||
|
||
/**
|
||
* Finds the index of the listener for the event in its storage array.
|
||
*
|
||
* @param {Function[]} listeners Array of listeners to search through.
|
||
* @param {Function} listener Method to look for.
|
||
* @return {Number} Index of the specified listener, -1 if not found
|
||
* @api private
|
||
*/
|
||
function indexOfListener(listeners, listener) {
|
||
var i = listeners.length;
|
||
while (i--) {
|
||
if (listeners[i].listener === listener) {
|
||
return i;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* Alias a method while keeping the context correct, to allow for overwriting of target method.
|
||
*
|
||
* @param {String} name The name of the target method.
|
||
* @return {Function} The aliased method
|
||
* @api private
|
||
*/
|
||
function alias(name) {
|
||
return function aliasClosure() {
|
||
return this[name].apply(this, arguments);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Returns the listener array for the specified event.
|
||
* Will initialise the event object and listener arrays if required.
|
||
* Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
|
||
* Each property in the object response is an array of listener functions.
|
||
*
|
||
* @param {String|RegExp} evt Name of the event to return the listeners from.
|
||
* @return {Function[]|Object} All listener functions for the event.
|
||
*/
|
||
proto.getListeners = function getListeners(evt) {
|
||
var events = this._getEvents();
|
||
var response;
|
||
var key;
|
||
|
||
// Return a concatenated array of all matching events if
|
||
// the selector is a regular expression.
|
||
if (evt instanceof RegExp) {
|
||
response = {};
|
||
for (key in events) {
|
||
if (events.hasOwnProperty(key) && evt.test(key)) {
|
||
response[key] = events[key];
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
response = events[evt] || (events[evt] = []);
|
||
}
|
||
|
||
return response;
|
||
};
|
||
|
||
/**
|
||
* Takes a list of listener objects and flattens it into a list of listener functions.
|
||
*
|
||
* @param {Object[]} listeners Raw listener objects.
|
||
* @return {Function[]} Just the listener functions.
|
||
*/
|
||
proto.flattenListeners = function flattenListeners(listeners) {
|
||
var flatListeners = [];
|
||
var i;
|
||
|
||
for (i = 0; i < listeners.length; i += 1) {
|
||
flatListeners.push(listeners[i].listener);
|
||
}
|
||
|
||
return flatListeners;
|
||
};
|
||
|
||
/**
|
||
* Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
|
||
*
|
||
* @param {String|RegExp} evt Name of the event to return the listeners from.
|
||
* @return {Object} All listener functions for an event in an object.
|
||
*/
|
||
proto.getListenersAsObject = function getListenersAsObject(evt) {
|
||
var listeners = this.getListeners(evt);
|
||
var response;
|
||
|
||
if (listeners instanceof Array) {
|
||
response = {};
|
||
response[evt] = listeners;
|
||
}
|
||
|
||
return response || listeners;
|
||
};
|
||
|
||
/**
|
||
* Adds a listener function to the specified event.
|
||
* The listener will not be added if it is a duplicate.
|
||
* If the listener returns true then it will be removed after it is called.
|
||
* If you pass a regular expression as the event name then the listener will be added to all events that match it.
|
||
*
|
||
* @param {String|RegExp} evt Name of the event to attach the listener to.
|
||
* @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.addListener = function addListener(evt, listener) {
|
||
var listeners = this.getListenersAsObject(evt);
|
||
var listenerIsWrapped = typeof listener === 'object';
|
||
var key;
|
||
|
||
for (key in listeners) {
|
||
if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
|
||
listeners[key].push(listenerIsWrapped ? listener : {
|
||
listener: listener,
|
||
once: false
|
||
});
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Alias of addListener
|
||
*/
|
||
proto.on = alias('addListener');
|
||
|
||
/**
|
||
* Semi-alias of addListener. It will add a listener that will be
|
||
* automatically removed after its first execution.
|
||
*
|
||
* @param {String|RegExp} evt Name of the event to attach the listener to.
|
||
* @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.addOnceListener = function addOnceListener(evt, listener) {
|
||
return this.addListener(evt, {
|
||
listener: listener,
|
||
once: true
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Alias of addOnceListener.
|
||
*/
|
||
proto.once = alias('addOnceListener');
|
||
|
||
/**
|
||
* Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
|
||
* You need to tell it what event names should be matched by a regex.
|
||
*
|
||
* @param {String} evt Name of the event to create.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.defineEvent = function defineEvent(evt) {
|
||
this.getListeners(evt);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Uses defineEvent to define multiple events.
|
||
*
|
||
* @param {String[]} evts An array of event names to define.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.defineEvents = function defineEvents(evts) {
|
||
for (var i = 0; i < evts.length; i += 1) {
|
||
this.defineEvent(evts[i]);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Removes a listener function from the specified event.
|
||
* When passed a regular expression as the event name, it will remove the listener from all events that match it.
|
||
*
|
||
* @param {String|RegExp} evt Name of the event to remove the listener from.
|
||
* @param {Function} listener Method to remove from the event.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.removeListener = function removeListener(evt, listener) {
|
||
var listeners = this.getListenersAsObject(evt);
|
||
var index;
|
||
var key;
|
||
|
||
for (key in listeners) {
|
||
if (listeners.hasOwnProperty(key)) {
|
||
index = indexOfListener(listeners[key], listener);
|
||
|
||
if (index !== -1) {
|
||
listeners[key].splice(index, 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Alias of removeListener
|
||
*/
|
||
proto.off = alias('removeListener');
|
||
|
||
/**
|
||
* Adds listeners in bulk using the manipulateListeners method.
|
||
* If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
|
||
* You can also pass it a regular expression to add the array of listeners to all events that match it.
|
||
* Yeah, this function does quite a bit. That's probably a bad thing.
|
||
*
|
||
* @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
|
||
* @param {Function[]} [listeners] An optional array of listener functions to add.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.addListeners = function addListeners(evt, listeners) {
|
||
// Pass through to manipulateListeners
|
||
return this.manipulateListeners(false, evt, listeners);
|
||
};
|
||
|
||
/**
|
||
* Removes listeners in bulk using the manipulateListeners method.
|
||
* If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
|
||
* You can also pass it an event name and an array of listeners to be removed.
|
||
* You can also pass it a regular expression to remove the listeners from all events that match it.
|
||
*
|
||
* @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
|
||
* @param {Function[]} [listeners] An optional array of listener functions to remove.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.removeListeners = function removeListeners(evt, listeners) {
|
||
// Pass through to manipulateListeners
|
||
return this.manipulateListeners(true, evt, listeners);
|
||
};
|
||
|
||
/**
|
||
* Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
|
||
* The first argument will determine if the listeners are removed (true) or added (false).
|
||
* If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
|
||
* You can also pass it an event name and an array of listeners to be added/removed.
|
||
* You can also pass it a regular expression to manipulate the listeners of all events that match it.
|
||
*
|
||
* @param {Boolean} remove True if you want to remove listeners, false if you want to add.
|
||
* @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
|
||
* @param {Function[]} [listeners] An optional array of listener functions to add/remove.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
|
||
var i;
|
||
var value;
|
||
var single = remove ? this.removeListener : this.addListener;
|
||
var multiple = remove ? this.removeListeners : this.addListeners;
|
||
|
||
// If evt is an object then pass each of its properties to this method
|
||
if (typeof evt === 'object' && !(evt instanceof RegExp)) {
|
||
for (i in evt) {
|
||
if (evt.hasOwnProperty(i) && (value = evt[i])) {
|
||
// Pass the single listener straight through to the singular method
|
||
if (typeof value === 'function') {
|
||
single.call(this, i, value);
|
||
}
|
||
else {
|
||
// Otherwise pass back to the multiple function
|
||
multiple.call(this, i, value);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
// So evt must be a string
|
||
// And listeners must be an array of listeners
|
||
// Loop over it and pass each one to the multiple method
|
||
i = listeners.length;
|
||
while (i--) {
|
||
single.call(this, evt, listeners[i]);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Removes all listeners from a specified event.
|
||
* If you do not specify an event then all listeners will be removed.
|
||
* That means every event will be emptied.
|
||
* You can also pass a regex to remove all events that match it.
|
||
*
|
||
* @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.removeEvent = function removeEvent(evt) {
|
||
var type = typeof evt;
|
||
var events = this._getEvents();
|
||
var key;
|
||
|
||
// Remove different things depending on the state of evt
|
||
if (type === 'string') {
|
||
// Remove all listeners for the specified event
|
||
delete events[evt];
|
||
}
|
||
else if (evt instanceof RegExp) {
|
||
// Remove all events matching the regex.
|
||
for (key in events) {
|
||
if (events.hasOwnProperty(key) && evt.test(key)) {
|
||
delete events[key];
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
// Remove all listeners in all events
|
||
delete this._events;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Alias of removeEvent.
|
||
*
|
||
* Added to mirror the node API.
|
||
*/
|
||
proto.removeAllListeners = alias('removeEvent');
|
||
|
||
/**
|
||
* Emits an event of your choice.
|
||
* When emitted, every listener attached to that event will be executed.
|
||
* If you pass the optional argument array then those arguments will be passed to every listener upon execution.
|
||
* Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
|
||
* So they will not arrive within the array on the other side, they will be separate.
|
||
* You can also pass a regular expression to emit to all events that match it.
|
||
*
|
||
* @param {String|RegExp} evt Name of the event to emit and execute listeners for.
|
||
* @param {Array} [args] Optional array of arguments to be passed to each listener.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.emitEvent = function emitEvent(evt, args) {
|
||
var listeners = this.getListenersAsObject(evt);
|
||
var listener;
|
||
var i;
|
||
var key;
|
||
var response;
|
||
|
||
for (key in listeners) {
|
||
if (listeners.hasOwnProperty(key)) {
|
||
i = listeners[key].length;
|
||
|
||
while (i--) {
|
||
// If the listener returns true then it shall be removed from the event
|
||
// The function is executed either with a basic call or an apply if there is an args array
|
||
listener = listeners[key][i];
|
||
|
||
if (listener.once === true) {
|
||
this.removeListener(evt, listener.listener);
|
||
}
|
||
|
||
response = listener.listener.apply(this, args || []);
|
||
|
||
if (response === this._getOnceReturnValue()) {
|
||
this.removeListener(evt, listener.listener);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Alias of emitEvent
|
||
*/
|
||
proto.trigger = alias('emitEvent');
|
||
|
||
/**
|
||
* Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
|
||
* As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
|
||
*
|
||
* @param {String|RegExp} evt Name of the event to emit and execute listeners for.
|
||
* @param {...*} Optional additional arguments to be passed to each listener.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.emit = function emit(evt) {
|
||
var args = Array.prototype.slice.call(arguments, 1);
|
||
return this.emitEvent(evt, args);
|
||
};
|
||
|
||
/**
|
||
* Sets the current value to check against when executing listeners. If a
|
||
* listeners return value matches the one set here then it will be removed
|
||
* after execution. This value defaults to true.
|
||
*
|
||
* @param {*} value The new value to check for when executing listeners.
|
||
* @return {Object} Current instance of EventEmitter for chaining.
|
||
*/
|
||
proto.setOnceReturnValue = function setOnceReturnValue(value) {
|
||
this._onceReturnValue = value;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Fetches the current value to check against when executing listeners. If
|
||
* the listeners return value matches this one then it should be removed
|
||
* automatically. It will return true by default.
|
||
*
|
||
* @return {*|Boolean} The current value to check for or the default, true.
|
||
* @api private
|
||
*/
|
||
proto._getOnceReturnValue = function _getOnceReturnValue() {
|
||
if (this.hasOwnProperty('_onceReturnValue')) {
|
||
return this._onceReturnValue;
|
||
}
|
||
else {
|
||
return true;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Fetches the events object and creates one if required.
|
||
*
|
||
* @return {Object} The events storage object.
|
||
* @api private
|
||
*/
|
||
proto._getEvents = function _getEvents() {
|
||
return this._events || (this._events = {});
|
||
};
|
||
|
||
/**
|
||
* Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
|
||
*
|
||
* @return {Function} Non conflicting EventEmitter class.
|
||
*/
|
||
EventEmitter.noConflict = function noConflict() {
|
||
exports.EventEmitter = originalGlobalValue;
|
||
return EventEmitter;
|
||
};
|
||
|
||
// Expose the class either via AMD, CommonJS or the global object
|
||
if (typeof define === 'function' && define.amd) {
|
||
define(function () {
|
||
return EventEmitter;
|
||
});
|
||
}
|
||
else if (typeof module === 'object' && module.exports){
|
||
module.exports = EventEmitter;
|
||
}
|
||
else {
|
||
exports.EventEmitter = EventEmitter;
|
||
}
|
||
}.call(this));
|
||
|
||
},{}],103:[function(require,module,exports){
|
||
|
||
/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var global = (function() { return this; })();
|
||
|
||
/**
|
||
* WebSocket constructor.
|
||
*/
|
||
|
||
var WebSocket = global.WebSocket || global.MozWebSocket;
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = WebSocket ? ws : null;
|
||
|
||
/**
|
||
* WebSocket constructor.
|
||
*
|
||
* The third `opts` options object gets ignored in web browsers, since it's
|
||
* non-standard, and throws a TypeError if passed to the constructor.
|
||
* See: https://github.com/einaros/ws/issues/227
|
||
*
|
||
* @param {String} uri
|
||
* @param {Array} protocols (optional)
|
||
* @param {Object) opts (optional)
|
||
* @api public
|
||
*/
|
||
|
||
function ws(uri, protocols, opts) {
|
||
var instance;
|
||
if (protocols) {
|
||
instance = new WebSocket(uri, protocols);
|
||
} else {
|
||
instance = new WebSocket(uri);
|
||
}
|
||
return instance;
|
||
}
|
||
|
||
if (WebSocket) ws.prototype = WebSocket.prototype;
|
||
|
||
},{}],104:[function(require,module,exports){
|
||
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
var OpenVidu_1 = require("./OpenVidu");
|
||
//This export with --standalone option allows using OpenVidu from bowser with namespace
|
||
//export { OpenVidu } from './OpenVidu';
|
||
//This "hack" allows to use OpenVidu from the global space window
|
||
if (window) {
|
||
window["OpenVidu"] = OpenVidu_1.OpenVidu;
|
||
}
|
||
//Command to generate bundle.js without namespace
|
||
//watchify Main.ts -p [ tsify ] --exclude kurento-browser-extensions --debug -o ../static/js/OpenVidu.js -v
|
||
|
||
},{"./OpenVidu":105}],105:[function(require,module,exports){
|
||
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
/*
|
||
* (C) Copyright 2016 OpenVidu (http://kurento.org/)
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*
|
||
*/
|
||
var OpenViduInternal_1 = require("../OpenViduInternal/OpenViduInternal");
|
||
var Session_1 = require("./Session");
|
||
var Publisher_1 = require("./Publisher");
|
||
var adapter = require("webrtc-adapter");
|
||
if (window) {
|
||
window["adapter"] = adapter;
|
||
}
|
||
var OpenVidu = (function () {
|
||
function OpenVidu() {
|
||
this.openVidu = new OpenViduInternal_1.OpenViduInternal();
|
||
}
|
||
;
|
||
OpenVidu.prototype.initSession = function (param1, param2) {
|
||
if (this.checkSystemRequirements()) {
|
||
if (typeof param2 == "string") {
|
||
return new Session_1.Session(this.openVidu.initSession(param2), this);
|
||
}
|
||
else {
|
||
return new Session_1.Session(this.openVidu.initSession(param1), this);
|
||
}
|
||
}
|
||
else {
|
||
alert("Browser not supported");
|
||
}
|
||
};
|
||
OpenVidu.prototype.initPublisher = function (parentId, cameraOptions, callback) {
|
||
if (this.checkSystemRequirements()) {
|
||
if (cameraOptions != null) {
|
||
var cameraOptionsAux = {
|
||
audio: cameraOptions.audio != null ? cameraOptions.audio : true,
|
||
video: cameraOptions.video != null ? cameraOptions.video : true,
|
||
data: true,
|
||
mediaConstraints: this.openVidu.generateMediaConstraints(cameraOptions.quality)
|
||
};
|
||
cameraOptions = cameraOptionsAux;
|
||
}
|
||
else {
|
||
cameraOptions = {
|
||
audio: true,
|
||
video: true,
|
||
data: true,
|
||
mediaConstraints: {
|
||
audio: true,
|
||
video: { width: { ideal: 1280 } }
|
||
}
|
||
};
|
||
}
|
||
return new Publisher_1.Publisher(this.openVidu.initPublisherTagged(parentId, cameraOptions, callback), parentId);
|
||
}
|
||
else {
|
||
alert("Browser not supported");
|
||
}
|
||
};
|
||
OpenVidu.prototype.checkSystemRequirements = function () {
|
||
var browser = adapter.browserDetails.browser;
|
||
var version = adapter.browserDetails.version;
|
||
//Bug fix: 'navigator.userAgent' in Firefox for Ubuntu 14.04 does not return "Firefox/[version]" in the string, so version returned is null
|
||
if ((browser == 'firefox') && (version == null)) {
|
||
return 1;
|
||
}
|
||
if (((browser == 'chrome') && (version >= 28)) || ((browser == 'edge') && (version >= 12)) || ((browser == 'firefox') && (version >= 22))) {
|
||
return 1;
|
||
}
|
||
else {
|
||
return 0;
|
||
}
|
||
};
|
||
OpenVidu.prototype.getDevices = function (callback) {
|
||
navigator.mediaDevices.enumerateDevices().then(function (deviceInfos) {
|
||
callback(null, deviceInfos);
|
||
}).catch(function (error) {
|
||
console.log("Error getting devices: " + error);
|
||
callback(error, null);
|
||
});
|
||
};
|
||
return OpenVidu;
|
||
}());
|
||
exports.OpenVidu = OpenVidu;
|
||
|
||
},{"../OpenViduInternal/OpenViduInternal":110,"./Publisher":106,"./Session":107,"webrtc-adapter":91}],106:[function(require,module,exports){
|
||
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
var EventEmitter = require("wolfy87-eventemitter");
|
||
var Publisher = (function () {
|
||
function Publisher(stream, parentId) {
|
||
var _this = this;
|
||
this.ee = new EventEmitter();
|
||
this.accessAllowed = false;
|
||
this.stream = stream;
|
||
this.stream.addEventListener('camera-access-changed', function (event) {
|
||
_this.accessAllowed = event.accessAllowed;
|
||
if (_this.accessAllowed) {
|
||
_this.ee.emitEvent('accessAllowed');
|
||
}
|
||
else {
|
||
_this.ee.emitEvent('accessDenied');
|
||
}
|
||
});
|
||
if (document.getElementById(parentId) != null) {
|
||
this.element = document.getElementById(parentId);
|
||
}
|
||
}
|
||
Publisher.prototype.publishAudio = function (value) {
|
||
this.stream.getWebRtcPeer().audioEnabled = value;
|
||
};
|
||
Publisher.prototype.publishVideo = function (value) {
|
||
this.stream.getWebRtcPeer().videoEnabled = value;
|
||
};
|
||
Publisher.prototype.destroy = function () {
|
||
this.session.unpublish(this);
|
||
this.stream.dispose();
|
||
this.stream.removeVideo(this.element);
|
||
return this;
|
||
};
|
||
Publisher.prototype.on = function (eventName, callback) {
|
||
var _this = this;
|
||
this.ee.addListener(eventName, function (event) {
|
||
callback(event);
|
||
});
|
||
if (eventName == 'videoElementCreated') {
|
||
if (this.stream.isReady) {
|
||
this.ee.emitEvent('videoElementCreated', [{
|
||
element: this.stream.getVideoElement()
|
||
}]);
|
||
}
|
||
else {
|
||
this.stream.addEventListener('video-element-created-by-stream', function (element) {
|
||
console.warn('Publisher emitting videoElementCreated');
|
||
_this.id = element.id;
|
||
_this.ee.emitEvent('videoElementCreated', [{
|
||
element: element.element
|
||
}]);
|
||
});
|
||
}
|
||
}
|
||
if (eventName == 'streamCreated') {
|
||
if (this.stream.isReady) {
|
||
this.ee.emitEvent('streamCreated', [{ stream: this.stream }]);
|
||
}
|
||
else {
|
||
this.stream.addEventListener('stream-created-by-publisher', function () {
|
||
console.warn('Publisher emitting streamCreated');
|
||
_this.ee.emitEvent('streamCreated', [{ stream: _this.stream }]);
|
||
});
|
||
}
|
||
}
|
||
if (eventName == 'accessAllowed') {
|
||
if (this.stream.accessIsAllowed) {
|
||
this.ee.emitEvent('accessAllowed');
|
||
}
|
||
else {
|
||
this.stream.addEventListener('access-allowed-by-publisher', function () {
|
||
_this.ee.emitEvent('accessAllowed');
|
||
});
|
||
}
|
||
}
|
||
if (eventName == 'accessDenied') {
|
||
if (this.stream.accessIsDenied) {
|
||
this.ee.emitEvent('accessDenied');
|
||
}
|
||
else {
|
||
this.stream.addEventListener('access-denied-by-publisher', function () {
|
||
_this.ee.emitEvent('accessDenied');
|
||
});
|
||
}
|
||
}
|
||
};
|
||
return Publisher;
|
||
}());
|
||
exports.Publisher = Publisher;
|
||
|
||
},{"wolfy87-eventemitter":102}],107:[function(require,module,exports){
|
||
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
var Subscriber_1 = require("./Subscriber");
|
||
var EventEmitter = require("wolfy87-eventemitter");
|
||
var Session = (function () {
|
||
function Session(session, openVidu) {
|
||
var _this = this;
|
||
this.session = session;
|
||
this.openVidu = openVidu;
|
||
this.ee = new EventEmitter();
|
||
this.sessionId = session.getSessionId();
|
||
// Listens to the deactivation of the default behaviour upon the deletion of a Stream object
|
||
this.session.addEventListener('stream-destroyed-default', function (event) {
|
||
event.stream.removeVideo();
|
||
});
|
||
// Listens to the deactivation of the default behaviour upon the disconnection of a Session
|
||
this.session.addEventListener('session-disconnected-default', function () {
|
||
var s;
|
||
for (var _i = 0, _a = _this.openVidu.openVidu.getRemoteStreams(); _i < _a.length; _i++) {
|
||
s = _a[_i];
|
||
s.removeVideo();
|
||
}
|
||
if (_this.connection) {
|
||
for (var streamId in _this.connection.getStreams()) {
|
||
_this.connection.getStreams()[streamId].removeVideo();
|
||
}
|
||
}
|
||
});
|
||
// Sets or updates the value of 'connection' property. Triggered by SessionInternal when succesful connection
|
||
this.session.addEventListener('update-connection-object', function (event) {
|
||
_this.connection = event.connection;
|
||
});
|
||
}
|
||
Session.prototype.connect = function (param1, param2, param3) {
|
||
// Early configuration to deactivate automatic subscription to streams
|
||
if (typeof param2 == "string") {
|
||
this.session.configure({
|
||
sessionId: this.session.getSessionId(),
|
||
participantId: param1,
|
||
metadata: param2,
|
||
subscribeToStreams: false
|
||
});
|
||
this.session.connect(param1, param3);
|
||
}
|
||
else {
|
||
this.session.configure({
|
||
sessionId: this.session.getSessionId(),
|
||
participantId: param1,
|
||
metadata: '',
|
||
subscribeToStreams: false
|
||
});
|
||
this.session.connect(param1, param2);
|
||
}
|
||
};
|
||
Session.prototype.disconnect = function () {
|
||
var _this = this;
|
||
this.openVidu.openVidu.close(false);
|
||
this.session.emitEvent('sessionDisconnected', [{
|
||
preventDefault: function () { _this.session.removeEvent('session-disconnected-default'); }
|
||
}]);
|
||
this.session.emitEvent('session-disconnected-default', [{}]);
|
||
};
|
||
Session.prototype.publish = function (publisher) {
|
||
publisher.session = this;
|
||
publisher.stream.publish();
|
||
};
|
||
Session.prototype.unpublish = function (publisher) {
|
||
this.session.unpublish(publisher.stream);
|
||
};
|
||
Session.prototype.on = function (eventName, callback) {
|
||
this.session.addEventListener(eventName, function (event) {
|
||
callback(event);
|
||
});
|
||
};
|
||
Session.prototype.once = function (eventName, callback) {
|
||
this.session.addOnceEventListener(eventName, function (event) {
|
||
callback(event);
|
||
});
|
||
};
|
||
Session.prototype.off = function (eventName, eventHandler) {
|
||
this.session.removeListener(eventName, eventHandler);
|
||
};
|
||
Session.prototype.subscribe = function (param1, param2, param3) {
|
||
// Subscription
|
||
this.session.subscribe(param1);
|
||
var subscriber = new Subscriber_1.Subscriber(param1, param2);
|
||
param1.playOnlyVideo(param2, null);
|
||
return subscriber;
|
||
};
|
||
Session.prototype.unsubscribe = function (subscriber) {
|
||
this.session.unsuscribe(subscriber.stream);
|
||
subscriber.stream.removeVideo();
|
||
};
|
||
/* Shortcut event API */
|
||
Session.prototype.onStreamCreated = function (callback) {
|
||
this.session.addEventListener("streamCreated", function (streamEvent) {
|
||
callback(streamEvent.stream);
|
||
});
|
||
};
|
||
Session.prototype.onStreamDestroyed = function (callback) {
|
||
this.session.addEventListener("streamDestroyed", function (streamEvent) {
|
||
callback(streamEvent.stream);
|
||
});
|
||
};
|
||
Session.prototype.onParticipantJoined = function (callback) {
|
||
this.session.addEventListener("participant-joined", function (participantEvent) {
|
||
callback(participantEvent.connection);
|
||
});
|
||
};
|
||
Session.prototype.onParticipantLeft = function (callback) {
|
||
this.session.addEventListener("participant-left", function (participantEvent) {
|
||
callback(participantEvent.connection);
|
||
});
|
||
};
|
||
Session.prototype.onParticipantPublished = function (callback) {
|
||
this.session.addEventListener("participant-published", function (participantEvent) {
|
||
callback(participantEvent.connection);
|
||
});
|
||
};
|
||
Session.prototype.onParticipantEvicted = function (callback) {
|
||
this.session.addEventListener("participant-evicted", function (participantEvent) {
|
||
callback(participantEvent.connection);
|
||
});
|
||
};
|
||
Session.prototype.onRoomClosed = function (callback) {
|
||
this.session.addEventListener("room-closed", function (roomEvent) {
|
||
callback(roomEvent.room);
|
||
});
|
||
};
|
||
Session.prototype.onLostConnection = function (callback) {
|
||
this.session.addEventListener("lost-connection", function (roomEvent) {
|
||
callback(roomEvent.room);
|
||
});
|
||
};
|
||
Session.prototype.onMediaError = function (callback) {
|
||
this.session.addEventListener("error-media", function (errorEvent) {
|
||
callback(errorEvent.error);
|
||
});
|
||
};
|
||
return Session;
|
||
}());
|
||
exports.Session = Session;
|
||
|
||
},{"./Subscriber":108,"wolfy87-eventemitter":102}],108:[function(require,module,exports){
|
||
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
var EventEmitter = require("wolfy87-eventemitter");
|
||
var Subscriber = (function () {
|
||
function Subscriber(stream, parentId) {
|
||
this.ee = new EventEmitter();
|
||
this.stream = stream;
|
||
if (document.getElementById(parentId) != null) {
|
||
this.element = document.getElementById(parentId);
|
||
}
|
||
}
|
||
Subscriber.prototype.on = function (eventName, callback) {
|
||
var _this = this;
|
||
this.ee.addListener(eventName, function (event) {
|
||
callback(event);
|
||
});
|
||
if (eventName == 'videoElementCreated') {
|
||
if (this.stream.isReady) {
|
||
this.ee.emitEvent('videoElementCreated', [{
|
||
element: this.stream.getVideoElement()
|
||
}]);
|
||
}
|
||
else {
|
||
this.stream.addEventListener('video-element-created-by-stream', function (element) {
|
||
console.warn("Subscriber emitting videoElementCreated");
|
||
_this.id = element.id;
|
||
_this.ee.emitEvent('videoElementCreated', [{
|
||
element: element
|
||
}]);
|
||
});
|
||
}
|
||
}
|
||
};
|
||
return Subscriber;
|
||
}());
|
||
exports.Subscriber = Subscriber;
|
||
|
||
},{"wolfy87-eventemitter":102}],109:[function(require,module,exports){
|
||
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
var Stream_1 = require("./Stream");
|
||
var Connection = (function () {
|
||
function Connection(openVidu, local, room, options) {
|
||
this.openVidu = openVidu;
|
||
this.local = local;
|
||
this.room = room;
|
||
this.options = options;
|
||
this.streams = {};
|
||
this.streamsOpts = [];
|
||
if (options) {
|
||
this.connectionId = options.id;
|
||
this.data = options.metadata;
|
||
if (options.streams) {
|
||
for (var _i = 0, _a = options.streams; _i < _a.length; _i++) {
|
||
var streamOptions = _a[_i];
|
||
var streamOpts = {
|
||
id: streamOptions.id,
|
||
connection: this,
|
||
recvVideo: (streamOptions.recvVideo == undefined ? true : streamOptions.recvVideo),
|
||
recvAudio: (streamOptions.recvAudio == undefined ? true : streamOptions.recvAudio),
|
||
audio: streamOptions.audio,
|
||
video: streamOptions.video,
|
||
data: streamOptions.data,
|
||
mediaConstraints: streamOptions.mediaConstraints
|
||
};
|
||
var stream = new Stream_1.Stream(openVidu, false, room, streamOpts);
|
||
this.addStream(stream);
|
||
this.streamsOpts.push(streamOpts);
|
||
}
|
||
}
|
||
}
|
||
console.log("New " + (local ? "local " : "remote ") + "participant " + this.connectionId
|
||
+ ", streams opts: ", this.streamsOpts);
|
||
}
|
||
Connection.prototype.addStream = function (stream) {
|
||
this.streams[stream.getIdInParticipant()] = stream;
|
||
this.room.getStreams()[stream.getIdInParticipant()] = stream;
|
||
};
|
||
Connection.prototype.getStreams = function () {
|
||
return this.streams;
|
||
};
|
||
Connection.prototype.dispose = function () {
|
||
for (var key in this.streams) {
|
||
this.streams[key].dispose();
|
||
}
|
||
};
|
||
Connection.prototype.sendIceCandidate = function (candidate) {
|
||
console.debug((this.local ? "Local" : "Remote"), "candidate for", this.connectionId, JSON.stringify(candidate));
|
||
this.openVidu.sendRequest("onIceCandidate", {
|
||
endpointName: this.connectionId,
|
||
candidate: candidate.candidate,
|
||
sdpMid: candidate.sdpMid,
|
||
sdpMLineIndex: candidate.sdpMLineIndex
|
||
}, function (error, response) {
|
||
if (error) {
|
||
console.error("Error sending ICE candidate: "
|
||
+ JSON.stringify(error));
|
||
}
|
||
});
|
||
};
|
||
return Connection;
|
||
}());
|
||
exports.Connection = Connection;
|
||
|
||
},{"./Stream":112}],110:[function(require,module,exports){
|
||
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
/*
|
||
* (C) Copyright 2016 OpenVidu (http://kurento.org/)
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*
|
||
*/
|
||
var SessionInternal_1 = require("./SessionInternal");
|
||
var Stream_1 = require("./Stream");
|
||
var RpcBuilder = require("kurento-jsonrpc");
|
||
var OpenViduInternal = (function () {
|
||
function OpenViduInternal() {
|
||
this.remoteStreams = [];
|
||
}
|
||
;
|
||
/* NEW METHODS */
|
||
OpenViduInternal.prototype.initSession = function (sessionId) {
|
||
console.log("Session initialized!");
|
||
this.session = new SessionInternal_1.SessionInternal(this, sessionId);
|
||
return this.session;
|
||
};
|
||
OpenViduInternal.prototype.initPublisherTagged = function (parentId, cameraOptions, callback) {
|
||
var _this = this;
|
||
console.log("Publisher tagged initialized!");
|
||
this.getCamera(cameraOptions);
|
||
if (callback == null) {
|
||
this.camera.requestCameraAccess(function (error, camera) {
|
||
if (error) {
|
||
console.log("Error accessing the camera");
|
||
}
|
||
else {
|
||
_this.camera.setVideoElement(_this.cameraReady(camera, parentId));
|
||
}
|
||
});
|
||
return this.camera;
|
||
}
|
||
else {
|
||
this.camera.requestCameraAccess(function (error, camera) {
|
||
if (error) {
|
||
callback(error);
|
||
}
|
||
else {
|
||
_this.camera.setVideoElement(_this.cameraReady(camera, parentId));
|
||
callback(undefined);
|
||
}
|
||
});
|
||
return this.camera;
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.cameraReady = function (camera, parentId) {
|
||
this.camera = camera;
|
||
var videoElement = this.camera.playOnlyVideo(parentId, null);
|
||
this.camera.emitStreamReadyEvent();
|
||
return videoElement;
|
||
};
|
||
OpenViduInternal.prototype.initPublisher = function (cameraOptions, callback) {
|
||
console.log("Publisher initialized!");
|
||
this.getCamera(cameraOptions);
|
||
this.camera.requestCameraAccess(function (error, camera) {
|
||
if (error)
|
||
callback(error);
|
||
else
|
||
callback(undefined);
|
||
});
|
||
};
|
||
OpenViduInternal.prototype.getLocalStream = function () {
|
||
return this.camera;
|
||
};
|
||
OpenViduInternal.prototype.getRemoteStreams = function () {
|
||
return this.remoteStreams;
|
||
};
|
||
/* NEW METHODS */
|
||
OpenViduInternal.prototype.getWsUri = function () {
|
||
return this.wsUri;
|
||
};
|
||
OpenViduInternal.prototype.setWsUri = function (wsUri) {
|
||
this.wsUri = wsUri;
|
||
};
|
||
OpenViduInternal.prototype.getOpenViduServerURL = function () {
|
||
return 'https://' + this.wsUri.split("wss://")[1].split("/room")[0];
|
||
};
|
||
OpenViduInternal.prototype.getRoom = function () {
|
||
return this.session;
|
||
};
|
||
OpenViduInternal.prototype.connect = function (callback) {
|
||
this.callback = callback;
|
||
this.initJsonRpcClient(this.wsUri);
|
||
};
|
||
OpenViduInternal.prototype.initJsonRpcClient = function (wsUri) {
|
||
var config = {
|
||
heartbeat: 3000,
|
||
sendCloseMessage: false,
|
||
ws: {
|
||
uri: wsUri,
|
||
useSockJS: false,
|
||
onconnected: this.connectCallback.bind(this),
|
||
ondisconnect: this.disconnectCallback.bind(this),
|
||
onreconnecting: this.reconnectingCallback.bind(this),
|
||
onreconnected: this.reconnectedCallback.bind(this)
|
||
},
|
||
rpc: {
|
||
requestTimeout: 15000,
|
||
//notifications
|
||
participantJoined: this.onParticipantJoined.bind(this),
|
||
participantPublished: this.onParticipantPublished.bind(this),
|
||
participantUnpublished: this.onParticipantLeft.bind(this),
|
||
participantLeft: this.onParticipantLeft.bind(this),
|
||
participantEvicted: this.onParticipantEvicted.bind(this),
|
||
sendMessage: this.onNewMessage.bind(this),
|
||
iceCandidate: this.iceCandidateEvent.bind(this),
|
||
mediaError: this.onMediaError.bind(this),
|
||
custonNotification: this.customNotification.bind(this)
|
||
}
|
||
};
|
||
this.jsonRpcClient = new RpcBuilder.clients.JsonRpcClient(config);
|
||
};
|
||
OpenViduInternal.prototype.customNotification = function (params) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.emitEvent("custom-message-received", [{ params: params }]);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.connectCallback = function (error) {
|
||
if (error) {
|
||
this.callback(error);
|
||
}
|
||
else {
|
||
this.callback(null);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.isRoomAvailable = function () {
|
||
if (this.session !== undefined && this.session instanceof SessionInternal_1.SessionInternal) {
|
||
return true;
|
||
}
|
||
else {
|
||
console.warn('Room instance not found');
|
||
return false;
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.disconnectCallback = function () {
|
||
console.log('Websocket connection lost');
|
||
if (this.isRoomAvailable()) {
|
||
this.session.onLostConnection();
|
||
}
|
||
else {
|
||
alert('Connection error. Please reload page.');
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.reconnectingCallback = function () {
|
||
console.log('Websocket connection lost (reconnecting)');
|
||
if (this.isRoomAvailable()) {
|
||
this.session.onLostConnection();
|
||
}
|
||
else {
|
||
alert('Connection error. Please reload page.');
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.reconnectedCallback = function () {
|
||
console.log('Websocket reconnected');
|
||
};
|
||
OpenViduInternal.prototype.onParticipantJoined = function (params) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.onParticipantJoined(params);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.onParticipantPublished = function (params) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.onParticipantPublished(params);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.onParticipantLeft = function (params) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.onParticipantLeft(params);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.onParticipantEvicted = function (params) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.onParticipantEvicted(params);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.onNewMessage = function (params) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.onNewMessage(params);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.iceCandidateEvent = function (params) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.recvIceCandidate(params);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.onRoomClosed = function (params) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.onRoomClosed(params);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.onMediaError = function (params) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.onMediaError(params);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.setRpcParams = function (params) {
|
||
this.rpcParams = params;
|
||
};
|
||
OpenViduInternal.prototype.sendRequest = function (method, params, callback) {
|
||
if (params && params instanceof Function) {
|
||
callback = params;
|
||
params = undefined;
|
||
}
|
||
params = params || {};
|
||
if (this.rpcParams && this.rpcParams !== null && this.rpcParams !== undefined) {
|
||
for (var index in this.rpcParams) {
|
||
if (this.rpcParams.hasOwnProperty(index)) {
|
||
params[index] = this.rpcParams[index];
|
||
console.log('RPC param added to request {' + index + ': ' + this.rpcParams[index] + '}');
|
||
}
|
||
}
|
||
}
|
||
console.log('Sending request: { method:"' + method + '", params: ' + JSON.stringify(params) + ' }');
|
||
this.jsonRpcClient.send(method, params, callback);
|
||
};
|
||
OpenViduInternal.prototype.close = function (forced) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.leave(forced, this.jsonRpcClient);
|
||
}
|
||
};
|
||
;
|
||
OpenViduInternal.prototype.disconnectParticipant = function (stream) {
|
||
if (this.isRoomAvailable()) {
|
||
this.session.disconnect(stream);
|
||
}
|
||
};
|
||
OpenViduInternal.prototype.getCamera = function (options) {
|
||
if (this.camera) {
|
||
return this.camera;
|
||
}
|
||
options = options || {
|
||
audio: true,
|
||
video: true,
|
||
data: true,
|
||
mediaConstraints: {
|
||
audio: true,
|
||
video: { width: { ideal: 1280 } }
|
||
}
|
||
};
|
||
options.connection = this.session.getLocalParticipant();
|
||
this.camera = new Stream_1.Stream(this, true, this.session, options);
|
||
return this.camera;
|
||
};
|
||
;
|
||
/*joinSession(options: SessionOptions, callback: Callback<Session>) {
|
||
|
||
this.session.configure(options);
|
||
|
||
this.session.connect2();
|
||
|
||
this.session.addEventListener('room-connected', roomEvent => callback(undefined,this.session));
|
||
|
||
this.session.addEventListener('error-room', error => callback(error));
|
||
|
||
return this.session;
|
||
};*/
|
||
//CHAT
|
||
OpenViduInternal.prototype.sendMessage = function (room, user, message) {
|
||
this.sendRequest('sendMessage', {
|
||
message: message,
|
||
userMessage: user,
|
||
roomMessage: room
|
||
}, function (error, response) {
|
||
if (error) {
|
||
console.error(error);
|
||
}
|
||
});
|
||
};
|
||
;
|
||
OpenViduInternal.prototype.sendCustomRequest = function (params, callback) {
|
||
this.sendRequest('customRequest', params, callback);
|
||
};
|
||
;
|
||
OpenViduInternal.prototype.toggleLocalVideoTrack = function (activate) {
|
||
this.getCamera().getWebRtcPeer().videoEnabled = activate;
|
||
};
|
||
OpenViduInternal.prototype.toggleLocalAudioTrack = function (activate) {
|
||
this.getCamera().getWebRtcPeer().audioEnabled = activate;
|
||
};
|
||
OpenViduInternal.prototype.publishLocalVideoAudio = function () {
|
||
this.toggleLocalVideoTrack(true);
|
||
this.toggleLocalAudioTrack(true);
|
||
};
|
||
OpenViduInternal.prototype.unpublishLocalVideoAudio = function () {
|
||
this.toggleLocalVideoTrack(false);
|
||
this.toggleLocalAudioTrack(false);
|
||
};
|
||
OpenViduInternal.prototype.generateMediaConstraints = function (quality) {
|
||
var mediaConstraints = {
|
||
audio: true,
|
||
video: {}
|
||
};
|
||
var w, h;
|
||
switch (quality) {
|
||
case 'LOW':
|
||
w = 320;
|
||
h = 240;
|
||
break;
|
||
case 'MEDIUM':
|
||
w = 640;
|
||
h = 480;
|
||
break;
|
||
case 'HIGH':
|
||
w = 1280;
|
||
h = 720;
|
||
break;
|
||
default:
|
||
w = 640;
|
||
h = 480;
|
||
}
|
||
mediaConstraints.video['width'] = { exact: w };
|
||
mediaConstraints.video['height'] = { exact: h };
|
||
//mediaConstraints.video['frameRate'] = { ideal: Number((<HTMLInputElement>document.getElementById('frameRate')).value) };
|
||
return mediaConstraints;
|
||
};
|
||
return OpenViduInternal;
|
||
}());
|
||
exports.OpenViduInternal = OpenViduInternal;
|
||
|
||
},{"./SessionInternal":111,"./Stream":112,"kurento-jsonrpc":14}],111:[function(require,module,exports){
|
||
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
var Connection_1 = require("./Connection");
|
||
var EventEmitter = require("wolfy87-eventemitter");
|
||
var SessionInternal = (function () {
|
||
function SessionInternal(openVidu, sessionId) {
|
||
this.openVidu = openVidu;
|
||
this.sessionId = sessionId;
|
||
this.ee = new EventEmitter();
|
||
this.streams = {};
|
||
this.participants = {};
|
||
this.participantsSpeaking = [];
|
||
this.connected = false;
|
||
this.localParticipant = new Connection_1.Connection(this.openVidu, true, this);
|
||
if (!this.openVidu.getWsUri()) {
|
||
this.openVidu.setWsUri(this.checkNgrokUri(sessionId));
|
||
}
|
||
}
|
||
SessionInternal.prototype.checkNgrokUri = function (sessionId) {
|
||
sessionId = sessionId.substring(0, sessionId.lastIndexOf('/')) + '/room';
|
||
if (sessionId.indexOf(".ngrok.io") !== -1) {
|
||
// OpenVidu server URL referes to a ngrok IP: secure wss protocol and delete port of URL
|
||
sessionId = sessionId.replace("ws://", "wss://");
|
||
var regex = /\.ngrok\.io:\d+/;
|
||
sessionId = sessionId.replace(regex, ".ngrok.io");
|
||
}
|
||
else if ((sessionId.indexOf("localhost") !== -1) || (sessionId.indexOf("127.0.0.1") != -1)) {
|
||
// OpenVidu server URL referes to localhost IP
|
||
}
|
||
return sessionId;
|
||
};
|
||
/* NEW METHODS */
|
||
SessionInternal.prototype.connect = function (token, callback) {
|
||
var _this = this;
|
||
this.openVidu.connect(function (error) {
|
||
if (error) {
|
||
callback('ERROR CONNECTING TO OPENVIDU');
|
||
}
|
||
else {
|
||
var joinParams = {
|
||
token: token,
|
||
session: _this.sessionId,
|
||
metadata: _this.options.metadata,
|
||
dataChannels: false
|
||
};
|
||
if (_this.localParticipant) {
|
||
if (Object.keys(_this.localParticipant.getStreams()).some(function (streamId) {
|
||
return _this.streams[streamId].isDataChannelEnabled();
|
||
})) {
|
||
joinParams.dataChannels = true;
|
||
}
|
||
}
|
||
_this.openVidu.sendRequest('joinRoom', joinParams, function (error, response) {
|
||
if (error) {
|
||
callback('UNABLE TO JOIN ROOM');
|
||
}
|
||
else {
|
||
_this.connected = true;
|
||
var exParticipants = response.value;
|
||
// IMPORTANT: Update connectionId with value send by server
|
||
_this.localParticipant.connectionId = response.id;
|
||
_this.participants[response.id] = _this.localParticipant;
|
||
var roomEvent = {
|
||
participants: new Array(),
|
||
streams: new Array()
|
||
};
|
||
var length_1 = exParticipants.length;
|
||
for (var i = 0; i < length_1; i++) {
|
||
var connection = new Connection_1.Connection(_this.openVidu, false, _this, exParticipants[i]);
|
||
connection.creationTime = new Date().getTime();
|
||
_this.participants[connection.connectionId] = connection;
|
||
roomEvent.participants.push(connection);
|
||
var streams = connection.getStreams();
|
||
for (var key in streams) {
|
||
roomEvent.streams.push(streams[key]);
|
||
if (_this.subscribeToStreams) {
|
||
streams[key].subscribe();
|
||
}
|
||
}
|
||
}
|
||
// Update local Connection object properties with values returned by server
|
||
_this.localParticipant.data = response.metadata;
|
||
_this.localParticipant.creationTime = new Date().getTime();
|
||
// Updates the value of property 'connection' in Session object
|
||
_this.ee.emitEvent('update-connection-object', [{ connection: _this.localParticipant }]);
|
||
// Own connection created event
|
||
_this.ee.emitEvent('connectionCreated', [{ connection: _this.localParticipant }]);
|
||
// One connection created event for each existing connection in the session
|
||
for (var _i = 0, _a = roomEvent.participants; _i < _a.length; _i++) {
|
||
var part = _a[_i];
|
||
_this.ee.emitEvent('connectionCreated', [{ connection: part }]);
|
||
}
|
||
//if (this.subscribeToStreams) {
|
||
for (var _b = 0, _c = roomEvent.streams; _b < _c.length; _b++) {
|
||
var stream = _c[_b];
|
||
_this.ee.emitEvent('streamCreated', [{ stream: stream }]);
|
||
// Adding the remote stream to the OpenVidu object
|
||
_this.openVidu.getRemoteStreams().push(stream);
|
||
}
|
||
//}
|
||
callback(undefined);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
};
|
||
SessionInternal.prototype.publish = function () {
|
||
this.openVidu.getCamera().publish();
|
||
};
|
||
/* NEW METHODS */
|
||
SessionInternal.prototype.configure = function (options) {
|
||
this.options = options;
|
||
this.id = options.sessionId;
|
||
this.subscribeToStreams = options.subscribeToStreams == null ? true : options.subscribeToStreams;
|
||
this.updateSpeakerInterval = options.updateSpeakerInterval || 1500;
|
||
this.thresholdSpeaker = options.thresholdSpeaker || -50;
|
||
this.activateUpdateMainSpeaker();
|
||
};
|
||
SessionInternal.prototype.getId = function () {
|
||
return this.id;
|
||
};
|
||
SessionInternal.prototype.getSessionId = function () {
|
||
return this.sessionId;
|
||
};
|
||
SessionInternal.prototype.activateUpdateMainSpeaker = function () {
|
||
var _this = this;
|
||
setInterval(function () {
|
||
if (_this.participantsSpeaking.length > 0) {
|
||
_this.ee.emitEvent('update-main-speaker', [{
|
||
participantId: _this.participantsSpeaking[_this.participantsSpeaking.length - 1]
|
||
}]);
|
||
}
|
||
}, this.updateSpeakerInterval);
|
||
};
|
||
SessionInternal.prototype.getLocalParticipant = function () {
|
||
return this.localParticipant;
|
||
};
|
||
SessionInternal.prototype.addEventListener = function (eventName, listener) {
|
||
this.ee.on(eventName, listener);
|
||
};
|
||
SessionInternal.prototype.addOnceEventListener = function (eventName, listener) {
|
||
this.ee.once(eventName, listener);
|
||
};
|
||
SessionInternal.prototype.removeListener = function (eventName, listener) {
|
||
this.ee.off(eventName, listener);
|
||
};
|
||
SessionInternal.prototype.removeEvent = function (eventName) {
|
||
this.ee.removeEvent(eventName);
|
||
};
|
||
SessionInternal.prototype.emitEvent = function (eventName, eventsArray) {
|
||
this.ee.emitEvent(eventName, eventsArray);
|
||
};
|
||
SessionInternal.prototype.subscribe = function (stream) {
|
||
stream.subscribe();
|
||
};
|
||
SessionInternal.prototype.unsuscribe = function (stream) {
|
||
console.log("Unsubscribing from " + stream.getId());
|
||
this.openVidu.sendRequest('unsubscribeFromVideo', {
|
||
sender: stream.getId()
|
||
}, function (error, response) {
|
||
if (error) {
|
||
console.error(error);
|
||
}
|
||
else {
|
||
console.info("Unsubscribed correctly from " + stream.getId());
|
||
}
|
||
});
|
||
};
|
||
SessionInternal.prototype.onParticipantPublished = function (options) {
|
||
options.metadata = this.participants[options.id].data;
|
||
var connection = new Connection_1.Connection(this.openVidu, false, this, options);
|
||
var pid = connection.connectionId;
|
||
if (!(pid in this.participants)) {
|
||
console.info("Publisher not found in participants list by its id", pid);
|
||
}
|
||
else {
|
||
console.log("Publisher found in participants list by its id", pid);
|
||
}
|
||
//replacing old connection (this one has streams)
|
||
connection.creationTime = this.participants[pid].creationTime;
|
||
this.participants[pid] = connection;
|
||
this.ee.emitEvent('participant-published', [{ connection: connection }]);
|
||
var streams = connection.getStreams();
|
||
for (var key in streams) {
|
||
var stream = streams[key];
|
||
if (this.subscribeToStreams) {
|
||
stream.subscribe();
|
||
}
|
||
this.ee.emitEvent('streamCreated', [{ stream: stream }]);
|
||
// Adding the remote stream to the OpenVidu object
|
||
this.openVidu.getRemoteStreams().push(stream);
|
||
}
|
||
};
|
||
SessionInternal.prototype.onParticipantJoined = function (msg) {
|
||
var connection = new Connection_1.Connection(this.openVidu, false, this, msg);
|
||
connection.creationTime = new Date().getTime();
|
||
var pid = connection.connectionId;
|
||
if (!(pid in this.participants)) {
|
||
console.log("New participant to participants list with id", pid);
|
||
this.participants[pid] = connection;
|
||
}
|
||
else {
|
||
//use existing so that we don't lose streams info
|
||
console.info("Participant already exists in participants list with " +
|
||
"the same id, old:", this.participants[pid], ", joined now:", connection);
|
||
connection = this.participants[pid];
|
||
}
|
||
this.ee.emitEvent('participant-joined', [{
|
||
connection: connection
|
||
}]);
|
||
this.ee.emitEvent('connectionCreated', [{
|
||
connection: connection
|
||
}]);
|
||
};
|
||
SessionInternal.prototype.onParticipantLeft = function (msg) {
|
||
var _this = this;
|
||
var connection = this.participants[msg.name];
|
||
if (connection !== undefined) {
|
||
delete this.participants[msg.name];
|
||
this.ee.emitEvent('participant-left', [{
|
||
connection: connection
|
||
}]);
|
||
var streams = connection.getStreams();
|
||
for (var key in streams) {
|
||
this.ee.emitEvent('streamDestroyed', [{
|
||
stream: streams[key],
|
||
preventDefault: function () { _this.ee.removeEvent('stream-destroyed-default'); }
|
||
}]);
|
||
this.ee.emitEvent('stream-destroyed-default', [{
|
||
stream: streams[key]
|
||
}]);
|
||
// Deleting the removed stream from the OpenVidu object
|
||
var index = this.openVidu.getRemoteStreams().indexOf(streams[key]);
|
||
this.openVidu.getRemoteStreams().splice(index, 1);
|
||
}
|
||
connection.dispose();
|
||
this.ee.emitEvent('connectionDestroyed', [{
|
||
connection: connection
|
||
}]);
|
||
}
|
||
else {
|
||
console.warn("Participant " + msg.name
|
||
+ " unknown. Participants: "
|
||
+ JSON.stringify(this.participants));
|
||
}
|
||
};
|
||
;
|
||
SessionInternal.prototype.onParticipantEvicted = function (msg) {
|
||
this.ee.emitEvent('participant-evicted', [{
|
||
localParticipant: this.localParticipant
|
||
}]);
|
||
};
|
||
;
|
||
SessionInternal.prototype.onNewMessage = function (msg) {
|
||
console.log("New message: " + JSON.stringify(msg));
|
||
var room = msg.room;
|
||
var user = msg.user;
|
||
var message = msg.message;
|
||
if (user !== undefined) {
|
||
this.ee.emitEvent('newMessage', [{
|
||
room: room,
|
||
user: user,
|
||
message: message
|
||
}]);
|
||
}
|
||
else {
|
||
console.warn("User undefined in new message:", msg);
|
||
}
|
||
};
|
||
SessionInternal.prototype.recvIceCandidate = function (msg) {
|
||
var candidate = {
|
||
candidate: msg.candidate,
|
||
sdpMid: msg.sdpMid,
|
||
sdpMLineIndex: msg.sdpMLineIndex
|
||
};
|
||
var connection = this.participants[msg.endpointName];
|
||
if (!connection) {
|
||
console.error("Participant not found for endpoint " +
|
||
msg.endpointName + ". Ice candidate will be ignored.", candidate);
|
||
return;
|
||
}
|
||
var streams = connection.getStreams();
|
||
var _loop_1 = function (key) {
|
||
var stream = streams[key];
|
||
stream.getWebRtcPeer().addIceCandidate(candidate, function (error) {
|
||
if (error) {
|
||
console.error("Error adding candidate for " + key
|
||
+ " stream of endpoint " + msg.endpointName
|
||
+ ": " + error);
|
||
}
|
||
});
|
||
};
|
||
for (var key in streams) {
|
||
_loop_1(key);
|
||
}
|
||
};
|
||
SessionInternal.prototype.onRoomClosed = function (msg) {
|
||
console.log("Room closed: " + JSON.stringify(msg));
|
||
var room = msg.room;
|
||
if (room !== undefined) {
|
||
this.ee.emitEvent('room-closed', [{
|
||
room: room
|
||
}]);
|
||
}
|
||
else {
|
||
console.warn("Room undefined in on room closed", msg);
|
||
}
|
||
};
|
||
SessionInternal.prototype.onLostConnection = function () {
|
||
if (!this.connected) {
|
||
console.warn('Not connected to room: if you are not debugging, this is probably a certificate error');
|
||
if (window.confirm('If you are not debugging, this is probably a certificate error at \"' + this.openVidu.getOpenViduServerURL() + '\"\n\nClick OK to navigate and accept it')) {
|
||
location.assign(this.openVidu.getOpenViduServerURL() + '/accept-certificate');
|
||
}
|
||
;
|
||
return;
|
||
}
|
||
console.log('Lost connection in room ' + this.id);
|
||
var room = this.id;
|
||
if (room !== undefined) {
|
||
this.ee.emitEvent('lost-connection', [{ room: room }]);
|
||
}
|
||
else {
|
||
console.warn('Room undefined when lost connection');
|
||
}
|
||
};
|
||
SessionInternal.prototype.onMediaError = function (params) {
|
||
console.error("Media error: " + JSON.stringify(params));
|
||
var error = params.error;
|
||
if (error) {
|
||
this.ee.emitEvent('error-media', [{
|
||
error: error
|
||
}]);
|
||
}
|
||
else {
|
||
console.warn("Received undefined media error. Params:", params);
|
||
}
|
||
};
|
||
/*
|
||
* forced means the user was evicted, no need to send the 'leaveRoom' request
|
||
*/
|
||
SessionInternal.prototype.leave = function (forced, jsonRpcClient) {
|
||
forced = !!forced;
|
||
console.log("Leaving room (forced=" + forced + ")");
|
||
if (this.connected && !forced) {
|
||
this.openVidu.sendRequest('leaveRoom', function (error, response) {
|
||
if (error) {
|
||
console.error(error);
|
||
}
|
||
jsonRpcClient.close();
|
||
});
|
||
}
|
||
else {
|
||
jsonRpcClient.close();
|
||
}
|
||
this.connected = false;
|
||
if (this.participants) {
|
||
for (var pid in this.participants) {
|
||
this.participants[pid].dispose();
|
||
delete this.participants[pid];
|
||
}
|
||
}
|
||
};
|
||
SessionInternal.prototype.disconnect = function (stream) {
|
||
var connection = stream.getParticipant();
|
||
if (!connection) {
|
||
console.error("Stream to disconnect has no participant", stream);
|
||
return;
|
||
}
|
||
delete this.participants[connection.connectionId];
|
||
connection.dispose();
|
||
if (connection === this.localParticipant) {
|
||
console.log("Unpublishing my media (I'm " + connection.connectionId + ")");
|
||
delete this.localParticipant;
|
||
this.openVidu.sendRequest('unpublishVideo', function (error, response) {
|
||
if (error) {
|
||
console.error(error);
|
||
}
|
||
else {
|
||
console.info("Media unpublished correctly");
|
||
}
|
||
});
|
||
}
|
||
else {
|
||
this.unsuscribe(stream);
|
||
}
|
||
};
|
||
SessionInternal.prototype.unpublish = function (stream) {
|
||
var connection = stream.getParticipant();
|
||
if (!connection) {
|
||
console.error("Stream to disconnect has no participant", stream);
|
||
return;
|
||
}
|
||
if (connection === this.localParticipant) {
|
||
delete this.participants[connection.connectionId];
|
||
connection.dispose();
|
||
console.log("Unpublishing my media (I'm " + connection.connectionId + ")");
|
||
delete this.localParticipant;
|
||
this.openVidu.sendRequest('unpublishVideo', function (error, response) {
|
||
if (error) {
|
||
console.error(error);
|
||
}
|
||
else {
|
||
console.info("Media unpublished correctly");
|
||
}
|
||
});
|
||
}
|
||
};
|
||
SessionInternal.prototype.getStreams = function () {
|
||
return this.streams;
|
||
};
|
||
SessionInternal.prototype.addParticipantSpeaking = function (participantId) {
|
||
this.participantsSpeaking.push(participantId);
|
||
};
|
||
SessionInternal.prototype.removeParticipantSpeaking = function (participantId) {
|
||
var pos = -1;
|
||
for (var i = 0; i < this.participantsSpeaking.length; i++) {
|
||
if (this.participantsSpeaking[i] == participantId) {
|
||
pos = i;
|
||
break;
|
||
}
|
||
}
|
||
if (pos != -1) {
|
||
this.participantsSpeaking.splice(pos, 1);
|
||
}
|
||
};
|
||
return SessionInternal;
|
||
}());
|
||
exports.SessionInternal = SessionInternal;
|
||
|
||
},{"./Connection":109,"wolfy87-eventemitter":102}],112:[function(require,module,exports){
|
||
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
var EventEmitter = require("wolfy87-eventemitter");
|
||
var kurentoUtils = require("kurento-utils");
|
||
var adapter = require("webrtc-adapter");
|
||
if (window) {
|
||
window["adapter"] = adapter;
|
||
}
|
||
function jq(id) {
|
||
return id.replace(/(@|:|\.|\[|\]|,)/g, "\\$1");
|
||
}
|
||
function show(id) {
|
||
document.getElementById(jq(id)).style.display = 'block';
|
||
}
|
||
function hide(id) {
|
||
document.getElementById(jq(id)).style.display = 'none';
|
||
}
|
||
var Stream = (function () {
|
||
function Stream(openVidu, local, room, options) {
|
||
var _this = this;
|
||
this.openVidu = openVidu;
|
||
this.local = local;
|
||
this.room = room;
|
||
this.ee = new EventEmitter();
|
||
this.videoElements = [];
|
||
this.elements = [];
|
||
this.showMyRemote = false;
|
||
this.localMirrored = false;
|
||
this.chanId = 0;
|
||
this.dataChannelOpened = false;
|
||
this.isReady = false;
|
||
this.accessIsAllowed = false;
|
||
this.accessIsDenied = false;
|
||
if (options.id) {
|
||
this.id = options.id;
|
||
}
|
||
else {
|
||
this.id = "webcam";
|
||
}
|
||
this.connection = options.connection;
|
||
this.recvVideo = options.recvVideo;
|
||
this.recvAudio = options.recvAudio;
|
||
this.dataChannel = options.data || false;
|
||
this.sendVideo = options.video;
|
||
this.sendAudio = options.audio;
|
||
this.mediaConstraints = options.mediaConstraints;
|
||
this.addEventListener('src-added', function (srcEvent) {
|
||
_this.videoSrc = srcEvent.src;
|
||
if (_this.video)
|
||
_this.video.src = srcEvent.src;
|
||
console.warn("Videosrc [" + srcEvent.src + "] added to stream [" + _this.getId() + "]");
|
||
});
|
||
}
|
||
Stream.prototype.emitSrcEvent = function (wrstream) {
|
||
this.ee.emitEvent('src-added', [{
|
||
src: URL.createObjectURL(wrstream)
|
||
}]);
|
||
};
|
||
Stream.prototype.emitStreamReadyEvent = function () {
|
||
this.ee.emitEvent('stream-ready'), [{}];
|
||
};
|
||
Stream.prototype.getVideoSrc = function () {
|
||
return this.videoSrc;
|
||
};
|
||
Stream.prototype.removeVideo = function (parentElement) {
|
||
if (typeof parentElement === "string") {
|
||
document.getElementById(parentElement).removeChild(this.video);
|
||
}
|
||
else if (parentElement instanceof Element) {
|
||
parentElement.removeChild(this.video);
|
||
}
|
||
else if (!parentElement) {
|
||
if (document.getElementById(this.parentId)) {
|
||
document.getElementById(this.parentId).removeChild(this.video);
|
||
}
|
||
}
|
||
};
|
||
Stream.prototype.getVideoElement = function () {
|
||
return this.video;
|
||
};
|
||
Stream.prototype.setVideoElement = function (video) {
|
||
this.video = video;
|
||
};
|
||
Stream.prototype.getRecvVideo = function () {
|
||
return this.recvVideo;
|
||
};
|
||
Stream.prototype.getRecvAudio = function () {
|
||
return this.recvAudio;
|
||
};
|
||
Stream.prototype.subscribeToMyRemote = function () {
|
||
this.showMyRemote = true;
|
||
};
|
||
Stream.prototype.displayMyRemote = function () {
|
||
return this.showMyRemote;
|
||
};
|
||
Stream.prototype.mirrorLocalStream = function (wr) {
|
||
this.showMyRemote = true;
|
||
this.localMirrored = true;
|
||
if (wr) {
|
||
this.wrStream = wr;
|
||
this.emitSrcEvent(this.wrStream);
|
||
}
|
||
};
|
||
Stream.prototype.isLocalMirrored = function () {
|
||
return this.localMirrored;
|
||
};
|
||
Stream.prototype.getChannelName = function () {
|
||
return this.getId() + '_' + this.chanId++;
|
||
};
|
||
Stream.prototype.isDataChannelEnabled = function () {
|
||
return this.dataChannel;
|
||
};
|
||
Stream.prototype.isDataChannelOpened = function () {
|
||
return this.dataChannelOpened;
|
||
};
|
||
Stream.prototype.onDataChannelOpen = function (event) {
|
||
console.log('Data channel is opened');
|
||
this.dataChannelOpened = true;
|
||
};
|
||
Stream.prototype.onDataChannelClosed = function (event) {
|
||
console.log('Data channel is closed');
|
||
this.dataChannelOpened = false;
|
||
};
|
||
Stream.prototype.sendData = function (data) {
|
||
if (this.wp === undefined) {
|
||
throw new Error('WebRTC peer has not been created yet');
|
||
}
|
||
if (!this.dataChannelOpened) {
|
||
throw new Error('Data channel is not opened');
|
||
}
|
||
console.log("Sending through data channel: " + data);
|
||
this.wp.send(data);
|
||
};
|
||
Stream.prototype.getWrStream = function () {
|
||
return this.wrStream;
|
||
};
|
||
Stream.prototype.getWebRtcPeer = function () {
|
||
return this.wp;
|
||
};
|
||
Stream.prototype.addEventListener = function (eventName, listener) {
|
||
this.ee.addListener(eventName, listener);
|
||
};
|
||
Stream.prototype.addOnceEventListener = function (eventName, listener) {
|
||
this.ee.addOnceListener(eventName, listener);
|
||
};
|
||
Stream.prototype.removeListener = function (eventName) {
|
||
this.ee.removeAllListeners(eventName);
|
||
};
|
||
Stream.prototype.showSpinner = function (spinnerParentId) {
|
||
var progress = document.createElement('div');
|
||
progress.id = 'progress-' + this.getId();
|
||
progress.style.background = "center transparent url('img/spinner.gif') no-repeat";
|
||
var spinnerParent = document.getElementById(spinnerParentId);
|
||
if (spinnerParent) {
|
||
spinnerParent.appendChild(progress);
|
||
}
|
||
};
|
||
Stream.prototype.hideSpinner = function (spinnerId) {
|
||
spinnerId = (spinnerId === undefined) ? this.getId() : spinnerId;
|
||
hide('progress-' + spinnerId);
|
||
};
|
||
Stream.prototype.playOnlyVideo = function (parentElement, thumbnailId) {
|
||
// TO-DO: check somehow if the stream is audio only, so the element created is <audio> instead of <video>
|
||
this.video = document.createElement('video');
|
||
this.video.id = 'native-video-' + this.getId();
|
||
this.video.autoplay = true;
|
||
this.video.controls = false;
|
||
this.video.src = this.videoSrc;
|
||
this.videoElements.push({
|
||
thumb: thumbnailId,
|
||
video: this.video
|
||
});
|
||
if (this.local) {
|
||
this.video.muted = true;
|
||
}
|
||
else {
|
||
this.video.title = this.getId();
|
||
}
|
||
if (typeof parentElement === "string") {
|
||
this.parentId = parentElement;
|
||
var parentElementDom = document.getElementById(parentElement);
|
||
if (parentElementDom) {
|
||
this.video = parentElementDom.appendChild(this.video);
|
||
}
|
||
}
|
||
else {
|
||
this.parentId = parentElement.id;
|
||
this.video = parentElement.appendChild(this.video);
|
||
}
|
||
this.ee.emitEvent('video-element-created-by-stream', [{
|
||
element: this.video
|
||
}]);
|
||
this.ee.emitEvent('stream-created-by-publisher');
|
||
this.isReady = true;
|
||
return this.video;
|
||
};
|
||
Stream.prototype.playThumbnail = function (thumbnailId) {
|
||
var container = document.createElement('div');
|
||
container.className = "participant";
|
||
container.id = this.getId();
|
||
var thumbnail = document.getElementById(thumbnailId);
|
||
if (thumbnail) {
|
||
thumbnail.appendChild(container);
|
||
}
|
||
this.elements.push(container);
|
||
var name = document.createElement('div');
|
||
container.appendChild(name);
|
||
var userName = this.getId().replace('_webcam', '');
|
||
if (userName.length >= 16) {
|
||
userName = userName.substring(0, 16) + "...";
|
||
}
|
||
name.appendChild(document.createTextNode(userName));
|
||
name.id = "name-" + this.getId();
|
||
name.className = "name";
|
||
name.title = this.getId();
|
||
this.showSpinner(thumbnailId);
|
||
return this.playOnlyVideo(container, thumbnailId);
|
||
};
|
||
Stream.prototype.getIdInParticipant = function () {
|
||
return this.id;
|
||
};
|
||
Stream.prototype.getParticipant = function () {
|
||
return this.connection;
|
||
};
|
||
Stream.prototype.getId = function () {
|
||
if (this.connection) {
|
||
return this.connection.connectionId + "_" + this.id;
|
||
}
|
||
else {
|
||
return this.id + "_webcam";
|
||
}
|
||
};
|
||
Stream.prototype.getRTCPeerConnection = function () {
|
||
return this.getWebRtcPeer().peerConnection;
|
||
};
|
||
Stream.prototype.requestCameraAccess = function (callback) {
|
||
var _this = this;
|
||
this.connection.addStream(this);
|
||
var constraints = this.mediaConstraints;
|
||
/*let constraints2 = {
|
||
audio: true,
|
||
video: {
|
||
width: {
|
||
ideal: 1280
|
||
},
|
||
frameRate: {
|
||
ideal: 15
|
||
}
|
||
}
|
||
};*/
|
||
this.userMediaHasVideo(function (hasVideo) {
|
||
if (!hasVideo) {
|
||
constraints.video = false;
|
||
_this.sendVideo = false;
|
||
_this.requestCameraAccesAux(constraints, callback);
|
||
}
|
||
else {
|
||
_this.requestCameraAccesAux(constraints, callback);
|
||
}
|
||
});
|
||
};
|
||
Stream.prototype.requestCameraAccesAux = function (constraints, callback) {
|
||
var _this = this;
|
||
navigator.mediaDevices.getUserMedia(constraints)
|
||
.then(function (userStream) {
|
||
_this.accessIsAllowed = true;
|
||
_this.accessIsDenied = false;
|
||
_this.ee.emitEvent('access-allowed-by-publisher');
|
||
if (userStream.getAudioTracks()[0] != null) {
|
||
userStream.getAudioTracks()[0].enabled = _this.sendAudio;
|
||
}
|
||
if (userStream.getVideoTracks()[0] != null) {
|
||
userStream.getVideoTracks()[0].enabled = _this.sendVideo;
|
||
}
|
||
_this.wrStream = userStream;
|
||
_this.emitSrcEvent(_this.wrStream);
|
||
callback(undefined, _this);
|
||
})
|
||
.catch(function (error) {
|
||
_this.accessIsDenied = true;
|
||
_this.accessIsAllowed = false;
|
||
_this.ee.emitEvent('access-denied-by-publisher');
|
||
console.error("Access denied", error);
|
||
callback(error, _this);
|
||
});
|
||
};
|
||
Stream.prototype.userMediaHasVideo = function (callback) {
|
||
navigator.mediaDevices.enumerateDevices().then(function (mediaDevices) {
|
||
var videoInput = mediaDevices.filter(function (deviceInfo) {
|
||
return deviceInfo.kind === 'videoinput';
|
||
})[0];
|
||
callback(videoInput != null);
|
||
});
|
||
};
|
||
Stream.prototype.publishVideoCallback = function (error, sdpOfferParam, wp) {
|
||
var _this = this;
|
||
if (error) {
|
||
return console.error("(publish) SDP offer error: "
|
||
+ JSON.stringify(error));
|
||
}
|
||
console.log("Sending SDP offer to publish as "
|
||
+ this.getId(), sdpOfferParam);
|
||
this.openVidu.sendRequest("publishVideo", {
|
||
sdpOffer: sdpOfferParam,
|
||
doLoopback: this.displayMyRemote() || false
|
||
}, function (error, response) {
|
||
if (error) {
|
||
console.error("Error on publishVideo: " + JSON.stringify(error));
|
||
}
|
||
else {
|
||
_this.room.emitEvent('stream-published', [{
|
||
stream: _this
|
||
}]);
|
||
_this.processSdpAnswer(response.sdpAnswer);
|
||
}
|
||
});
|
||
};
|
||
Stream.prototype.startVideoCallback = function (error, sdpOfferParam, wp) {
|
||
var _this = this;
|
||
if (error) {
|
||
return console.error("(subscribe) SDP offer error: "
|
||
+ JSON.stringify(error));
|
||
}
|
||
console.log("Sending SDP offer to subscribe to "
|
||
+ this.getId(), sdpOfferParam);
|
||
this.openVidu.sendRequest("receiveVideoFrom", {
|
||
sender: this.getId(),
|
||
sdpOffer: sdpOfferParam
|
||
}, function (error, response) {
|
||
if (error) {
|
||
console.error("Error on recvVideoFrom: " + JSON.stringify(error));
|
||
}
|
||
else {
|
||
_this.processSdpAnswer(response.sdpAnswer);
|
||
}
|
||
});
|
||
};
|
||
Stream.prototype.initWebRtcPeer = function (sdpOfferCallback) {
|
||
var _this = this;
|
||
if (this.local) {
|
||
var userMediaConstraints = {
|
||
audio: this.sendAudio,
|
||
video: this.sendVideo
|
||
};
|
||
var options = {
|
||
videoStream: this.wrStream,
|
||
mediaConstraints: userMediaConstraints,
|
||
onicecandidate: this.connection.sendIceCandidate.bind(this.connection),
|
||
};
|
||
if (this.dataChannel) {
|
||
options.dataChannelConfig = {
|
||
id: this.getChannelName(),
|
||
onopen: this.onDataChannelOpen,
|
||
onclose: this.onDataChannelClosed
|
||
};
|
||
options.dataChannels = true;
|
||
}
|
||
if (this.displayMyRemote()) {
|
||
this.wp = new kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv(options, function (error) {
|
||
if (error) {
|
||
return console.error(error);
|
||
}
|
||
_this.wp.generateOffer(sdpOfferCallback.bind(_this));
|
||
});
|
||
}
|
||
else {
|
||
this.wp = new kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options, function (error) {
|
||
if (error) {
|
||
return console.error(error);
|
||
}
|
||
_this.wp.generateOffer(sdpOfferCallback.bind(_this));
|
||
});
|
||
}
|
||
}
|
||
else {
|
||
var offerConstraints = {
|
||
mandatory: {
|
||
OfferToReceiveVideo: this.recvVideo,
|
||
OfferToReceiveAudio: this.recvAudio
|
||
}
|
||
};
|
||
console.log("Constraints of generate SDP offer (subscribing)", offerConstraints);
|
||
var options = {
|
||
onicecandidate: this.connection.sendIceCandidate.bind(this.connection),
|
||
connectionConstraints: offerConstraints
|
||
};
|
||
this.wp = new kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, function (error) {
|
||
if (error) {
|
||
return console.error(error);
|
||
}
|
||
_this.wp.generateOffer(sdpOfferCallback.bind(_this));
|
||
});
|
||
}
|
||
console.log("Waiting for SDP offer to be generated ("
|
||
+ (this.local ? "local" : "remote") + " peer: " + this.getId() + ")");
|
||
};
|
||
Stream.prototype.publish = function () {
|
||
var _this = this;
|
||
// FIXME: Throw error when stream is not local
|
||
if (this.isReady) {
|
||
this.initWebRtcPeer(this.publishVideoCallback);
|
||
}
|
||
else {
|
||
this.ee.once('stream-ready', function (streamEvent) {
|
||
_this.publish();
|
||
});
|
||
}
|
||
// FIXME: Now we have coupled connecting to a room and adding a
|
||
// stream to this room. But in the new API, there are two steps.
|
||
// This is the second step. For now, it do nothing.
|
||
};
|
||
Stream.prototype.subscribe = function () {
|
||
// FIXME: In the current implementation all participants are subscribed
|
||
// automatically to all other participants. We use this method only to
|
||
// negotiate SDP
|
||
this.initWebRtcPeer(this.startVideoCallback);
|
||
};
|
||
Stream.prototype.processSdpAnswer = function (sdpAnswer) {
|
||
var _this = this;
|
||
var answer = new RTCSessionDescription({
|
||
type: 'answer',
|
||
sdp: sdpAnswer,
|
||
});
|
||
console.log(this.getId() + ": set peer connection with recvd SDP answer", sdpAnswer);
|
||
var participantId = this.getId();
|
||
var pc = this.wp.peerConnection;
|
||
pc.setRemoteDescription(answer, function () {
|
||
// Avoids to subscribe to your own stream remotely
|
||
// except when showMyRemote is true
|
||
if (!_this.local || _this.displayMyRemote()) {
|
||
_this.wrStream = pc.getRemoteStreams()[0];
|
||
console.log("Peer remote stream", _this.wrStream);
|
||
if (_this.wrStream != undefined) {
|
||
_this.emitSrcEvent(_this.wrStream);
|
||
_this.speechEvent = kurentoUtils.WebRtcPeer.hark(_this.wrStream, { threshold: _this.room.thresholdSpeaker });
|
||
_this.speechEvent.on('speaking', function () {
|
||
_this.room.addParticipantSpeaking(participantId);
|
||
_this.room.emitEvent('stream-speaking', [{
|
||
participantId: participantId
|
||
}]);
|
||
});
|
||
_this.speechEvent.on('stopped_speaking', function () {
|
||
_this.room.removeParticipantSpeaking(participantId);
|
||
_this.room.emitEvent('stream-stopped-speaking', [{
|
||
participantId: participantId
|
||
}]);
|
||
});
|
||
}
|
||
for (var _i = 0, _a = _this.videoElements; _i < _a.length; _i++) {
|
||
var videoElement = _a[_i];
|
||
var thumbnailId = videoElement.thumb;
|
||
var video = videoElement.video;
|
||
video.src = URL.createObjectURL(_this.wrStream);
|
||
video.onplay = function () {
|
||
console.log(_this.getId() + ': ' + 'Video playing');
|
||
//show(thumbnailId);
|
||
//this.hideSpinner(this.getId());
|
||
};
|
||
}
|
||
_this.room.emitEvent('stream-subscribed', [{
|
||
stream: _this
|
||
}]);
|
||
}
|
||
}, function (error) {
|
||
console.error(_this.getId() + ": Error setting SDP to the peer connection: "
|
||
+ JSON.stringify(error));
|
||
});
|
||
};
|
||
Stream.prototype.unpublish = function () {
|
||
if (this.wp) {
|
||
this.wp.dispose();
|
||
}
|
||
else {
|
||
if (this.wrStream) {
|
||
this.wrStream.getAudioTracks().forEach(function (track) {
|
||
track.stop && track.stop();
|
||
});
|
||
this.wrStream.getVideoTracks().forEach(function (track) {
|
||
track.stop && track.stop();
|
||
});
|
||
}
|
||
}
|
||
if (this.speechEvent) {
|
||
this.speechEvent.stop();
|
||
}
|
||
console.log(this.getId() + ": Stream '" + this.id + "' unpublished");
|
||
};
|
||
Stream.prototype.dispose = function () {
|
||
function disposeElement(element) {
|
||
if (element && element.parentNode) {
|
||
element.parentNode.removeChild(element);
|
||
}
|
||
}
|
||
this.elements.forEach(function (e) { return disposeElement(e); });
|
||
this.videoElements.forEach(function (ve) { return disposeElement(ve); });
|
||
disposeElement("progress-" + this.getId());
|
||
if (this.wp) {
|
||
this.wp.dispose();
|
||
}
|
||
else {
|
||
if (this.wrStream) {
|
||
this.wrStream.getAudioTracks().forEach(function (track) {
|
||
track.stop && track.stop();
|
||
});
|
||
this.wrStream.getVideoTracks().forEach(function (track) {
|
||
track.stop && track.stop();
|
||
});
|
||
}
|
||
}
|
||
if (this.speechEvent) {
|
||
this.speechEvent.stop();
|
||
}
|
||
console.log(this.getId() + ": Stream '" + this.id + "' disposed");
|
||
};
|
||
return Stream;
|
||
}());
|
||
exports.Stream = Stream;
|
||
|
||
},{"kurento-utils":19,"webrtc-adapter":91,"wolfy87-eventemitter":102}],113:[function(require,module,exports){
|
||
// Copyright Joyent, Inc. and other Node contributors.
|
||
//
|
||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||
// copy of this software and associated documentation files (the
|
||
// "Software"), to deal in the Software without restriction, including
|
||
// without limitation the rights to use, copy, modify, merge, publish,
|
||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||
// persons to whom the Software is furnished to do so, subject to the
|
||
// following conditions:
|
||
//
|
||
// The above copyright notice and this permission notice shall be included
|
||
// in all copies or substantial portions of the Software.
|
||
//
|
||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
||
function EventEmitter() {
|
||
this._events = this._events || {};
|
||
this._maxListeners = this._maxListeners || undefined;
|
||
}
|
||
module.exports = EventEmitter;
|
||
|
||
// Backwards-compat with node 0.10.x
|
||
EventEmitter.EventEmitter = EventEmitter;
|
||
|
||
EventEmitter.prototype._events = undefined;
|
||
EventEmitter.prototype._maxListeners = undefined;
|
||
|
||
// By default EventEmitters will print a warning if more than 10 listeners are
|
||
// added to it. This is a useful default which helps finding memory leaks.
|
||
EventEmitter.defaultMaxListeners = 10;
|
||
|
||
// Obviously not all Emitters should be limited to 10. This function allows
|
||
// that to be increased. Set to zero for unlimited.
|
||
EventEmitter.prototype.setMaxListeners = function(n) {
|
||
if (!isNumber(n) || n < 0 || isNaN(n))
|
||
throw TypeError('n must be a positive number');
|
||
this._maxListeners = n;
|
||
return this;
|
||
};
|
||
|
||
EventEmitter.prototype.emit = function(type) {
|
||
var er, handler, len, args, i, listeners;
|
||
|
||
if (!this._events)
|
||
this._events = {};
|
||
|
||
// If there is no 'error' event listener then throw.
|
||
if (type === 'error') {
|
||
if (!this._events.error ||
|
||
(isObject(this._events.error) && !this._events.error.length)) {
|
||
er = arguments[1];
|
||
if (er instanceof Error) {
|
||
throw er; // Unhandled 'error' event
|
||
} else {
|
||
// At least give some kind of context to the user
|
||
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
|
||
err.context = er;
|
||
throw err;
|
||
}
|
||
}
|
||
}
|
||
|
||
handler = this._events[type];
|
||
|
||
if (isUndefined(handler))
|
||
return false;
|
||
|
||
if (isFunction(handler)) {
|
||
switch (arguments.length) {
|
||
// fast cases
|
||
case 1:
|
||
handler.call(this);
|
||
break;
|
||
case 2:
|
||
handler.call(this, arguments[1]);
|
||
break;
|
||
case 3:
|
||
handler.call(this, arguments[1], arguments[2]);
|
||
break;
|
||
// slower
|
||
default:
|
||
args = Array.prototype.slice.call(arguments, 1);
|
||
handler.apply(this, args);
|
||
}
|
||
} else if (isObject(handler)) {
|
||
args = Array.prototype.slice.call(arguments, 1);
|
||
listeners = handler.slice();
|
||
len = listeners.length;
|
||
for (i = 0; i < len; i++)
|
||
listeners[i].apply(this, args);
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
EventEmitter.prototype.addListener = function(type, listener) {
|
||
var m;
|
||
|
||
if (!isFunction(listener))
|
||
throw TypeError('listener must be a function');
|
||
|
||
if (!this._events)
|
||
this._events = {};
|
||
|
||
// To avoid recursion in the case that type === "newListener"! Before
|
||
// adding it to the listeners, first emit "newListener".
|
||
if (this._events.newListener)
|
||
this.emit('newListener', type,
|
||
isFunction(listener.listener) ?
|
||
listener.listener : listener);
|
||
|
||
if (!this._events[type])
|
||
// Optimize the case of one listener. Don't need the extra array object.
|
||
this._events[type] = listener;
|
||
else if (isObject(this._events[type]))
|
||
// If we've already got an array, just append.
|
||
this._events[type].push(listener);
|
||
else
|
||
// Adding the second element, need to change to array.
|
||
this._events[type] = [this._events[type], listener];
|
||
|
||
// Check for listener leak
|
||
if (isObject(this._events[type]) && !this._events[type].warned) {
|
||
if (!isUndefined(this._maxListeners)) {
|
||
m = this._maxListeners;
|
||
} else {
|
||
m = EventEmitter.defaultMaxListeners;
|
||
}
|
||
|
||
if (m && m > 0 && this._events[type].length > m) {
|
||
this._events[type].warned = true;
|
||
console.error('(node) warning: possible EventEmitter memory ' +
|
||
'leak detected. %d listeners added. ' +
|
||
'Use emitter.setMaxListeners() to increase limit.',
|
||
this._events[type].length);
|
||
if (typeof console.trace === 'function') {
|
||
// not supported in IE 10
|
||
console.trace();
|
||
}
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
||
|
||
EventEmitter.prototype.once = function(type, listener) {
|
||
if (!isFunction(listener))
|
||
throw TypeError('listener must be a function');
|
||
|
||
var fired = false;
|
||
|
||
function g() {
|
||
this.removeListener(type, g);
|
||
|
||
if (!fired) {
|
||
fired = true;
|
||
listener.apply(this, arguments);
|
||
}
|
||
}
|
||
|
||
g.listener = listener;
|
||
this.on(type, g);
|
||
|
||
return this;
|
||
};
|
||
|
||
// emits a 'removeListener' event iff the listener was removed
|
||
EventEmitter.prototype.removeListener = function(type, listener) {
|
||
var list, position, length, i;
|
||
|
||
if (!isFunction(listener))
|
||
throw TypeError('listener must be a function');
|
||
|
||
if (!this._events || !this._events[type])
|
||
return this;
|
||
|
||
list = this._events[type];
|
||
length = list.length;
|
||
position = -1;
|
||
|
||
if (list === listener ||
|
||
(isFunction(list.listener) && list.listener === listener)) {
|
||
delete this._events[type];
|
||
if (this._events.removeListener)
|
||
this.emit('removeListener', type, listener);
|
||
|
||
} else if (isObject(list)) {
|
||
for (i = length; i-- > 0;) {
|
||
if (list[i] === listener ||
|
||
(list[i].listener && list[i].listener === listener)) {
|
||
position = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (position < 0)
|
||
return this;
|
||
|
||
if (list.length === 1) {
|
||
list.length = 0;
|
||
delete this._events[type];
|
||
} else {
|
||
list.splice(position, 1);
|
||
}
|
||
|
||
if (this._events.removeListener)
|
||
this.emit('removeListener', type, listener);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
EventEmitter.prototype.removeAllListeners = function(type) {
|
||
var key, listeners;
|
||
|
||
if (!this._events)
|
||
return this;
|
||
|
||
// not listening for removeListener, no need to emit
|
||
if (!this._events.removeListener) {
|
||
if (arguments.length === 0)
|
||
this._events = {};
|
||
else if (this._events[type])
|
||
delete this._events[type];
|
||
return this;
|
||
}
|
||
|
||
// emit removeListener for all listeners on all events
|
||
if (arguments.length === 0) {
|
||
for (key in this._events) {
|
||
if (key === 'removeListener') continue;
|
||
this.removeAllListeners(key);
|
||
}
|
||
this.removeAllListeners('removeListener');
|
||
this._events = {};
|
||
return this;
|
||
}
|
||
|
||
listeners = this._events[type];
|
||
|
||
if (isFunction(listeners)) {
|
||
this.removeListener(type, listeners);
|
||
} else if (listeners) {
|
||
// LIFO order
|
||
while (listeners.length)
|
||
this.removeListener(type, listeners[listeners.length - 1]);
|
||
}
|
||
delete this._events[type];
|
||
|
||
return this;
|
||
};
|
||
|
||
EventEmitter.prototype.listeners = function(type) {
|
||
var ret;
|
||
if (!this._events || !this._events[type])
|
||
ret = [];
|
||
else if (isFunction(this._events[type]))
|
||
ret = [this._events[type]];
|
||
else
|
||
ret = this._events[type].slice();
|
||
return ret;
|
||
};
|
||
|
||
EventEmitter.prototype.listenerCount = function(type) {
|
||
if (this._events) {
|
||
var evlistener = this._events[type];
|
||
|
||
if (isFunction(evlistener))
|
||
return 1;
|
||
else if (evlistener)
|
||
return evlistener.length;
|
||
}
|
||
return 0;
|
||
};
|
||
|
||
EventEmitter.listenerCount = function(emitter, type) {
|
||
return emitter.listenerCount(type);
|
||
};
|
||
|
||
function isFunction(arg) {
|
||
return typeof arg === 'function';
|
||
}
|
||
|
||
function isNumber(arg) {
|
||
return typeof arg === 'number';
|
||
}
|
||
|
||
function isObject(arg) {
|
||
return typeof arg === 'object' && arg !== null;
|
||
}
|
||
|
||
function isUndefined(arg) {
|
||
return arg === void 0;
|
||
}
|
||
|
||
},{}],114:[function(require,module,exports){
|
||
// shim for using process in browser
|
||
var process = module.exports = {};
|
||
|
||
// cached from whatever global is present so that test runners that stub it
|
||
// don't break things. But we need to wrap it in a try catch in case it is
|
||
// wrapped in strict mode code which doesn't define any globals. It's inside a
|
||
// function because try/catches deoptimize in certain engines.
|
||
|
||
var cachedSetTimeout;
|
||
var cachedClearTimeout;
|
||
|
||
function defaultSetTimout() {
|
||
throw new Error('setTimeout has not been defined');
|
||
}
|
||
function defaultClearTimeout () {
|
||
throw new Error('clearTimeout has not been defined');
|
||
}
|
||
(function () {
|
||
try {
|
||
if (typeof setTimeout === 'function') {
|
||
cachedSetTimeout = setTimeout;
|
||
} else {
|
||
cachedSetTimeout = defaultSetTimout;
|
||
}
|
||
} catch (e) {
|
||
cachedSetTimeout = defaultSetTimout;
|
||
}
|
||
try {
|
||
if (typeof clearTimeout === 'function') {
|
||
cachedClearTimeout = clearTimeout;
|
||
} else {
|
||
cachedClearTimeout = defaultClearTimeout;
|
||
}
|
||
} catch (e) {
|
||
cachedClearTimeout = defaultClearTimeout;
|
||
}
|
||
} ())
|
||
function runTimeout(fun) {
|
||
if (cachedSetTimeout === setTimeout) {
|
||
//normal enviroments in sane situations
|
||
return setTimeout(fun, 0);
|
||
}
|
||
// if setTimeout wasn't available but was latter defined
|
||
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
||
cachedSetTimeout = setTimeout;
|
||
return setTimeout(fun, 0);
|
||
}
|
||
try {
|
||
// when when somebody has screwed with setTimeout but no I.E. maddness
|
||
return cachedSetTimeout(fun, 0);
|
||
} catch(e){
|
||
try {
|
||
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
||
return cachedSetTimeout.call(null, fun, 0);
|
||
} catch(e){
|
||
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
|
||
return cachedSetTimeout.call(this, fun, 0);
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
function runClearTimeout(marker) {
|
||
if (cachedClearTimeout === clearTimeout) {
|
||
//normal enviroments in sane situations
|
||
return clearTimeout(marker);
|
||
}
|
||
// if clearTimeout wasn't available but was latter defined
|
||
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
||
cachedClearTimeout = clearTimeout;
|
||
return clearTimeout(marker);
|
||
}
|
||
try {
|
||
// when when somebody has screwed with setTimeout but no I.E. maddness
|
||
return cachedClearTimeout(marker);
|
||
} catch (e){
|
||
try {
|
||
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
||
return cachedClearTimeout.call(null, marker);
|
||
} catch (e){
|
||
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
|
||
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
|
||
return cachedClearTimeout.call(this, marker);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
}
|
||
var queue = [];
|
||
var draining = false;
|
||
var currentQueue;
|
||
var queueIndex = -1;
|
||
|
||
function cleanUpNextTick() {
|
||
if (!draining || !currentQueue) {
|
||
return;
|
||
}
|
||
draining = false;
|
||
if (currentQueue.length) {
|
||
queue = currentQueue.concat(queue);
|
||
} else {
|
||
queueIndex = -1;
|
||
}
|
||
if (queue.length) {
|
||
drainQueue();
|
||
}
|
||
}
|
||
|
||
function drainQueue() {
|
||
if (draining) {
|
||
return;
|
||
}
|
||
var timeout = runTimeout(cleanUpNextTick);
|
||
draining = true;
|
||
|
||
var len = queue.length;
|
||
while(len) {
|
||
currentQueue = queue;
|
||
queue = [];
|
||
while (++queueIndex < len) {
|
||
if (currentQueue) {
|
||
currentQueue[queueIndex].run();
|
||
}
|
||
}
|
||
queueIndex = -1;
|
||
len = queue.length;
|
||
}
|
||
currentQueue = null;
|
||
draining = false;
|
||
runClearTimeout(timeout);
|
||
}
|
||
|
||
process.nextTick = function (fun) {
|
||
var args = new Array(arguments.length - 1);
|
||
if (arguments.length > 1) {
|
||
for (var i = 1; i < arguments.length; i++) {
|
||
args[i - 1] = arguments[i];
|
||
}
|
||
}
|
||
queue.push(new Item(fun, args));
|
||
if (queue.length === 1 && !draining) {
|
||
runTimeout(drainQueue);
|
||
}
|
||
};
|
||
|
||
// v8 likes predictible objects
|
||
function Item(fun, array) {
|
||
this.fun = fun;
|
||
this.array = array;
|
||
}
|
||
Item.prototype.run = function () {
|
||
this.fun.apply(null, this.array);
|
||
};
|
||
process.title = 'browser';
|
||
process.browser = true;
|
||
process.env = {};
|
||
process.argv = [];
|
||
process.version = ''; // empty string to avoid regexp issues
|
||
process.versions = {};
|
||
|
||
function noop() {}
|
||
|
||
process.on = noop;
|
||
process.addListener = noop;
|
||
process.once = noop;
|
||
process.off = noop;
|
||
process.removeListener = noop;
|
||
process.removeAllListeners = noop;
|
||
process.emit = noop;
|
||
process.prependListener = noop;
|
||
process.prependOnceListener = noop;
|
||
|
||
process.listeners = function (name) { return [] }
|
||
|
||
process.binding = function (name) {
|
||
throw new Error('process.binding is not supported');
|
||
};
|
||
|
||
process.cwd = function () { return '/' };
|
||
process.chdir = function (dir) {
|
||
throw new Error('process.chdir is not supported');
|
||
};
|
||
process.umask = function() { return 0; };
|
||
|
||
},{}]},{},[104])
|
||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Vzci9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvYnJvd3Nlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9kZWJ1Zy9zcmMvZGVidWcuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvZnJlZWljZS9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9mcmVlaWNlL3N0dW4uanNvbiIsIi4uLy4uL25vZGVfbW9kdWxlcy9mcmVlaWNlL3R1cm4uanNvbiIsIi4uLy4uL25vZGVfbW9kdWxlcy9oYXJrL2hhcmsuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvaW5oZXJpdHMvaW5oZXJpdHNfYnJvd3Nlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9qc29uMy9saWIvanNvbjMuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMva3VyZW50by1qc29ucnBjL2xpYi9NYXBwZXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMva3VyZW50by1qc29ucnBjL2xpYi9jbGllbnRzL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2t1cmVudG8tanNvbnJwYy9saWIvY2xpZW50cy9qc29ucnBjY2xpZW50LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2t1cmVudG8tanNvbnJwYy9saWIvY2xpZW50cy90cmFuc3BvcnRzL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2t1cmVudG8tanNvbnJwYy9saWIvY2xpZW50cy90cmFuc3BvcnRzL3dlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb24uanMiLCIuLi8uLi9ub2RlX21vZHVsZXMva3VyZW50by1qc29ucnBjL2xpYi9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9rdXJlbnRvLWpzb25ycGMvbGliL3BhY2tlcnMvSnNvblJQQy5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9rdXJlbnRvLWpzb25ycGMvbGliL3BhY2tlcnMvWG1sUlBDLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2t1cmVudG8tanNvbnJwYy9saWIvcGFja2Vycy9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9rdXJlbnRvLXV0aWxzL2xpYi9XZWJSdGNQZWVyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL2t1cmVudG8tdXRpbHMvbGliL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL21lcmdlL21lcmdlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL21zL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL25vcm1hbGljZS9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9yZXF1aXJlcy1wb3J0L2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC10cmFuc2Zvcm0vbGliL2dyYW1tYXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc2RwLXRyYW5zZm9ybS9saWIvaW5kZXguanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc2RwLXRyYW5zZm9ybS9saWIvcGFyc2VyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC10cmFuc2Zvcm0vbGliL3dyaXRlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNsYXRvci9saWIvYXJyYXktZXF1YWxzLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC10cmFuc2xhdG9yL2xpYi9pbmRleC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNsYXRvci9saWIvaW50ZXJvcC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zZHAtdHJhbnNsYXRvci9saWIvdHJhbnNmb3JtLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NkcC9zZHAuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvZW50cnkuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvZXZlbnQvY2xvc2UuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvZXZlbnQvZW1pdHRlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9ldmVudC9ldmVudC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9ldmVudC9ldmVudHRhcmdldC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9ldmVudC90cmFucy1tZXNzYWdlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL2ZhY2FkZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9pZnJhbWUtYm9vdHN0cmFwLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL2luZm8tYWpheC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9pbmZvLWlmcmFtZS1yZWNlaXZlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9pbmZvLWlmcmFtZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi9pbmZvLXJlY2VpdmVyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL2xvY2F0aW9uLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL21haW4uanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvc2hpbXMuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0LWxpc3QuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L2Jyb3dzZXIvYWJzdHJhY3QteGhyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9icm93c2VyL2V2ZW50c291cmNlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9icm93c2VyL3dlYnNvY2tldC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi90cmFuc3BvcnQvZXZlbnRzb3VyY2UuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L2h0bWxmaWxlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9pZnJhbWUuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L2pzb25wLXBvbGxpbmcuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L2xpYi9hamF4LWJhc2VkLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9saWIvYnVmZmVyZWQtc2VuZGVyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9saWIvaWZyYW1lLXdyYXAuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L2xpYi9wb2xsaW5nLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9saWIvc2VuZGVyLXJlY2VpdmVyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9yZWNlaXZlci9ldmVudHNvdXJjZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi90cmFuc3BvcnQvcmVjZWl2ZXIvaHRtbGZpbGUuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3JlY2VpdmVyL2pzb25wLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9yZWNlaXZlci94aHIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3NlbmRlci9qc29ucC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi90cmFuc3BvcnQvc2VuZGVyL3hkci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi90cmFuc3BvcnQvc2VuZGVyL3hoci1jb3JzLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC9zZW5kZXIveGhyLWZha2UuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3NlbmRlci94aHItbG9jYWwuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3dlYnNvY2tldC5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi90cmFuc3BvcnQveGRyLXBvbGxpbmcuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3hkci1zdHJlYW1pbmcuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdHJhbnNwb3J0L3hoci1wb2xsaW5nLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3RyYW5zcG9ydC94aHItc3RyZWFtaW5nLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3V0aWxzL2Jyb3dzZXItY3J5cHRvLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3V0aWxzL2Jyb3dzZXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdXRpbHMvZXNjYXBlLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3V0aWxzL2V2ZW50LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3V0aWxzL2lmcmFtZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi91dGlscy9sb2cuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdXRpbHMvb2JqZWN0LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3V0aWxzL3JhbmRvbS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy9zb2NranMtY2xpZW50L2xpYi91dGlscy90cmFuc3BvcnQuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvc29ja2pzLWNsaWVudC9saWIvdXRpbHMvdXJsLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3NvY2tqcy1jbGllbnQvbGliL3ZlcnNpb24uanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvdWEtcGFyc2VyLWpzL3NyYy91YS1wYXJzZXIuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvdXJsLXBhcnNlL2luZGV4LmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3VybC1wYXJzZS9ub2RlX21vZHVsZXMvcXVlcnlzdHJpbmdpZnkvaW5kZXguanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvdXVpZC9ybmctYnJvd3Nlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy91dWlkL3V1aWQuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL2FkYXB0ZXJfY29yZS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93ZWJydGMtYWRhcHRlci9zcmMvanMvY2hyb21lL2Nocm9tZV9zaGltLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dlYnJ0Yy1hZGFwdGVyL3NyYy9qcy9jaHJvbWUvZ2V0dXNlcm1lZGlhLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dlYnJ0Yy1hZGFwdGVyL3NyYy9qcy9lZGdlL2VkZ2Vfc2hpbS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93ZWJydGMtYWRhcHRlci9zcmMvanMvZWRnZS9nZXR1c2VybWVkaWEuanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL2VkZ2UvcnRjcGVlcmNvbm5lY3Rpb25fc2hpbS5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93ZWJydGMtYWRhcHRlci9zcmMvanMvZmlyZWZveC9maXJlZm94X3NoaW0uanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL2ZpcmVmb3gvZ2V0dXNlcm1lZGlhLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dlYnJ0Yy1hZGFwdGVyL3NyYy9qcy9zYWZhcmkvc2FmYXJpX3NoaW0uanMiLCIuLi8uLi9ub2RlX21vZHVsZXMvd2VicnRjLWFkYXB0ZXIvc3JjL2pzL3V0aWxzLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dpbGRlbWl0dGVyL3dpbGRlbWl0dGVyLmpzIiwiLi4vLi4vbm9kZV9tb2R1bGVzL3dvbGZ5ODctZXZlbnRlbWl0dGVyL0V2ZW50RW1pdHRlci5qcyIsIi4uLy4uL25vZGVfbW9kdWxlcy93cy9saWIvYnJvd3Nlci5qcyIsIk1haW4udHMiLCJPcGVuVmlkdS50cyIsIlB1Ymxpc2hlci50cyIsIlNlc3Npb24udHMiLCJTdWJzY3JpYmVyLnRzIiwiLi4vT3BlblZpZHVJbnRlcm5hbC9Db25uZWN0aW9uLnRzIiwiLi4vT3BlblZpZHVJbnRlcm5hbC9PcGVuVmlkdUludGVybmFsLnRzIiwiLi4vT3BlblZpZHVJbnRlcm5hbC9TZXNzaW9uSW50ZXJuYWwudHMiLCIuLi9PcGVuVmlkdUludGVybmFsL1N0cmVhbS50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Vzci9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2V2ZW50cy9ldmVudHMuanMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi91c3IvbGliL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9wcm9jZXNzL2Jyb3dzZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDekxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMU1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hCQTtBQUNBOztBQ0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDdDRCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5TkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3J6QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDendCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4SkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUM5bEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUMzQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDdEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ2pDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUNyRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ3pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ1ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDN1hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6ZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ2xCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ2pNQTtBQUNBOzs7OztBQ0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ1JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUN6QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDN0lBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDbENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ3ZGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUNqQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDekRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQzdDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUMvREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDdkZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ3ZMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ3RFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUNuR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ3ZHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDbEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDakNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUN6Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQzNCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUN6RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUMzTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNsQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDN0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUNsREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDL0NBO0FBQ0E7O0FDREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ241QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDdlpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUN4RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDaENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4VkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdktBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtB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R0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsR0FBRyxZQUFZLEdBQUcsSUFBSSxDQUFDLEVBQUUsR0FBRyxZQUFZLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBQ0wsYUFBQztBQUFELENBdmxCQSxBQXVsQkMsSUFBQTtBQXZsQlksd0JBQU07OztBQ2pEbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlTQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qKlxuICogVGhpcyBpcyB0aGUgd2ViIGJyb3dzZXIgaW1wbGVtZW50YXRpb24gb2YgYGRlYnVnKClgLlxuICpcbiAqIEV4cG9zZSBgZGVidWcoKWAgYXMgdGhlIG1vZHVsZS5cbiAqL1xuXG5leHBvcnRzID0gbW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL2RlYnVnJyk7XG5leHBvcnRzLmxvZyA9IGxvZztcbmV4cG9ydHMuZm9ybWF0QXJncyA9IGZvcm1hdEFyZ3M7XG5leHBvcnRzLnNhdmUgPSBzYXZlO1xuZXhwb3J0cy5sb2FkID0gbG9hZDtcbmV4cG9ydHMudXNlQ29sb3JzID0gdXNlQ29sb3JzO1xuZXhwb3J0cy5zdG9yYWdlID0gJ3VuZGVmaW5lZCcgIT0gdHlwZW9mIGNocm9tZVxuICAgICAgICAgICAgICAgJiYgJ3VuZGVmaW5lZCcgIT0gdHlwZW9mIGNocm9tZS5zdG9yYWdlXG4gICAgICAgICAgICAgICAgICA/IGNocm9tZS5zdG9yYWdlLmxvY2FsXG4gICAgICAgICAgICAgICAgICA6IGxvY2Fsc3RvcmFnZSgpO1xuXG4vKipcbiAqIENvbG9ycy5cbiAqL1xuXG5leHBvcnRzLmNvbG9ycyA9IFtcbiAgJ2xpZ2h0c2VhZ3JlZW4nLFxuICAnZm9yZXN0Z3JlZW4nLFxuICAnZ29sZGVucm9kJyxcbiAgJ2RvZGdlcmJsdWUnLFxuICAnZGFya29yY2hpZCcsXG4gICdjcmltc29uJ1xuXTtcblxuLyoqXG4gKiBDdXJyZW50bHkgb25seSBXZWJLaXQtYmFzZWQgV2ViIEluc3BlY3RvcnMsIEZpcmVmb3ggPj0gdjMxLFxuICogYW5kIHRoZSBGaXJlYnVnIGV4dGVuc2lvbiAoYW55IEZpcmVmb3ggdmVyc2lvbikgYXJlIGtub3duXG4gKiB0byBzdXBwb3J0IFwiJWNcIiBDU1MgY3VzdG9taXphdGlvbnMuXG4gKlxuICogVE9ETzogYWRkIGEgYGxvY2FsU3RvcmFnZWAgdmFyaWFibGUgdG8gZXhwbGljaXRseSBlbmFibGUvZGlzYWJsZSBjb2xvcnNcbiAqL1xuXG5mdW5jdGlvbiB1c2VDb2xvcnMoKSB7XG4gIC8vIE5COiBJbiBhbiBFbGVjdHJvbiBwcmVsb2FkIHNjcmlwdCwgZG9jdW1lbnQgd2lsbCBiZSBkZWZpbmVkIGJ1dCBub3QgZnVsbHlcbiAgLy8gaW5pdGlhbGl6ZWQuIFNpbmNlIHdlIGtub3cgd2UncmUgaW4gQ2hyb21lLCB3ZSdsbCBqdXN0IGRldGVjdCB0aGlzIGNhc2VcbiAgLy8gZXhwbGljaXRseVxuICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgd2luZG93LnByb2Nlc3MgJiYgd2luZG93LnByb2Nlc3MudHlwZSA9PT0gJ3JlbmRlcmVyJykge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLy8gaXMgd2Via2l0PyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8xNjQ1OTYwNi8zNzY3NzNcbiAgLy8gZG9jdW1lbnQgaXMgdW5kZWZpbmVkIGluIHJlYWN0LW5hdGl2ZTogaHR0cHM6Ly9naXRodWIuY29tL2ZhY2Vib29rL3JlYWN0LW5hdGl2ZS9wdWxsLzE2MzJcbiAgcmV0dXJuICh0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCAmJiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUgJiYgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlLldlYmtpdEFwcGVhcmFuY2UpIHx8XG4gICAgLy8gaXMgZmlyZWJ1Zz8gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzk4MTIwLzM3Njc3M1xuICAgICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiB3aW5kb3cuY29uc29sZSAmJiAod2luZG93LmNvbnNvbGUuZmlyZWJ1ZyB8fCAod2luZG93LmNvbnNvbGUuZXhjZXB0aW9uICYmIHdpbmRvdy5jb25zb2xlLnRhYmxlKSkpIHx8XG4gICAgLy8gaXMgZmlyZWZveCA+PSB2MzE/XG4gICAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9Ub29scy9XZWJfQ29uc29sZSNTdHlsaW5nX21lc3NhZ2VzXG4gICAgKHR5cGVvZiBuYXZpZ2F0b3IgIT09ICd1bmRlZmluZWQnICYmIG5hdmlnYXRvci51c2VyQWdlbnQgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudC50b0xvd2VyQ2FzZSgpLm1hdGNoKC9maXJlZm94XFwvKFxcZCspLykgJiYgcGFyc2VJbnQoUmVnRXhwLiQxLCAxMCkgPj0gMzEpIHx8XG4gICAgLy8gZG91YmxlIGNoZWNrIHdlYmtpdCBpbiB1c2VyQWdlbnQganVzdCBpbiBjYXNlIHdlIGFyZSBpbiBhIHdvcmtlclxuICAgICh0eXBlb2YgbmF2aWdhdG9yICE9PSAndW5kZWZpbmVkJyAmJiBuYXZpZ2F0b3IudXNlckFnZW50ICYmIG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5tYXRjaCgvYXBwbGV3ZWJraXRcXC8oXFxkKykvKSk7XG59XG5cbi8qKlxuICogTWFwICVqIHRvIGBKU09OLnN0cmluZ2lmeSgpYCwgc2luY2Ugbm8gV2ViIEluc3BlY3RvcnMgZG8gdGhhdCBieSBkZWZhdWx0LlxuICovXG5cbmV4cG9ydHMuZm9ybWF0dGVycy5qID0gZnVuY3Rpb24odikge1xuICB0cnkge1xuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh2KTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgcmV0dXJuICdbVW5leHBlY3RlZEpTT05QYXJzZUVycm9yXTogJyArIGVyci5tZXNzYWdlO1xuICB9XG59O1xuXG5cbi8qKlxuICogQ29sb3JpemUgbG9nIGFyZ3VtZW50cyBpZiBlbmFibGVkLlxuICpcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gZm9ybWF0QXJncyhhcmdzKSB7XG4gIHZhciB1c2VDb2xvcnMgPSB0aGlzLnVzZUNvbG9ycztcblxuICBhcmdzWzBdID0gKHVzZUNvbG9ycyA/ICclYycgOiAnJylcbiAgICArIHRoaXMubmFtZXNwYWNlXG4gICAgKyAodXNlQ29sb3JzID8gJyAlYycgOiAnICcpXG4gICAgKyBhcmdzWzBdXG4gICAgKyAodXNlQ29sb3JzID8gJyVjICcgOiAnICcpXG4gICAgKyAnKycgKyBleHBvcnRzLmh1bWFuaXplKHRoaXMuZGlmZik7XG5cbiAgaWYgKCF1c2VDb2xvcnMpIHJldHVybjtcblxuICB2YXIgYyA9ICdjb2xvcjogJyArIHRoaXMuY29sb3I7XG4gIGFyZ3Muc3BsaWNlKDEsIDAsIGMsICdjb2xvcjogaW5oZXJpdCcpXG5cbiAgLy8gdGhlIGZpbmFsIFwiJWNcIiBpcyBzb21ld2hhdCB0cmlja3ksIGJlY2F1c2UgdGhlcmUgY291bGQgYmUgb3RoZXJcbiAgLy8gYXJndW1lbnRzIHBhc3NlZCBlaXRoZXIgYmVmb3JlIG9yIGFmdGVyIHRoZSAlYywgc28gd2UgbmVlZCB0b1xuICAvLyBmaWd1cmUgb3V0IHRoZSBjb3JyZWN0IGluZGV4IHRvIGluc2VydCB0aGUgQ1NTIGludG9cbiAgdmFyIGluZGV4ID0gMDtcbiAgdmFyIGxhc3RDID0gMDtcbiAgYXJnc1swXS5yZXBsYWNlKC8lW2EtekEtWiVdL2csIGZ1bmN0aW9uKG1hdGNoKSB7XG4gICAgaWYgKCclJScgPT09IG1hdGNoKSByZXR1cm47XG4gICAgaW5kZXgrKztcbiAgICBpZiAoJyVjJyA9PT0gbWF0Y2gpIHtcbiAgICAgIC8vIHdlIG9ubHkgYXJlIGludGVyZXN0ZWQgaW4gdGhlICpsYXN0KiAlY1xuICAgICAgLy8gKHRoZSB1c2VyIG1heSBoYXZlIHByb3ZpZGVkIHRoZWlyIG93bilcbiAgICAgIGxhc3RDID0gaW5kZXg7XG4gICAgfVxuICB9KTtcblxuICBhcmdzLnNwbGljZShsYXN0QywgMCwgYyk7XG59XG5cbi8qKlxuICogSW52b2tlcyBgY29uc29sZS5sb2coKWAgd2hlbiBhdmFpbGFibGUuXG4gKiBOby1vcCB3aGVuIGBjb25zb2xlLmxvZ2AgaXMgbm90IGEgXCJmdW5jdGlvblwiLlxuICpcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gbG9nKCkge1xuICAvLyB0aGlzIGhhY2tlcnkgaXMgcmVxdWlyZWQgZm9yIElFOC85LCB3aGVyZVxuICAvLyB0aGUgYGNvbnNvbGUubG9nYCBmdW5jdGlvbiBkb2Vzbid0IGhhdmUgJ2FwcGx5J1xuICByZXR1cm4gJ29iamVjdCcgPT09IHR5cGVvZiBjb25zb2xlXG4gICAgJiYgY29uc29sZS5sb2dcbiAgICAmJiBGdW5jdGlvbi5wcm90b3R5cGUuYXBwbHkuY2FsbChjb25zb2xlLmxvZywgY29uc29sZSwgYXJndW1lbnRzKTtcbn1cblxuLyoqXG4gKiBTYXZlIGBuYW1lc3BhY2VzYC5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZXNwYWNlc1xuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gc2F2ZShuYW1lc3BhY2VzKSB7XG4gIHRyeSB7XG4gICAgaWYgKG51bGwgPT0gbmFtZXNwYWNlcykge1xuICAgICAgZXhwb3J0cy5zdG9yYWdlLnJlbW92ZUl0ZW0oJ2RlYnVnJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGV4cG9ydHMuc3RvcmFnZS5kZWJ1ZyA9IG5hbWVzcGFjZXM7XG4gICAgfVxuICB9IGNhdGNoKGUpIHt9XG59XG5cbi8qKlxuICogTG9hZCBgbmFtZXNwYWNlc2AuXG4gKlxuICogQHJldHVybiB7U3RyaW5nfSByZXR1cm5zIHRoZSBwcmV2aW91c2x5IHBlcnNpc3RlZCBkZWJ1ZyBtb2Rlc1xuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gbG9hZCgpIHtcbiAgdmFyIHI7XG4gIHRyeSB7XG4gICAgciA9IGV4cG9ydHMuc3RvcmFnZS5kZWJ1ZztcbiAgfSBjYXRjaChlKSB7fVxuXG4gIC8vIElmIGRlYnVnIGlzbid0IHNldCBpbiBMUywgYW5kIHdlJ3JlIGluIEVsZWN0cm9uLCB0cnkgdG8gbG9hZCAkREVCVUdcbiAgaWYgKCFyICYmIHR5cGVvZiBwcm9jZXNzICE9PSAndW5kZWZpbmVkJyAmJiAnZW52JyBpbiBwcm9jZXNzKSB7XG4gICAgciA9IHByb2Nlc3MuZW52LkRFQlVHO1xuICB9XG5cbiAgcmV0dXJuIHI7XG59XG5cbi8qKlxuICogRW5hYmxlIG5hbWVzcGFjZXMgbGlzdGVkIGluIGBsb2NhbFN0b3JhZ2UuZGVidWdgIGluaXRpYWxseS5cbiAqL1xuXG5leHBvcnRzLmVuYWJsZShsb2FkKCkpO1xuXG4vKipcbiAqIExvY2Fsc3RvcmFnZSBhdHRlbXB0cyB0byByZXR1cm4gdGhlIGxvY2Fsc3RvcmFnZS5cbiAqXG4gKiBUaGlzIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIHNhZmFyaSB0aHJvd3NcbiAqIHdoZW4gYSB1c2VyIGRpc2FibGVzIGNvb2tpZXMvbG9jYWxzdG9yYWdlXG4gKiBhbmQgeW91IGF0dGVtcHQgdG8gYWNjZXNzIGl0LlxuICpcbiAqIEByZXR1cm4ge0xvY2FsU3RvcmFnZX1cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5cbmZ1bmN0aW9uIGxvY2Fsc3RvcmFnZSgpIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gd2luZG93LmxvY2FsU3RvcmFnZTtcbiAgfSBjYXRjaCAoZSkge31cbn1cbiIsIlxuLyoqXG4gKiBUaGlzIGlzIHRoZSBjb21tb24gbG9naWMgZm9yIGJvdGggdGhlIE5vZGUuanMgYW5kIHdlYiBicm93c2VyXG4gKiBpbXBsZW1lbnRhdGlvbnMgb2YgYGRlYnVnKClgLlxuICpcbiAqIEV4cG9zZSBgZGVidWcoKWAgYXMgdGhlIG1vZHVsZS5cbiAqL1xuXG5leHBvcnRzID0gbW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVEZWJ1Zy5kZWJ1ZyA9IGNyZWF0ZURlYnVnWydkZWZhdWx0J10gPSBjcmVhdGVEZWJ1ZztcbmV4cG9ydHMuY29lcmNlID0gY29lcmNlO1xuZXhwb3J0cy5kaXNhYmxlID0gZGlzYWJsZTtcbmV4cG9ydHMuZW5hYmxlID0gZW5hYmxlO1xuZXhwb3J0cy5lbmFibGVkID0gZW5hYmxlZDtcbmV4cG9ydHMuaHVtYW5pemUgPSByZXF1aXJlKCdtcycpO1xuXG4vKipcbiAqIFRoZSBjdXJyZW50bHkgYWN0aXZlIGRlYnVnIG1vZGUgbmFtZXMsIGFuZCBuYW1lcyB0byBza2lwLlxuICovXG5cbmV4cG9ydHMubmFtZXMgPSBbXTtcbmV4cG9ydHMuc2tpcHMgPSBbXTtcblxuLyoqXG4gKiBNYXAgb2Ygc3BlY2lhbCBcIiVuXCIgaGFuZGxpbmcgZnVuY3Rpb25zLCBmb3IgdGhlIGRlYnVnIFwiZm9ybWF0XCIgYXJndW1lbnQuXG4gKlxuICogVmFsaWQga2V5IG5hbWVzIGFyZSBhIHNpbmdsZSwgbG93ZXIgb3IgdXBwZXItY2FzZSBsZXR0ZXIsIGkuZS4gXCJuXCIgYW5kIFwiTlwiLlxuICovXG5cbmV4cG9ydHMuZm9ybWF0dGVycyA9IHt9O1xuXG4vKipcbiAqIFByZXZpb3VzIGxvZyB0aW1lc3RhbXAuXG4gKi9cblxudmFyIHByZXZUaW1lO1xuXG4vKipcbiAqIFNlbGVjdCBhIGNvbG9yLlxuICogQHBhcmFtIHtTdHJpbmd9IG5hbWVzcGFjZVxuICogQHJldHVybiB7TnVtYmVyfVxuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gc2VsZWN0Q29sb3IobmFtZXNwYWNlKSB7XG4gIHZhciBoYXNoID0gMCwgaTtcblxuICBmb3IgKGkgaW4gbmFtZXNwYWNlKSB7XG4gICAgaGFzaCAgPSAoKGhhc2ggPDwgNSkgLSBoYXNoKSArIG5hbWVzcGFjZS5jaGFyQ29kZUF0KGkpO1xuICAgIGhhc2ggfD0gMDsgLy8gQ29udmVydCB0byAzMmJpdCBpbnRlZ2VyXG4gIH1cblxuICByZXR1cm4gZXhwb3J0cy5jb2xvcnNbTWF0aC5hYnMoaGFzaCkgJSBleHBvcnRzLmNvbG9ycy5sZW5ndGhdO1xufVxuXG4vKipcbiAqIENyZWF0ZSBhIGRlYnVnZ2VyIHdpdGggdGhlIGdpdmVuIGBuYW1lc3BhY2VgLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lc3BhY2VcbiAqIEByZXR1cm4ge0Z1bmN0aW9ufVxuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5mdW5jdGlvbiBjcmVhdGVEZWJ1ZyhuYW1lc3BhY2UpIHtcblxuICBmdW5jdGlvbiBkZWJ1ZygpIHtcbiAgICAvLyBkaXNhYmxlZD9cbiAgICBpZiAoIWRlYnVnLmVuYWJsZWQpIHJldHVybjtcblxuICAgIHZhciBzZWxmID0gZGVidWc7XG5cbiAgICAvLyBzZXQgYGRpZmZgIHRpbWVzdGFtcFxuICAgIHZhciBjdXJyID0gK25ldyBEYXRlKCk7XG4gICAgdmFyIG1zID0gY3VyciAtIChwcmV2VGltZSB8fCBjdXJyKTtcbiAgICBzZWxmLmRpZmYgPSBtcztcbiAgICBzZWxmLnByZXYgPSBwcmV2VGltZTtcbiAgICBzZWxmLmN1cnIgPSBjdXJyO1xuICAgIHByZXZUaW1lID0gY3VycjtcblxuICAgIC8vIHR1cm4gdGhlIGBhcmd1bWVudHNgIGludG8gYSBwcm9wZXIgQXJyYXlcbiAgICB2YXIgYXJncyA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcbiAgICAgIGFyZ3NbaV0gPSBhcmd1bWVudHNbaV07XG4gICAgfVxuXG4gICAgYXJnc1swXSA9IGV4cG9ydHMuY29lcmNlKGFyZ3NbMF0pO1xuXG4gICAgaWYgKCdzdHJpbmcnICE9PSB0eXBlb2YgYXJnc1swXSkge1xuICAgICAgLy8gYW55dGhpbmcgZWxzZSBsZXQncyBpbnNwZWN0IHdpdGggJU9cbiAgICAgIGFyZ3MudW5zaGlmdCgnJU8nKTtcbiAgICB9XG5cbiAgICAvLyBhcHBseSBhbnkgYGZvcm1hdHRlcnNgIHRyYW5zZm9ybWF0aW9uc1xuICAgIHZhciBpbmRleCA9IDA7XG4gICAgYXJnc1swXSA9IGFyZ3NbMF0ucmVwbGFjZSgvJShbYS16QS1aJV0pL2csIGZ1bmN0aW9uKG1hdGNoLCBmb3JtYXQpIHtcbiAgICAgIC8vIGlmIHdlIGVuY291bnRlciBhbiBlc2NhcGVkICUgdGhlbiBkb24ndCBpbmNyZWFzZSB0aGUgYXJyYXkgaW5kZXhcbiAgICAgIGlmIChtYXRjaCA9PT0gJyUlJykgcmV0dXJuIG1hdGNoO1xuICAgICAgaW5kZXgrKztcbiAgICAgIHZhciBmb3JtYXR0ZXIgPSBleHBvcnRzLmZvcm1hdHRlcnNbZm9ybWF0XTtcbiAgICAgIGlmICgnZnVuY3Rpb24nID09PSB0eXBlb2YgZm9ybWF0dGVyKSB7XG4gICAgICAgIHZhciB2YWwgPSBhcmdzW2luZGV4XTtcbiAgICAgICAgbWF0Y2ggPSBmb3JtYXR0ZXIuY2FsbChzZWxmLCB2YWwpO1xuXG4gICAgICAgIC8vIG5vdyB3ZSBuZWVkIHRvIHJlbW92ZSBgYXJnc1tpbmRleF1gIHNpbmNlIGl0J3MgaW5saW5lZCBpbiB0aGUgYGZvcm1hdGBcbiAgICAgICAgYXJncy5zcGxpY2UoaW5kZXgsIDEpO1xuICAgICAgICBpbmRleC0tO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG1hdGNoO1xuICAgIH0pO1xuXG4gICAgLy8gYXBwbHkgZW52LXNwZWNpZmljIGZvcm1hdHRpbmcgKGNvbG9ycywgZXRjLilcbiAgICBleHBvcnRzLmZvcm1hdEFyZ3MuY2FsbChzZWxmLCBhcmdzKTtcblxuICAgIHZhciBsb2dGbiA9IGRlYnVnLmxvZyB8fCBleHBvcnRzLmxvZyB8fCBjb25zb2xlLmxvZy5iaW5kKGNvbnNvbGUpO1xuICAgIGxvZ0ZuLmFwcGx5KHNlbGYsIGFyZ3MpO1xuICB9XG5cbiAgZGVidWcubmFtZXNwYWNlID0gbmFtZXNwYWNlO1xuICBkZWJ1Zy5lbmFibGVkID0gZXhwb3J0cy5lbmFibGVkKG5hbWVzcGFjZSk7XG4gIGRlYnVnLnVzZUNvbG9ycyA9IGV4cG9ydHMudXNlQ29sb3JzKCk7XG4gIGRlYnVnLmNvbG9yID0gc2VsZWN0Q29sb3IobmFtZXNwYWNlKTtcblxuICAvLyBlbnYtc3BlY2lmaWMgaW5pdGlhbGl6YXRpb24gbG9naWMgZm9yIGRlYnVnIGluc3RhbmNlc1xuICBpZiAoJ2Z1bmN0aW9uJyA9PT0gdHlwZW9mIGV4cG9ydHMuaW5pdCkge1xuICAgIGV4cG9ydHMuaW5pdChkZWJ1Zyk7XG4gIH1cblxuICByZXR1cm4gZGVidWc7XG59XG5cbi8qKlxuICogRW5hYmxlcyBhIGRlYnVnIG1vZGUgYnkgbmFtZXNwYWNlcy4gVGhpcyBjYW4gaW5jbHVkZSBtb2Rlc1xuICogc2VwYXJhdGVkIGJ5IGEgY29sb24gYW5kIHdpbGRjYXJkcy5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZXNwYWNlc1xuICogQGFwaSBwdWJsaWNcbiAqL1xuXG5mdW5jdGlvbiBlbmFibGUobmFtZXNwYWNlcykge1xuICBleHBvcnRzLnNhdmUobmFtZXNwYWNlcyk7XG5cbiAgZXhwb3J0cy5uYW1lcyA9IFtdO1xuICBleHBvcnRzLnNraXBzID0gW107XG5cbiAgdmFyIHNwbGl0ID0gKHR5cGVvZiBuYW1lc3BhY2VzID09PSAnc3RyaW5nJyA/IG5hbWVzcGFjZXMgOiAnJykuc3BsaXQoL1tcXHMsXSsvKTtcbiAgdmFyIGxlbiA9IHNwbGl0Lmxlbmd0aDtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgaWYgKCFzcGxpdFtpXSkgY29udGludWU7IC8vIGlnbm9yZSBlbXB0eSBzdHJpbmdzXG4gICAgbmFtZXNwYWNlcyA9IHNwbGl0W2ldLnJlcGxhY2UoL1xcKi9nLCAnLio/Jyk7XG4gICAgaWYgKG5hbWVzcGFjZXNbMF0gPT09ICctJykge1xuICAgICAgZXhwb3J0cy5za2lwcy5wdXNoKG5ldyBSZWdFeHAoJ14nICsgbmFtZXNwYWNlcy5zdWJzdHIoMSkgKyAnJCcpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZXhwb3J0cy5uYW1lcy5wdXNoKG5ldyBSZWdFeHAoJ14nICsgbmFtZXNwYWNlcyArICckJykpO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIERpc2FibGUgZGVidWcgb3V0cHV0LlxuICpcbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gZGlzYWJsZSgpIHtcbiAgZXhwb3J0cy5lbmFibGUoJycpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgZ2l2ZW4gbW9kZSBuYW1lIGlzIGVuYWJsZWQsIGZhbHNlIG90aGVyd2lzZS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqIEBhcGkgcHVibGljXG4gKi9cblxuZnVuY3Rpb24gZW5hYmxlZChuYW1lKSB7XG4gIHZhciBpLCBsZW47XG4gIGZvciAoaSA9IDAsIGxlbiA9IGV4cG9ydHMuc2tpcHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICBpZiAoZXhwb3J0cy5za2lwc1tpXS50ZXN0KG5hbWUpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG4gIGZvciAoaSA9IDAsIGxlbiA9IGV4cG9ydHMubmFtZXMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICBpZiAoZXhwb3J0cy5uYW1lc1tpXS50ZXN0KG5hbWUpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKipcbiAqIENvZXJjZSBgdmFsYC5cbiAqXG4gKiBAcGFyYW0ge01peGVkfSB2YWxcbiAqIEByZXR1cm4ge01peGVkfVxuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gY29lcmNlKHZhbCkge1xuICBpZiAodmFsIGluc3RhbmNlb2YgRXJyb3IpIHJldHVybiB2YWwuc3RhY2sgfHwgdmFsLm1lc3NhZ2U7XG4gIHJldHVybiB2YWw7XG59XG4iLCIvKiBqc2hpbnQgbm9kZTogdHJ1ZSAqL1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgbm9ybWFsaWNlID0gcmVxdWlyZSgnbm9ybWFsaWNlJyk7XG5cbi8qKlxuICAjIGZyZWVpY2VcblxuICBUaGUgYGZyZWVpY2VgIG1vZHVsZSBpcyBhIHNpbXBsZSB3YXkgb2YgZ2V0dGluZyByYW5kb20gU1RVTiBvciBUVVJOIHNlcnZlclxuICBmb3IgeW91ciBXZWJSVEMgYXBwbGljYXRpb24uICBUaGUgbGlzdCBvZiBzZXJ2ZXJzIChqdXN0IFNUVU4gYXQgdGhpcyBzdGFnZSlcbiAgd2VyZSBzb3VyY2VkIGZyb20gdGhpcyBbZ2lzdF0oaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20venppdW5pLzM3NDE5MzMpLlxuXG4gICMjIEV4YW1wbGUgVXNlXG5cbiAgVGhlIGZvbGxvd2luZyBkZW1vbnN0cmF0ZXMgaG93IHlvdSBjYW4gdXNlIGBmcmVlaWNlYCB3aXRoXG4gIFtydGMtcXVpY2tjb25uZWN0XShodHRwczovL2dpdGh1Yi5jb20vcnRjLWlvL3J0Yy1xdWlja2Nvbm5lY3QpOlxuXG4gIDw8PCBleGFtcGxlcy9xdWlja2Nvbm5lY3QuanNcblxuICBBcyB0aGUgYGZyZWVpY2VgIG1vZHVsZSBnZW5lcmF0ZXMgaWNlIHNlcnZlcnMgaW4gYSBsaXN0IGNvbXBsaWFudCB3aXRoIHRoZVxuICBXZWJSVEMgc3BlYyB5b3Ugd2lsbCBiZSBhYmxlIHRvIHVzZSBpdCB3aXRoIHJhdyBgUlRDUGVlckNvbm5lY3Rpb25gXG4gIGNvbnN0cnVjdG9ycyBhbmQgb3RoZXIgV2ViUlRDIGxpYnJhcmllcy5cblxuICAjIyBIZXksIGRvbid0IHVzZSBteSBTVFVOL1RVUk4gc2VydmVyIVxuXG4gIElmIGZvciBzb21lIHJlYXNvbiB5b3VyIGZyZWUgU1RVTiBvciBUVVJOIHNlcnZlciBlbmRzIHVwIGluIHRoZVxuICBsaXN0IG9mIHNlcnZlcnMgKFtzdHVuXShodHRwczovL2dpdGh1Yi5jb20vRGFtb25PZWhsbWFuL2ZyZWVpY2UvYmxvYi9tYXN0ZXIvc3R1bi5qc29uKSBvclxuICBbdHVybl0oaHR0cHM6Ly9naXRodWIuY29tL0RhbW9uT2VobG1hbi9mcmVlaWNlL2Jsb2IvbWFzdGVyL3R1cm4uanNvbikpXG4gIHRoYXQgaXMgdXNlZCBpbiB0aGlzIG1vZHVsZSwgeW91IGNhbiBmZWVsXG4gIGZyZWUgdG8gb3BlbiBhbiBpc3N1ZSBvbiB0aGlzIHJlcG9zaXRvcnkgYW5kIHRob3NlIHNlcnZlcnMgd2lsbCBiZSByZW1vdmVkXG4gIHdpdGhpbiAyNCBob3VycyAob3Igc29vbmVyKS4gIFRoaXMgaXMgdGhlIHF1aWNrZXN0IGFuZCBwcm9iYWJseSB0aGUgbW9zdFxuICBwb2xpdGUgd2F5IHRvIGhhdmUgc29tZXRoaW5nIHJlbW92ZWQgKGFuZCBwcm92aWRlcyB1cyBzb21lIHZpc2liaWxpdHlcbiAgaWYgc29tZW9uZSBvcGVucyBhIHB1bGwgcmVxdWVzdCByZXF1ZXN0aW5nIHRoYXQgYSBzZXJ2ZXIgaXMgYWRkZWQpLlxuXG4gICMjIFBsZWFzZSBhZGQgbXkgc2VydmVyIVxuXG4gIElmIHlvdSBoYXZlIGEgc2VydmVyIHRoYXQgeW91IHdpc2ggdG8gYWRkIHRvIHRoZSBsaXN0LCB0aGF0J3MgYXdlc29tZSEgSSdtXG4gIHN1cmUgSSBzcGVhayBvbiBiZWhhbGYgb2YgYSB3aG9sZSBwaWxlIG9mIFdlYlJUQyBkZXZlbG9wZXJzIHdobyBzYXkgdGhhbmtzLlxuICBUbyBnZXQgaXQgaW50byB0aGUgbGlzdCwgZmVlbCBmcmVlIHRvIGVpdGhlciBvcGVuIGEgcHVsbCByZXF1ZXN0IG9yIGlmIHlvdVxuICBmaW5kIHRoYXQgcHJvY2VzcyBhIGJpdCBkYXVudGluZyB0aGVuIGp1c3QgY3JlYXRlIGFuIGlzc3VlIHJlcXVlc3RpbmdcbiAgdGhlIGFkZGl0aW9uIG9mIHRoZSBzZXJ2ZXIgKG1ha2Ugc3VyZSB5b3UgcHJvdmlkZSBhbGwgdGhlIGRldGFpbHMsIGFuZCBpZlxuICB5b3UgaGF2ZSBhIFRlcm1zIG9mIFNlcnZpY2UgdGhlbiBpbmNsdWRpbmcgdGhhdCBpbiB0aGUgUFIvaXNzdWUgd291bGQgYmVcbiAgYXdlc29tZSkuXG5cbiAgIyMgSSBrbm93IG9mIGEgZnJlZSBzZXJ2ZXIsIGNhbiBJIGFkZCBpdD9cblxuICBTdXJlLCBpZiB5b3UgZG8geW91ciBob21ld29yayBhbmQgbWFrZSBzdXJlIGl0IGlzIG9rIHRvIHVzZSAoSSdtIGN1cnJlbnRseVxuICBpbiB0aGUgcHJvY2VzcyBvZiByZXZpZXdpbmcgdGhlIHRlcm1zIG9mIHRob3NlIFNUVU4gc2VydmVycyBpbmNsdWRlZCBmcm9tXG4gIHRoZSBvcmlnaW5hbCBsaXN0KS4gIElmIGl0J3Mgb2sgdG8gZ28sIHRoZW4gcGxlYXNlIHNlZSB0aGUgcHJldmlvdXMgZW50cnlcbiAgZm9yIGhvdyB0byBhZGQgaXQuXG5cbiAgIyMgQ3VycmVudCBMaXN0IG9mIFNlcnZlcnNcblxuICAqIGN1cnJlbnQgYXMgYXQgdGhlIHRpbWUgb2YgbGFzdCBgUkVBRE1FLm1kYCBmaWxlIGdlbmVyYXRpb25cblxuICAjIyMgU1RVTlxuXG4gIDw8PCBzdHVuLmpzb25cblxuICAjIyMgVFVSTlxuXG4gIDw8PCB0dXJuLmpzb25cblxuKiovXG5cbnZhciBmcmVlaWNlID0gbW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihvcHRzKSB7XG4gIC8vIGlmIGEgbGlzdCBvZiBzZXJ2ZXJzIGhhcyBiZWVuIHByb3ZpZGVkLCB0aGVuIHVzZSBpdCBpbnN0ZWFkIG9mIGRlZmF1bHRzXG4gIHZhciBzZXJ2ZXJzID0ge1xuICAgIHN0dW46IChvcHRzIHx8IHt9KS5zdHVuIHx8IHJlcXVpcmUoJy4vc3R1bi5qc29uJyksXG4gICAgdHVybjogKG9wdHMgfHwge30pLnR1cm4gfHwgcmVxdWlyZSgnLi90dXJuLmpzb24nKVxuICB9O1xuXG4gIHZhciBzdHVuQ291bnQgPSAob3B0cyB8fCB7fSkuc3R1bkNvdW50IHx8IDI7XG4gIHZhciB0dXJuQ291bnQgPSAob3B0cyB8fCB7fSkudHVybkNvdW50IHx8IDA7XG4gIHZhciBzZWxlY3RlZDtcblxuICBmdW5jdGlvbiBnZXRTZXJ2ZXJzKHR5cGUsIGNvdW50KSB7XG4gICAgdmFyIG91dCA9IFtdO1xuICAgIHZhciBpbnB1dCA9IFtdLmNvbmNhdChzZXJ2ZXJzW3R5cGVdKTtcbiAgICB2YXIgaWR4O1xuXG4gICAgd2hpbGUgKGlucHV0Lmxlbmd0aCAmJiBvdXQubGVuZ3RoIDwgY291bnQpIHtcbiAgICAgIGlkeCA9IChNYXRoLnJhbmRvbSgpICogaW5wdXQubGVuZ3RoKSB8IDA7XG4gICAgICBvdXQgPSBvdXQuY29uY2F0KGlucHV0LnNwbGljZShpZHgsIDEpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gb3V0Lm1hcChmdW5jdGlvbih1cmwpIHtcbiAgICAgICAgLy9JZiBpdCdzIGEgbm90IGEgc3RyaW5nLCBkb24ndCB0cnkgdG8gXCJub3JtYWxpY2VcIiBpdCBvdGhlcndpc2UgdXNpbmcgdHlwZTp1cmwgd2lsbCBzY3JldyBpdCB1cFxuICAgICAgICBpZiAoKHR5cGVvZiB1cmwgIT09ICdzdHJpbmcnKSAmJiAoISAodXJsIGluc3RhbmNlb2YgU3RyaW5nKSkpIHtcbiAgICAgICAgICAgIHJldHVybiB1cmw7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbm9ybWFsaWNlKHR5cGUgKyAnOicgKyB1cmwpO1xuICAgICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvLyBhZGQgc3R1biBzZXJ2ZXJzXG4gIHNlbGVjdGVkID0gW10uY29uY2F0KGdldFNlcnZlcnMoJ3N0dW4nLCBzdHVuQ291bnQpKTtcblxuICBpZiAodHVybkNvdW50KSB7XG4gICAgc2VsZWN0ZWQgPSBzZWxlY3RlZC5jb25jYXQoZ2V0U2VydmVycygndHVybicsIHR1cm5Db3VudCkpO1xuICB9XG5cbiAgcmV0dXJuIHNlbGVjdGVkO1xufTtcbiIsIm1vZHVsZS5leHBvcnRzPVtcbiAgXCJzdHVuLmwuZ29vZ2xlLmNvbToxOTMwMlwiLFxuICBcInN0dW4xLmwuZ29vZ2xlLmNvbToxOTMwMlwiLFxuICBcInN0dW4yLmwuZ29vZ2xlLmNvbToxOTMwMlwiLFxuICBcInN0dW4zLmwuZ29vZ2xlLmNvbToxOTMwMlwiLFxuICBcInN0dW40LmwuZ29vZ2xlLmNvbToxOTMwMlwiLFxuICBcInN0dW4uZWtpZ2EubmV0XCIsXG4gIFwic3R1bi5pZGVhc2lwLmNvbVwiLFxuICBcInN0dW4uc2NobHVuZC5kZVwiLFxuICBcInN0dW4uc3R1bnByb3RvY29sLm9yZzozNDc4XCIsXG4gIFwic3R1bi52b2lwYXJvdW5kLmNvbVwiLFxuICBcInN0dW4udm9pcGJ1c3Rlci5jb21cIixcbiAgXCJzdHVuLnZvaXBzdHVudC5jb21cIixcbiAgXCJzdHVuLnZveGdyYXRpYS5vcmdcIixcbiAgXCJzdHVuLnNlcnZpY2VzLm1vemlsbGEuY29tXCJcbl1cbiIsIm1vZHVsZS5leHBvcnRzPVtdXG4iLCJ2YXIgV2lsZEVtaXR0ZXIgPSByZXF1aXJlKCd3aWxkZW1pdHRlcicpO1xuXG5mdW5jdGlvbiBnZXRNYXhWb2x1bWUgKGFuYWx5c2VyLCBmZnRCaW5zKSB7XG4gIHZhciBtYXhWb2x1bWUgPSAtSW5maW5pdHk7XG4gIGFuYWx5c2VyLmdldEZsb2F0RnJlcXVlbmN5RGF0YShmZnRCaW5zKTtcblxuICBmb3IodmFyIGk9NCwgaWk9ZmZ0Qmlucy5sZW5ndGg7IGkgPCBpaTsgaSsrKSB7XG4gICAgaWYgKGZmdEJpbnNbaV0gPiBtYXhWb2x1bWUgJiYgZmZ0Qmluc1tpXSA8IDApIHtcbiAgICAgIG1heFZvbHVtZSA9IGZmdEJpbnNbaV07XG4gICAgfVxuICB9O1xuXG4gIHJldHVybiBtYXhWb2x1bWU7XG59XG5cblxudmFyIGF1ZGlvQ29udGV4dFR5cGUgPSB3aW5kb3cuQXVkaW9Db250ZXh0IHx8IHdpbmRvdy53ZWJraXRBdWRpb0NvbnRleHQ7XG4vLyB1c2UgYSBzaW5nbGUgYXVkaW8gY29udGV4dCBkdWUgdG8gaGFyZHdhcmUgbGltaXRzXG52YXIgYXVkaW9Db250ZXh0ID0gbnVsbDtcbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oc3RyZWFtLCBvcHRpb25zKSB7XG4gIHZhciBoYXJrZXIgPSBuZXcgV2lsZEVtaXR0ZXIoKTtcblxuXG4gIC8vIG1ha2UgaXQgbm90IGJyZWFrIGluIG5vbi1zdXBwb3J0ZWQgYnJvd3NlcnNcbiAgaWYgKCFhdWRpb0NvbnRleHRUeXBlKSByZXR1cm4gaGFya2VyO1xuXG4gIC8vQ29uZmlnXG4gIHZhciBvcHRpb25zID0gb3B0aW9ucyB8fCB7fSxcbiAgICAgIHNtb290aGluZyA9IChvcHRpb25zLnNtb290aGluZyB8fCAwLjEpLFxuICAgICAgaW50ZXJ2YWwgPSAob3B0aW9ucy5pbnRlcnZhbCB8fCA1MCksXG4gICAgICB0aHJlc2hvbGQgPSBvcHRpb25zLnRocmVzaG9sZCxcbiAgICAgIHBsYXkgPSBvcHRpb25zLnBsYXksXG4gICAgICBoaXN0b3J5ID0gb3B0aW9ucy5oaXN0b3J5IHx8IDEwLFxuICAgICAgcnVubmluZyA9IHRydWU7XG5cbiAgLy9TZXR1cCBBdWRpbyBDb250ZXh0XG4gIGlmICghYXVkaW9Db250ZXh0KSB7XG4gICAgYXVkaW9Db250ZXh0ID0gbmV3IGF1ZGlvQ29udGV4dFR5cGUoKTtcbiAgfVxuICB2YXIgc291cmNlTm9kZSwgZmZ0QmlucywgYW5hbHlzZXI7XG5cbiAgYW5hbHlzZXIgPSBhdWRpb0NvbnRleHQuY3JlYXRlQW5hbHlzZXIoKTtcbiAgYW5hbHlzZXIuZmZ0U2l6ZSA9IDUxMjtcbiAgYW5hbHlzZXIuc21vb3RoaW5nVGltZUNvbnN0YW50ID0gc21vb3RoaW5nO1xuICBmZnRCaW5zID0gbmV3IEZsb2F0MzJBcnJheShhbmFseXNlci5mZnRTaXplKTtcblxuICBpZiAoc3RyZWFtLmpxdWVyeSkgc3RyZWFtID0gc3RyZWFtWzBdO1xuICBpZiAoc3RyZWFtIGluc3RhbmNlb2YgSFRNTEF1ZGlvRWxlbWVudCB8fCBzdHJlYW0gaW5zdGFuY2VvZiBIVE1MVmlkZW9FbGVtZW50KSB7XG4gICAgLy9BdWRpbyBUYWdcbiAgICBzb3VyY2VOb2RlID0gYXVkaW9Db250ZXh0LmNyZWF0ZU1lZGlhRWxlbWVudFNvdXJjZShzdHJlYW0pO1xuICAgIGlmICh0eXBlb2YgcGxheSA9PT0gJ3VuZGVmaW5lZCcpIHBsYXkgPSB0cnVlO1xuICAgIHRocmVzaG9sZCA9IHRocmVzaG9sZCB8fCAtNTA7XG4gIH0gZWxzZSB7XG4gICAgLy9XZWJSVEMgU3RyZWFtXG4gICAgc291cmNlTm9kZSA9IGF1ZGlvQ29udGV4dC5jcmVhdGVNZWRpYVN0cmVhbVNvdXJjZShzdHJlYW0pO1xuICAgIHRocmVzaG9sZCA9IHRocmVzaG9sZCB8fCAtNTA7XG4gIH1cblxuICBzb3VyY2VOb2RlLmNvbm5lY3QoYW5hbHlzZXIpO1xuICBpZiAocGxheSkgYW5hbHlzZXIuY29ubmVjdChhdWRpb0NvbnRleHQuZGVzdGluYXRpb24pO1xuXG4gIGhhcmtlci5zcGVha2luZyA9IGZhbHNlO1xuXG4gIGhhcmtlci5zZXRUaHJlc2hvbGQgPSBmdW5jdGlvbih0KSB7XG4gICAgdGhyZXNob2xkID0gdDtcbiAgfTtcblxuICBoYXJrZXIuc2V0SW50ZXJ2YWwgPSBmdW5jdGlvbihpKSB7XG4gICAgaW50ZXJ2YWwgPSBpO1xuICB9O1xuICBcbiAgaGFya2VyLnN0b3AgPSBmdW5jdGlvbigpIHtcbiAgICBydW5uaW5nID0gZmFsc2U7XG4gICAgaGFya2VyLmVtaXQoJ3ZvbHVtZV9jaGFuZ2UnLCAtMTAwLCB0aHJlc2hvbGQpO1xuICAgIGlmIChoYXJrZXIuc3BlYWtpbmcpIHtcbiAgICAgIGhhcmtlci5zcGVha2luZyA9IGZhbHNlO1xuICAgICAgaGFya2VyLmVtaXQoJ3N0b3BwZWRfc3BlYWtpbmcnKTtcbiAgICB9XG4gIH07XG4gIGhhcmtlci5zcGVha2luZ0hpc3RvcnkgPSBbXTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBoaXN0b3J5OyBpKyspIHtcbiAgICAgIGhhcmtlci5zcGVha2luZ0hpc3RvcnkucHVzaCgwKTtcbiAgfVxuXG4gIC8vIFBvbGwgdGhlIGFuYWx5c2VyIG5vZGUgdG8gZGV0ZXJtaW5lIGlmIHNwZWFraW5nXG4gIC8vIGFuZCBlbWl0IGV2ZW50cyBpZiBjaGFuZ2VkXG4gIHZhciBsb29wZXIgPSBmdW5jdGlvbigpIHtcbiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgIFxuICAgICAgLy9jaGVjayBpZiBzdG9wIGhhcyBiZWVuIGNhbGxlZFxuICAgICAgaWYoIXJ1bm5pbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgXG4gICAgICB2YXIgY3VycmVudFZvbHVtZSA9IGdldE1heFZvbHVtZShhbmFseXNlciwgZmZ0Qmlucyk7XG5cbiAgICAgIGhhcmtlci5lbWl0KCd2b2x1bWVfY2hhbmdlJywgY3VycmVudFZvbHVtZSwgdGhyZXNob2xkKTtcblxuICAgICAgdmFyIGhpc3RvcnkgPSAwO1xuICAgICAgaWYgKGN1cnJlbnRWb2x1bWUgPiB0aHJlc2hvbGQgJiYgIWhhcmtlci5zcGVha2luZykge1xuICAgICAgICAvLyB0cmlnZ2VyIHF1aWNrbHksIHNob3J0IGhpc3RvcnlcbiAgICAgICAgZm9yICh2YXIgaSA9IGhhcmtlci5zcGVha2luZ0hpc3RvcnkubGVuZ3RoIC0gMzsgaSA8IGhhcmtlci5zcGVha2luZ0hpc3RvcnkubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICBoaXN0b3J5ICs9IGhhcmtlci5zcGVha2luZ0hpc3RvcnlbaV07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGhpc3RvcnkgPj0gMikge1xuICAgICAgICAgIGhhcmtlci5zcGVha2luZyA9IHRydWU7XG4gICAgICAgICAgaGFya2VyLmVtaXQoJ3NwZWFraW5nJyk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoY3VycmVudFZvbHVtZSA8IHRocmVzaG9sZCAmJiBoYXJrZXIuc3BlYWtpbmcpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgaGlzdG9yeSArPSBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5W2ldO1xuICAgICAgICB9XG4gICAgICAgIGlmIChoaXN0b3J5ID09IDApIHtcbiAgICAgICAgICBoYXJrZXIuc3BlYWtpbmcgPSBmYWxzZTtcbiAgICAgICAgICBoYXJrZXIuZW1pdCgnc3RvcHBlZF9zcGVha2luZycpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5LnNoaWZ0KCk7XG4gICAgICBoYXJrZXIuc3BlYWtpbmdIaXN0b3J5LnB1c2goMCArIChjdXJyZW50Vm9sdW1lID4gdGhyZXNob2xkKSk7XG5cbiAgICAgIGxvb3BlcigpO1xuICAgIH0sIGludGVydmFsKTtcbiAgfTtcbiAgbG9vcGVyKCk7XG5cblxuICByZXR1cm4gaGFya2VyO1xufVxuIiwiaWYgKHR5cGVvZiBPYmplY3QuY3JlYXRlID09PSAnZnVuY3Rpb24nKSB7XG4gIC8vIGltcGxlbWVudGF0aW9uIGZyb20gc3RhbmRhcmQgbm9kZS5qcyAndXRpbCcgbW9kdWxlXG4gIG1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gaW5oZXJpdHMoY3Rvciwgc3VwZXJDdG9yKSB7XG4gICAgY3Rvci5zdXBlcl8gPSBzdXBlckN0b3JcbiAgICBjdG9yLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoc3VwZXJDdG9yLnByb3RvdHlwZSwge1xuICAgICAgY29uc3RydWN0b3I6IHtcbiAgICAgICAgdmFsdWU6IGN0b3IsXG4gICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICB3cml0YWJsZTogdHJ1ZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgICB9XG4gICAgfSk7XG4gIH07XG59IGVsc2Uge1xuICAvLyBvbGQgc2Nob29sIHNoaW0gZm9yIG9sZCBicm93c2Vyc1xuICBtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGluaGVyaXRzKGN0b3IsIHN1cGVyQ3Rvcikge1xuICAgIGN0b3Iuc3VwZXJfID0gc3VwZXJDdG9yXG4gICAgdmFyIFRlbXBDdG9yID0gZnVuY3Rpb24gKCkge31cbiAgICBUZW1wQ3Rvci5wcm90b3R5cGUgPSBzdXBlckN0b3IucHJvdG90eXBlXG4gICAgY3Rvci5wcm90b3R5cGUgPSBuZXcgVGVtcEN0b3IoKVxuICAgIGN0b3IucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gY3RvclxuICB9XG59XG4iLCIvKiEgSlNPTiB2My4zLjIgfCBodHRwOi8vYmVzdGllanMuZ2l0aHViLmlvL2pzb24zIHwgQ29weXJpZ2h0IDIwMTItMjAxNCwgS2l0IENhbWJyaWRnZSB8IGh0dHA6Ly9raXQubWl0LWxpY2Vuc2Uub3JnICovXG47KGZ1bmN0aW9uICgpIHtcbiAgLy8gRGV0ZWN0IHRoZSBgZGVmaW5lYCBmdW5jdGlvbiBleHBvc2VkIGJ5IGFzeW5jaHJvbm91cyBtb2R1bGUgbG9hZGVycy4gVGhlXG4gIC8vIHN0cmljdCBgZGVmaW5lYCBjaGVjayBpcyBuZWNlc3NhcnkgZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBgci5qc2AuXG4gIHZhciBpc0xvYWRlciA9IHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kO1xuXG4gIC8vIEEgc2V0IG9mIHR5cGVzIHVzZWQgdG8gZGlzdGluZ3Vpc2ggb2JqZWN0cyBmcm9tIHByaW1pdGl2ZXMuXG4gIHZhciBvYmplY3RUeXBlcyA9IHtcbiAgICBcImZ1bmN0aW9uXCI6IHRydWUsXG4gICAgXCJvYmplY3RcIjogdHJ1ZVxuICB9O1xuXG4gIC8vIERldGVjdCB0aGUgYGV4cG9ydHNgIG9iamVjdCBleHBvc2VkIGJ5IENvbW1vbkpTIGltcGxlbWVudGF0aW9ucy5cbiAgdmFyIGZyZWVFeHBvcnRzID0gb2JqZWN0VHlwZXNbdHlwZW9mIGV4cG9ydHNdICYmIGV4cG9ydHMgJiYgIWV4cG9ydHMubm9kZVR5cGUgJiYgZXhwb3J0cztcblxuICAvLyBVc2UgdGhlIGBnbG9iYWxgIG9iamVjdCBleHBvc2VkIGJ5IE5vZGUgKGluY2x1ZGluZyBCcm93c2VyaWZ5IHZpYVxuICAvLyBgaW5zZXJ0LW1vZHVsZS1nbG9iYWxzYCksIE5hcndoYWwsIGFuZCBSaW5nbyBhcyB0aGUgZGVmYXVsdCBjb250ZXh0LFxuICAvLyBhbmQgdGhlIGB3aW5kb3dgIG9iamVjdCBpbiBicm93c2Vycy4gUmhpbm8gZXhwb3J0cyBhIGBnbG9iYWxgIGZ1bmN0aW9uXG4gIC8vIGluc3RlYWQuXG4gIHZhciByb290ID0gb2JqZWN0VHlwZXNbdHlwZW9mIHdpbmRvd10gJiYgd2luZG93IHx8IHRoaXMsXG4gICAgICBmcmVlR2xvYmFsID0gZnJlZUV4cG9ydHMgJiYgb2JqZWN0VHlwZXNbdHlwZW9mIG1vZHVsZV0gJiYgbW9kdWxlICYmICFtb2R1bGUubm9kZVR5cGUgJiYgdHlwZW9mIGdsb2JhbCA9PSBcIm9iamVjdFwiICYmIGdsb2JhbDtcblxuICBpZiAoZnJlZUdsb2JhbCAmJiAoZnJlZUdsb2JhbFtcImdsb2JhbFwiXSA9PT0gZnJlZUdsb2JhbCB8fCBmcmVlR2xvYmFsW1wid2luZG93XCJdID09PSBmcmVlR2xvYmFsIHx8IGZyZWVHbG9iYWxbXCJzZWxmXCJdID09PSBmcmVlR2xvYmFsKSkge1xuICAgIHJvb3QgPSBmcmVlR2xvYmFsO1xuICB9XG5cbiAgLy8gUHVibGljOiBJbml0aWFsaXplcyBKU09OIDMgdXNpbmcgdGhlIGdpdmVuIGBjb250ZXh0YCBvYmplY3QsIGF0dGFjaGluZyB0aGVcbiAgLy8gYHN0cmluZ2lmeWAgYW5kIGBwYXJzZWAgZnVuY3Rpb25zIHRvIHRoZSBzcGVjaWZpZWQgYGV4cG9ydHNgIG9iamVjdC5cbiAgZnVuY3Rpb24gcnVuSW5Db250ZXh0KGNvbnRleHQsIGV4cG9ydHMpIHtcbiAgICBjb250ZXh0IHx8IChjb250ZXh0ID0gcm9vdFtcIk9iamVjdFwiXSgpKTtcbiAgICBleHBvcnRzIHx8IChleHBvcnRzID0gcm9vdFtcIk9iamVjdFwiXSgpKTtcblxuICAgIC8vIE5hdGl2ZSBjb25zdHJ1Y3RvciBhbGlhc2VzLlxuICAgIHZhciBOdW1iZXIgPSBjb250ZXh0W1wiTnVtYmVyXCJdIHx8IHJvb3RbXCJOdW1iZXJcIl0sXG4gICAgICAgIFN0cmluZyA9IGNvbnRleHRbXCJTdHJpbmdcIl0gfHwgcm9vdFtcIlN0cmluZ1wiXSxcbiAgICAgICAgT2JqZWN0ID0gY29udGV4dFtcIk9iamVjdFwiXSB8fCByb290W1wiT2JqZWN0XCJdLFxuICAgICAgICBEYXRlID0gY29udGV4dFtcIkRhdGVcIl0gfHwgcm9vdFtcIkRhdGVcIl0sXG4gICAgICAgIFN5bnRheEVycm9yID0gY29udGV4dFtcIlN5bnRheEVycm9yXCJdIHx8IHJvb3RbXCJTeW50YXhFcnJvclwiXSxcbiAgICAgICAgVHlwZUVycm9yID0gY29udGV4dFtcIlR5cGVFcnJvclwiXSB8fCByb290W1wiVHlwZUVycm9yXCJdLFxuICAgICAgICBNYXRoID0gY29udGV4dFtcIk1hdGhcIl0gfHwgcm9vdFtcIk1hdGhcIl0sXG4gICAgICAgIG5hdGl2ZUpTT04gPSBjb250ZXh0W1wiSlNPTlwiXSB8fCByb290W1wiSlNPTlwiXTtcblxuICAgIC8vIERlbGVnYXRlIHRvIHRoZSBuYXRpdmUgYHN0cmluZ2lmeWAgYW5kIGBwYXJzZWAgaW1wbGVtZW50YXRpb25zLlxuICAgIGlmICh0eXBlb2YgbmF0aXZlSlNPTiA9PSBcIm9iamVjdFwiICYmIG5hdGl2ZUpTT04pIHtcbiAgICAgIGV4cG9ydHMuc3RyaW5naWZ5ID0gbmF0aXZlSlNPTi5zdHJpbmdpZnk7XG4gICAgICBleHBvcnRzLnBhcnNlID0gbmF0aXZlSlNPTi5wYXJzZTtcbiAgICB9XG5cbiAgICAvLyBDb252ZW5pZW5jZSBhbGlhc2VzLlxuICAgIHZhciBvYmplY3RQcm90byA9IE9iamVjdC5wcm90b3R5cGUsXG4gICAgICAgIGdldENsYXNzID0gb2JqZWN0UHJvdG8udG9TdHJpbmcsXG4gICAgICAgIGlzUHJvcGVydHksIGZvckVhY2gsIHVuZGVmO1xuXG4gICAgLy8gVGVzdCB0aGUgYERhdGUjZ2V0VVRDKmAgbWV0aG9kcy4gQmFzZWQgb24gd29yayBieSBAWWFmZmxlLlxuICAgIHZhciBpc0V4dGVuZGVkID0gbmV3IERhdGUoLTM1MDk4MjczMzQ1NzMyOTIpO1xuICAgIHRyeSB7XG4gICAgICAvLyBUaGUgYGdldFVUQ0Z1bGxZZWFyYCwgYE1vbnRoYCwgYW5kIGBEYXRlYCBtZXRob2RzIHJldHVybiBub25zZW5zaWNhbFxuICAgICAgLy8gcmVzdWx0cyBmb3IgY2VydGFpbiBkYXRlcyBpbiBPcGVyYSA+PSAxMC41My5cbiAgICAgIGlzRXh0ZW5kZWQgPSBpc0V4dGVuZGVkLmdldFVUQ0Z1bGxZZWFyKCkgPT0gLTEwOTI1MiAmJiBpc0V4dGVuZGVkLmdldFVUQ01vbnRoKCkgPT09IDAgJiYgaXNFeHRlbmRlZC5nZXRVVENEYXRlKCkgPT09IDEgJiZcbiAgICAgICAgLy8gU2FmYXJpIDwgMi4wLjIgc3RvcmVzIHRoZSBpbnRlcm5hbCBtaWxsaXNlY29uZCB0aW1lIHZhbHVlIGNvcnJlY3RseSxcbiAgICAgICAgLy8gYnV0IGNsaXBzIHRoZSB2YWx1ZXMgcmV0dXJuZWQgYnkgdGhlIGRhdGUgbWV0aG9kcyB0byB0aGUgcmFuZ2Ugb2ZcbiAgICAgICAgLy8gc2lnbmVkIDMyLWJpdCBpbnRlZ2VycyAoWy0yICoqIDMxLCAyICoqIDMxIC0gMV0pLlxuICAgICAgICBpc0V4dGVuZGVkLmdldFVUQ0hvdXJzKCkgPT0gMTAgJiYgaXNFeHRlbmRlZC5nZXRVVENNaW51dGVzKCkgPT0gMzcgJiYgaXNFeHRlbmRlZC5nZXRVVENTZWNvbmRzKCkgPT0gNiAmJiBpc0V4dGVuZGVkLmdldFVUQ01pbGxpc2Vjb25kcygpID09IDcwODtcbiAgICB9IGNhdGNoIChleGNlcHRpb24pIHt9XG5cbiAgICAvLyBJbnRlcm5hbDogRGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBuYXRpdmUgYEpTT04uc3RyaW5naWZ5YCBhbmQgYHBhcnNlYFxuICAgIC8vIGltcGxlbWVudGF0aW9ucyBhcmUgc3BlYy1jb21wbGlhbnQuIEJhc2VkIG9uIHdvcmsgYnkgS2VuIFNueWRlci5cbiAgICBmdW5jdGlvbiBoYXMobmFtZSkge1xuICAgICAgaWYgKGhhc1tuYW1lXSAhPT0gdW5kZWYpIHtcbiAgICAgICAgLy8gUmV0dXJuIGNhY2hlZCBmZWF0dXJlIHRlc3QgcmVzdWx0LlxuICAgICAgICByZXR1cm4gaGFzW25hbWVdO1xuICAgICAgfVxuICAgICAgdmFyIGlzU3VwcG9ydGVkO1xuICAgICAgaWYgKG5hbWUgPT0gXCJidWctc3RyaW5nLWNoYXItaW5kZXhcIikge1xuICAgICAgICAvLyBJRSA8PSA3IGRvZXNuJ3Qgc3VwcG9ydCBhY2Nlc3Npbmcgc3RyaW5nIGNoYXJhY3RlcnMgdXNpbmcgc3F1YXJlXG4gICAgICAgIC8vIGJyYWNrZXQgbm90YXRpb24uIElFIDggb25seSBzdXBwb3J0cyB0aGlzIGZvciBwcmltaXRpdmVzLlxuICAgICAgICBpc1N1cHBvcnRlZCA9IFwiYVwiWzBdICE9IFwiYVwiO1xuICAgICAgfSBlbHNlIGlmIChuYW1lID09IFwianNvblwiKSB7XG4gICAgICAgIC8vIEluZGljYXRlcyB3aGV0aGVyIGJvdGggYEpTT04uc3RyaW5naWZ5YCBhbmQgYEpTT04ucGFyc2VgIGFyZVxuICAgICAgICAvLyBzdXBwb3J0ZWQuXG4gICAgICAgIGlzU3VwcG9ydGVkID0gaGFzKFwianNvbi1zdHJpbmdpZnlcIikgJiYgaGFzKFwianNvbi1wYXJzZVwiKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciB2YWx1ZSwgc2VyaWFsaXplZCA9ICd7XCJhXCI6WzEsdHJ1ZSxmYWxzZSxudWxsLFwiXFxcXHUwMDAwXFxcXGJcXFxcblxcXFxmXFxcXHJcXFxcdFwiXX0nO1xuICAgICAgICAvLyBUZXN0IGBKU09OLnN0cmluZ2lmeWAuXG4gICAgICAgIGlmIChuYW1lID09IFwianNvbi1zdHJpbmdpZnlcIikge1xuICAgICAgICAgIHZhciBzdHJpbmdpZnkgPSBleHBvcnRzLnN0cmluZ2lmeSwgc3RyaW5naWZ5U3VwcG9ydGVkID0gdHlwZW9mIHN0cmluZ2lmeSA9PSBcImZ1bmN0aW9uXCIgJiYgaXNFeHRlbmRlZDtcbiAgICAgICAgICBpZiAoc3RyaW5naWZ5U3VwcG9ydGVkKSB7XG4gICAgICAgICAgICAvLyBBIHRlc3QgZnVuY3Rpb24gb2JqZWN0IHdpdGggYSBjdXN0b20gYHRvSlNPTmAgbWV0aG9kLlxuICAgICAgICAgICAgKHZhbHVlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICAgIH0pLnRvSlNPTiA9IHZhbHVlO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgc3RyaW5naWZ5U3VwcG9ydGVkID1cbiAgICAgICAgICAgICAgICAvLyBGaXJlZm94IDMuMWIxIGFuZCBiMiBzZXJpYWxpemUgc3RyaW5nLCBudW1iZXIsIGFuZCBib29sZWFuXG4gICAgICAgICAgICAgICAgLy8gcHJpbWl0aXZlcyBhcyBvYmplY3QgbGl0ZXJhbHMuXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KDApID09PSBcIjBcIiAmJlxuICAgICAgICAgICAgICAgIC8vIEZGIDMuMWIxLCBiMiwgYW5kIEpTT04gMiBzZXJpYWxpemUgd3JhcHBlZCBwcmltaXRpdmVzIGFzIG9iamVjdFxuICAgICAgICAgICAgICAgIC8vIGxpdGVyYWxzLlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeShuZXcgTnVtYmVyKCkpID09PSBcIjBcIiAmJlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeShuZXcgU3RyaW5nKCkpID09ICdcIlwiJyAmJlxuICAgICAgICAgICAgICAgIC8vIEZGIDMuMWIxLCAyIHRocm93IGFuIGVycm9yIGlmIHRoZSB2YWx1ZSBpcyBgbnVsbGAsIGB1bmRlZmluZWRgLCBvclxuICAgICAgICAgICAgICAgIC8vIGRvZXMgbm90IGRlZmluZSBhIGNhbm9uaWNhbCBKU09OIHJlcHJlc2VudGF0aW9uICh0aGlzIGFwcGxpZXMgdG9cbiAgICAgICAgICAgICAgICAvLyBvYmplY3RzIHdpdGggYHRvSlNPTmAgcHJvcGVydGllcyBhcyB3ZWxsLCAqdW5sZXNzKiB0aGV5IGFyZSBuZXN0ZWRcbiAgICAgICAgICAgICAgICAvLyB3aXRoaW4gYW4gb2JqZWN0IG9yIGFycmF5KS5cbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkoZ2V0Q2xhc3MpID09PSB1bmRlZiAmJlxuICAgICAgICAgICAgICAgIC8vIElFIDggc2VyaWFsaXplcyBgdW5kZWZpbmVkYCBhcyBgXCJ1bmRlZmluZWRcImAuIFNhZmFyaSA8PSA1LjEuNyBhbmRcbiAgICAgICAgICAgICAgICAvLyBGRiAzLjFiMyBwYXNzIHRoaXMgdGVzdC5cbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkodW5kZWYpID09PSB1bmRlZiAmJlxuICAgICAgICAgICAgICAgIC8vIFNhZmFyaSA8PSA1LjEuNyBhbmQgRkYgMy4xYjMgdGhyb3cgYEVycm9yYHMgYW5kIGBUeXBlRXJyb3JgcyxcbiAgICAgICAgICAgICAgICAvLyByZXNwZWN0aXZlbHksIGlmIHRoZSB2YWx1ZSBpcyBvbWl0dGVkIGVudGlyZWx5LlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeSgpID09PSB1bmRlZiAmJlxuICAgICAgICAgICAgICAgIC8vIEZGIDMuMWIxLCAyIHRocm93IGFuIGVycm9yIGlmIHRoZSBnaXZlbiB2YWx1ZSBpcyBub3QgYSBudW1iZXIsXG4gICAgICAgICAgICAgICAgLy8gc3RyaW5nLCBhcnJheSwgb2JqZWN0LCBCb29sZWFuLCBvciBgbnVsbGAgbGl0ZXJhbC4gVGhpcyBhcHBsaWVzIHRvXG4gICAgICAgICAgICAgICAgLy8gb2JqZWN0cyB3aXRoIGN1c3RvbSBgdG9KU09OYCBtZXRob2RzIGFzIHdlbGwsIHVubGVzcyB0aGV5IGFyZSBuZXN0ZWRcbiAgICAgICAgICAgICAgICAvLyBpbnNpZGUgb2JqZWN0IG9yIGFycmF5IGxpdGVyYWxzLiBZVUkgMy4wLjBiMSBpZ25vcmVzIGN1c3RvbSBgdG9KU09OYFxuICAgICAgICAgICAgICAgIC8vIG1ldGhvZHMgZW50aXJlbHkuXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KHZhbHVlKSA9PT0gXCIxXCIgJiZcbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkoW3ZhbHVlXSkgPT0gXCJbMV1cIiAmJlxuICAgICAgICAgICAgICAgIC8vIFByb3RvdHlwZSA8PSAxLjYuMSBzZXJpYWxpemVzIGBbdW5kZWZpbmVkXWAgYXMgYFwiW11cImAgaW5zdGVhZCBvZlxuICAgICAgICAgICAgICAgIC8vIGBcIltudWxsXVwiYC5cbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkoW3VuZGVmXSkgPT0gXCJbbnVsbF1cIiAmJlxuICAgICAgICAgICAgICAgIC8vIFlVSSAzLjAuMGIxIGZhaWxzIHRvIHNlcmlhbGl6ZSBgbnVsbGAgbGl0ZXJhbHMuXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KG51bGwpID09IFwibnVsbFwiICYmXG4gICAgICAgICAgICAgICAgLy8gRkYgMy4xYjEsIDIgaGFsdHMgc2VyaWFsaXphdGlvbiBpZiBhbiBhcnJheSBjb250YWlucyBhIGZ1bmN0aW9uOlxuICAgICAgICAgICAgICAgIC8vIGBbMSwgdHJ1ZSwgZ2V0Q2xhc3MsIDFdYCBzZXJpYWxpemVzIGFzIFwiWzEsdHJ1ZSxdLFwiLiBGRiAzLjFiM1xuICAgICAgICAgICAgICAgIC8vIGVsaWRlcyBub24tSlNPTiB2YWx1ZXMgZnJvbSBvYmplY3RzIGFuZCBhcnJheXMsIHVubGVzcyB0aGV5XG4gICAgICAgICAgICAgICAgLy8gZGVmaW5lIGN1c3RvbSBgdG9KU09OYCBtZXRob2RzLlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeShbdW5kZWYsIGdldENsYXNzLCBudWxsXSkgPT0gXCJbbnVsbCxudWxsLG51bGxdXCIgJiZcbiAgICAgICAgICAgICAgICAvLyBTaW1wbGUgc2VyaWFsaXphdGlvbiB0ZXN0LiBGRiAzLjFiMSB1c2VzIFVuaWNvZGUgZXNjYXBlIHNlcXVlbmNlc1xuICAgICAgICAgICAgICAgIC8vIHdoZXJlIGNoYXJhY3RlciBlc2NhcGUgY29kZXMgYXJlIGV4cGVjdGVkIChlLmcuLCBgXFxiYCA9PiBgXFx1MDAwOGApLlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeSh7IFwiYVwiOiBbdmFsdWUsIHRydWUsIGZhbHNlLCBudWxsLCBcIlxceDAwXFxiXFxuXFxmXFxyXFx0XCJdIH0pID09IHNlcmlhbGl6ZWQgJiZcbiAgICAgICAgICAgICAgICAvLyBGRiAzLjFiMSBhbmQgYjIgaWdub3JlIHRoZSBgZmlsdGVyYCBhbmQgYHdpZHRoYCBhcmd1bWVudHMuXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KG51bGwsIHZhbHVlKSA9PT0gXCIxXCIgJiZcbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkoWzEsIDJdLCBudWxsLCAxKSA9PSBcIltcXG4gMSxcXG4gMlxcbl1cIiAmJlxuICAgICAgICAgICAgICAgIC8vIEpTT04gMiwgUHJvdG90eXBlIDw9IDEuNywgYW5kIG9sZGVyIFdlYktpdCBidWlsZHMgaW5jb3JyZWN0bHlcbiAgICAgICAgICAgICAgICAvLyBzZXJpYWxpemUgZXh0ZW5kZWQgeWVhcnMuXG4gICAgICAgICAgICAgICAgc3RyaW5naWZ5KG5ldyBEYXRlKC04LjY0ZTE1KSkgPT0gJ1wiLTI3MTgyMS0wNC0yMFQwMDowMDowMC4wMDBaXCInICYmXG4gICAgICAgICAgICAgICAgLy8gVGhlIG1pbGxpc2Vjb25kcyBhcmUgb3B0aW9uYWwgaW4gRVMgNSwgYnV0IHJlcXVpcmVkIGluIDUuMS5cbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkobmV3IERhdGUoOC42NGUxNSkpID09ICdcIisyNzU3NjAtMDktMTNUMDA6MDA6MDAuMDAwWlwiJyAmJlxuICAgICAgICAgICAgICAgIC8vIEZpcmVmb3ggPD0gMTEuMCBpbmNvcnJlY3RseSBzZXJpYWxpemVzIHllYXJzIHByaW9yIHRvIDAgYXMgbmVnYXRpdmVcbiAgICAgICAgICAgICAgICAvLyBmb3VyLWRpZ2l0IHllYXJzIGluc3RlYWQgb2Ygc2l4LWRpZ2l0IHllYXJzLiBDcmVkaXRzOiBAWWFmZmxlLlxuICAgICAgICAgICAgICAgIHN0cmluZ2lmeShuZXcgRGF0ZSgtNjIxOTg3NTUyZTUpKSA9PSAnXCItMDAwMDAxLTAxLTAxVDAwOjAwOjAwLjAwMFpcIicgJiZcbiAgICAgICAgICAgICAgICAvLyBTYWZhcmkgPD0gNS4xLjUgYW5kIE9wZXJhID49IDEwLjUzIGluY29ycmVjdGx5IHNlcmlhbGl6ZSBtaWxsaXNlY29uZFxuICAgICAgICAgICAgICAgIC8vIHZhbHVlcyBsZXNzIHRoYW4gMTAwMC4gQ3JlZGl0czogQFlhZmZsZS5cbiAgICAgICAgICAgICAgICBzdHJpbmdpZnkobmV3IERhdGUoLTEpKSA9PSAnXCIxOTY5LTEyLTMxVDIzOjU5OjU5Ljk5OVpcIic7XG4gICAgICAgICAgICB9IGNhdGNoIChleGNlcHRpb24pIHtcbiAgICAgICAgICAgICAgc3RyaW5naWZ5U3VwcG9ydGVkID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGlzU3VwcG9ydGVkID0gc3RyaW5naWZ5U3VwcG9ydGVkO1xuICAgICAgICB9XG4gICAgICAgIC8vIFRlc3QgYEpTT04ucGFyc2VgLlxuICAgICAgICBpZiAobmFtZSA9PSBcImpzb24tcGFyc2VcIikge1xuICAgICAgICAgIHZhciBwYXJzZSA9IGV4cG9ydHMucGFyc2U7XG4gICAgICAgICAgaWYgKHR5cGVvZiBwYXJzZSA9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIC8vIEZGIDMuMWIxLCBiMiB3aWxsIHRocm93IGFuIGV4Y2VwdGlvbiBpZiBhIGJhcmUgbGl0ZXJhbCBpcyBwcm92aWRlZC5cbiAgICAgICAgICAgICAgLy8gQ29uZm9ybWluZyBpbXBsZW1lbnRhdGlvbnMgc2hvdWxkIGFsc28gY29lcmNlIHRoZSBpbml0aWFsIGFyZ3VtZW50IHRvXG4gICAgICAgICAgICAgIC8vIGEgc3RyaW5nIHByaW9yIHRvIHBhcnNpbmcuXG4gICAgICAgICAgICAgIGlmIChwYXJzZShcIjBcIikgPT09IDAgJiYgIXBhcnNlKGZhbHNlKSkge1xuICAgICAgICAgICAgICAgIC8vIFNpbXBsZSBwYXJzaW5nIHRlc3QuXG4gICAgICAgICAgICAgICAgdmFsdWUgPSBwYXJzZShzZXJpYWxpemVkKTtcbiAgICAgICAgICAgICAgICB2YXIgcGFyc2VTdXBwb3J0ZWQgPSB2YWx1ZVtcImFcIl0ubGVuZ3RoID09IDUgJiYgdmFsdWVbXCJhXCJdWzBdID09PSAxO1xuICAgICAgICAgICAgICAgIGlmIChwYXJzZVN1cHBvcnRlZCkge1xuICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgLy8gU2FmYXJpIDw9IDUuMS4yIGFuZCBGRiAzLjFiMSBhbGxvdyB1bmVzY2FwZWQgdGFicyBpbiBzdHJpbmdzLlxuICAgICAgICAgICAgICAgICAgICBwYXJzZVN1cHBvcnRlZCA9ICFwYXJzZSgnXCJcXHRcIicpO1xuICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZXhjZXB0aW9uKSB7fVxuICAgICAgICAgICAgICAgICAgaWYgKHBhcnNlU3VwcG9ydGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gRkYgNC4wIGFuZCA0LjAuMSBhbGxvdyBsZWFkaW5nIGArYCBzaWducyBhbmQgbGVhZGluZ1xuICAgICAgICAgICAgICAgICAgICAgIC8vIGRlY2ltYWwgcG9pbnRzLiBGRiA0LjAsIDQuMC4xLCBhbmQgSUUgOS0xMCBhbHNvIGFsbG93XG4gICAgICAgICAgICAgICAgICAgICAgLy8gY2VydGFpbiBvY3RhbCBsaXRlcmFscy5cbiAgICAgICAgICAgICAgICAgICAgICBwYXJzZVN1cHBvcnRlZCA9IHBhcnNlKFwiMDFcIikgIT09IDE7XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGV4Y2VwdGlvbikge31cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIGlmIChwYXJzZVN1cHBvcnRlZCkge1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIEZGIDQuMCwgNC4wLjEsIGFuZCBSaGlubyAxLjdSMy1SNCBhbGxvdyB0cmFpbGluZyBkZWNpbWFsXG4gICAgICAgICAgICAgICAgICAgICAgLy8gcG9pbnRzLiBUaGVzZSBlbnZpcm9ubWVudHMsIGFsb25nIHdpdGggRkYgMy4xYjEgYW5kIDIsXG4gICAgICAgICAgICAgICAgICAgICAgLy8gYWxzbyBhbGxvdyB0cmFpbGluZyBjb21tYXMgaW4gSlNPTiBvYmplY3RzIGFuZCBhcnJheXMuXG4gICAgICAgICAgICAgICAgICAgICAgcGFyc2VTdXBwb3J0ZWQgPSBwYXJzZShcIjEuXCIpICE9PSAxO1xuICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChleGNlcHRpb24pIHt9XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGNhdGNoIChleGNlcHRpb24pIHtcbiAgICAgICAgICAgICAgcGFyc2VTdXBwb3J0ZWQgPSBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaXNTdXBwb3J0ZWQgPSBwYXJzZVN1cHBvcnRlZDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIGhhc1tuYW1lXSA9ICEhaXNTdXBwb3J0ZWQ7XG4gICAgfVxuXG4gICAgaWYgKCFoYXMoXCJqc29uXCIpKSB7XG4gICAgICAvLyBDb21tb24gYFtbQ2xhc3NdXWAgbmFtZSBhbGlhc2VzLlxuICAgICAgdmFyIGZ1bmN0aW9uQ2xhc3MgPSBcIltvYmplY3QgRnVuY3Rpb25dXCIsXG4gICAgICAgICAgZGF0ZUNsYXNzID0gXCJbb2JqZWN0IERhdGVdXCIsXG4gICAgICAgICAgbnVtYmVyQ2xhc3MgPSBcIltvYmplY3QgTnVtYmVyXVwiLFxuICAgICAgICAgIHN0cmluZ0NsYXNzID0gXCJbb2JqZWN0IFN0cmluZ11cIixcbiAgICAgICAgICBhcnJheUNsYXNzID0gXCJbb2JqZWN0IEFycmF5XVwiLFxuICAgICAgICAgIGJvb2xlYW5DbGFzcyA9IFwiW29iamVjdCBCb29sZWFuXVwiO1xuXG4gICAgICAvLyBEZXRlY3QgaW5jb21wbGV0ZSBzdXBwb3J0IGZvciBhY2Nlc3Npbmcgc3RyaW5nIGNoYXJhY3RlcnMgYnkgaW5kZXguXG4gICAgICB2YXIgY2hhckluZGV4QnVnZ3kgPSBoYXMoXCJidWctc3RyaW5nLWNoYXItaW5kZXhcIik7XG5cbiAgICAgIC8vIERlZmluZSBhZGRpdGlvbmFsIHV0aWxpdHkgbWV0aG9kcyBpZiB0aGUgYERhdGVgIG1ldGhvZHMgYXJlIGJ1Z2d5LlxuICAgICAgaWYgKCFpc0V4dGVuZGVkKSB7XG4gICAgICAgIHZhciBmbG9vciA9IE1hdGguZmxvb3I7XG4gICAgICAgIC8vIEEgbWFwcGluZyBiZXR3ZWVuIHRoZSBtb250aHMgb2YgdGhlIHllYXIgYW5kIHRoZSBudW1iZXIgb2YgZGF5cyBiZXR3ZWVuXG4gICAgICAgIC8vIEphbnVhcnkgMXN0IGFuZCB0aGUgZmlyc3Qgb2YgdGhlIHJlc3BlY3RpdmUgbW9udGguXG4gICAgICAgIHZhciBNb250aHMgPSBbMCwgMzEsIDU5LCA5MCwgMTIwLCAxNTEsIDE4MSwgMjEyLCAyNDMsIDI3MywgMzA0LCAzMzRdO1xuICAgICAgICAvLyBJbnRlcm5hbDogQ2FsY3VsYXRlcyB0aGUgbnVtYmVyIG9mIGRheXMgYmV0d2VlbiB0aGUgVW5peCBlcG9jaCBhbmQgdGhlXG4gICAgICAgIC8vIGZpcnN0IGRheSBvZiB0aGUgZ2l2ZW4gbW9udGguXG4gICAgICAgIHZhciBnZXREYXkgPSBmdW5jdGlvbiAoeWVhciwgbW9udGgpIHtcbiAgICAgICAgICByZXR1cm4gTW9udGhzW21vbnRoXSArIDM2NSAqICh5ZWFyIC0gMTk3MCkgKyBmbG9vcigoeWVhciAtIDE5NjkgKyAobW9udGggPSArKG1vbnRoID4gMSkpKSAvIDQpIC0gZmxvb3IoKHllYXIgLSAxOTAxICsgbW9udGgpIC8gMTAwKSArIGZsb29yKCh5ZWFyIC0gMTYwMSArIG1vbnRoKSAvIDQwMCk7XG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIC8vIEludGVybmFsOiBEZXRlcm1pbmVzIGlmIGEgcHJvcGVydHkgaXMgYSBkaXJlY3QgcHJvcGVydHkgb2YgdGhlIGdpdmVuXG4gICAgICAvLyBvYmplY3QuIERlbGVnYXRlcyB0byB0aGUgbmF0aXZlIGBPYmplY3QjaGFzT3duUHJvcGVydHlgIG1ldGhvZC5cbiAgICAgIGlmICghKGlzUHJvcGVydHkgPSBvYmplY3RQcm90by5oYXNPd25Qcm9wZXJ0eSkpIHtcbiAgICAgICAgaXNQcm9wZXJ0eSA9IGZ1bmN0aW9uIChwcm9wZXJ0eSkge1xuICAgICAgICAgIHZhciBtZW1iZXJzID0ge30sIGNvbnN0cnVjdG9yO1xuICAgICAgICAgIGlmICgobWVtYmVycy5fX3Byb3RvX18gPSBudWxsLCBtZW1iZXJzLl9fcHJvdG9fXyA9IHtcbiAgICAgICAgICAgIC8vIFRoZSAqcHJvdG8qIHByb3BlcnR5IGNhbm5vdCBiZSBzZXQgbXVsdGlwbGUgdGltZXMgaW4gcmVjZW50XG4gICAgICAgICAgICAvLyB2ZXJzaW9ucyBvZiBGaXJlZm94IGFuZCBTZWFNb25rZXkuXG4gICAgICAgICAgICBcInRvU3RyaW5nXCI6IDFcbiAgICAgICAgICB9LCBtZW1iZXJzKS50b1N0cmluZyAhPSBnZXRDbGFzcykge1xuICAgICAgICAgICAgLy8gU2FmYXJpIDw9IDIuMC4zIGRvZXNuJ3QgaW1wbGVtZW50IGBPYmplY3QjaGFzT3duUHJvcGVydHlgLCBidXRcbiAgICAgICAgICAgIC8vIHN1cHBvcnRzIHRoZSBtdXRhYmxlICpwcm90byogcHJvcGVydHkuXG4gICAgICAgICAgICBpc1Byb3BlcnR5ID0gZnVuY3Rpb24gKHByb3BlcnR5KSB7XG4gICAgICAgICAgICAgIC8vIENhcHR1cmUgYW5kIGJyZWFrIHRoZSBvYmplY3QncyBwcm90b3R5cGUgY2hhaW4gKHNlZSBzZWN0aW9uIDguNi4yXG4gICAgICAgICAgICAgIC8vIG9mIHRoZSBFUyA1LjEgc3BlYykuIFRoZSBwYXJlbnRoZXNpemVkIGV4cHJlc3Npb24gcHJldmVudHMgYW5cbiAgICAgICAgICAgICAgLy8gdW5zYWZlIHRyYW5zZm9ybWF0aW9uIGJ5IHRoZSBDbG9zdXJlIENvbXBpbGVyLlxuICAgICAgICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzLl9fcHJvdG9fXywgcmVzdWx0ID0gcHJvcGVydHkgaW4gKHRoaXMuX19wcm90b19fID0gbnVsbCwgdGhpcyk7XG4gICAgICAgICAgICAgIC8vIFJlc3RvcmUgdGhlIG9yaWdpbmFsIHByb3RvdHlwZSBjaGFpbi5cbiAgICAgICAgICAgICAgdGhpcy5fX3Byb3RvX18gPSBvcmlnaW5hbDtcbiAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIENhcHR1cmUgYSByZWZlcmVuY2UgdG8gdGhlIHRvcC1sZXZlbCBgT2JqZWN0YCBjb25zdHJ1Y3Rvci5cbiAgICAgICAgICAgIGNvbnN0cnVjdG9yID0gbWVtYmVycy5jb25zdHJ1Y3RvcjtcbiAgICAgICAgICAgIC8vIFVzZSB0aGUgYGNvbnN0cnVjdG9yYCBwcm9wZXJ0eSB0byBzaW11bGF0ZSBgT2JqZWN0I2hhc093blByb3BlcnR5YCBpblxuICAgICAgICAgICAgLy8gb3RoZXIgZW52aXJvbm1lbnRzLlxuICAgICAgICAgICAgaXNQcm9wZXJ0eSA9IGZ1bmN0aW9uIChwcm9wZXJ0eSkge1xuICAgICAgICAgICAgICB2YXIgcGFyZW50ID0gKHRoaXMuY29uc3RydWN0b3IgfHwgY29uc3RydWN0b3IpLnByb3RvdHlwZTtcbiAgICAgICAgICAgICAgcmV0dXJuIHByb3BlcnR5IGluIHRoaXMgJiYgIShwcm9wZXJ0eSBpbiBwYXJlbnQgJiYgdGhpc1twcm9wZXJ0eV0gPT09IHBhcmVudFtwcm9wZXJ0eV0pO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgICAgbWVtYmVycyA9IG51bGw7XG4gICAgICAgICAgcmV0dXJuIGlzUHJvcGVydHkuY2FsbCh0aGlzLCBwcm9wZXJ0eSk7XG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIC8vIEludGVybmFsOiBOb3JtYWxpemVzIHRoZSBgZm9yLi4uaW5gIGl0ZXJhdGlvbiBhbGdvcml0aG0gYWNyb3NzXG4gICAgICAvLyBlbnZpcm9ubWVudHMuIEVhY2ggZW51bWVyYXRlZCBrZXkgaXMgeWllbGRlZCB0byBhIGBjYWxsYmFja2AgZnVuY3Rpb24uXG4gICAgICBmb3JFYWNoID0gZnVuY3Rpb24gKG9iamVjdCwgY2FsbGJhY2spIHtcbiAgICAgICAgdmFyIHNpemUgPSAwLCBQcm9wZXJ0aWVzLCBtZW1iZXJzLCBwcm9wZXJ0eTtcblxuICAgICAgICAvLyBUZXN0cyBmb3IgYnVncyBpbiB0aGUgY3VycmVudCBlbnZpcm9ubWVudCdzIGBmb3IuLi5pbmAgYWxnb3JpdGhtLiBUaGVcbiAgICAgICAgLy8gYHZhbHVlT2ZgIHByb3BlcnR5IGluaGVyaXRzIHRoZSBub24tZW51bWVyYWJsZSBmbGFnIGZyb21cbiAgICAgICAgLy8gYE9iamVjdC5wcm90b3R5cGVgIGluIG9sZGVyIHZlcnNpb25zIG9mIElFLCBOZXRzY2FwZSwgYW5kIE1vemlsbGEuXG4gICAgICAgIChQcm9wZXJ0aWVzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgIHRoaXMudmFsdWVPZiA9IDA7XG4gICAgICAgIH0pLnByb3RvdHlwZS52YWx1ZU9mID0gMDtcblxuICAgICAgICAvLyBJdGVyYXRlIG92ZXIgYSBuZXcgaW5zdGFuY2Ugb2YgdGhlIGBQcm9wZXJ0aWVzYCBjbGFzcy5cbiAgICAgICAgbWVtYmVycyA9IG5ldyBQcm9wZXJ0aWVzKCk7XG4gICAgICAgIGZvciAocHJvcGVydHkgaW4gbWVtYmVycykge1xuICAgICAgICAgIC8vIElnbm9yZSBhbGwgcHJvcGVydGllcyBpbmhlcml0ZWQgZnJvbSBgT2JqZWN0LnByb3RvdHlwZWAuXG4gICAgICAgICAgaWYgKGlzUHJvcGVydHkuY2FsbChtZW1iZXJzLCBwcm9wZXJ0eSkpIHtcbiAgICAgICAgICAgIHNpemUrKztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgUHJvcGVydGllcyA9IG1lbWJlcnMgPSBudWxsO1xuXG4gICAgICAgIC8vIE5vcm1hbGl6ZSB0aGUgaXRlcmF0aW9uIGFsZ29yaXRobS5cbiAgICAgICAgaWYgKCFzaXplKSB7XG4gICAgICAgICAgLy8gQSBsaXN0IG9mIG5vbi1lbnVtZXJhYmxlIHByb3BlcnRpZXMgaW5oZXJpdGVkIGZyb20gYE9iamVjdC5wcm90b3R5cGVgLlxuICAgICAgICAgIG1lbWJlcnMgPSBbXCJ2YWx1ZU9mXCIsIFwidG9TdHJpbmdcIiwgXCJ0b0xvY2FsZVN0cmluZ1wiLCBcInByb3BlcnR5SXNFbnVtZXJhYmxlXCIsIFwiaXNQcm90b3R5cGVPZlwiLCBcImhhc093blByb3BlcnR5XCIsIFwiY29uc3RydWN0b3JcIl07XG4gICAgICAgICAgLy8gSUUgPD0gOCwgTW96aWxsYSAxLjAsIGFuZCBOZXRzY2FwZSA2LjIgaWdub3JlIHNoYWRvd2VkIG5vbi1lbnVtZXJhYmxlXG4gICAgICAgICAgLy8gcHJvcGVydGllcy5cbiAgICAgICAgICBmb3JFYWNoID0gZnVuY3Rpb24gKG9iamVjdCwgY2FsbGJhY2spIHtcbiAgICAgICAgICAgIHZhciBpc0Z1bmN0aW9uID0gZ2V0Q2xhc3MuY2FsbChvYmplY3QpID09IGZ1bmN0aW9uQ2xhc3MsIHByb3BlcnR5LCBsZW5ndGg7XG4gICAgICAgICAgICB2YXIgaGFzUHJvcGVydHkgPSAhaXNGdW5jdGlvbiAmJiB0eXBlb2Ygb2JqZWN0LmNvbnN0cnVjdG9yICE9IFwiZnVuY3Rpb25cIiAmJiBvYmplY3RUeXBlc1t0eXBlb2Ygb2JqZWN0Lmhhc093blByb3BlcnR5XSAmJiBvYmplY3QuaGFzT3duUHJvcGVydHkgfHwgaXNQcm9wZXJ0eTtcbiAgICAgICAgICAgIGZvciAocHJvcGVydHkgaW4gb2JqZWN0KSB7XG4gICAgICAgICAgICAgIC8vIEdlY2tvIDw9IDEuMCBlbnVtZXJhdGVzIHRoZSBgcHJvdG90eXBlYCBwcm9wZXJ0eSBvZiBmdW5jdGlvbnMgdW5kZXJcbiAgICAgICAgICAgICAgLy8gY2VydGFpbiBjb25kaXRpb25zOyBJRSBkb2VzIG5vdC5cbiAgICAgICAgICAgICAgaWYgKCEoaXNGdW5jdGlvbiAmJiBwcm9wZXJ0eSA9PSBcInByb3RvdHlwZVwiKSAmJiBoYXNQcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2socHJvcGVydHkpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBNYW51YWxseSBpbnZva2UgdGhlIGNhbGxiYWNrIGZvciBlYWNoIG5vbi1lbnVtZXJhYmxlIHByb3BlcnR5LlxuICAgICAgICAgICAgZm9yIChsZW5ndGggPSBtZW1iZXJzLmxlbmd0aDsgcHJvcGVydHkgPSBtZW1iZXJzWy0tbGVuZ3RoXTsgaGFzUHJvcGVydHkuY2FsbChvYmplY3QsIHByb3BlcnR5KSAmJiBjYWxsYmFjayhwcm9wZXJ0eSkpO1xuICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSBpZiAoc2l6ZSA9PSAyKSB7XG4gICAgICAgICAgLy8gU2FmYXJpIDw9IDIuMC40IGVudW1lcmF0ZXMgc2hhZG93ZWQgcHJvcGVydGllcyB0d2ljZS5cbiAgICAgICAgICBmb3JFYWNoID0gZnVuY3Rpb24gKG9iamVjdCwgY2FsbGJhY2spIHtcbiAgICAgICAgICAgIC8vIENyZWF0ZSBhIHNldCBvZiBpdGVyYXRlZCBwcm9wZXJ0aWVzLlxuICAgICAgICAgICAgdmFyIG1lbWJlcnMgPSB7fSwgaXNGdW5jdGlvbiA9IGdldENsYXNzLmNhbGwob2JqZWN0KSA9PSBmdW5jdGlvbkNsYXNzLCBwcm9wZXJ0eTtcbiAgICAgICAgICAgIGZvciAocHJvcGVydHkgaW4gb2JqZWN0KSB7XG4gICAgICAgICAgICAgIC8vIFN0b3JlIGVhY2ggcHJvcGVydHkgbmFtZSB0byBwcmV2ZW50IGRvdWJsZSBlbnVtZXJhdGlvbi4gVGhlXG4gICAgICAgICAgICAgIC8vIGBwcm90b3R5cGVgIHByb3BlcnR5IG9mIGZ1bmN0aW9ucyBpcyBub3QgZW51bWVyYXRlZCBkdWUgdG8gY3Jvc3MtXG4gICAgICAgICAgICAgIC8vIGVudmlyb25tZW50IGluY29uc2lzdGVuY2llcy5cbiAgICAgICAgICAgICAgaWYgKCEoaXNGdW5jdGlvbiAmJiBwcm9wZXJ0eSA9PSBcInByb3RvdHlwZVwiKSAmJiAhaXNQcm9wZXJ0eS5jYWxsKG1lbWJlcnMsIHByb3BlcnR5KSAmJiAobWVtYmVyc1twcm9wZXJ0eV0gPSAxKSAmJiBpc1Byb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSkpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhwcm9wZXJ0eSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIE5vIGJ1Z3MgZGV0ZWN0ZWQ7IHVzZSB0aGUgc3RhbmRhcmQgYGZvci4uLmluYCBhbGdvcml0aG0uXG4gICAgICAgICAgZm9yRWFjaCA9IGZ1bmN0aW9uIChvYmplY3QsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICB2YXIgaXNGdW5jdGlvbiA9IGdldENsYXNzLmNhbGwob2JqZWN0KSA9PSBmdW5jdGlvbkNsYXNzLCBwcm9wZXJ0eSwgaXNDb25zdHJ1Y3RvcjtcbiAgICAgICAgICAgIGZvciAocHJvcGVydHkgaW4gb2JqZWN0KSB7XG4gICAgICAgICAgICAgIGlmICghKGlzRnVuY3Rpb24gJiYgcHJvcGVydHkgPT0gXCJwcm90b3R5cGVcIikgJiYgaXNQcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpICYmICEoaXNDb25zdHJ1Y3RvciA9IHByb3BlcnR5ID09PSBcImNvbnN0cnVjdG9yXCIpKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2socHJvcGVydHkpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBNYW51YWxseSBpbnZva2UgdGhlIGNhbGxiYWNrIGZvciB0aGUgYGNvbnN0cnVjdG9yYCBwcm9wZXJ0eSBkdWUgdG9cbiAgICAgICAgICAgIC8vIGNyb3NzLWVudmlyb25tZW50IGluY29uc2lzdGVuY2llcy5cbiAgICAgICAgICAgIGlmIChpc0NvbnN0cnVjdG9yIHx8IGlzUHJvcGVydHkuY2FsbChvYmplY3QsIChwcm9wZXJ0eSA9IFwiY29uc3RydWN0b3JcIikpKSB7XG4gICAgICAgICAgICAgIGNhbGxiYWNrKHByb3BlcnR5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmb3JFYWNoKG9iamVjdCwgY2FsbGJhY2spO1xuICAgICAgfTtcblxuICAgICAgLy8gUHVibGljOiBTZXJpYWxpemVzIGEgSmF2YVNjcmlwdCBgdmFsdWVgIGFzIGEgSlNPTiBzdHJpbmcuIFRoZSBvcHRpb25hbFxuICAgICAgLy8gYGZpbHRlcmAgYXJndW1lbnQgbWF5IHNwZWNpZnkgZWl0aGVyIGEgZnVuY3Rpb24gdGhhdCBhbHRlcnMgaG93IG9iamVjdCBhbmRcbiAgICAgIC8vIGFycmF5IG1lbWJlcnMgYXJlIHNlcmlhbGl6ZWQsIG9yIGFuIGFycmF5IG9mIHN0cmluZ3MgYW5kIG51bWJlcnMgdGhhdFxuICAgICAgLy8gaW5kaWNhdGVzIHdoaWNoIHByb3BlcnRpZXMgc2hvdWxkIGJlIHNlcmlhbGl6ZWQuIFRoZSBvcHRpb25hbCBgd2lkdGhgXG4gICAgICAvLyBhcmd1bWVudCBtYXkgYmUgZWl0aGVyIGEgc3RyaW5nIG9yIG51bWJlciB0aGF0IHNwZWNpZmllcyB0aGUgaW5kZW50YXRpb25cbiAgICAgIC8vIGxldmVsIG9mIHRoZSBvdXRwdXQuXG4gICAgICBpZiAoIWhhcyhcImpzb24tc3RyaW5naWZ5XCIpKSB7XG4gICAgICAgIC8vIEludGVybmFsOiBBIG1hcCBvZiBjb250cm9sIGNoYXJhY3RlcnMgYW5kIHRoZWlyIGVzY2FwZWQgZXF1aXZhbGVudHMuXG4gICAgICAgIHZhciBFc2NhcGVzID0ge1xuICAgICAgICAgIDkyOiBcIlxcXFxcXFxcXCIsXG4gICAgICAgICAgMzQ6ICdcXFxcXCInLFxuICAgICAgICAgIDg6IFwiXFxcXGJcIixcbiAgICAgICAgICAxMjogXCJcXFxcZlwiLFxuICAgICAgICAgIDEwOiBcIlxcXFxuXCIsXG4gICAgICAgICAgMTM6IFwiXFxcXHJcIixcbiAgICAgICAgICA5OiBcIlxcXFx0XCJcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBJbnRlcm5hbDogQ29udmVydHMgYHZhbHVlYCBpbnRvIGEgemVyby1wYWRkZWQgc3RyaW5nIHN1Y2ggdGhhdCBpdHNcbiAgICAgICAgLy8gbGVuZ3RoIGlzIGF0IGxlYXN0IGVxdWFsIHRvIGB3aWR0aGAuIFRoZSBgd2lkdGhgIG11c3QgYmUgPD0gNi5cbiAgICAgICAgdmFyIGxlYWRpbmdaZXJvZXMgPSBcIjAwMDAwMFwiO1xuICAgICAgICB2YXIgdG9QYWRkZWRTdHJpbmcgPSBmdW5jdGlvbiAod2lkdGgsIHZhbHVlKSB7XG4gICAgICAgICAgLy8gVGhlIGB8fCAwYCBleHByZXNzaW9uIGlzIG5lY2Vzc2FyeSB0byB3b3JrIGFyb3VuZCBhIGJ1ZyBpblxuICAgICAgICAgIC8vIE9wZXJhIDw9IDcuNTR1MiB3aGVyZSBgMCA9PSAtMGAsIGJ1dCBgU3RyaW5nKC0wKSAhPT0gXCIwXCJgLlxuICAgICAgICAgIHJldHVybiAobGVhZGluZ1plcm9lcyArICh2YWx1ZSB8fCAwKSkuc2xpY2UoLXdpZHRoKTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBJbnRlcm5hbDogRG91YmxlLXF1b3RlcyBhIHN0cmluZyBgdmFsdWVgLCByZXBsYWNpbmcgYWxsIEFTQ0lJIGNvbnRyb2xcbiAgICAgICAgLy8gY2hhcmFjdGVycyAoY2hhcmFjdGVycyB3aXRoIGNvZGUgdW5pdCB2YWx1ZXMgYmV0d2VlbiAwIGFuZCAzMSkgd2l0aFxuICAgICAgICAvLyB0aGVpciBlc2NhcGVkIGVxdWl2YWxlbnRzLiBUaGlzIGlzIGFuIGltcGxlbWVudGF0aW9uIG9mIHRoZVxuICAgICAgICAvLyBgUXVvdGUodmFsdWUpYCBvcGVyYXRpb24gZGVmaW5lZCBpbiBFUyA1LjEgc2VjdGlvbiAxNS4xMi4zLlxuICAgICAgICB2YXIgdW5pY29kZVByZWZpeCA9IFwiXFxcXHUwMFwiO1xuICAgICAgICB2YXIgcXVvdGUgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICB2YXIgcmVzdWx0ID0gJ1wiJywgaW5kZXggPSAwLCBsZW5ndGggPSB2YWx1ZS5sZW5ndGgsIHVzZUNoYXJJbmRleCA9ICFjaGFySW5kZXhCdWdneSB8fCBsZW5ndGggPiAxMDtcbiAgICAgICAgICB2YXIgc3ltYm9scyA9IHVzZUNoYXJJbmRleCAmJiAoY2hhckluZGV4QnVnZ3kgPyB2YWx1ZS5zcGxpdChcIlwiKSA6IHZhbHVlKTtcbiAgICAgICAgICBmb3IgKDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KyspIHtcbiAgICAgICAgICAgIHZhciBjaGFyQ29kZSA9IHZhbHVlLmNoYXJDb2RlQXQoaW5kZXgpO1xuICAgICAgICAgICAgLy8gSWYgdGhlIGNoYXJhY3RlciBpcyBhIGNvbnRyb2wgY2hhcmFjdGVyLCBhcHBlbmQgaXRzIFVuaWNvZGUgb3JcbiAgICAgICAgICAgIC8vIHNob3J0aGFuZCBlc2NhcGUgc2VxdWVuY2U7IG90aGVyd2lzZSwgYXBwZW5kIHRoZSBjaGFyYWN0ZXIgYXMtaXMuXG4gICAgICAgICAgICBzd2l0Y2ggKGNoYXJDb2RlKSB7XG4gICAgICAgICAgICAgIGNhc2UgODogY2FzZSA5OiBjYXNlIDEwOiBjYXNlIDEyOiBjYXNlIDEzOiBjYXNlIDM0OiBjYXNlIDkyOlxuICAgICAgICAgICAgICAgIHJlc3VsdCArPSBFc2NhcGVzW2NoYXJDb2RlXTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICBpZiAoY2hhckNvZGUgPCAzMikge1xuICAgICAgICAgICAgICAgICAgcmVzdWx0ICs9IHVuaWNvZGVQcmVmaXggKyB0b1BhZGRlZFN0cmluZygyLCBjaGFyQ29kZS50b1N0cmluZygxNikpO1xuICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJlc3VsdCArPSB1c2VDaGFySW5kZXggPyBzeW1ib2xzW2luZGV4XSA6IHZhbHVlLmNoYXJBdChpbmRleCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiByZXN1bHQgKyAnXCInO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEludGVybmFsOiBSZWN1cnNpdmVseSBzZXJpYWxpemVzIGFuIG9iamVjdC4gSW1wbGVtZW50cyB0aGVcbiAgICAgICAgLy8gYFN0cihrZXksIGhvbGRlcilgLCBgSk8odmFsdWUpYCwgYW5kIGBKQSh2YWx1ZSlgIG9wZXJhdGlvbnMuXG4gICAgICAgIHZhciBzZXJpYWxpemUgPSBmdW5jdGlvbiAocHJvcGVydHksIG9iamVjdCwgY2FsbGJhY2ssIHByb3BlcnRpZXMsIHdoaXRlc3BhY2UsIGluZGVudGF0aW9uLCBzdGFjaykge1xuICAgICAgICAgIHZhciB2YWx1ZSwgY2xhc3NOYW1lLCB5ZWFyLCBtb250aCwgZGF0ZSwgdGltZSwgaG91cnMsIG1pbnV0ZXMsIHNlY29uZHMsIG1pbGxpc2Vjb25kcywgcmVzdWx0cywgZWxlbWVudCwgaW5kZXgsIGxlbmd0aCwgcHJlZml4LCByZXN1bHQ7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIE5lY2Vzc2FyeSBmb3IgaG9zdCBvYmplY3Qgc3VwcG9ydC5cbiAgICAgICAgICAgIHZhbHVlID0gb2JqZWN0W3Byb3BlcnR5XTtcbiAgICAgICAgICB9IGNhdGNoIChleGNlcHRpb24pIHt9XG4gICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PSBcIm9iamVjdFwiICYmIHZhbHVlKSB7XG4gICAgICAgICAgICBjbGFzc05hbWUgPSBnZXRDbGFzcy5jYWxsKHZhbHVlKTtcbiAgICAgICAgICAgIGlmIChjbGFzc05hbWUgPT0gZGF0ZUNsYXNzICYmICFpc1Byb3BlcnR5LmNhbGwodmFsdWUsIFwidG9KU09OXCIpKSB7XG4gICAgICAgICAgICAgIGlmICh2YWx1ZSA+IC0xIC8gMCAmJiB2YWx1ZSA8IDEgLyAwKSB7XG4gICAgICAgICAgICAgICAgLy8gRGF0ZXMgYXJlIHNlcmlhbGl6ZWQgYWNjb3JkaW5nIHRvIHRoZSBgRGF0ZSN0b0pTT05gIG1ldGhvZFxuICAgICAgICAgICAgICAgIC8vIHNwZWNpZmllZCBpbiBFUyA1LjEgc2VjdGlvbiAxNS45LjUuNDQuIFNlZSBzZWN0aW9uIDE1LjkuMS4xNVxuICAgICAgICAgICAgICAgIC8vIGZvciB0aGUgSVNPIDg2MDEgZGF0ZSB0aW1lIHN0cmluZyBmb3JtYXQuXG4gICAgICAgICAgICAgICAgaWYgKGdldERheSkge1xuICAgICAgICAgICAgICAgICAgLy8gTWFudWFsbHkgY29tcHV0ZSB0aGUgeWVhciwgbW9udGgsIGRhdGUsIGhvdXJzLCBtaW51dGVzLFxuICAgICAgICAgICAgICAgICAgLy8gc2Vjb25kcywgYW5kIG1pbGxpc2Vjb25kcyBpZiB0aGUgYGdldFVUQypgIG1ldGhvZHMgYXJlXG4gICAgICAgICAgICAgICAgICAvLyBidWdneS4gQWRhcHRlZCBmcm9tIEBZYWZmbGUncyBgZGF0ZS1zaGltYCBwcm9qZWN0LlxuICAgICAgICAgICAgICAgICAgZGF0ZSA9IGZsb29yKHZhbHVlIC8gODY0ZTUpO1xuICAgICAgICAgICAgICAgICAgZm9yICh5ZWFyID0gZmxvb3IoZGF0ZSAvIDM2NS4yNDI1KSArIDE5NzAgLSAxOyBnZXREYXkoeWVhciArIDEsIDApIDw9IGRhdGU7IHllYXIrKyk7XG4gICAgICAgICAgICAgICAgICBmb3IgKG1vbnRoID0gZmxvb3IoKGRhdGUgLSBnZXREYXkoeWVhciwgMCkpIC8gMzAuNDIpOyBnZXREYXkoeWVhciwgbW9udGggKyAxKSA8PSBkYXRlOyBtb250aCsrKTtcbiAgICAgICAgICAgICAgICAgIGRhdGUgPSAxICsgZGF0ZSAtIGdldERheSh5ZWFyLCBtb250aCk7XG4gICAgICAgICAgICAgICAgICAvLyBUaGUgYHRpbWVgIHZhbHVlIHNwZWNpZmllcyB0aGUgdGltZSB3aXRoaW4gdGhlIGRheSAoc2VlIEVTXG4gICAgICAgICAgICAgICAgICAvLyA1LjEgc2VjdGlvbiAxNS45LjEuMikuIFRoZSBmb3JtdWxhIGAoQSAlIEIgKyBCKSAlIEJgIGlzIHVzZWRcbiAgICAgICAgICAgICAgICAgIC8vIHRvIGNvbXB1dGUgYEEgbW9kdWxvIEJgLCBhcyB0aGUgYCVgIG9wZXJhdG9yIGRvZXMgbm90XG4gICAgICAgICAgICAgICAgICAvLyBjb3JyZXNwb25kIHRvIHRoZSBgbW9kdWxvYCBvcGVyYXRpb24gZm9yIG5lZ2F0aXZlIG51bWJlcnMuXG4gICAgICAgICAgICAgICAgICB0aW1lID0gKHZhbHVlICUgODY0ZTUgKyA4NjRlNSkgJSA4NjRlNTtcbiAgICAgICAgICAgICAgICAgIC8vIFRoZSBob3VycywgbWludXRlcywgc2Vjb25kcywgYW5kIG1pbGxpc2Vjb25kcyBhcmUgb2J0YWluZWQgYnlcbiAgICAgICAgICAgICAgICAgIC8vIGRlY29tcG9zaW5nIHRoZSB0aW1lIHdpdGhpbiB0aGUgZGF5LiBTZWUgc2VjdGlvbiAxNS45LjEuMTAuXG4gICAgICAgICAgICAgICAgICBob3VycyA9IGZsb29yKHRpbWUgLyAzNmU1KSAlIDI0O1xuICAgICAgICAgICAgICAgICAgbWludXRlcyA9IGZsb29yKHRpbWUgLyA2ZTQpICUgNjA7XG4gICAgICAgICAgICAgICAgICBzZWNvbmRzID0gZmxvb3IodGltZSAvIDFlMykgJSA2MDtcbiAgICAgICAgICAgICAgICAgIG1pbGxpc2Vjb25kcyA9IHRpbWUgJSAxZTM7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgIHllYXIgPSB2YWx1ZS5nZXRVVENGdWxsWWVhcigpO1xuICAgICAgICAgICAgICAgICAgbW9udGggPSB2YWx1ZS5nZXRVVENNb250aCgpO1xuICAgICAgICAgICAgICAgICAgZGF0ZSA9IHZhbHVlLmdldFVUQ0RhdGUoKTtcbiAgICAgICAgICAgICAgICAgIGhvdXJzID0gdmFsdWUuZ2V0VVRDSG91cnMoKTtcbiAgICAgICAgICAgICAgICAgIG1pbnV0ZXMgPSB2YWx1ZS5nZXRVVENNaW51dGVzKCk7XG4gICAgICAgICAgICAgICAgICBzZWNvbmRzID0gdmFsdWUuZ2V0VVRDU2Vjb25kcygpO1xuICAgICAgICAgICAgICAgICAgbWlsbGlzZWNvbmRzID0gdmFsdWUuZ2V0VVRDTWlsbGlzZWNvbmRzKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIFNlcmlhbGl6ZSBleHRlbmRlZCB5ZWFycyBjb3JyZWN0bHkuXG4gICAgICAgICAgICAgICAgdmFsdWUgPSAoeWVhciA8PSAwIHx8IHllYXIgPj0gMWU0ID8gKHllYXIgPCAwID8gXCItXCIgOiBcIitcIikgKyB0b1BhZGRlZFN0cmluZyg2LCB5ZWFyIDwgMCA/IC15ZWFyIDogeWVhcikgOiB0b1BhZGRlZFN0cmluZyg0LCB5ZWFyKSkgK1xuICAgICAgICAgICAgICAgICAgXCItXCIgKyB0b1BhZGRlZFN0cmluZygyLCBtb250aCArIDEpICsgXCItXCIgKyB0b1BhZGRlZFN0cmluZygyLCBkYXRlKSArXG4gICAgICAgICAgICAgICAgICAvLyBNb250aHMsIGRhdGVzLCBob3VycywgbWludXRlcywgYW5kIHNlY29uZHMgc2hvdWxkIGhhdmUgdHdvXG4gICAgICAgICAgICAgICAgICAvLyBkaWdpdHM7IG1pbGxpc2Vjb25kcyBzaG91bGQgaGF2ZSB0aHJlZS5cbiAgICAgICAgICAgICAgICAgIFwiVFwiICsgdG9QYWRkZWRTdHJpbmcoMiwgaG91cnMpICsgXCI6XCIgKyB0b1BhZGRlZFN0cmluZygyLCBtaW51dGVzKSArIFwiOlwiICsgdG9QYWRkZWRTdHJpbmcoMiwgc2Vjb25kcykgK1xuICAgICAgICAgICAgICAgICAgLy8gTWlsbGlzZWNvbmRzIGFyZSBvcHRpb25hbCBpbiBFUyA1LjAsIGJ1dCByZXF1aXJlZCBpbiA1LjEuXG4gICAgICAgICAgICAgICAgICBcIi5cIiArIHRvUGFkZGVkU3RyaW5nKDMsIG1pbGxpc2Vjb25kcykgKyBcIlpcIjtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YWx1ZSA9IG51bGw7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbHVlLnRvSlNPTiA9PSBcImZ1bmN0aW9uXCIgJiYgKChjbGFzc05hbWUgIT0gbnVtYmVyQ2xhc3MgJiYgY2xhc3NOYW1lICE9IHN0cmluZ0NsYXNzICYmIGNsYXNzTmFtZSAhPSBhcnJheUNsYXNzKSB8fCBpc1Byb3BlcnR5LmNhbGwodmFsdWUsIFwidG9KU09OXCIpKSkge1xuICAgICAgICAgICAgICAvLyBQcm90b3R5cGUgPD0gMS42LjEgYWRkcyBub24tc3RhbmRhcmQgYHRvSlNPTmAgbWV0aG9kcyB0byB0aGVcbiAgICAgICAgICAgICAgLy8gYE51bWJlcmAsIGBTdHJpbmdgLCBgRGF0ZWAsIGFuZCBgQXJyYXlgIHByb3RvdHlwZXMuIEpTT04gM1xuICAgICAgICAgICAgICAvLyBpZ25vcmVzIGFsbCBgdG9KU09OYCBtZXRob2RzIG9uIHRoZXNlIG9iamVjdHMgdW5sZXNzIHRoZXkgYXJlXG4gICAgICAgICAgICAgIC8vIGRlZmluZWQgZGlyZWN0bHkgb24gYW4gaW5zdGFuY2UuXG4gICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUudG9KU09OKHByb3BlcnR5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAvLyBJZiBhIHJlcGxhY2VtZW50IGZ1bmN0aW9uIHdhcyBwcm92aWRlZCwgY2FsbCBpdCB0byBvYnRhaW4gdGhlIHZhbHVlXG4gICAgICAgICAgICAvLyBmb3Igc2VyaWFsaXphdGlvbi5cbiAgICAgICAgICAgIHZhbHVlID0gY2FsbGJhY2suY2FsbChvYmplY3QsIHByb3BlcnR5LCB2YWx1ZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICh2YWx1ZSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIFwibnVsbFwiO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjbGFzc05hbWUgPSBnZXRDbGFzcy5jYWxsKHZhbHVlKTtcbiAgICAgICAgICBpZiAoY2xhc3NOYW1lID09IGJvb2xlYW5DbGFzcykge1xuICAgICAgICAgICAgLy8gQm9vbGVhbnMgYXJlIHJlcHJlc2VudGVkIGxpdGVyYWxseS5cbiAgICAgICAgICAgIHJldHVybiBcIlwiICsgdmFsdWU7XG4gICAgICAgICAgfSBlbHNlIGlmIChjbGFzc05hbWUgPT0gbnVtYmVyQ2xhc3MpIHtcbiAgICAgICAgICAgIC8vIEpTT04gbnVtYmVycyBtdXN0IGJlIGZpbml0ZS4gYEluZmluaXR5YCBhbmQgYE5hTmAgYXJlIHNlcmlhbGl6ZWQgYXNcbiAgICAgICAgICAgIC8vIGBcIm51bGxcImAuXG4gICAgICAgICAgICByZXR1cm4gdmFsdWUgPiAtMSAvIDAgJiYgdmFsdWUgPCAxIC8gMCA/IFwiXCIgKyB2YWx1ZSA6IFwibnVsbFwiO1xuICAgICAgICAgIH0gZWxzZSBpZiAoY2xhc3NOYW1lID09IHN0cmluZ0NsYXNzKSB7XG4gICAgICAgICAgICAvLyBTdHJpbmdzIGFyZSBkb3VibGUtcXVvdGVkIGFuZCBlc2NhcGVkLlxuICAgICAgICAgICAgcmV0dXJuIHF1b3RlKFwiXCIgKyB2YWx1ZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIFJlY3Vyc2l2ZWx5IHNlcmlhbGl6ZSBvYmplY3RzIGFuZCBhcnJheXMuXG4gICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAvLyBDaGVjayBmb3IgY3ljbGljIHN0cnVjdHVyZXMuIFRoaXMgaXMgYSBsaW5lYXIgc2VhcmNoOyBwZXJmb3JtYW5jZVxuICAgICAgICAgICAgLy8gaXMgaW52ZXJzZWx5IHByb3BvcnRpb25hbCB0byB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBuZXN0ZWQgb2JqZWN0cy5cbiAgICAgICAgICAgIGZvciAobGVuZ3RoID0gc3RhY2subGVuZ3RoOyBsZW5ndGgtLTspIHtcbiAgICAgICAgICAgICAgaWYgKHN0YWNrW2xlbmd0aF0gPT09IHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgLy8gQ3ljbGljIHN0cnVjdHVyZXMgY2Fubm90IGJlIHNlcmlhbGl6ZWQgYnkgYEpTT04uc3RyaW5naWZ5YC5cbiAgICAgICAgICAgICAgICB0aHJvdyBUeXBlRXJyb3IoKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gQWRkIHRoZSBvYmplY3QgdG8gdGhlIHN0YWNrIG9mIHRyYXZlcnNlZCBvYmplY3RzLlxuICAgICAgICAgICAgc3RhY2sucHVzaCh2YWx1ZSk7XG4gICAgICAgICAgICByZXN1bHRzID0gW107XG4gICAgICAgICAgICAvLyBTYXZlIHRoZSBjdXJyZW50IGluZGVudGF0aW9uIGxldmVsIGFuZCBpbmRlbnQgb25lIGFkZGl0aW9uYWwgbGV2ZWwuXG4gICAgICAgICAgICBwcmVmaXggPSBpbmRlbnRhdGlvbjtcbiAgICAgICAgICAgIGluZGVudGF0aW9uICs9IHdoaXRlc3BhY2U7XG4gICAgICAgICAgICBpZiAoY2xhc3NOYW1lID09IGFycmF5Q2xhc3MpIHtcbiAgICAgICAgICAgICAgLy8gUmVjdXJzaXZlbHkgc2VyaWFsaXplIGFycmF5IGVsZW1lbnRzLlxuICAgICAgICAgICAgICBmb3IgKGluZGV4ID0gMCwgbGVuZ3RoID0gdmFsdWUubGVuZ3RoOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKykge1xuICAgICAgICAgICAgICAgIGVsZW1lbnQgPSBzZXJpYWxpemUoaW5kZXgsIHZhbHVlLCBjYWxsYmFjaywgcHJvcGVydGllcywgd2hpdGVzcGFjZSwgaW5kZW50YXRpb24sIHN0YWNrKTtcbiAgICAgICAgICAgICAgICByZXN1bHRzLnB1c2goZWxlbWVudCA9PT0gdW5kZWYgPyBcIm51bGxcIiA6IGVsZW1lbnQpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJlc3VsdCA9IHJlc3VsdHMubGVuZ3RoID8gKHdoaXRlc3BhY2UgPyBcIltcXG5cIiArIGluZGVudGF0aW9uICsgcmVzdWx0cy5qb2luKFwiLFxcblwiICsgaW5kZW50YXRpb24pICsgXCJcXG5cIiArIHByZWZpeCArIFwiXVwiIDogKFwiW1wiICsgcmVzdWx0cy5qb2luKFwiLFwiKSArIFwiXVwiKSkgOiBcIltdXCI7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAvLyBSZWN1cnNpdmVseSBzZXJpYWxpemUgb2JqZWN0IG1lbWJlcnMuIE1lbWJlcnMgYXJlIHNlbGVjdGVkIGZyb21cbiAgICAgICAgICAgICAgLy8gZWl0aGVyIGEgdXNlci1zcGVjaWZpZWQgbGlzdCBvZiBwcm9wZXJ0eSBuYW1lcywgb3IgdGhlIG9iamVjdFxuICAgICAgICAgICAgICAvLyBpdHNlbGYuXG4gICAgICAgICAgICAgIGZvckVhY2gocHJvcGVydGllcyB8fCB2YWx1ZSwgZnVuY3Rpb24gKHByb3BlcnR5KSB7XG4gICAgICAgICAgICAgICAgdmFyIGVsZW1lbnQgPSBzZXJpYWxpemUocHJvcGVydHksIHZhbHVlLCBjYWxsYmFjaywgcHJvcGVydGllcywgd2hpdGVzcGFjZSwgaW5kZW50YXRpb24sIHN0YWNrKTtcbiAgICAgICAgICAgICAgICBpZiAoZWxlbWVudCAhPT0gdW5kZWYpIHtcbiAgICAgICAgICAgICAgICAgIC8vIEFjY29yZGluZyB0byBFUyA1LjEgc2VjdGlvbiAxNS4xMi4zOiBcIklmIGBnYXBgIHt3aGl0ZXNwYWNlfVxuICAgICAgICAgICAgICAgICAgLy8gaXMgbm90IHRoZSBlbXB0eSBzdHJpbmcsIGxldCBgbWVtYmVyYCB7cXVvdGUocHJvcGVydHkpICsgXCI6XCJ9XG4gICAgICAgICAgICAgICAgICAvLyBiZSB0aGUgY29uY2F0ZW5hdGlvbiBvZiBgbWVtYmVyYCBhbmQgdGhlIGBzcGFjZWAgY2hhcmFjdGVyLlwiXG4gICAgICAgICAgICAgICAgICAvLyBUaGUgXCJgc3BhY2VgIGNoYXJhY3RlclwiIHJlZmVycyB0byB0aGUgbGl0ZXJhbCBzcGFjZVxuICAgICAgICAgICAgICAgICAgLy8gY2hhcmFjdGVyLCBub3QgdGhlIGBzcGFjZWAge3dpZHRofSBhcmd1bWVudCBwcm92aWRlZCB0b1xuICAgICAgICAgICAgICAgICAgLy8gYEpTT04uc3RyaW5naWZ5YC5cbiAgICAgICAgICAgICAgICAgIHJlc3VsdHMucHVzaChxdW90ZShwcm9wZXJ0eSkgKyBcIjpcIiArICh3aGl0ZXNwYWNlID8gXCIgXCIgOiBcIlwiKSArIGVsZW1lbnQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIHJlc3VsdCA9IHJlc3VsdHMubGVuZ3RoID8gKHdoaXRlc3BhY2UgPyBcIntcXG5cIiArIGluZGVudGF0aW9uICsgcmVzdWx0cy5qb2luKFwiLFxcblwiICsgaW5kZW50YXRpb24pICsgXCJcXG5cIiArIHByZWZpeCArIFwifVwiIDogKFwie1wiICsgcmVzdWx0cy5qb2luKFwiLFwiKSArIFwifVwiKSkgOiBcInt9XCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBSZW1vdmUgdGhlIG9iamVjdCBmcm9tIHRoZSB0cmF2ZXJzZWQgb2JqZWN0IHN0YWNrLlxuICAgICAgICAgICAgc3RhY2sucG9wKCk7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICAvLyBQdWJsaWM6IGBKU09OLnN0cmluZ2lmeWAuIFNlZSBFUyA1LjEgc2VjdGlvbiAxNS4xMi4zLlxuICAgICAgICBleHBvcnRzLnN0cmluZ2lmeSA9IGZ1bmN0aW9uIChzb3VyY2UsIGZpbHRlciwgd2lkdGgpIHtcbiAgICAgICAgICB2YXIgd2hpdGVzcGFjZSwgY2FsbGJhY2ssIHByb3BlcnRpZXMsIGNsYXNzTmFtZTtcbiAgICAgICAgICBpZiAob2JqZWN0VHlwZXNbdHlwZW9mIGZpbHRlcl0gJiYgZmlsdGVyKSB7XG4gICAgICAgICAgICBpZiAoKGNsYXNzTmFtZSA9IGdldENsYXNzLmNhbGwoZmlsdGVyKSkgPT0gZnVuY3Rpb25DbGFzcykge1xuICAgICAgICAgICAgICBjYWxsYmFjayA9IGZpbHRlcjtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY2xhc3NOYW1lID09IGFycmF5Q2xhc3MpIHtcbiAgICAgICAgICAgICAgLy8gQ29udmVydCB0aGUgcHJvcGVydHkgbmFtZXMgYXJyYXkgaW50byBhIG1ha2VzaGlmdCBzZXQuXG4gICAgICAgICAgICAgIHByb3BlcnRpZXMgPSB7fTtcbiAgICAgICAgICAgICAgZm9yICh2YXIgaW5kZXggPSAwLCBsZW5ndGggPSBmaWx0ZXIubGVuZ3RoLCB2YWx1ZTsgaW5kZXggPCBsZW5ndGg7IHZhbHVlID0gZmlsdGVyW2luZGV4KytdLCAoKGNsYXNzTmFtZSA9IGdldENsYXNzLmNhbGwodmFsdWUpKSwgY2xhc3NOYW1lID09IHN0cmluZ0NsYXNzIHx8IGNsYXNzTmFtZSA9PSBudW1iZXJDbGFzcykgJiYgKHByb3BlcnRpZXNbdmFsdWVdID0gMSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAod2lkdGgpIHtcbiAgICAgICAgICAgIGlmICgoY2xhc3NOYW1lID0gZ2V0Q2xhc3MuY2FsbCh3aWR0aCkpID09IG51bWJlckNsYXNzKSB7XG4gICAgICAgICAgICAgIC8vIENvbnZlcnQgdGhlIGB3aWR0aGAgdG8gYW4gaW50ZWdlciBhbmQgY3JlYXRlIGEgc3RyaW5nIGNvbnRhaW5pbmdcbiAgICAgICAgICAgICAgLy8gYHdpZHRoYCBudW1iZXIgb2Ygc3BhY2UgY2hhcmFjdGVycy5cbiAgICAgICAgICAgICAgaWYgKCh3aWR0aCAtPSB3aWR0aCAlIDEpID4gMCkge1xuICAgICAgICAgICAgICAgIGZvciAod2hpdGVzcGFjZSA9IFwiXCIsIHdpZHRoID4gMTAgJiYgKHdpZHRoID0gMTApOyB3aGl0ZXNwYWNlLmxlbmd0aCA8IHdpZHRoOyB3aGl0ZXNwYWNlICs9IFwiIFwiKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmIChjbGFzc05hbWUgPT0gc3RyaW5nQ2xhc3MpIHtcbiAgICAgICAgICAgICAgd2hpdGVzcGFjZSA9IHdpZHRoLmxlbmd0aCA8PSAxMCA/IHdpZHRoIDogd2lkdGguc2xpY2UoMCwgMTApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBPcGVyYSA8PSA3LjU0dTIgZGlzY2FyZHMgdGhlIHZhbHVlcyBhc3NvY2lhdGVkIHdpdGggZW1wdHkgc3RyaW5nIGtleXNcbiAgICAgICAgICAvLyAoYFwiXCJgKSBvbmx5IGlmIHRoZXkgYXJlIHVzZWQgZGlyZWN0bHkgd2l0aGluIGFuIG9iamVjdCBtZW1iZXIgbGlzdFxuICAgICAgICAgIC8vIChlLmcuLCBgIShcIlwiIGluIHsgXCJcIjogMX0pYCkuXG4gICAgICAgICAgcmV0dXJuIHNlcmlhbGl6ZShcIlwiLCAodmFsdWUgPSB7fSwgdmFsdWVbXCJcIl0gPSBzb3VyY2UsIHZhbHVlKSwgY2FsbGJhY2ssIHByb3BlcnRpZXMsIHdoaXRlc3BhY2UsIFwiXCIsIFtdKTtcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgLy8gUHVibGljOiBQYXJzZXMgYSBKU09OIHNvdXJjZSBzdHJpbmcuXG4gICAgICBpZiAoIWhhcyhcImpzb24tcGFyc2VcIikpIHtcbiAgICAgICAgdmFyIGZyb21DaGFyQ29kZSA9IFN0cmluZy5mcm9tQ2hhckNvZGU7XG5cbiAgICAgICAgLy8gSW50ZXJuYWw6IEEgbWFwIG9mIGVzY2FwZWQgY29udHJvbCBjaGFyYWN0ZXJzIGFuZCB0aGVpciB1bmVzY2FwZWRcbiAgICAgICAgLy8gZXF1aXZhbGVudHMuXG4gICAgICAgIHZhciBVbmVzY2FwZXMgPSB7XG4gICAgICAgICAgOTI6IFwiXFxcXFwiLFxuICAgICAgICAgIDM0OiAnXCInLFxuICAgICAgICAgIDQ3OiBcIi9cIixcbiAgICAgICAgICA5ODogXCJcXGJcIixcbiAgICAgICAgICAxMTY6IFwiXFx0XCIsXG4gICAgICAgICAgMTEwOiBcIlxcblwiLFxuICAgICAgICAgIDEwMjogXCJcXGZcIixcbiAgICAgICAgICAxMTQ6IFwiXFxyXCJcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBJbnRlcm5hbDogU3RvcmVzIHRoZSBwYXJzZXIgc3RhdGUuXG4gICAgICAgIHZhciBJbmRleCwgU291cmNlO1xuXG4gICAgICAgIC8vIEludGVybmFsOiBSZXNldHMgdGhlIHBhcnNlciBzdGF0ZSBhbmQgdGhyb3dzIGEgYFN5bnRheEVycm9yYC5cbiAgICAgICAgdmFyIGFib3J0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgIEluZGV4ID0gU291cmNlID0gbnVsbDtcbiAgICAgICAgICB0aHJvdyBTeW50YXhFcnJvcigpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEludGVybmFsOiBSZXR1cm5zIHRoZSBuZXh0IHRva2VuLCBvciBgXCIkXCJgIGlmIHRoZSBwYXJzZXIgaGFzIHJlYWNoZWRcbiAgICAgICAgLy8gdGhlIGVuZCBvZiB0aGUgc291cmNlIHN0cmluZy4gQSB0b2tlbiBtYXkgYmUgYSBzdHJpbmcsIG51bWJlciwgYG51bGxgXG4gICAgICAgIC8vIGxpdGVyYWwsIG9yIEJvb2xlYW4gbGl0ZXJhbC5cbiAgICAgICAgdmFyIGxleCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICB2YXIgc291cmNlID0gU291cmNlLCBsZW5ndGggPSBzb3VyY2UubGVuZ3RoLCB2YWx1ZSwgYmVnaW4sIHBvc2l0aW9uLCBpc1NpZ25lZCwgY2hhckNvZGU7XG4gICAgICAgICAgd2hpbGUgKEluZGV4IDwgbGVuZ3RoKSB7XG4gICAgICAgICAgICBjaGFyQ29kZSA9IHNvdXJjZS5jaGFyQ29kZUF0KEluZGV4KTtcbiAgICAgICAgICAgIHN3aXRjaCAoY2hhckNvZGUpIHtcbiAgICAgICAgICAgICAgY2FzZSA5OiBjYXNlIDEwOiBjYXNlIDEzOiBjYXNlIDMyOlxuICAgICAgICAgICAgICAgIC8vIFNraXAgd2hpdGVzcGFjZSB0b2tlbnMsIGluY2x1ZGluZyB0YWJzLCBjYXJyaWFnZSByZXR1cm5zLCBsaW5lXG4gICAgICAgICAgICAgICAgLy8gZmVlZHMsIGFuZCBzcGFjZSBjaGFyYWN0ZXJzLlxuICAgICAgICAgICAgICAgIEluZGV4Kys7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgIGNhc2UgMTIzOiBjYXNlIDEyNTogY2FzZSA5MTogY2FzZSA5MzogY2FzZSA1ODogY2FzZSA0NDpcbiAgICAgICAgICAgICAgICAvLyBQYXJzZSBhIHB1bmN0dWF0b3IgdG9rZW4gKGB7YCwgYH1gLCBgW2AsIGBdYCwgYDpgLCBvciBgLGApIGF0XG4gICAgICAgICAgICAgICAgLy8gdGhlIGN1cnJlbnQgcG9zaXRpb24uXG4gICAgICAgICAgICAgICAgdmFsdWUgPSBjaGFySW5kZXhCdWdneSA/IHNvdXJjZS5jaGFyQXQoSW5kZXgpIDogc291cmNlW0luZGV4XTtcbiAgICAgICAgICAgICAgICBJbmRleCsrO1xuICAgICAgICAgICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgICAgICAgICAgY2FzZSAzNDpcbiAgICAgICAgICAgICAgICAvLyBgXCJgIGRlbGltaXRzIGEgSlNPTiBzdHJpbmc7IGFkdmFuY2UgdG8gdGhlIG5leHQgY2hhcmFjdGVyIGFuZFxuICAgICAgICAgICAgICAgIC8vIGJlZ2luIHBhcnNpbmcgdGhlIHN0cmluZy4gU3RyaW5nIHRva2VucyBhcmUgcHJlZml4ZWQgd2l0aCB0aGVcbiAgICAgICAgICAgICAgICAvLyBzZW50aW5lbCBgQGAgY2hhcmFjdGVyIHRvIGRpc3Rpbmd1aXNoIHRoZW0gZnJvbSBwdW5jdHVhdG9ycyBhbmRcbiAgICAgICAgICAgICAgICAvLyBlbmQtb2Ytc3RyaW5nIHRva2Vucy5cbiAgICAgICAgICAgICAgICBmb3IgKHZhbHVlID0gXCJAXCIsIEluZGV4Kys7IEluZGV4IDwgbGVuZ3RoOykge1xuICAgICAgICAgICAgICAgICAgY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdChJbmRleCk7XG4gICAgICAgICAgICAgICAgICBpZiAoY2hhckNvZGUgPCAzMikge1xuICAgICAgICAgICAgICAgICAgICAvLyBVbmVzY2FwZWQgQVNDSUkgY29udHJvbCBjaGFyYWN0ZXJzICh0aG9zZSB3aXRoIGEgY29kZSB1bml0XG4gICAgICAgICAgICAgICAgICAgIC8vIGxlc3MgdGhhbiB0aGUgc3BhY2UgY2hhcmFjdGVyKSBhcmUgbm90IHBlcm1pdHRlZC5cbiAgICAgICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoY2hhckNvZGUgPT0gOTIpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQSByZXZlcnNlIHNvbGlkdXMgKGBcXGApIG1hcmtzIHRoZSBiZWdpbm5pbmcgb2YgYW4gZXNjYXBlZFxuICAgICAgICAgICAgICAgICAgICAvLyBjb250cm9sIGNoYXJhY3RlciAoaW5jbHVkaW5nIGBcImAsIGBcXGAsIGFuZCBgL2ApIG9yIFVuaWNvZGVcbiAgICAgICAgICAgICAgICAgICAgLy8gZXNjYXBlIHNlcXVlbmNlLlxuICAgICAgICAgICAgICAgICAgICBjaGFyQ29kZSA9IHNvdXJjZS5jaGFyQ29kZUF0KCsrSW5kZXgpO1xuICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKGNoYXJDb2RlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgY2FzZSA5MjogY2FzZSAzNDogY2FzZSA0NzogY2FzZSA5ODogY2FzZSAxMTY6IGNhc2UgMTEwOiBjYXNlIDEwMjogY2FzZSAxMTQ6XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBSZXZpdmUgZXNjYXBlZCBjb250cm9sIGNoYXJhY3RlcnMuXG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSArPSBVbmVzY2FwZXNbY2hhckNvZGVdO1xuICAgICAgICAgICAgICAgICAgICAgICAgSW5kZXgrKztcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgIGNhc2UgMTE3OlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYFxcdWAgbWFya3MgdGhlIGJlZ2lubmluZyBvZiBhIFVuaWNvZGUgZXNjYXBlIHNlcXVlbmNlLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWR2YW5jZSB0byB0aGUgZmlyc3QgY2hhcmFjdGVyIGFuZCB2YWxpZGF0ZSB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZvdXItZGlnaXQgY29kZSBwb2ludC5cbiAgICAgICAgICAgICAgICAgICAgICAgIGJlZ2luID0gKytJbmRleDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAocG9zaXRpb24gPSBJbmRleCArIDQ7IEluZGV4IDwgcG9zaXRpb247IEluZGV4KyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdChJbmRleCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEEgdmFsaWQgc2VxdWVuY2UgY29tcHJpc2VzIGZvdXIgaGV4ZGlnaXRzIChjYXNlLVxuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpbnNlbnNpdGl2ZSkgdGhhdCBmb3JtIGEgc2luZ2xlIGhleGFkZWNpbWFsIHZhbHVlLlxuICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIShjaGFyQ29kZSA+PSA0OCAmJiBjaGFyQ29kZSA8PSA1NyB8fCBjaGFyQ29kZSA+PSA5NyAmJiBjaGFyQ29kZSA8PSAxMDIgfHwgY2hhckNvZGUgPj0gNjUgJiYgY2hhckNvZGUgPD0gNzApKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW52YWxpZCBVbmljb2RlIGVzY2FwZSBzZXF1ZW5jZS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBSZXZpdmUgdGhlIGVzY2FwZWQgY2hhcmFjdGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgKz0gZnJvbUNoYXJDb2RlKFwiMHhcIiArIHNvdXJjZS5zbGljZShiZWdpbiwgSW5kZXgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJbnZhbGlkIGVzY2FwZSBzZXF1ZW5jZS5cbiAgICAgICAgICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjaGFyQ29kZSA9PSAzNCkge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIEFuIHVuZXNjYXBlZCBkb3VibGUtcXVvdGUgY2hhcmFjdGVyIG1hcmtzIHRoZSBlbmQgb2YgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgLy8gc3RyaW5nLlxuICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNoYXJDb2RlID0gc291cmNlLmNoYXJDb2RlQXQoSW5kZXgpO1xuICAgICAgICAgICAgICAgICAgICBiZWdpbiA9IEluZGV4O1xuICAgICAgICAgICAgICAgICAgICAvLyBPcHRpbWl6ZSBmb3IgdGhlIGNvbW1vbiBjYXNlIHdoZXJlIGEgc3RyaW5nIGlzIHZhbGlkLlxuICAgICAgICAgICAgICAgICAgICB3aGlsZSAoY2hhckNvZGUgPj0gMzIgJiYgY2hhckNvZGUgIT0gOTIgJiYgY2hhckNvZGUgIT0gMzQpIHtcbiAgICAgICAgICAgICAgICAgICAgICBjaGFyQ29kZSA9IHNvdXJjZS5jaGFyQ29kZUF0KCsrSW5kZXgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8vIEFwcGVuZCB0aGUgc3RyaW5nIGFzLWlzLlxuICAgICAgICAgICAgICAgICAgICB2YWx1ZSArPSBzb3VyY2Uuc2xpY2UoYmVnaW4sIEluZGV4KTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHNvdXJjZS5jaGFyQ29kZUF0KEluZGV4KSA9PSAzNCkge1xuICAgICAgICAgICAgICAgICAgLy8gQWR2YW5jZSB0byB0aGUgbmV4dCBjaGFyYWN0ZXIgYW5kIHJldHVybiB0aGUgcmV2aXZlZCBzdHJpbmcuXG4gICAgICAgICAgICAgICAgICBJbmRleCsrO1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBVbnRlcm1pbmF0ZWQgc3RyaW5nLlxuICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgLy8gUGFyc2UgbnVtYmVycyBhbmQgbGl0ZXJhbHMuXG4gICAgICAgICAgICAgICAgYmVnaW4gPSBJbmRleDtcbiAgICAgICAgICAgICAgICAvLyBBZHZhbmNlIHBhc3QgdGhlIG5lZ2F0aXZlIHNpZ24sIGlmIG9uZSBpcyBzcGVjaWZpZWQuXG4gICAgICAgICAgICAgICAgaWYgKGNoYXJDb2RlID09IDQ1KSB7XG4gICAgICAgICAgICAgICAgICBpc1NpZ25lZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICBjaGFyQ29kZSA9IHNvdXJjZS5jaGFyQ29kZUF0KCsrSW5kZXgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBQYXJzZSBhbiBpbnRlZ2VyIG9yIGZsb2F0aW5nLXBvaW50IHZhbHVlLlxuICAgICAgICAgICAgICAgIGlmIChjaGFyQ29kZSA+PSA0OCAmJiBjaGFyQ29kZSA8PSA1Nykge1xuICAgICAgICAgICAgICAgICAgLy8gTGVhZGluZyB6ZXJvZXMgYXJlIGludGVycHJldGVkIGFzIG9jdGFsIGxpdGVyYWxzLlxuICAgICAgICAgICAgICAgICAgaWYgKGNoYXJDb2RlID09IDQ4ICYmICgoY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdChJbmRleCArIDEpKSwgY2hhckNvZGUgPj0gNDggJiYgY2hhckNvZGUgPD0gNTcpKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIElsbGVnYWwgb2N0YWwgbGl0ZXJhbC5cbiAgICAgICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIGlzU2lnbmVkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAvLyBQYXJzZSB0aGUgaW50ZWdlciBjb21wb25lbnQuXG4gICAgICAgICAgICAgICAgICBmb3IgKDsgSW5kZXggPCBsZW5ndGggJiYgKChjaGFyQ29kZSA9IHNvdXJjZS5jaGFyQ29kZUF0KEluZGV4KSksIGNoYXJDb2RlID49IDQ4ICYmIGNoYXJDb2RlIDw9IDU3KTsgSW5kZXgrKyk7XG4gICAgICAgICAgICAgICAgICAvLyBGbG9hdHMgY2Fubm90IGNvbnRhaW4gYSBsZWFkaW5nIGRlY2ltYWwgcG9pbnQ7IGhvd2V2ZXIsIHRoaXNcbiAgICAgICAgICAgICAgICAgIC8vIGNhc2UgaXMgYWxyZWFkeSBhY2NvdW50ZWQgZm9yIGJ5IHRoZSBwYXJzZXIuXG4gICAgICAgICAgICAgICAgICBpZiAoc291cmNlLmNoYXJDb2RlQXQoSW5kZXgpID09IDQ2KSB7XG4gICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gKytJbmRleDtcbiAgICAgICAgICAgICAgICAgICAgLy8gUGFyc2UgdGhlIGRlY2ltYWwgY29tcG9uZW50LlxuICAgICAgICAgICAgICAgICAgICBmb3IgKDsgcG9zaXRpb24gPCBsZW5ndGggJiYgKChjaGFyQ29kZSA9IHNvdXJjZS5jaGFyQ29kZUF0KHBvc2l0aW9uKSksIGNoYXJDb2RlID49IDQ4ICYmIGNoYXJDb2RlIDw9IDU3KTsgcG9zaXRpb24rKyk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChwb3NpdGlvbiA9PSBJbmRleCkge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIElsbGVnYWwgdHJhaWxpbmcgZGVjaW1hbC5cbiAgICAgICAgICAgICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIEluZGV4ID0gcG9zaXRpb247XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAvLyBQYXJzZSBleHBvbmVudHMuIFRoZSBgZWAgZGVub3RpbmcgdGhlIGV4cG9uZW50IGlzXG4gICAgICAgICAgICAgICAgICAvLyBjYXNlLWluc2Vuc2l0aXZlLlxuICAgICAgICAgICAgICAgICAgY2hhckNvZGUgPSBzb3VyY2UuY2hhckNvZGVBdChJbmRleCk7XG4gICAgICAgICAgICAgICAgICBpZiAoY2hhckNvZGUgPT0gMTAxIHx8IGNoYXJDb2RlID09IDY5KSB7XG4gICAgICAgICAgICAgICAgICAgIGNoYXJDb2RlID0gc291cmNlLmNoYXJDb2RlQXQoKytJbmRleCk7XG4gICAgICAgICAgICAgICAgICAgIC8vIFNraXAgcGFzdCB0aGUgc2lnbiBmb2xsb3dpbmcgdGhlIGV4cG9uZW50LCBpZiBvbmUgaXNcbiAgICAgICAgICAgICAgICAgICAgLy8gc3BlY2lmaWVkLlxuICAgICAgICAgICAgICAgICAgICBpZiAoY2hhckNvZGUgPT0gNDMgfHwgY2hhckNvZGUgPT0gNDUpIHtcbiAgICAgICAgICAgICAgICAgICAgICBJbmRleCsrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8vIFBhcnNlIHRoZSBleHBvbmVudGlhbCBjb21wb25lbnQuXG4gICAgICAgICAgICAgICAgICAgIGZvciAocG9zaXRpb24gPSBJbmRleDsgcG9zaXRpb24gPCBsZW5ndGggJiYgKChjaGFyQ29kZSA9IHNvdXJjZS5jaGFyQ29kZUF0KHBvc2l0aW9uKSksIGNoYXJDb2RlID49IDQ4ICYmIGNoYXJDb2RlIDw9IDU3KTsgcG9zaXRpb24rKyk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChwb3NpdGlvbiA9PSBJbmRleCkge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIElsbGVnYWwgZW1wdHkgZXhwb25lbnQuXG4gICAgICAgICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBJbmRleCA9IHBvc2l0aW9uO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgLy8gQ29lcmNlIHRoZSBwYXJzZWQgdmFsdWUgdG8gYSBKYXZhU2NyaXB0IG51bWJlci5cbiAgICAgICAgICAgICAgICAgIHJldHVybiArc291cmNlLnNsaWNlKGJlZ2luLCBJbmRleCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIEEgbmVnYXRpdmUgc2lnbiBtYXkgb25seSBwcmVjZWRlIG51bWJlcnMuXG4gICAgICAgICAgICAgICAgaWYgKGlzU2lnbmVkKSB7XG4gICAgICAgICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBgdHJ1ZWAsIGBmYWxzZWAsIGFuZCBgbnVsbGAgbGl0ZXJhbHMuXG4gICAgICAgICAgICAgICAgaWYgKHNvdXJjZS5zbGljZShJbmRleCwgSW5kZXggKyA0KSA9PSBcInRydWVcIikge1xuICAgICAgICAgICAgICAgICAgSW5kZXggKz0gNDtcbiAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoc291cmNlLnNsaWNlKEluZGV4LCBJbmRleCArIDUpID09IFwiZmFsc2VcIikge1xuICAgICAgICAgICAgICAgICAgSW5kZXggKz0gNTtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHNvdXJjZS5zbGljZShJbmRleCwgSW5kZXggKyA0KSA9PSBcIm51bGxcIikge1xuICAgICAgICAgICAgICAgICAgSW5kZXggKz0gNDtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBVbnJlY29nbml6ZWQgdG9rZW4uXG4gICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gUmV0dXJuIHRoZSBzZW50aW5lbCBgJGAgY2hhcmFjdGVyIGlmIHRoZSBwYXJzZXIgaGFzIHJlYWNoZWQgdGhlIGVuZFxuICAgICAgICAgIC8vIG9mIHRoZSBzb3VyY2Ugc3RyaW5nLlxuICAgICAgICAgIHJldHVybiBcIiRcIjtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBJbnRlcm5hbDogUGFyc2VzIGEgSlNPTiBgdmFsdWVgIHRva2VuLlxuICAgICAgICB2YXIgZ2V0ID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgdmFyIHJlc3VsdHMsIGhhc01lbWJlcnM7XG4gICAgICAgICAgaWYgKHZhbHVlID09IFwiJFwiKSB7XG4gICAgICAgICAgICAvLyBVbmV4cGVjdGVkIGVuZCBvZiBpbnB1dC5cbiAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgaWYgKChjaGFySW5kZXhCdWdneSA/IHZhbHVlLmNoYXJBdCgwKSA6IHZhbHVlWzBdKSA9PSBcIkBcIikge1xuICAgICAgICAgICAgICAvLyBSZW1vdmUgdGhlIHNlbnRpbmVsIGBAYCBjaGFyYWN0ZXIuXG4gICAgICAgICAgICAgIHJldHVybiB2YWx1ZS5zbGljZSgxKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFBhcnNlIG9iamVjdCBhbmQgYXJyYXkgbGl0ZXJhbHMuXG4gICAgICAgICAgICBpZiAodmFsdWUgPT0gXCJbXCIpIHtcbiAgICAgICAgICAgICAgLy8gUGFyc2VzIGEgSlNPTiBhcnJheSwgcmV0dXJuaW5nIGEgbmV3IEphdmFTY3JpcHQgYXJyYXkuXG4gICAgICAgICAgICAgIHJlc3VsdHMgPSBbXTtcbiAgICAgICAgICAgICAgZm9yICg7OyBoYXNNZW1iZXJzIHx8IChoYXNNZW1iZXJzID0gdHJ1ZSkpIHtcbiAgICAgICAgICAgICAgICB2YWx1ZSA9IGxleCgpO1xuICAgICAgICAgICAgICAgIC8vIEEgY2xvc2luZyBzcXVhcmUgYnJhY2tldCBtYXJrcyB0aGUgZW5kIG9mIHRoZSBhcnJheSBsaXRlcmFsLlxuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSA9PSBcIl1cIikge1xuICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIElmIHRoZSBhcnJheSBsaXRlcmFsIGNvbnRhaW5zIGVsZW1lbnRzLCB0aGUgY3VycmVudCB0b2tlblxuICAgICAgICAgICAgICAgIC8vIHNob3VsZCBiZSBhIGNvbW1hIHNlcGFyYXRpbmcgdGhlIHByZXZpb3VzIGVsZW1lbnQgZnJvbSB0aGVcbiAgICAgICAgICAgICAgICAvLyBuZXh0LlxuICAgICAgICAgICAgICAgIGlmIChoYXNNZW1iZXJzKSB7XG4gICAgICAgICAgICAgICAgICBpZiAodmFsdWUgPT0gXCIsXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBsZXgoKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlID09IFwiXVwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gVW5leHBlY3RlZCB0cmFpbGluZyBgLGAgaW4gYXJyYXkgbGl0ZXJhbC5cbiAgICAgICAgICAgICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBBIGAsYCBtdXN0IHNlcGFyYXRlIGVhY2ggYXJyYXkgZWxlbWVudC5cbiAgICAgICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gRWxpc2lvbnMgYW5kIGxlYWRpbmcgY29tbWFzIGFyZSBub3QgcGVybWl0dGVkLlxuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSA9PSBcIixcIikge1xuICAgICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmVzdWx0cy5wdXNoKGdldCh2YWx1ZSkpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybiByZXN1bHRzO1xuICAgICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PSBcIntcIikge1xuICAgICAgICAgICAgICAvLyBQYXJzZXMgYSBKU09OIG9iamVjdCwgcmV0dXJuaW5nIGEgbmV3IEphdmFTY3JpcHQgb2JqZWN0LlxuICAgICAgICAgICAgICByZXN1bHRzID0ge307XG4gICAgICAgICAgICAgIGZvciAoOzsgaGFzTWVtYmVycyB8fCAoaGFzTWVtYmVycyA9IHRydWUpKSB7XG4gICAgICAgICAgICAgICAgdmFsdWUgPSBsZXgoKTtcbiAgICAgICAgICAgICAgICAvLyBBIGNsb3NpbmcgY3VybHkgYnJhY2UgbWFya3MgdGhlIGVuZCBvZiB0aGUgb2JqZWN0IGxpdGVyYWwuXG4gICAgICAgICAgICAgICAgaWYgKHZhbHVlID09IFwifVwiKSB7XG4gICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gSWYgdGhlIG9iamVjdCBsaXRlcmFsIGNvbnRhaW5zIG1lbWJlcnMsIHRoZSBjdXJyZW50IHRva2VuXG4gICAgICAgICAgICAgICAgLy8gc2hvdWxkIGJlIGEgY29tbWEgc2VwYXJhdG9yLlxuICAgICAgICAgICAgICAgIGlmIChoYXNNZW1iZXJzKSB7XG4gICAgICAgICAgICAgICAgICBpZiAodmFsdWUgPT0gXCIsXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBsZXgoKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlID09IFwifVwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gVW5leHBlY3RlZCB0cmFpbGluZyBgLGAgaW4gb2JqZWN0IGxpdGVyYWwuXG4gICAgICAgICAgICAgICAgICAgICAgYWJvcnQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQSBgLGAgbXVzdCBzZXBhcmF0ZSBlYWNoIG9iamVjdCBtZW1iZXIuXG4gICAgICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIExlYWRpbmcgY29tbWFzIGFyZSBub3QgcGVybWl0dGVkLCBvYmplY3QgcHJvcGVydHkgbmFtZXMgbXVzdCBiZVxuICAgICAgICAgICAgICAgIC8vIGRvdWJsZS1xdW90ZWQgc3RyaW5ncywgYW5kIGEgYDpgIG11c3Qgc2VwYXJhdGUgZWFjaCBwcm9wZXJ0eVxuICAgICAgICAgICAgICAgIC8vIG5hbWUgYW5kIHZhbHVlLlxuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSA9PSBcIixcIiB8fCB0eXBlb2YgdmFsdWUgIT0gXCJzdHJpbmdcIiB8fCAoY2hhckluZGV4QnVnZ3kgPyB2YWx1ZS5jaGFyQXQoMCkgOiB2YWx1ZVswXSkgIT0gXCJAXCIgfHwgbGV4KCkgIT0gXCI6XCIpIHtcbiAgICAgICAgICAgICAgICAgIGFib3J0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJlc3VsdHNbdmFsdWUuc2xpY2UoMSldID0gZ2V0KGxleCgpKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0cztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFVuZXhwZWN0ZWQgdG9rZW4gZW5jb3VudGVyZWQuXG4gICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gSW50ZXJuYWw6IFVwZGF0ZXMgYSB0cmF2ZXJzZWQgb2JqZWN0IG1lbWJlci5cbiAgICAgICAgdmFyIHVwZGF0ZSA9IGZ1bmN0aW9uIChzb3VyY2UsIHByb3BlcnR5LCBjYWxsYmFjaykge1xuICAgICAgICAgIHZhciBlbGVtZW50ID0gd2Fsayhzb3VyY2UsIHByb3BlcnR5LCBjYWxsYmFjayk7XG4gICAgICAgICAgaWYgKGVsZW1lbnQgPT09IHVuZGVmKSB7XG4gICAgICAgICAgICBkZWxldGUgc291cmNlW3Byb3BlcnR5XTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc291cmNlW3Byb3BlcnR5XSA9IGVsZW1lbnQ7XG4gICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEludGVybmFsOiBSZWN1cnNpdmVseSB0cmF2ZXJzZXMgYSBwYXJzZWQgSlNPTiBvYmplY3QsIGludm9raW5nIHRoZVxuICAgICAgICAvLyBgY2FsbGJhY2tgIGZ1bmN0aW9uIGZvciBlYWNoIHZhbHVlLiBUaGlzIGlzIGFuIGltcGxlbWVudGF0aW9uIG9mIHRoZVxuICAgICAgICAvLyBgV2Fsayhob2xkZXIsIG5hbWUpYCBvcGVyYXRpb24gZGVmaW5lZCBpbiBFUyA1LjEgc2VjdGlvbiAxNS4xMi4yLlxuICAgICAgICB2YXIgd2FsayA9IGZ1bmN0aW9uIChzb3VyY2UsIHByb3BlcnR5LCBjYWxsYmFjaykge1xuICAgICAgICAgIHZhciB2YWx1ZSA9IHNvdXJjZVtwcm9wZXJ0eV0sIGxlbmd0aDtcbiAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09IFwib2JqZWN0XCIgJiYgdmFsdWUpIHtcbiAgICAgICAgICAgIC8vIGBmb3JFYWNoYCBjYW4ndCBiZSB1c2VkIHRvIHRyYXZlcnNlIGFuIGFycmF5IGluIE9wZXJhIDw9IDguNTRcbiAgICAgICAgICAgIC8vIGJlY2F1c2UgaXRzIGBPYmplY3QjaGFzT3duUHJvcGVydHlgIGltcGxlbWVudGF0aW9uIHJldHVybnMgYGZhbHNlYFxuICAgICAgICAgICAgLy8gZm9yIGFycmF5IGluZGljZXMgKGUuZy4sIGAhWzEsIDIsIDNdLmhhc093blByb3BlcnR5KFwiMFwiKWApLlxuICAgICAgICAgICAgaWYgKGdldENsYXNzLmNhbGwodmFsdWUpID09IGFycmF5Q2xhc3MpIHtcbiAgICAgICAgICAgICAgZm9yIChsZW5ndGggPSB2YWx1ZS5sZW5ndGg7IGxlbmd0aC0tOykge1xuICAgICAgICAgICAgICAgIHVwZGF0ZSh2YWx1ZSwgbGVuZ3RoLCBjYWxsYmFjayk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGZvckVhY2godmFsdWUsIGZ1bmN0aW9uIChwcm9wZXJ0eSkge1xuICAgICAgICAgICAgICAgIHVwZGF0ZSh2YWx1ZSwgcHJvcGVydHksIGNhbGxiYWNrKTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBjYWxsYmFjay5jYWxsKHNvdXJjZSwgcHJvcGVydHksIHZhbHVlKTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBQdWJsaWM6IGBKU09OLnBhcnNlYC4gU2VlIEVTIDUuMSBzZWN0aW9uIDE1LjEyLjIuXG4gICAgICAgIGV4cG9ydHMucGFyc2UgPSBmdW5jdGlvbiAoc291cmNlLCBjYWxsYmFjaykge1xuICAgICAgICAgIHZhciByZXN1bHQsIHZhbHVlO1xuICAgICAgICAgIEluZGV4ID0gMDtcbiAgICAgICAgICBTb3VyY2UgPSBcIlwiICsgc291cmNlO1xuICAgICAgICAgIHJlc3VsdCA9IGdldChsZXgoKSk7XG4gICAgICAgICAgLy8gSWYgYSBKU09OIHN0cmluZyBjb250YWlucyBtdWx0aXBsZSB0b2tlbnMsIGl0IGlzIGludmFsaWQuXG4gICAgICAgICAgaWYgKGxleCgpICE9IFwiJFwiKSB7XG4gICAgICAgICAgICBhYm9ydCgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBSZXNldCB0aGUgcGFyc2VyIHN0YXRlLlxuICAgICAgICAgIEluZGV4ID0gU291cmNlID0gbnVsbDtcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2sgJiYgZ2V0Q2xhc3MuY2FsbChjYWxsYmFjaykgPT0gZnVuY3Rpb25DbGFzcyA/IHdhbGsoKHZhbHVlID0ge30sIHZhbHVlW1wiXCJdID0gcmVzdWx0LCB2YWx1ZSksIFwiXCIsIGNhbGxiYWNrKSA6IHJlc3VsdDtcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBleHBvcnRzW1wicnVuSW5Db250ZXh0XCJdID0gcnVuSW5Db250ZXh0O1xuICAgIHJldHVybiBleHBvcnRzO1xuICB9XG5cbiAgaWYgKGZyZWVFeHBvcnRzICYmICFpc0xvYWRlcikge1xuICAgIC8vIEV4cG9ydCBmb3IgQ29tbW9uSlMgZW52aXJvbm1lbnRzLlxuICAgIHJ1bkluQ29udGV4dChyb290LCBmcmVlRXhwb3J0cyk7XG4gIH0gZWxzZSB7XG4gICAgLy8gRXhwb3J0IGZvciB3ZWIgYnJvd3NlcnMgYW5kIEphdmFTY3JpcHQgZW5naW5lcy5cbiAgICB2YXIgbmF0aXZlSlNPTiA9IHJvb3QuSlNPTixcbiAgICAgICAgcHJldmlvdXNKU09OID0gcm9vdFtcIkpTT04zXCJdLFxuICAgICAgICBpc1Jlc3RvcmVkID0gZmFsc2U7XG5cbiAgICB2YXIgSlNPTjMgPSBydW5JbkNvbnRleHQocm9vdCwgKHJvb3RbXCJKU09OM1wiXSA9IHtcbiAgICAgIC8vIFB1YmxpYzogUmVzdG9yZXMgdGhlIG9yaWdpbmFsIHZhbHVlIG9mIHRoZSBnbG9iYWwgYEpTT05gIG9iamVjdCBhbmRcbiAgICAgIC8vIHJldHVybnMgYSByZWZlcmVuY2UgdG8gdGhlIGBKU09OM2Agb2JqZWN0LlxuICAgICAgXCJub0NvbmZsaWN0XCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFpc1Jlc3RvcmVkKSB7XG4gICAgICAgICAgaXNSZXN0b3JlZCA9IHRydWU7XG4gICAgICAgICAgcm9vdC5KU09OID0gbmF0aXZlSlNPTjtcbiAgICAgICAgICByb290W1wiSlNPTjNcIl0gPSBwcmV2aW91c0pTT047XG4gICAgICAgICAgbmF0aXZlSlNPTiA9IHByZXZpb3VzSlNPTiA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIEpTT04zO1xuICAgICAgfVxuICAgIH0pKTtcblxuICAgIHJvb3QuSlNPTiA9IHtcbiAgICAgIFwicGFyc2VcIjogSlNPTjMucGFyc2UsXG4gICAgICBcInN0cmluZ2lmeVwiOiBKU09OMy5zdHJpbmdpZnlcbiAgICB9O1xuICB9XG5cbiAgLy8gRXhwb3J0IGZvciBhc3luY2hyb25vdXMgbW9kdWxlIGxvYWRlcnMuXG4gIGlmIChpc0xvYWRlcikge1xuICAgIGRlZmluZShmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gSlNPTjM7XG4gICAgfSk7XG4gIH1cbn0pLmNhbGwodGhpcyk7XG4iLCJmdW5jdGlvbiBNYXBwZXIoKVxue1xuICB2YXIgc291cmNlcyA9IHt9O1xuXG5cbiAgdGhpcy5mb3JFYWNoID0gZnVuY3Rpb24oY2FsbGJhY2spXG4gIHtcbiAgICBmb3IodmFyIGtleSBpbiBzb3VyY2VzKVxuICAgIHtcbiAgICAgIHZhciBzb3VyY2UgPSBzb3VyY2VzW2tleV07XG5cbiAgICAgIGZvcih2YXIga2V5MiBpbiBzb3VyY2UpXG4gICAgICAgIGNhbGxiYWNrKHNvdXJjZVtrZXkyXSk7XG4gICAgfTtcbiAgfTtcblxuICB0aGlzLmdldCA9IGZ1bmN0aW9uKGlkLCBzb3VyY2UpXG4gIHtcbiAgICB2YXIgaWRzID0gc291cmNlc1tzb3VyY2VdO1xuICAgIGlmKGlkcyA9PSB1bmRlZmluZWQpXG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuXG4gICAgcmV0dXJuIGlkc1tpZF07XG4gIH07XG5cbiAgdGhpcy5yZW1vdmUgPSBmdW5jdGlvbihpZCwgc291cmNlKVxuICB7XG4gICAgdmFyIGlkcyA9IHNvdXJjZXNbc291cmNlXTtcbiAgICBpZihpZHMgPT0gdW5kZWZpbmVkKVxuICAgICAgcmV0dXJuO1xuXG4gICAgZGVsZXRlIGlkc1tpZF07XG5cbiAgICAvLyBDaGVjayBpdCdzIGVtcHR5XG4gICAgZm9yKHZhciBpIGluIGlkcyl7cmV0dXJuIGZhbHNlfVxuXG4gICAgZGVsZXRlIHNvdXJjZXNbc291cmNlXTtcbiAgfTtcblxuICB0aGlzLnNldCA9IGZ1bmN0aW9uKHZhbHVlLCBpZCwgc291cmNlKVxuICB7XG4gICAgaWYodmFsdWUgPT0gdW5kZWZpbmVkKVxuICAgICAgcmV0dXJuIHRoaXMucmVtb3ZlKGlkLCBzb3VyY2UpO1xuXG4gICAgdmFyIGlkcyA9IHNvdXJjZXNbc291cmNlXTtcbiAgICBpZihpZHMgPT0gdW5kZWZpbmVkKVxuICAgICAgc291cmNlc1tzb3VyY2VdID0gaWRzID0ge307XG5cbiAgICBpZHNbaWRdID0gdmFsdWU7XG4gIH07XG59O1xuXG5cbk1hcHBlci5wcm90b3R5cGUucG9wID0gZnVuY3Rpb24oaWQsIHNvdXJjZSlcbntcbiAgdmFyIHZhbHVlID0gdGhpcy5nZXQoaWQsIHNvdXJjZSk7XG4gIGlmKHZhbHVlID09IHVuZGVmaW5lZClcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuXG4gIHRoaXMucmVtb3ZlKGlkLCBzb3VyY2UpO1xuXG4gIHJldHVybiB2YWx1ZTtcbn07XG5cblxubW9kdWxlLmV4cG9ydHMgPSBNYXBwZXI7XG4iLCIvKlxuICogKEMpIENvcHlyaWdodCAyMDE0IEt1cmVudG8gKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cblxudmFyIEpzb25ScGNDbGllbnQgID0gcmVxdWlyZSgnLi9qc29ucnBjY2xpZW50Jyk7XG5cblxuZXhwb3J0cy5Kc29uUnBjQ2xpZW50ICA9IEpzb25ScGNDbGllbnQ7IiwiLypcbiAqIChDKSBDb3B5cmlnaHQgMjAxNCBLdXJlbnRvIChodHRwOi8va3VyZW50by5vcmcvKVxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICovXG5cbnZhciBScGNCdWlsZGVyID0gcmVxdWlyZSgnLi4vLi4nKTtcbnZhciBXZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uID0gcmVxdWlyZSgnLi90cmFuc3BvcnRzL3dlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb24nKTtcblxuRGF0ZS5ub3cgPSBEYXRlLm5vdyB8fCBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gK25ldyBEYXRlO1xufTtcblxudmFyIFBJTkdfSU5URVJWQUwgPSA1MDAwO1xuXG52YXIgUkVDT05ORUNUSU5HID0gJ1JFQ09OTkVDVElORyc7XG52YXIgQ09OTkVDVEVEID0gJ0NPTk5FQ1RFRCc7XG52YXIgRElTQ09OTkVDVEVEID0gJ0RJU0NPTk5FQ1RFRCc7XG5cbnZhciBSRUNPTk5FQ1RJTkcgPSBcIlJFQ09OTkVDVElOR1wiO1xudmFyIENPTk5FQ1RFRCA9IFwiQ09OTkVDVEVEXCI7XG52YXIgRElTQ09OTkVDVEVEID0gXCJESVNDT05ORUNURURcIjtcblxuXG4vKipcbiAqXG4gKiBoZWFydGJlYXQ6IGludGVydmFsIGluIG1zIGZvciBlYWNoIGhlYXJ0YmVhdCBtZXNzYWdlLFxuICogc2VuZENsb3NlTWVzc2FnZSA6IHRydWUgLyBmYWxzZSwgYmVmb3JlIGNsb3NpbmcgdGhlIGNvbm5lY3Rpb24sIGl0IHNlbmRzIGEgY2xvc2VTZXNzaW9uIG1lc3NhZ2VcbiAqIDxwcmU+XG4gKiB3cyA6IHtcbiAqIFx0dXJpIDogVVJJIHRvIGNvbm50ZWN0IHRvLFxuICogIHVzZVNvY2tKUyA6IHRydWUgKHVzZSBTb2NrSlMpIC8gZmFsc2UgKHVzZSBXZWJTb2NrZXQpIGJ5IGRlZmF1bHQsXG4gKiBcdG9uY29ubmVjdGVkIDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIGNvbm5lY3Rpb24gaXMgc3VjY2Vzc2Z1bCxcbiAqIFx0b25kaXNjb25uZWN0IDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIHRoZSBjb25uZWN0aW9uIGlzIGxvc3QsXG4gKiBcdG9ucmVjb25uZWN0aW5nIDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIHRoZSBjbGllbnQgaXMgcmVjb25uZWN0aW5nLFxuICogXHRvbnJlY29ubmVjdGVkIDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIHRoZSBjbGllbnQgc3VjY2VzZnVsbHkgcmVjb25uZWN0cyxcbiAqIH0sXG4gKiBycGMgOiB7XG4gKiBcdHJlcXVlc3RUaW1lb3V0IDogdGltZW91dCBmb3IgYSByZXF1ZXN0LFxuICogXHRzZXNzaW9uU3RhdHVzQ2hhbmdlZDogY2FsbGJhY2sgbWV0aG9kIGZvciBjaGFuZ2VzIGluIHNlc3Npb24gc3RhdHVzLFxuICogXHRtZWRpYVJlbmVnb3RpYXRpb246IG1lZGlhUmVuZWdvdGlhdGlvblxuICogfVxuICogPC9wcmU+XG4gKi9cbmZ1bmN0aW9uIEpzb25ScGNDbGllbnQoY29uZmlndXJhdGlvbikge1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgdmFyIHdzQ29uZmlnID0gY29uZmlndXJhdGlvbi53cztcblxuICAgIHZhciBub3RSZWNvbm5lY3RJZk51bUxlc3NUaGFuID0gLTE7XG5cbiAgICB2YXIgcGluZ05leHROdW0gPSAwO1xuICAgIHZhciBlbmFibGVkUGluZ3MgPSB0cnVlO1xuICAgIHZhciBwaW5nUG9uZ1N0YXJ0ZWQgPSBmYWxzZTtcbiAgICB2YXIgcGluZ0ludGVydmFsO1xuXG4gICAgdmFyIHN0YXR1cyA9IERJU0NPTk5FQ1RFRDtcblxuICAgIHZhciBvbnJlY29ubmVjdGluZyA9IHdzQ29uZmlnLm9ucmVjb25uZWN0aW5nO1xuICAgIHZhciBvbnJlY29ubmVjdGVkID0gd3NDb25maWcub25yZWNvbm5lY3RlZDtcbiAgICB2YXIgb25jb25uZWN0ZWQgPSB3c0NvbmZpZy5vbmNvbm5lY3RlZDtcblxuICAgIGNvbmZpZ3VyYXRpb24ucnBjLnB1bGwgPSBmdW5jdGlvbihwYXJhbXMsIHJlcXVlc3QpIHtcbiAgICAgICAgcmVxdWVzdC5yZXBseShudWxsLCBcInB1c2hcIik7XG4gICAgfVxuXG4gICAgd3NDb25maWcub25yZWNvbm5lY3RpbmcgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCItLS0tLS0tLS0gT05SRUNPTk5FQ1RJTkcgLS0tLS0tLS0tLS1cIik7XG4gICAgICAgIGlmIChzdGF0dXMgPT09IFJFQ09OTkVDVElORykge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIldlYnNvY2tldCBhbHJlYWR5IGluIFJFQ09OTkVDVElORyBzdGF0ZSB3aGVuIHJlY2VpdmluZyBhIG5ldyBPTlJFQ09OTkVDVElORyBtZXNzYWdlLiBJZ25vcmluZyBpdFwiKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHN0YXR1cyA9IFJFQ09OTkVDVElORztcbiAgICAgICAgaWYgKG9ucmVjb25uZWN0aW5nKSB7XG4gICAgICAgICAgICBvbnJlY29ubmVjdGluZygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgd3NDb25maWcub25yZWNvbm5lY3RlZCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBjb25zb2xlLmxvZyhcIi0tLS0tLS0tLSBPTlJFQ09OTkVDVEVEIC0tLS0tLS0tLS0tXCIpO1xuICAgICAgICBpZiAoc3RhdHVzID09PSBDT05ORUNURUQpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJXZWJzb2NrZXQgYWxyZWFkeSBpbiBDT05ORUNURUQgc3RhdGUgd2hlbiByZWNlaXZpbmcgYSBuZXcgT05SRUNPTk5FQ1RFRCBtZXNzYWdlLiBJZ25vcmluZyBpdFwiKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzdGF0dXMgPSBDT05ORUNURUQ7XG5cbiAgICAgICAgZW5hYmxlZFBpbmdzID0gdHJ1ZTtcbiAgICAgICAgdXBkYXRlTm90UmVjb25uZWN0SWZMZXNzVGhhbigpO1xuICAgICAgICB1c2VQaW5nKCk7XG5cbiAgICAgICAgaWYgKG9ucmVjb25uZWN0ZWQpIHtcbiAgICAgICAgICAgIG9ucmVjb25uZWN0ZWQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHdzQ29uZmlnLm9uY29ubmVjdGVkID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiLS0tLS0tLS0tIE9OQ09OTkVDVEVEIC0tLS0tLS0tLS0tXCIpO1xuICAgICAgICBpZiAoc3RhdHVzID09PSBDT05ORUNURUQpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJXZWJzb2NrZXQgYWxyZWFkeSBpbiBDT05ORUNURUQgc3RhdGUgd2hlbiByZWNlaXZpbmcgYSBuZXcgT05DT05ORUNURUQgbWVzc2FnZS4gSWdub3JpbmcgaXRcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc3RhdHVzID0gQ09OTkVDVEVEO1xuXG4gICAgICAgIGVuYWJsZWRQaW5ncyA9IHRydWU7XG4gICAgICAgIHVzZVBpbmcoKTtcblxuICAgICAgICBpZiAob25jb25uZWN0ZWQpIHtcbiAgICAgICAgICAgIG9uY29ubmVjdGVkKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgd3MgPSBuZXcgV2ViU29ja2V0V2l0aFJlY29ubmVjdGlvbih3c0NvbmZpZyk7XG5cbiAgICBjb25zb2xlLmxvZygnQ29ubmVjdGluZyB3ZWJzb2NrZXQgdG8gVVJJOiAnICsgd3NDb25maWcudXJpKTtcblxuICAgIHZhciBycGNCdWlsZGVyT3B0aW9ucyA9IHtcbiAgICAgICAgcmVxdWVzdF90aW1lb3V0OiBjb25maWd1cmF0aW9uLnJwYy5yZXF1ZXN0VGltZW91dFxuICAgIH07XG5cbiAgICB2YXIgcnBjID0gbmV3IFJwY0J1aWxkZXIoUnBjQnVpbGRlci5wYWNrZXJzLkpzb25SUEMsIHJwY0J1aWxkZXJPcHRpb25zLCB3cyxcbiAgICAgICAgZnVuY3Rpb24ocmVxdWVzdCkge1xuXG4gICAgICAgICAgICBjb25zb2xlLmxvZygnUmVjZWl2ZWQgcmVxdWVzdDogJyArIEpTT04uc3RyaW5naWZ5KHJlcXVlc3QpKTtcblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB2YXIgZnVuYyA9IGNvbmZpZ3VyYXRpb24ucnBjW3JlcXVlc3QubWV0aG9kXTtcblxuICAgICAgICAgICAgICAgIGlmIChmdW5jID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIk1ldGhvZCBcIiArIHJlcXVlc3QubWV0aG9kICsgXCIgbm90IHJlZ2lzdGVyZWQgaW4gY2xpZW50XCIpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGZ1bmMocmVxdWVzdC5wYXJhbXMsIHJlcXVlc3QpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0V4Y2VwdGlvbiBwcm9jZXNzaW5nIHJlcXVlc3Q6ICcgKyBKU09OLnN0cmluZ2lmeShyZXF1ZXN0KSk7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgIHRoaXMuc2VuZCA9IGZ1bmN0aW9uKG1ldGhvZCwgcGFyYW1zLCBjYWxsYmFjaykge1xuICAgICAgICBpZiAobWV0aG9kICE9PSAncGluZycpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdSZXF1ZXN0OiBtZXRob2Q6JyArIG1ldGhvZCArIFwiIHBhcmFtczpcIiArIEpTT04uc3RyaW5naWZ5KHBhcmFtcykpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHJlcXVlc3RUaW1lID0gRGF0ZS5ub3coKTtcblxuICAgICAgICBycGMuZW5jb2RlKG1ldGhvZCwgcGFyYW1zLCBmdW5jdGlvbihlcnJvciwgcmVzdWx0KSB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRVJST1I6XCIgKyBlcnJvci5tZXNzYWdlICsgXCIgaW4gUmVxdWVzdDogbWV0aG9kOlwiICsgbWV0aG9kICsgXCIgcGFyYW1zOlwiICsgSlNPTi5zdHJpbmdpZnkocGFyYW1zKSk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlcnJvci5kYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRVJST1IgREFUQTpcIiArIEpTT04uc3RyaW5naWZ5KGVycm9yLmRhdGEpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHt9XG4gICAgICAgICAgICAgICAgZXJyb3IucmVxdWVzdFRpbWUgPSByZXF1ZXN0VGltZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIGlmIChyZXN1bHQgIT0gdW5kZWZpbmVkICYmIHJlc3VsdC52YWx1ZSAhPT0gJ3BvbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdSZXNwb25zZTogJyArIEpTT04uc3RyaW5naWZ5KHJlc3VsdCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjYWxsYmFjayhlcnJvciwgcmVzdWx0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdXBkYXRlTm90UmVjb25uZWN0SWZMZXNzVGhhbigpIHtcbiAgICAgICAgbm90UmVjb25uZWN0SWZOdW1MZXNzVGhhbiA9IHBpbmdOZXh0TnVtO1xuICAgICAgICBjb25zb2xlLmxvZyhcIm5vdFJlY29ubmVjdElmTnVtTGVzc1RoYW4gPSBcIiArIG5vdFJlY29ubmVjdElmTnVtTGVzc1RoYW4pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHNlbmRQaW5nKCkge1xuICAgICAgICBpZiAoZW5hYmxlZFBpbmdzKSB7XG4gICAgICAgICAgICB2YXIgcGFyYW1zID0gbnVsbDtcblxuICAgICAgICAgICAgaWYgKHBpbmdOZXh0TnVtID09IDAgfHwgcGluZ05leHROdW0gPT0gbm90UmVjb25uZWN0SWZOdW1MZXNzVGhhbikge1xuICAgICAgICAgICAgICAgIHBhcmFtcyA9IHtcbiAgICAgICAgICAgICAgICAgICAgaW50ZXJ2YWw6IFBJTkdfSU5URVJWQUxcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBwaW5nTmV4dE51bSsrO1xuXG4gICAgICAgICAgICBzZWxmLnNlbmQoJ3BpbmcnLCBwYXJhbXMsIChmdW5jdGlvbihwaW5nTnVtKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKGVycm9yLCByZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocGluZ051bSA+IG5vdFJlY29ubmVjdElmTnVtTGVzc1RoYW4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmFibGVkUGluZ3MgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cGRhdGVOb3RSZWNvbm5lY3RJZkxlc3NUaGFuKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJEU1MgZGlkIG5vdCByZXNwb25kIHRvIHBpbmcgbWVzc2FnZSBcIiArIHBpbmdOdW0gKyBcIi4gUmVjb25uZWN0aW5nLi4uIFwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3cy5yZWNvbm5lY3RXcygpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSkocGluZ05leHROdW0pKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiVHJ5aW5nIHRvIHNlbmQgcGluZywgYnV0IHBpbmcgaXMgbm90IGVuYWJsZWRcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKlxuICAgICogSWYgY29uZmlndXJhdGlvbi5oZWFyYmVhdCBoYXMgYW55IHZhbHVlLCB0aGUgcGluZy1wb25nIHdpbGwgd29yayB3aXRoIHRoZSBpbnRlcnZhbFxuICAgICogb2YgY29uZmlndXJhdGlvbi5oZWFyYmVhdFxuICAgICovXG4gICAgZnVuY3Rpb24gdXNlUGluZygpIHtcbiAgICAgICAgaWYgKCFwaW5nUG9uZ1N0YXJ0ZWQpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiU3RhcnRpbmcgcGluZyAoaWYgY29uZmlndXJlZClcIilcbiAgICAgICAgICAgIHBpbmdQb25nU3RhcnRlZCA9IHRydWU7XG5cbiAgICAgICAgICAgIGlmIChjb25maWd1cmF0aW9uLmhlYXJ0YmVhdCAhPSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBwaW5nSW50ZXJ2YWwgPSBzZXRJbnRlcnZhbChzZW5kUGluZywgY29uZmlndXJhdGlvbi5oZWFydGJlYXQpO1xuICAgICAgICAgICAgICAgIHNlbmRQaW5nKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmNsb3NlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiQ2xvc2luZyBqc29uUnBjQ2xpZW50IGV4cGxpY2l0ZWx5IGJ5IGNsaWVudFwiKTtcblxuICAgICAgICBpZiAocGluZ0ludGVydmFsICE9IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgY2xlYXJJbnRlcnZhbChwaW5nSW50ZXJ2YWwpO1xuICAgICAgICB9XG4gICAgICAgIHBpbmdQb25nU3RhcnRlZCA9IGZhbHNlO1xuICAgICAgICBlbmFibGVkUGluZ3MgPSBmYWxzZTtcblxuICAgICAgICBpZiAoY29uZmlndXJhdGlvbi5zZW5kQ2xvc2VNZXNzYWdlKSB7XG4gICAgICAgICAgICB0aGlzLnNlbmQoJ2Nsb3NlU2Vzc2lvbicsIG51bGwsIGZ1bmN0aW9uKGVycm9yLCByZXN1bHQpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIHNlbmRpbmcgY2xvc2UgbWVzc2FnZTogXCIgKyBKU09OLnN0cmluZ2lmeShlcnJvcikpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHdzLmNsb3NlKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcblx0XHRcdHdzLmNsb3NlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUaGlzIG1ldGhvZCBpcyBvbmx5IGZvciB0ZXN0aW5nXG4gICAgdGhpcy5mb3JjZUNsb3NlID0gZnVuY3Rpb24obWlsbGlzKSB7XG4gICAgICAgIHdzLmZvcmNlQ2xvc2UobWlsbGlzKTtcbiAgICB9XG5cbiAgICB0aGlzLnJlY29ubmVjdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB3cy5yZWNvbm5lY3RXcygpO1xuICAgIH1cbn1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IEpzb25ScGNDbGllbnQ7XG4iLCIvKlxuICogKEMpIENvcHlyaWdodCAyMDE0IEt1cmVudG8gKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKi9cblxudmFyIFdlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb24gID0gcmVxdWlyZSgnLi93ZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uJyk7XG5cblxuZXhwb3J0cy5XZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uICA9IFdlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb247IiwiLypcbiAqIChDKSBDb3B5cmlnaHQgMjAxMy0yMDE1IEt1cmVudG8gKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFdlYlNvY2tldCA9IHJlcXVpcmUoJ3dzJyk7XG52YXIgU29ja0pTID0gcmVxdWlyZSgnc29ja2pzLWNsaWVudCcpO1xuXG52YXIgTUFYX1JFVFJJRVMgPSAyMDAwOyAvLyBGb3JldmVyLi4uXG52YXIgUkVUUllfVElNRV9NUyA9IDMwMDA7IC8vIEZJWE1FOiBJbXBsZW1lbnQgZXhwb25lbnRpYWwgd2FpdCB0aW1lcy4uLlxudmFyIFBJTkdfSU5URVJWQUwgPSA1MDAwO1xudmFyIFBJTkdfTVNHID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgICdtZXRob2QnOiAncGluZydcbn0pO1xuXG52YXIgQ09OTkVDVElORyA9IDA7XG52YXIgT1BFTiA9IDE7XG52YXIgQ0xPU0lORyA9IDI7XG52YXIgQ0xPU0VEID0gMztcblxuLypcbmNvbmZpZyA9IHtcblx0XHR1cmkgOiB3c1VyaSxcblx0XHR1c2VTb2NrSlMgOiB0cnVlICh1c2UgU29ja0pTKSAvIGZhbHNlICh1c2UgV2ViU29ja2V0KSBieSBkZWZhdWx0LFxuXHRcdG9uY29ubmVjdGVkIDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIGNvbm5lY3Rpb24gaXMgc3VjY2Vzc2Z1bCxcblx0XHRvbmRpc2Nvbm5lY3QgOiBjYWxsYmFjayBtZXRob2QgdG8gaW52b2tlIHdoZW4gdGhlIGNvbm5lY3Rpb24gaXMgbG9zdCxcblx0XHRvbnJlY29ubmVjdGluZyA6IGNhbGxiYWNrIG1ldGhvZCB0byBpbnZva2Ugd2hlbiB0aGUgY2xpZW50IGlzIHJlY29ubmVjdGluZyxcblx0XHRvbnJlY29ubmVjdGVkIDogY2FsbGJhY2sgbWV0aG9kIHRvIGludm9rZSB3aGVuIHRoZSBjbGllbnQgc3VjY2VzZnVsbHkgcmVjb25uZWN0cyxcblx0fTtcbiovXG5mdW5jdGlvbiBXZWJTb2NrZXRXaXRoUmVjb25uZWN0aW9uKGNvbmZpZykge1xuXG4gICAgdmFyIGNsb3NpbmcgPSBmYWxzZTtcbiAgICB2YXIgcmVnaXN0ZXJNZXNzYWdlSGFuZGxlcjtcbiAgICB2YXIgd3NVcmkgPSBjb25maWcudXJpO1xuICAgIHZhciB1c2VTb2NrSlMgPSBjb25maWcudXNlU29ja0pTO1xuICAgIHZhciByZWNvbm5lY3RpbmcgPSBmYWxzZTtcblxuICAgIHZhciBmb3JjaW5nRGlzY29ubmVjdGlvbiA9IGZhbHNlO1xuXG4gICAgdmFyIHdzO1xuXG4gICAgaWYgKHVzZVNvY2tKUykge1xuICAgICAgICB3cyA9IG5ldyBTb2NrSlMod3NVcmkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHdzID0gbmV3IFdlYlNvY2tldCh3c1VyaSk7XG4gICAgfVxuXG4gICAgd3Mub25vcGVuID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIGxvZ0Nvbm5lY3RlZCh3cywgd3NVcmkpO1xuICAgICAgICBjb25maWcub25jb25uZWN0ZWQoKTtcbiAgICB9O1xuXG4gICAgd3Mub25lcnJvciA9IGZ1bmN0aW9uKGV2dCkge1xuICAgICAgICBjb25maWcub25jb25uZWN0ZWQoZXZ0LmRhdGEpO1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiBsb2dDb25uZWN0ZWQod3MsIHdzVXJpKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIldlYlNvY2tldCBjb25uZWN0ZWQgdG8gXCIgKyB3c1VyaSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgcmVjb25uZWN0aW9uT25DbG9zZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAod3MucmVhZHlTdGF0ZSA9PT0gQ0xPU0VEKSB7XG4gICAgICAgICAgICBpZiAoY2xvc2luZykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiQ29ubmVjdGlvbiBDbG9zZWQgYnkgdXNlclwiKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJDb25uZWN0aW9uIGNsb3NlZCB1bmV4cGVjdGVjbHkuIFJlY29ubmVjdGluZy4uLlwiKTtcbiAgICAgICAgICAgICAgICByZWNvbm5lY3RJbk5ld1VyaShNQVhfUkVUUklFUywgMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIkNsb3NlIGNhbGxiYWNrIGZyb20gcHJldmlvdXMgd2Vic29ja2V0LiBJZ25vcmluZyBpdFwiKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB3cy5vbmNsb3NlID0gcmVjb25uZWN0aW9uT25DbG9zZTtcblxuICAgIGZ1bmN0aW9uIHJlY29ubmVjdEluTmV3VXJpKG1heFJldHJpZXMsIG51bVJldHJpZXMpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJyZWNvbm5lY3RJbk5ld1VyaVwiKTtcblxuICAgICAgICBpZiAobnVtUmV0cmllcyA9PT0gMSkge1xuICAgICAgICAgICAgaWYgKHJlY29ubmVjdGluZykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGVcbiAgICAgICAgICAgICAgICAgICAgLndhcm4oXCJUcnlpbmcgdG8gcmVjb25uZWN0IHdoZW4gcmVjb25uZWN0aW5nLi4uIElnbm9yaW5nIHRoaXMgcmVjb25uZWN0aW9uLlwiKVxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVjb25uZWN0aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGNvbmZpZy5vbnJlY29ubmVjdGluZykge1xuICAgICAgICAgICAgICAgIGNvbmZpZy5vbnJlY29ubmVjdGluZygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGZvcmNpbmdEaXNjb25uZWN0aW9uKSB7XG4gICAgICAgICAgICByZWNvbm5lY3QobWF4UmV0cmllcywgbnVtUmV0cmllcywgd3NVcmkpO1xuXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoY29uZmlnLm5ld1dzVXJpT25SZWNvbm5lY3Rpb24pIHtcbiAgICAgICAgICAgICAgICBjb25maWcubmV3V3NVcmlPblJlY29ubmVjdGlvbihmdW5jdGlvbihlcnJvciwgbmV3V3NVcmkpIHtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjb25uZWN0SW5OZXdVcmkobWF4UmV0cmllcywgbnVtUmV0cmllcyArIDEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSwgUkVUUllfVElNRV9NUyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWNvbm5lY3QobWF4UmV0cmllcywgbnVtUmV0cmllcywgbmV3V3NVcmkpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVjb25uZWN0KG1heFJldHJpZXMsIG51bVJldHJpZXMsIHdzVXJpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRPRE8gVGVzdCByZXRyaWVzLiBIb3cgdG8gZm9yY2Ugbm90IGNvbm5lY3Rpb24/XG4gICAgZnVuY3Rpb24gcmVjb25uZWN0KG1heFJldHJpZXMsIG51bVJldHJpZXMsIHJlY29ubmVjdFdzVXJpKSB7XG5cbiAgICAgICAgY29uc29sZS5sb2coXCJUcnlpbmcgdG8gcmVjb25uZWN0IFwiICsgbnVtUmV0cmllcyArIFwiIHRpbWVzXCIpO1xuXG4gICAgICAgIHZhciBuZXdXcztcbiAgICAgICAgaWYgKHVzZVNvY2tKUykge1xuICAgICAgICAgICAgbmV3V3MgPSBuZXcgU29ja0pTKHdzVXJpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG5ld1dzID0gbmV3IFdlYlNvY2tldCh3c1VyaSk7XG4gICAgICAgIH1cblxuICAgICAgICBuZXdXcy5vbm9wZW4gPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiUmVjb25uZWN0ZWQgaW4gXCIgKyBudW1SZXRyaWVzICsgXCIgcmV0cmllcy4uLlwiKTtcbiAgICAgICAgICAgIGxvZ0Nvbm5lY3RlZChuZXdXcywgcmVjb25uZWN0V3NVcmkpO1xuICAgICAgICAgICAgcmVjb25uZWN0aW5nID0gZmFsc2U7XG4gICAgICAgICAgICByZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKCk7XG4gICAgICAgICAgICBpZiAoY29uZmlnLm9ucmVjb25uZWN0ZWQoKSkge1xuICAgICAgICAgICAgICAgIGNvbmZpZy5vbnJlY29ubmVjdGVkKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG5ld1dzLm9uY2xvc2UgPSByZWNvbm5lY3Rpb25PbkNsb3NlO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBvbkVycm9yT3JDbG9zZSA9IGZ1bmN0aW9uKGVycm9yKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIlJlY29ubmVjdGlvbiBlcnJvcjogXCIsIGVycm9yKTtcblxuICAgICAgICAgICAgaWYgKG51bVJldHJpZXMgPT09IG1heFJldHJpZXMpIHtcbiAgICAgICAgICAgICAgICBpZiAoY29uZmlnLm9uZGlzY29ubmVjdCkge1xuICAgICAgICAgICAgICAgICAgICBjb25maWcub25kaXNjb25uZWN0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICByZWNvbm5lY3RJbk5ld1VyaShtYXhSZXRyaWVzLCBudW1SZXRyaWVzICsgMSk7XG4gICAgICAgICAgICAgICAgfSwgUkVUUllfVElNRV9NUyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgbmV3V3Mub25lcnJvciA9IG9uRXJyb3JPckNsb3NlO1xuXG4gICAgICAgIHdzID0gbmV3V3M7XG4gICAgfVxuXG4gICAgdGhpcy5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBjbG9zaW5nID0gdHJ1ZTtcbiAgICAgICAgd3MuY2xvc2UoKTtcbiAgICB9O1xuXG5cbiAgICAvLyBUaGlzIG1ldGhvZCBpcyBvbmx5IGZvciB0ZXN0aW5nXG4gICAgdGhpcy5mb3JjZUNsb3NlID0gZnVuY3Rpb24obWlsbGlzKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiVGVzdGluZzogRm9yY2UgV2ViU29ja2V0IGNsb3NlXCIpO1xuXG4gICAgICAgIGlmIChtaWxsaXMpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiVGVzdGluZzogQ2hhbmdlIHdzVXJpIGZvciBcIiArIG1pbGxpcyArIFwiIG1pbGxpcyB0byBzaW11bGF0ZSBuZXQgZmFpbHVyZVwiKTtcbiAgICAgICAgICAgIHZhciBnb29kV3NVcmkgPSB3c1VyaTtcbiAgICAgICAgICAgIHdzVXJpID0gXCJ3c3M6Ly8yMS4yMzQuMTIuMzQuNDo0NDMvXCI7XG5cbiAgICAgICAgICAgIGZvcmNpbmdEaXNjb25uZWN0aW9uID0gdHJ1ZTtcblxuICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIlRlc3Rpbmc6IFJlY292ZXIgZ29vZCB3c1VyaSBcIiArIGdvb2RXc1VyaSk7XG4gICAgICAgICAgICAgICAgd3NVcmkgPSBnb29kV3NVcmk7XG5cbiAgICAgICAgICAgICAgICBmb3JjaW5nRGlzY29ubmVjdGlvbiA9IGZhbHNlO1xuXG4gICAgICAgICAgICB9LCBtaWxsaXMpO1xuICAgICAgICB9XG5cbiAgICAgICAgd3MuY2xvc2UoKTtcbiAgICB9O1xuXG4gICAgdGhpcy5yZWNvbm5lY3RXcyA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBjb25zb2xlLmxvZyhcInJlY29ubmVjdFdzXCIpO1xuICAgICAgICByZWNvbm5lY3RJbk5ld1VyaShNQVhfUkVUUklFUywgMSwgd3NVcmkpO1xuICAgIH07XG5cbiAgICB0aGlzLnNlbmQgPSBmdW5jdGlvbihtZXNzYWdlKSB7XG4gICAgICAgIHdzLnNlbmQobWVzc2FnZSk7XG4gICAgfTtcblxuICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGNhbGxiYWNrKSB7XG4gICAgICAgIHJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHdzLmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgY2FsbGJhY2spO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoKTtcbiAgICB9O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IFdlYlNvY2tldFdpdGhSZWNvbm5lY3Rpb247IiwiLypcbiAqIChDKSBDb3B5cmlnaHQgMjAxNCBLdXJlbnRvIChodHRwOi8va3VyZW50by5vcmcvKVxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICovXG5cblxudmFyIGRlZmluZVByb3BlcnR5X0lFOCA9IGZhbHNlXG5pZihPYmplY3QuZGVmaW5lUHJvcGVydHkpXG57XG4gIHRyeVxuICB7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHt9LCBcInhcIiwge30pO1xuICB9XG4gIGNhdGNoKGUpXG4gIHtcbiAgICBkZWZpbmVQcm9wZXJ0eV9JRTggPSB0cnVlXG4gIH1cbn1cblxuLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvRnVuY3Rpb24vYmluZFxuaWYgKCFGdW5jdGlvbi5wcm90b3R5cGUuYmluZCkge1xuICBGdW5jdGlvbi5wcm90b3R5cGUuYmluZCA9IGZ1bmN0aW9uKG9UaGlzKSB7XG4gICAgaWYgKHR5cGVvZiB0aGlzICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAvLyBjbG9zZXN0IHRoaW5nIHBvc3NpYmxlIHRvIHRoZSBFQ01BU2NyaXB0IDVcbiAgICAgIC8vIGludGVybmFsIElzQ2FsbGFibGUgZnVuY3Rpb25cbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0Z1bmN0aW9uLnByb3RvdHlwZS5iaW5kIC0gd2hhdCBpcyB0cnlpbmcgdG8gYmUgYm91bmQgaXMgbm90IGNhbGxhYmxlJyk7XG4gICAgfVxuXG4gICAgdmFyIGFBcmdzICAgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpLFxuICAgICAgICBmVG9CaW5kID0gdGhpcyxcbiAgICAgICAgZk5PUCAgICA9IGZ1bmN0aW9uKCkge30sXG4gICAgICAgIGZCb3VuZCAgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gZlRvQmluZC5hcHBseSh0aGlzIGluc3RhbmNlb2YgZk5PUCAmJiBvVGhpc1xuICAgICAgICAgICAgICAgICA/IHRoaXNcbiAgICAgICAgICAgICAgICAgOiBvVGhpcyxcbiAgICAgICAgICAgICAgICAgYUFyZ3MuY29uY2F0KEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgICAgfTtcblxuICAgIGZOT1AucHJvdG90eXBlID0gdGhpcy5wcm90b3R5cGU7XG4gICAgZkJvdW5kLnByb3RvdHlwZSA9IG5ldyBmTk9QKCk7XG5cbiAgICByZXR1cm4gZkJvdW5kO1xuICB9O1xufVxuXG5cbnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXI7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJyk7XG5cbnZhciBwYWNrZXJzID0gcmVxdWlyZSgnLi9wYWNrZXJzJyk7XG52YXIgTWFwcGVyID0gcmVxdWlyZSgnLi9NYXBwZXInKTtcblxuXG52YXIgQkFTRV9USU1FT1VUID0gNTAwMDtcblxuXG5mdW5jdGlvbiB1bmlmeVJlc3BvbnNlTWV0aG9kcyhyZXNwb25zZU1ldGhvZHMpXG57XG4gIGlmKCFyZXNwb25zZU1ldGhvZHMpIHJldHVybiB7fTtcblxuICBmb3IodmFyIGtleSBpbiByZXNwb25zZU1ldGhvZHMpXG4gIHtcbiAgICB2YXIgdmFsdWUgPSByZXNwb25zZU1ldGhvZHNba2V5XTtcblxuICAgIGlmKHR5cGVvZiB2YWx1ZSA9PSAnc3RyaW5nJylcbiAgICAgIHJlc3BvbnNlTWV0aG9kc1trZXldID1cbiAgICAgIHtcbiAgICAgICAgcmVzcG9uc2U6IHZhbHVlXG4gICAgICB9XG4gIH07XG5cbiAgcmV0dXJuIHJlc3BvbnNlTWV0aG9kcztcbn07XG5cbmZ1bmN0aW9uIHVuaWZ5VHJhbnNwb3J0KHRyYW5zcG9ydClcbntcbiAgaWYoIXRyYW5zcG9ydCkgcmV0dXJuO1xuXG4gIC8vIFRyYW5zcG9ydCBhcyBhIGZ1bmN0aW9uXG4gIGlmKHRyYW5zcG9ydCBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICAgIHJldHVybiB7c2VuZDogdHJhbnNwb3J0fTtcblxuICAvLyBXZWJTb2NrZXQgJiBEYXRhQ2hhbm5lbFxuICBpZih0cmFuc3BvcnQuc2VuZCBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICAgIHJldHVybiB0cmFuc3BvcnQ7XG5cbiAgLy8gTWVzc2FnZSBBUEkgKEludGVyLXdpbmRvdyAmIFdlYldvcmtlcilcbiAgaWYodHJhbnNwb3J0LnBvc3RNZXNzYWdlIGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gIHtcbiAgICB0cmFuc3BvcnQuc2VuZCA9IHRyYW5zcG9ydC5wb3N0TWVzc2FnZTtcbiAgICByZXR1cm4gdHJhbnNwb3J0O1xuICB9XG5cbiAgLy8gU3RyZWFtIEFQSVxuICBpZih0cmFuc3BvcnQud3JpdGUgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAge1xuICAgIHRyYW5zcG9ydC5zZW5kID0gdHJhbnNwb3J0LndyaXRlO1xuICAgIHJldHVybiB0cmFuc3BvcnQ7XG4gIH1cblxuICAvLyBUcmFuc3BvcnRzIHRoYXQgb25seSBjYW4gcmVjZWl2ZSBtZXNzYWdlcywgYnV0IG5vdCBzZW5kXG4gIGlmKHRyYW5zcG9ydC5vbm1lc3NhZ2UgIT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICBpZih0cmFuc3BvcnQucGF1c2UgaW5zdGFuY2VvZiBGdW5jdGlvbikgcmV0dXJuO1xuXG4gIHRocm93IG5ldyBTeW50YXhFcnJvcihcIlRyYW5zcG9ydCBpcyBub3QgYSBmdW5jdGlvbiBub3IgYSB2YWxpZCBvYmplY3RcIik7XG59O1xuXG5cbi8qKlxuICogUmVwcmVzZW50YXRpb24gb2YgYSBSUEMgbm90aWZpY2F0aW9uXG4gKlxuICogQGNsYXNzXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1ldGhvZCAtbWV0aG9kIG9mIHRoZSBub3RpZmljYXRpb25cbiAqIEBwYXJhbSBwYXJhbXMgLSBwYXJhbWV0ZXJzIG9mIHRoZSBub3RpZmljYXRpb25cbiAqL1xuZnVuY3Rpb24gUnBjTm90aWZpY2F0aW9uKG1ldGhvZCwgcGFyYW1zKVxue1xuICBpZihkZWZpbmVQcm9wZXJ0eV9JRTgpXG4gIHtcbiAgICB0aGlzLm1ldGhvZCA9IG1ldGhvZFxuICAgIHRoaXMucGFyYW1zID0gcGFyYW1zXG4gIH1cbiAgZWxzZVxuICB7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICdtZXRob2QnLCB7dmFsdWU6IG1ldGhvZCwgZW51bWVyYWJsZTogdHJ1ZX0pO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAncGFyYW1zJywge3ZhbHVlOiBwYXJhbXMsIGVudW1lcmFibGU6IHRydWV9KTtcbiAgfVxufTtcblxuXG4vKipcbiAqIEBjbGFzc1xuICpcbiAqIEBjb25zdHJ1Y3RvclxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBwYWNrZXJcbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gW29wdGlvbnNdXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IFt0cmFuc3BvcnRdXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gW29uUmVxdWVzdF1cbiAqL1xuZnVuY3Rpb24gUnBjQnVpbGRlcihwYWNrZXIsIG9wdGlvbnMsIHRyYW5zcG9ydCwgb25SZXF1ZXN0KVxue1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgaWYoIXBhY2tlcilcbiAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoJ1BhY2tlciBpcyBub3QgZGVmaW5lZCcpO1xuXG4gIGlmKCFwYWNrZXIucGFjayB8fCAhcGFja2VyLnVucGFjaylcbiAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoJ1BhY2tlciBpcyBpbnZhbGlkJyk7XG5cbiAgdmFyIHJlc3BvbnNlTWV0aG9kcyA9IHVuaWZ5UmVzcG9uc2VNZXRob2RzKHBhY2tlci5yZXNwb25zZU1ldGhvZHMpO1xuXG5cbiAgaWYob3B0aW9ucyBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICB7XG4gICAgaWYodHJhbnNwb3J0ICE9IHVuZGVmaW5lZClcbiAgICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIlRoZXJlIGNhbid0IGJlIHBhcmFtZXRlcnMgYWZ0ZXIgb25SZXF1ZXN0XCIpO1xuXG4gICAgb25SZXF1ZXN0ID0gb3B0aW9ucztcbiAgICB0cmFuc3BvcnQgPSB1bmRlZmluZWQ7XG4gICAgb3B0aW9ucyAgID0gdW5kZWZpbmVkO1xuICB9O1xuXG4gIGlmKG9wdGlvbnMgJiYgb3B0aW9ucy5zZW5kIGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gIHtcbiAgICBpZih0cmFuc3BvcnQgJiYgISh0cmFuc3BvcnQgaW5zdGFuY2VvZiBGdW5jdGlvbikpXG4gICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJPbmx5IGEgZnVuY3Rpb24gY2FuIGJlIGFmdGVyIHRyYW5zcG9ydFwiKTtcblxuICAgIG9uUmVxdWVzdCA9IHRyYW5zcG9ydDtcbiAgICB0cmFuc3BvcnQgPSBvcHRpb25zO1xuICAgIG9wdGlvbnMgICA9IHVuZGVmaW5lZDtcbiAgfTtcblxuICBpZih0cmFuc3BvcnQgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAge1xuICAgIGlmKG9uUmVxdWVzdCAhPSB1bmRlZmluZWQpXG4gICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJUaGVyZSBjYW4ndCBiZSBwYXJhbWV0ZXJzIGFmdGVyIG9uUmVxdWVzdFwiKTtcblxuICAgIG9uUmVxdWVzdCA9IHRyYW5zcG9ydDtcbiAgICB0cmFuc3BvcnQgPSB1bmRlZmluZWQ7XG4gIH07XG5cbiAgaWYodHJhbnNwb3J0ICYmIHRyYW5zcG9ydC5zZW5kIGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gICAgaWYob25SZXF1ZXN0ICYmICEob25SZXF1ZXN0IGluc3RhbmNlb2YgRnVuY3Rpb24pKVxuICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiT25seSBhIGZ1bmN0aW9uIGNhbiBiZSBhZnRlciB0cmFuc3BvcnRcIik7XG5cbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cblxuICBFdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcblxuICBpZihvblJlcXVlc3QpXG4gICAgdGhpcy5vbigncmVxdWVzdCcsIG9uUmVxdWVzdCk7XG5cblxuICBpZihkZWZpbmVQcm9wZXJ0eV9JRTgpXG4gICAgdGhpcy5wZWVySUQgPSBvcHRpb25zLnBlZXJJRFxuICBlbHNlXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICdwZWVySUQnLCB7dmFsdWU6IG9wdGlvbnMucGVlcklEfSk7XG5cbiAgdmFyIG1heF9yZXRyaWVzID0gb3B0aW9ucy5tYXhfcmV0cmllcyB8fCAwO1xuXG5cbiAgZnVuY3Rpb24gdHJhbnNwb3J0TWVzc2FnZShldmVudClcbiAge1xuICAgIHNlbGYuZGVjb2RlKGV2ZW50LmRhdGEgfHwgZXZlbnQpO1xuICB9O1xuXG4gIHRoaXMuZ2V0VHJhbnNwb3J0ID0gZnVuY3Rpb24oKVxuICB7XG4gICAgcmV0dXJuIHRyYW5zcG9ydDtcbiAgfVxuICB0aGlzLnNldFRyYW5zcG9ydCA9IGZ1bmN0aW9uKHZhbHVlKVxuICB7XG4gICAgLy8gUmVtb3ZlIGxpc3RlbmVyIGZyb20gb2xkIHRyYW5zcG9ydFxuICAgIGlmKHRyYW5zcG9ydClcbiAgICB7XG4gICAgICAvLyBXM0MgdHJhbnNwb3J0c1xuICAgICAgaWYodHJhbnNwb3J0LnJlbW92ZUV2ZW50TGlzdGVuZXIpXG4gICAgICAgIHRyYW5zcG9ydC5yZW1vdmVFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgdHJhbnNwb3J0TWVzc2FnZSk7XG5cbiAgICAgIC8vIE5vZGUuanMgU3RyZWFtcyBBUElcbiAgICAgIGVsc2UgaWYodHJhbnNwb3J0LnJlbW92ZUxpc3RlbmVyKVxuICAgICAgICB0cmFuc3BvcnQucmVtb3ZlTGlzdGVuZXIoJ2RhdGEnLCB0cmFuc3BvcnRNZXNzYWdlKTtcbiAgICB9O1xuXG4gICAgLy8gU2V0IGxpc3RlbmVyIG9uIG5ldyB0cmFuc3BvcnRcbiAgICBpZih2YWx1ZSlcbiAgICB7XG4gICAgICAvLyBXM0MgdHJhbnNwb3J0c1xuICAgICAgaWYodmFsdWUuYWRkRXZlbnRMaXN0ZW5lcilcbiAgICAgICAgdmFsdWUuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIHRyYW5zcG9ydE1lc3NhZ2UpO1xuXG4gICAgICAvLyBOb2RlLmpzIFN0cmVhbXMgQVBJXG4gICAgICBlbHNlIGlmKHZhbHVlLmFkZExpc3RlbmVyKVxuICAgICAgICB2YWx1ZS5hZGRMaXN0ZW5lcignZGF0YScsIHRyYW5zcG9ydE1lc3NhZ2UpO1xuICAgIH07XG5cbiAgICB0cmFuc3BvcnQgPSB1bmlmeVRyYW5zcG9ydCh2YWx1ZSk7XG4gIH1cblxuICBpZighZGVmaW5lUHJvcGVydHlfSUU4KVxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAndHJhbnNwb3J0JyxcbiAgICB7XG4gICAgICBnZXQ6IHRoaXMuZ2V0VHJhbnNwb3J0LmJpbmQodGhpcyksXG4gICAgICBzZXQ6IHRoaXMuc2V0VHJhbnNwb3J0LmJpbmQodGhpcylcbiAgICB9KVxuXG4gIHRoaXMuc2V0VHJhbnNwb3J0KHRyYW5zcG9ydCk7XG5cblxuICB2YXIgcmVxdWVzdF90aW1lb3V0ICAgID0gb3B0aW9ucy5yZXF1ZXN0X3RpbWVvdXQgICAgfHwgQkFTRV9USU1FT1VUO1xuICB2YXIgcmVzcG9uc2VfdGltZW91dCAgID0gb3B0aW9ucy5yZXNwb25zZV90aW1lb3V0ICAgfHwgQkFTRV9USU1FT1VUO1xuICB2YXIgZHVwbGljYXRlc190aW1lb3V0ID0gb3B0aW9ucy5kdXBsaWNhdGVzX3RpbWVvdXQgfHwgQkFTRV9USU1FT1VUO1xuXG5cbiAgdmFyIHJlcXVlc3RJRCA9IDA7XG5cbiAgdmFyIHJlcXVlc3RzICA9IG5ldyBNYXBwZXIoKTtcbiAgdmFyIHJlc3BvbnNlcyA9IG5ldyBNYXBwZXIoKTtcbiAgdmFyIHByb2Nlc3NlZFJlc3BvbnNlcyA9IG5ldyBNYXBwZXIoKTtcblxuICB2YXIgbWVzc2FnZTJLZXkgPSB7fTtcblxuXG4gIC8qKlxuICAgKiBTdG9yZSB0aGUgcmVzcG9uc2UgdG8gcHJldmVudCB0byBwcm9jZXNzIGR1cGxpY2F0ZSByZXF1ZXN0IGxhdGVyXG4gICAqL1xuICBmdW5jdGlvbiBzdG9yZVJlc3BvbnNlKG1lc3NhZ2UsIGlkLCBkZXN0KVxuICB7XG4gICAgdmFyIHJlc3BvbnNlID1cbiAgICB7XG4gICAgICBtZXNzYWdlOiBtZXNzYWdlLFxuICAgICAgLyoqIFRpbWVvdXQgdG8gYXV0by1jbGVhbiBvbGQgcmVzcG9uc2VzICovXG4gICAgICB0aW1lb3V0OiBzZXRUaW1lb3V0KGZ1bmN0aW9uKClcbiAgICAgIHtcbiAgICAgICAgcmVzcG9uc2VzLnJlbW92ZShpZCwgZGVzdCk7XG4gICAgICB9LFxuICAgICAgcmVzcG9uc2VfdGltZW91dClcbiAgICB9O1xuXG4gICAgcmVzcG9uc2VzLnNldChyZXNwb25zZSwgaWQsIGRlc3QpO1xuICB9O1xuXG4gIC8qKlxuICAgKiBTdG9yZSB0aGUgcmVzcG9uc2UgdG8gaWdub3JlIGR1cGxpY2F0ZWQgbWVzc2FnZXMgbGF0ZXJcbiAgICovXG4gIGZ1bmN0aW9uIHN0b3JlUHJvY2Vzc2VkUmVzcG9uc2UoYWNrLCBmcm9tKVxuICB7XG4gICAgdmFyIHRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKClcbiAgICB7XG4gICAgICBwcm9jZXNzZWRSZXNwb25zZXMucmVtb3ZlKGFjaywgZnJvbSk7XG4gICAgfSxcbiAgICBkdXBsaWNhdGVzX3RpbWVvdXQpO1xuXG4gICAgcHJvY2Vzc2VkUmVzcG9uc2VzLnNldCh0aW1lb3V0LCBhY2ssIGZyb20pO1xuICB9O1xuXG5cbiAgLyoqXG4gICAqIFJlcHJlc2VudGF0aW9uIG9mIGEgUlBDIHJlcXVlc3RcbiAgICpcbiAgICogQGNsYXNzXG4gICAqIEBleHRlbmRzIFJwY05vdGlmaWNhdGlvblxuICAgKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICpcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1ldGhvZCAtbWV0aG9kIG9mIHRoZSBub3RpZmljYXRpb25cbiAgICogQHBhcmFtIHBhcmFtcyAtIHBhcmFtZXRlcnMgb2YgdGhlIG5vdGlmaWNhdGlvblxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGlkIC0gaWRlbnRpZmllciBvZiB0aGUgcmVxdWVzdFxuICAgKiBAcGFyYW0gW2Zyb21dIC0gc291cmNlIG9mIHRoZSBub3RpZmljYXRpb25cbiAgICovXG4gIGZ1bmN0aW9uIFJwY1JlcXVlc3QobWV0aG9kLCBwYXJhbXMsIGlkLCBmcm9tLCB0cmFuc3BvcnQpXG4gIHtcbiAgICBScGNOb3RpZmljYXRpb24uY2FsbCh0aGlzLCBtZXRob2QsIHBhcmFtcyk7XG5cbiAgICB0aGlzLmdldFRyYW5zcG9ydCA9IGZ1bmN0aW9uKClcbiAgICB7XG4gICAgICByZXR1cm4gdHJhbnNwb3J0O1xuICAgIH1cbiAgICB0aGlzLnNldFRyYW5zcG9ydCA9IGZ1bmN0aW9uKHZhbHVlKVxuICAgIHtcbiAgICAgIHRyYW5zcG9ydCA9IHVuaWZ5VHJhbnNwb3J0KHZhbHVlKTtcbiAgICB9XG5cbiAgICBpZighZGVmaW5lUHJvcGVydHlfSUU4KVxuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsICd0cmFuc3BvcnQnLFxuICAgICAge1xuICAgICAgICBnZXQ6IHRoaXMuZ2V0VHJhbnNwb3J0LmJpbmQodGhpcyksXG4gICAgICAgIHNldDogdGhpcy5zZXRUcmFuc3BvcnQuYmluZCh0aGlzKVxuICAgICAgfSlcblxuICAgIHZhciByZXNwb25zZSA9IHJlc3BvbnNlcy5nZXQoaWQsIGZyb20pO1xuXG4gICAgLyoqXG4gICAgICogQGNvbnN0YW50IHtCb29sZWFufSBkdXBsaWNhdGVkXG4gICAgICovXG4gICAgaWYoISh0cmFuc3BvcnQgfHwgc2VsZi5nZXRUcmFuc3BvcnQoKSkpXG4gICAge1xuICAgICAgaWYoZGVmaW5lUHJvcGVydHlfSUU4KVxuICAgICAgICB0aGlzLmR1cGxpY2F0ZWQgPSBCb29sZWFuKHJlc3BvbnNlKVxuICAgICAgZWxzZVxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ2R1cGxpY2F0ZWQnLFxuICAgICAgICB7XG4gICAgICAgICAgdmFsdWU6IEJvb2xlYW4ocmVzcG9uc2UpXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHZhciByZXNwb25zZU1ldGhvZCA9IHJlc3BvbnNlTWV0aG9kc1ttZXRob2RdO1xuXG4gICAgdGhpcy5wYWNrID0gcGFja2VyLnBhY2suYmluZChwYWNrZXIsIHRoaXMsIGlkKVxuXG4gICAgLyoqXG4gICAgICogR2VuZXJhdGUgYSByZXNwb25zZSB0byB0aGlzIHJlcXVlc3RcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7RXJyb3J9IFtlcnJvcl1cbiAgICAgKiBAcGFyYW0geyp9IFtyZXN1bHRdXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgICAqL1xuICAgIHRoaXMucmVwbHkgPSBmdW5jdGlvbihlcnJvciwgcmVzdWx0LCB0cmFuc3BvcnQpXG4gICAge1xuICAgICAgLy8gRml4IG9wdGlvbmFsIHBhcmFtZXRlcnNcbiAgICAgIGlmKGVycm9yIGluc3RhbmNlb2YgRnVuY3Rpb24gfHwgZXJyb3IgJiYgZXJyb3Iuc2VuZCBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICAgICAge1xuICAgICAgICBpZihyZXN1bHQgIT0gdW5kZWZpbmVkKVxuICAgICAgICAgIHRocm93IG5ldyBTeW50YXhFcnJvcihcIlRoZXJlIGNhbid0IGJlIHBhcmFtZXRlcnMgYWZ0ZXIgY2FsbGJhY2tcIik7XG5cbiAgICAgICAgdHJhbnNwb3J0ID0gZXJyb3I7XG4gICAgICAgIHJlc3VsdCA9IG51bGw7XG4gICAgICAgIGVycm9yID0gdW5kZWZpbmVkO1xuICAgICAgfVxuXG4gICAgICBlbHNlIGlmKHJlc3VsdCBpbnN0YW5jZW9mIEZ1bmN0aW9uXG4gICAgICB8fCByZXN1bHQgJiYgcmVzdWx0LnNlbmQgaW5zdGFuY2VvZiBGdW5jdGlvbilcbiAgICAgIHtcbiAgICAgICAgaWYodHJhbnNwb3J0ICE9IHVuZGVmaW5lZClcbiAgICAgICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJUaGVyZSBjYW4ndCBiZSBwYXJhbWV0ZXJzIGFmdGVyIGNhbGxiYWNrXCIpO1xuXG4gICAgICAgIHRyYW5zcG9ydCA9IHJlc3VsdDtcbiAgICAgICAgcmVzdWx0ID0gbnVsbDtcbiAgICAgIH07XG5cbiAgICAgIHRyYW5zcG9ydCA9IHVuaWZ5VHJhbnNwb3J0KHRyYW5zcG9ydCk7XG5cbiAgICAgIC8vIER1cGxpY2F0ZWQgcmVxdWVzdCwgcmVtb3ZlIG9sZCByZXNwb25zZSB0aW1lb3V0XG4gICAgICBpZihyZXNwb25zZSlcbiAgICAgICAgY2xlYXJUaW1lb3V0KHJlc3BvbnNlLnRpbWVvdXQpO1xuXG4gICAgICBpZihmcm9tICE9IHVuZGVmaW5lZClcbiAgICAgIHtcbiAgICAgICAgaWYoZXJyb3IpXG4gICAgICAgICAgZXJyb3IuZGVzdCA9IGZyb207XG5cbiAgICAgICAgaWYocmVzdWx0KVxuICAgICAgICAgIHJlc3VsdC5kZXN0ID0gZnJvbTtcbiAgICAgIH07XG5cbiAgICAgIHZhciBtZXNzYWdlO1xuXG4gICAgICAvLyBOZXcgcmVxdWVzdCBvciBvdmVycmlkZW4gb25lLCBjcmVhdGUgbmV3IHJlc3BvbnNlIHdpdGggcHJvdmlkZWQgZGF0YVxuICAgICAgaWYoZXJyb3IgfHwgcmVzdWx0ICE9IHVuZGVmaW5lZClcbiAgICAgIHtcbiAgICAgICAgaWYoc2VsZi5wZWVySUQgIT0gdW5kZWZpbmVkKVxuICAgICAgICB7XG4gICAgICAgICAgaWYoZXJyb3IpXG4gICAgICAgICAgICBlcnJvci5mcm9tID0gc2VsZi5wZWVySUQ7XG4gICAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmVzdWx0LmZyb20gPSBzZWxmLnBlZXJJRDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFByb3RvY29sIGluZGljYXRlcyB0aGF0IHJlc3BvbnNlcyBoYXMgb3duIHJlcXVlc3QgbWV0aG9kc1xuICAgICAgICBpZihyZXNwb25zZU1ldGhvZClcbiAgICAgICAge1xuICAgICAgICAgIGlmKHJlc3BvbnNlTWV0aG9kLmVycm9yID09IHVuZGVmaW5lZCAmJiBlcnJvcilcbiAgICAgICAgICAgIG1lc3NhZ2UgPVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBlcnJvcjogZXJyb3JcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICBlbHNlXG4gICAgICAgICAge1xuICAgICAgICAgICAgdmFyIG1ldGhvZCA9IGVycm9yXG4gICAgICAgICAgICAgICAgICAgICAgID8gcmVzcG9uc2VNZXRob2QuZXJyb3JcbiAgICAgICAgICAgICAgICAgICAgICAgOiByZXNwb25zZU1ldGhvZC5yZXNwb25zZTtcblxuICAgICAgICAgICAgbWVzc2FnZSA9XG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG1ldGhvZDogbWV0aG9kLFxuICAgICAgICAgICAgICBwYXJhbXM6IGVycm9yIHx8IHJlc3VsdFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICAgIG1lc3NhZ2UgPVxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGVycm9yOiAgZXJyb3IsXG4gICAgICAgICAgICByZXN1bHQ6IHJlc3VsdFxuICAgICAgICAgIH07XG5cbiAgICAgICAgbWVzc2FnZSA9IHBhY2tlci5wYWNrKG1lc3NhZ2UsIGlkKTtcbiAgICAgIH1cblxuICAgICAgLy8gRHVwbGljYXRlICYgbm90LW92ZXJyaWRlbiByZXF1ZXN0LCByZS1zZW5kIG9sZCByZXNwb25zZVxuICAgICAgZWxzZSBpZihyZXNwb25zZSlcbiAgICAgICAgbWVzc2FnZSA9IHJlc3BvbnNlLm1lc3NhZ2U7XG5cbiAgICAgIC8vIE5ldyBlbXB0eSByZXBseSwgcmVzcG9uc2UgbnVsbCB2YWx1ZVxuICAgICAgZWxzZVxuICAgICAgICBtZXNzYWdlID0gcGFja2VyLnBhY2soe3Jlc3VsdDogbnVsbH0sIGlkKTtcblxuICAgICAgLy8gU3RvcmUgdGhlIHJlc3BvbnNlIHRvIHByZXZlbnQgdG8gcHJvY2VzcyBhIGR1cGxpY2F0ZWQgcmVxdWVzdCBsYXRlclxuICAgICAgc3RvcmVSZXNwb25zZShtZXNzYWdlLCBpZCwgZnJvbSk7XG5cbiAgICAgIC8vIFJldHVybiB0aGUgc3RvcmVkIHJlc3BvbnNlIHNvIGl0IGNhbiBiZSBkaXJlY3RseSBzZW5kIGJhY2tcbiAgICAgIHRyYW5zcG9ydCA9IHRyYW5zcG9ydCB8fCB0aGlzLmdldFRyYW5zcG9ydCgpIHx8IHNlbGYuZ2V0VHJhbnNwb3J0KCk7XG5cbiAgICAgIGlmKHRyYW5zcG9ydClcbiAgICAgICAgcmV0dXJuIHRyYW5zcG9ydC5zZW5kKG1lc3NhZ2UpO1xuXG4gICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICB9XG4gIH07XG4gIGluaGVyaXRzKFJwY1JlcXVlc3QsIFJwY05vdGlmaWNhdGlvbik7XG5cblxuICBmdW5jdGlvbiBjYW5jZWwobWVzc2FnZSlcbiAge1xuICAgIHZhciBrZXkgPSBtZXNzYWdlMktleVttZXNzYWdlXTtcbiAgICBpZigha2V5KSByZXR1cm47XG5cbiAgICBkZWxldGUgbWVzc2FnZTJLZXlbbWVzc2FnZV07XG5cbiAgICB2YXIgcmVxdWVzdCA9IHJlcXVlc3RzLnBvcChrZXkuaWQsIGtleS5kZXN0KTtcbiAgICBpZighcmVxdWVzdCkgcmV0dXJuO1xuXG4gICAgY2xlYXJUaW1lb3V0KHJlcXVlc3QudGltZW91dCk7XG5cbiAgICAvLyBTdGFydCBkdXBsaWNhdGVkIHJlc3BvbnNlcyB0aW1lb3V0XG4gICAgc3RvcmVQcm9jZXNzZWRSZXNwb25zZShrZXkuaWQsIGtleS5kZXN0KTtcbiAgfTtcblxuICAvKipcbiAgICogQWxsb3cgdG8gY2FuY2VsIGEgcmVxdWVzdCBhbmQgZG9uJ3Qgd2FpdCBmb3IgYSByZXNwb25zZVxuICAgKlxuICAgKiBJZiBgbWVzc2FnZWAgaXMgbm90IGdpdmVuLCBjYW5jZWwgYWxsIHRoZSByZXF1ZXN0XG4gICAqL1xuICB0aGlzLmNhbmNlbCA9IGZ1bmN0aW9uKG1lc3NhZ2UpXG4gIHtcbiAgICBpZihtZXNzYWdlKSByZXR1cm4gY2FuY2VsKG1lc3NhZ2UpO1xuXG4gICAgZm9yKHZhciBtZXNzYWdlIGluIG1lc3NhZ2UyS2V5KVxuICAgICAgY2FuY2VsKG1lc3NhZ2UpO1xuICB9O1xuXG5cbiAgdGhpcy5jbG9zZSA9IGZ1bmN0aW9uKClcbiAge1xuICAgIC8vIFByZXZlbnQgdG8gcmVjZWl2ZSBuZXcgbWVzc2FnZXNcbiAgICB2YXIgdHJhbnNwb3J0ID0gdGhpcy5nZXRUcmFuc3BvcnQoKTtcbiAgICBpZih0cmFuc3BvcnQgJiYgdHJhbnNwb3J0LmNsb3NlKVxuICAgICAgIHRyYW5zcG9ydC5jbG9zZSgpO1xuXG4gICAgLy8gUmVxdWVzdCAmIHByb2Nlc3NlZCByZXNwb25zZXNcbiAgICB0aGlzLmNhbmNlbCgpO1xuXG4gICAgcHJvY2Vzc2VkUmVzcG9uc2VzLmZvckVhY2goY2xlYXJUaW1lb3V0KTtcblxuICAgIC8vIFJlc3BvbnNlc1xuICAgIHJlc3BvbnNlcy5mb3JFYWNoKGZ1bmN0aW9uKHJlc3BvbnNlKVxuICAgIHtcbiAgICAgIGNsZWFyVGltZW91dChyZXNwb25zZS50aW1lb3V0KTtcbiAgICB9KTtcbiAgfTtcblxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZXMgYW5kIGVuY29kZSBhIEpzb25SUEMgMi4wIG1lc3NhZ2VcbiAgICpcbiAgICogQHBhcmFtIHtTdHJpbmd9IG1ldGhvZCAtbWV0aG9kIG9mIHRoZSBub3RpZmljYXRpb25cbiAgICogQHBhcmFtIHBhcmFtcyAtIHBhcmFtZXRlcnMgb2YgdGhlIG5vdGlmaWNhdGlvblxuICAgKiBAcGFyYW0gW2Rlc3RdIC0gZGVzdGluYXRpb24gb2YgdGhlIG5vdGlmaWNhdGlvblxuICAgKiBAcGFyYW0ge29iamVjdH0gW3RyYW5zcG9ydF0gLSB0cmFuc3BvcnQgd2hlcmUgdG8gc2VuZCB0aGUgbWVzc2FnZVxuICAgKiBAcGFyYW0gW2NhbGxiYWNrXSAtIGZ1bmN0aW9uIGNhbGxlZCB3aGVuIGEgcmVzcG9uc2UgdG8gdGhpcyByZXF1ZXN0IGlzXG4gICAqICAgcmVjZWl2ZWQuIElmIG5vdCBkZWZpbmVkLCBhIG5vdGlmaWNhdGlvbiB3aWxsIGJlIHNlbmQgaW5zdGVhZFxuICAgKlxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBBIHJhdyBKc29uUlBDIDIuMCByZXF1ZXN0IG9yIG5vdGlmaWNhdGlvbiBzdHJpbmdcbiAgICovXG4gIHRoaXMuZW5jb2RlID0gZnVuY3Rpb24obWV0aG9kLCBwYXJhbXMsIGRlc3QsIHRyYW5zcG9ydCwgY2FsbGJhY2spXG4gIHtcbiAgICAvLyBGaXggb3B0aW9uYWwgcGFyYW1ldGVyc1xuICAgIGlmKHBhcmFtcyBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICAgIHtcbiAgICAgIGlmKGRlc3QgIT0gdW5kZWZpbmVkKVxuICAgICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJUaGVyZSBjYW4ndCBiZSBwYXJhbWV0ZXJzIGFmdGVyIGNhbGxiYWNrXCIpO1xuXG4gICAgICBjYWxsYmFjayAgPSBwYXJhbXM7XG4gICAgICB0cmFuc3BvcnQgPSB1bmRlZmluZWQ7XG4gICAgICBkZXN0ICAgICAgPSB1bmRlZmluZWQ7XG4gICAgICBwYXJhbXMgICAgPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgZWxzZSBpZihkZXN0IGluc3RhbmNlb2YgRnVuY3Rpb24pXG4gICAge1xuICAgICAgaWYodHJhbnNwb3J0ICE9IHVuZGVmaW5lZClcbiAgICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlcmUgY2FuJ3QgYmUgcGFyYW1ldGVycyBhZnRlciBjYWxsYmFja1wiKTtcblxuICAgICAgY2FsbGJhY2sgID0gZGVzdDtcbiAgICAgIHRyYW5zcG9ydCA9IHVuZGVmaW5lZDtcbiAgICAgIGRlc3QgICAgICA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBlbHNlIGlmKHRyYW5zcG9ydCBpbnN0YW5jZW9mIEZ1bmN0aW9uKVxuICAgIHtcbiAgICAgIGlmKGNhbGxiYWNrICE9IHVuZGVmaW5lZClcbiAgICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlcmUgY2FuJ3QgYmUgcGFyYW1ldGVycyBhZnRlciBjYWxsYmFja1wiKTtcblxuICAgICAgY2FsbGJhY2sgID0gdHJhbnNwb3J0O1xuICAgICAgdHJhbnNwb3J0ID0gdW5kZWZpbmVkO1xuICAgIH07XG5cbiAgICBpZihzZWxmLnBlZXJJRCAhPSB1bmRlZmluZWQpXG4gICAge1xuICAgICAgcGFyYW1zID0gcGFyYW1zIHx8IHt9O1xuXG4gICAgICBwYXJhbXMuZnJvbSA9IHNlbGYucGVlcklEO1xuICAgIH07XG5cbiAgICBpZihkZXN0ICE9IHVuZGVmaW5lZClcbiAgICB7XG4gICAgICBwYXJhbXMgPSBwYXJhbXMgfHwge307XG5cbiAgICAgIHBhcmFtcy5kZXN0ID0gZGVzdDtcbiAgICB9O1xuXG4gICAgLy8gRW5jb2RlIG1lc3NhZ2VcbiAgICB2YXIgbWVzc2FnZSA9XG4gICAge1xuICAgICAgbWV0aG9kOiBtZXRob2QsXG4gICAgICBwYXJhbXM6IHBhcmFtc1xuICAgIH07XG5cbiAgICBpZihjYWxsYmFjaylcbiAgICB7XG4gICAgICB2YXIgaWQgPSByZXF1ZXN0SUQrKztcbiAgICAgIHZhciByZXRyaWVkID0gMDtcblxuICAgICAgbWVzc2FnZSA9IHBhY2tlci5wYWNrKG1lc3NhZ2UsIGlkKTtcblxuICAgICAgZnVuY3Rpb24gZGlzcGF0Y2hDYWxsYmFjayhlcnJvciwgcmVzdWx0KVxuICAgICAge1xuICAgICAgICBzZWxmLmNhbmNlbChtZXNzYWdlKTtcblxuICAgICAgICBjYWxsYmFjayhlcnJvciwgcmVzdWx0KTtcbiAgICAgIH07XG5cbiAgICAgIHZhciByZXF1ZXN0ID1cbiAgICAgIHtcbiAgICAgICAgbWVzc2FnZTogICAgICAgICBtZXNzYWdlLFxuICAgICAgICBjYWxsYmFjazogICAgICAgIGRpc3BhdGNoQ2FsbGJhY2ssXG4gICAgICAgIHJlc3BvbnNlTWV0aG9kczogcmVzcG9uc2VNZXRob2RzW21ldGhvZF0gfHwge31cbiAgICAgIH07XG5cbiAgICAgIHZhciBlbmNvZGVfdHJhbnNwb3J0ID0gdW5pZnlUcmFuc3BvcnQodHJhbnNwb3J0KTtcblxuICAgICAgZnVuY3Rpb24gc2VuZFJlcXVlc3QodHJhbnNwb3J0KVxuICAgICAge1xuICAgICAgICByZXF1ZXN0LnRpbWVvdXQgPSBzZXRUaW1lb3V0KHRpbWVvdXQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWVzdF90aW1lb3V0Kk1hdGgucG93KDIsIHJldHJpZWQrKykpO1xuICAgICAgICBtZXNzYWdlMktleVttZXNzYWdlXSA9IHtpZDogaWQsIGRlc3Q6IGRlc3R9O1xuICAgICAgICByZXF1ZXN0cy5zZXQocmVxdWVzdCwgaWQsIGRlc3QpO1xuXG4gICAgICAgIHRyYW5zcG9ydCA9IHRyYW5zcG9ydCB8fCBlbmNvZGVfdHJhbnNwb3J0IHx8IHNlbGYuZ2V0VHJhbnNwb3J0KCk7XG4gICAgICAgIGlmKHRyYW5zcG9ydClcbiAgICAgICAgICByZXR1cm4gdHJhbnNwb3J0LnNlbmQobWVzc2FnZSk7XG5cbiAgICAgICAgcmV0dXJuIG1lc3NhZ2U7XG4gICAgICB9O1xuXG4gICAgICBmdW5jdGlvbiByZXRyeSh0cmFuc3BvcnQpXG4gICAgICB7XG4gICAgICAgIHRyYW5zcG9ydCA9IHVuaWZ5VHJhbnNwb3J0KHRyYW5zcG9ydCk7XG5cbiAgICAgICAgY29uc29sZS53YXJuKHJldHJpZWQrJyByZXRyeSBmb3IgcmVxdWVzdCBtZXNzYWdlOicsbWVzc2FnZSk7XG5cbiAgICAgICAgdmFyIHRpbWVvdXQgPSBwcm9jZXNzZWRSZXNwb25zZXMucG9wKGlkLCBkZXN0KTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuXG4gICAgICAgIHJldHVybiBzZW5kUmVxdWVzdCh0cmFuc3BvcnQpO1xuICAgICAgfTtcblxuICAgICAgZnVuY3Rpb24gdGltZW91dCgpXG4gICAgICB7XG4gICAgICAgIGlmKHJldHJpZWQgPCBtYXhfcmV0cmllcylcbiAgICAgICAgICByZXR1cm4gcmV0cnkodHJhbnNwb3J0KTtcblxuICAgICAgICB2YXIgZXJyb3IgPSBuZXcgRXJyb3IoJ1JlcXVlc3QgaGFzIHRpbWVkIG91dCcpO1xuICAgICAgICAgICAgZXJyb3IucmVxdWVzdCA9IG1lc3NhZ2U7XG5cbiAgICAgICAgZXJyb3IucmV0cnkgPSByZXRyeTtcblxuICAgICAgICBkaXNwYXRjaENhbGxiYWNrKGVycm9yKVxuICAgICAgfTtcblxuICAgICAgcmV0dXJuIHNlbmRSZXF1ZXN0KHRyYW5zcG9ydCk7XG4gICAgfTtcblxuICAgIC8vIFJldHVybiB0aGUgcGFja2VkIG1lc3NhZ2VcbiAgICBtZXNzYWdlID0gcGFja2VyLnBhY2sobWVzc2FnZSk7XG5cbiAgICB0cmFuc3BvcnQgPSB0cmFuc3BvcnQgfHwgdGhpcy5nZXRUcmFuc3BvcnQoKTtcbiAgICBpZih0cmFuc3BvcnQpXG4gICAgICByZXR1cm4gdHJhbnNwb3J0LnNlbmQobWVzc2FnZSk7XG5cbiAgICByZXR1cm4gbWVzc2FnZTtcbiAgfTtcblxuICAvKipcbiAgICogRGVjb2RlIGFuZCBwcm9jZXNzIGEgSnNvblJQQyAyLjAgbWVzc2FnZVxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIHN0cmluZyB3aXRoIHRoZSBjb250ZW50IG9mIHRoZSBtZXNzYWdlXG4gICAqXG4gICAqIEByZXR1cm5zIHtScGNOb3RpZmljYXRpb258UnBjUmVxdWVzdHx1bmRlZmluZWR9IC0gdGhlIHJlcHJlc2VudGF0aW9uIG9mIHRoZVxuICAgKiAgIG5vdGlmaWNhdGlvbiBvciB0aGUgcmVxdWVzdC4gSWYgYSByZXNwb25zZSB3YXMgcHJvY2Vzc2VkLCBpdCB3aWxsIHJldHVyblxuICAgKiAgIGB1bmRlZmluZWRgIHRvIG5vdGlmeSB0aGF0IGl0IHdhcyBwcm9jZXNzZWRcbiAgICpcbiAgICogQHRocm93cyB7VHlwZUVycm9yfSAtIE1lc3NhZ2UgaXMgbm90IGRlZmluZWRcbiAgICovXG4gIHRoaXMuZGVjb2RlID0gZnVuY3Rpb24obWVzc2FnZSwgdHJhbnNwb3J0KVxuICB7XG4gICAgaWYoIW1lc3NhZ2UpXG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTWVzc2FnZSBpcyBub3QgZGVmaW5lZFwiKTtcblxuICAgIHRyeVxuICAgIHtcbiAgICAgIG1lc3NhZ2UgPSBwYWNrZXIudW5wYWNrKG1lc3NhZ2UpO1xuICAgIH1cbiAgICBjYXRjaChlKVxuICAgIHtcbiAgICAgIC8vIElnbm9yZSBpbnZhbGlkIG1lc3NhZ2VzXG4gICAgICByZXR1cm4gY29uc29sZS5sb2coZSwgbWVzc2FnZSk7XG4gICAgfTtcblxuICAgIHZhciBpZCAgICAgPSBtZXNzYWdlLmlkO1xuICAgIHZhciBhY2sgICAgPSBtZXNzYWdlLmFjaztcbiAgICB2YXIgbWV0aG9kID0gbWVzc2FnZS5tZXRob2Q7XG4gICAgdmFyIHBhcmFtcyA9IG1lc3NhZ2UucGFyYW1zIHx8IHt9O1xuXG4gICAgdmFyIGZyb20gPSBwYXJhbXMuZnJvbTtcbiAgICB2YXIgZGVzdCA9IHBhcmFtcy5kZXN0O1xuXG4gICAgLy8gSWdub3JlIG1lc3NhZ2VzIHNlbmQgYnkgdXNcbiAgICBpZihzZWxmLnBlZXJJRCAhPSB1bmRlZmluZWQgJiYgZnJvbSA9PSBzZWxmLnBlZXJJRCkgcmV0dXJuO1xuXG4gICAgLy8gTm90aWZpY2F0aW9uXG4gICAgaWYoaWQgPT0gdW5kZWZpbmVkICYmIGFjayA9PSB1bmRlZmluZWQpXG4gICAge1xuICAgICAgdmFyIG5vdGlmaWNhdGlvbiA9IG5ldyBScGNOb3RpZmljYXRpb24obWV0aG9kLCBwYXJhbXMpO1xuXG4gICAgICBpZihzZWxmLmVtaXQoJ3JlcXVlc3QnLCBub3RpZmljYXRpb24pKSByZXR1cm47XG4gICAgICByZXR1cm4gbm90aWZpY2F0aW9uO1xuICAgIH07XG5cblxuICAgIGZ1bmN0aW9uIHByb2Nlc3NSZXF1ZXN0KClcbiAgICB7XG4gICAgICAvLyBJZiB3ZSBoYXZlIGEgdHJhbnNwb3J0IGFuZCBpdCdzIGEgZHVwbGljYXRlZCByZXF1ZXN0LCByZXBseSBpbm1lZGlhdGx5XG4gICAgICB0cmFuc3BvcnQgPSB1bmlmeVRyYW5zcG9ydCh0cmFuc3BvcnQpIHx8IHNlbGYuZ2V0VHJhbnNwb3J0KCk7XG4gICAgICBpZih0cmFuc3BvcnQpXG4gICAgICB7XG4gICAgICAgIHZhciByZXNwb25zZSA9IHJlc3BvbnNlcy5nZXQoaWQsIGZyb20pO1xuICAgICAgICBpZihyZXNwb25zZSlcbiAgICAgICAgICByZXR1cm4gdHJhbnNwb3J0LnNlbmQocmVzcG9uc2UubWVzc2FnZSk7XG4gICAgICB9O1xuXG4gICAgICB2YXIgaWRBY2sgPSAoaWQgIT0gdW5kZWZpbmVkKSA/IGlkIDogYWNrO1xuICAgICAgdmFyIHJlcXVlc3QgPSBuZXcgUnBjUmVxdWVzdChtZXRob2QsIHBhcmFtcywgaWRBY2ssIGZyb20sIHRyYW5zcG9ydCk7XG5cbiAgICAgIGlmKHNlbGYuZW1pdCgncmVxdWVzdCcsIHJlcXVlc3QpKSByZXR1cm47XG4gICAgICByZXR1cm4gcmVxdWVzdDtcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gcHJvY2Vzc1Jlc3BvbnNlKHJlcXVlc3QsIGVycm9yLCByZXN1bHQpXG4gICAge1xuICAgICAgcmVxdWVzdC5jYWxsYmFjayhlcnJvciwgcmVzdWx0KTtcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gZHVwbGljYXRlZFJlc3BvbnNlKHRpbWVvdXQpXG4gICAge1xuICAgICAgY29uc29sZS53YXJuKFwiUmVzcG9uc2UgYWxyZWFkeSBwcm9jZXNzZWRcIiwgbWVzc2FnZSk7XG5cbiAgICAgIC8vIFVwZGF0ZSBkdXBsaWNhdGVkIHJlc3BvbnNlcyB0aW1lb3V0XG4gICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICBzdG9yZVByb2Nlc3NlZFJlc3BvbnNlKGFjaywgZnJvbSk7XG4gICAgfTtcblxuXG4gICAgLy8gUmVxdWVzdCwgb3IgcmVzcG9uc2Ugd2l0aCBvd24gbWV0aG9kXG4gICAgaWYobWV0aG9kKVxuICAgIHtcbiAgICAgIC8vIENoZWNrIGlmIGl0J3MgYSByZXNwb25zZSB3aXRoIG93biBtZXRob2RcbiAgICAgIGlmKGRlc3QgPT0gdW5kZWZpbmVkIHx8IGRlc3QgPT0gc2VsZi5wZWVySUQpXG4gICAgICB7XG4gICAgICAgIHZhciByZXF1ZXN0ID0gcmVxdWVzdHMuZ2V0KGFjaywgZnJvbSk7XG4gICAgICAgIGlmKHJlcXVlc3QpXG4gICAgICAgIHtcbiAgICAgICAgICB2YXIgcmVzcG9uc2VNZXRob2RzID0gcmVxdWVzdC5yZXNwb25zZU1ldGhvZHM7XG5cbiAgICAgICAgICBpZihtZXRob2QgPT0gcmVzcG9uc2VNZXRob2RzLmVycm9yKVxuICAgICAgICAgICAgcmV0dXJuIHByb2Nlc3NSZXNwb25zZShyZXF1ZXN0LCBwYXJhbXMpO1xuXG4gICAgICAgICAgaWYobWV0aG9kID09IHJlc3BvbnNlTWV0aG9kcy5yZXNwb25zZSlcbiAgICAgICAgICAgIHJldHVybiBwcm9jZXNzUmVzcG9uc2UocmVxdWVzdCwgbnVsbCwgcGFyYW1zKTtcblxuICAgICAgICAgIHJldHVybiBwcm9jZXNzUmVxdWVzdCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHByb2Nlc3NlZCA9IHByb2Nlc3NlZFJlc3BvbnNlcy5nZXQoYWNrLCBmcm9tKTtcbiAgICAgICAgaWYocHJvY2Vzc2VkKVxuICAgICAgICAgIHJldHVybiBkdXBsaWNhdGVkUmVzcG9uc2UocHJvY2Vzc2VkKTtcbiAgICAgIH1cblxuICAgICAgLy8gUmVxdWVzdFxuICAgICAgcmV0dXJuIHByb2Nlc3NSZXF1ZXN0KCk7XG4gICAgfTtcblxuICAgIHZhciBlcnJvciAgPSBtZXNzYWdlLmVycm9yO1xuICAgIHZhciByZXN1bHQgPSBtZXNzYWdlLnJlc3VsdDtcblxuICAgIC8vIElnbm9yZSByZXNwb25zZXMgbm90IHNlbmQgdG8gdXNcbiAgICBpZihlcnJvciAgJiYgZXJyb3IuZGVzdCAgJiYgZXJyb3IuZGVzdCAgIT0gc2VsZi5wZWVySUQpIHJldHVybjtcbiAgICBpZihyZXN1bHQgJiYgcmVzdWx0LmRlc3QgJiYgcmVzdWx0LmRlc3QgIT0gc2VsZi5wZWVySUQpIHJldHVybjtcblxuICAgIC8vIFJlc3BvbnNlXG4gICAgdmFyIHJlcXVlc3QgPSByZXF1ZXN0cy5nZXQoYWNrLCBmcm9tKTtcbiAgICBpZighcmVxdWVzdClcbiAgICB7XG4gICAgICB2YXIgcHJvY2Vzc2VkID0gcHJvY2Vzc2VkUmVzcG9uc2VzLmdldChhY2ssIGZyb20pO1xuICAgICAgaWYocHJvY2Vzc2VkKVxuICAgICAgICByZXR1cm4gZHVwbGljYXRlZFJlc3BvbnNlKHByb2Nlc3NlZCk7XG5cbiAgICAgIHJldHVybiBjb25zb2xlLndhcm4oXCJObyBjYWxsYmFjayB3YXMgZGVmaW5lZCBmb3IgdGhpcyBtZXNzYWdlXCIsIG1lc3NhZ2UpO1xuICAgIH07XG5cbiAgICAvLyBQcm9jZXNzIHJlc3BvbnNlXG4gICAgcHJvY2Vzc1Jlc3BvbnNlKHJlcXVlc3QsIGVycm9yLCByZXN1bHQpO1xuICB9O1xufTtcbmluaGVyaXRzKFJwY0J1aWxkZXIsIEV2ZW50RW1pdHRlcik7XG5cblxuUnBjQnVpbGRlci5ScGNOb3RpZmljYXRpb24gPSBScGNOb3RpZmljYXRpb247XG5cblxubW9kdWxlLmV4cG9ydHMgPSBScGNCdWlsZGVyO1xuXG52YXIgY2xpZW50cyA9IHJlcXVpcmUoJy4vY2xpZW50cycpO1xudmFyIHRyYW5zcG9ydHMgPSByZXF1aXJlKCcuL2NsaWVudHMvdHJhbnNwb3J0cycpO1xuXG5ScGNCdWlsZGVyLmNsaWVudHMgPSBjbGllbnRzO1xuUnBjQnVpbGRlci5jbGllbnRzLnRyYW5zcG9ydHMgPSB0cmFuc3BvcnRzO1xuUnBjQnVpbGRlci5wYWNrZXJzID0gcGFja2VycztcbiIsIi8qKlxuICogSnNvblJQQyAyLjAgcGFja2VyXG4gKi9cblxuLyoqXG4gKiBQYWNrIGEgSnNvblJQQyAyLjAgbWVzc2FnZVxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBtZXNzYWdlIC0gb2JqZWN0IHRvIGJlIHBhY2thZ2VkLiBJdCByZXF1aXJlcyB0byBoYXZlIGFsbCB0aGVcbiAqICAgZmllbGRzIG5lZWRlZCBieSB0aGUgSnNvblJQQyAyLjAgbWVzc2FnZSB0aGF0IGl0J3MgZ29pbmcgdG8gYmUgZ2VuZXJhdGVkXG4gKlxuICogQHJldHVybiB7U3RyaW5nfSAtIHRoZSBzdHJpbmdpZmllZCBKc29uUlBDIDIuMCBtZXNzYWdlXG4gKi9cbmZ1bmN0aW9uIHBhY2sobWVzc2FnZSwgaWQpXG57XG4gIHZhciByZXN1bHQgPVxuICB7XG4gICAganNvbnJwYzogXCIyLjBcIlxuICB9O1xuXG4gIC8vIFJlcXVlc3RcbiAgaWYobWVzc2FnZS5tZXRob2QpXG4gIHtcbiAgICByZXN1bHQubWV0aG9kID0gbWVzc2FnZS5tZXRob2Q7XG5cbiAgICBpZihtZXNzYWdlLnBhcmFtcylcbiAgICAgIHJlc3VsdC5wYXJhbXMgPSBtZXNzYWdlLnBhcmFtcztcblxuICAgIC8vIFJlcXVlc3QgaXMgYSBub3RpZmljYXRpb25cbiAgICBpZihpZCAhPSB1bmRlZmluZWQpXG4gICAgICByZXN1bHQuaWQgPSBpZDtcbiAgfVxuXG4gIC8vIFJlc3BvbnNlXG4gIGVsc2UgaWYoaWQgIT0gdW5kZWZpbmVkKVxuICB7XG4gICAgaWYobWVzc2FnZS5lcnJvcilcbiAgICB7XG4gICAgICBpZihtZXNzYWdlLnJlc3VsdCAhPT0gdW5kZWZpbmVkKVxuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQm90aCByZXN1bHQgYW5kIGVycm9yIGFyZSBkZWZpbmVkXCIpO1xuXG4gICAgICByZXN1bHQuZXJyb3IgPSBtZXNzYWdlLmVycm9yO1xuICAgIH1cbiAgICBlbHNlIGlmKG1lc3NhZ2UucmVzdWx0ICE9PSB1bmRlZmluZWQpXG4gICAgICByZXN1bHQucmVzdWx0ID0gbWVzc2FnZS5yZXN1bHQ7XG4gICAgZWxzZVxuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk5vIHJlc3VsdCBvciBlcnJvciBpcyBkZWZpbmVkXCIpO1xuXG4gICAgcmVzdWx0LmlkID0gaWQ7XG4gIH07XG5cbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHJlc3VsdCk7XG59O1xuXG4vKipcbiAqIFVucGFjayBhIEpzb25SUEMgMi4wIG1lc3NhZ2VcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSAtIHN0cmluZyB3aXRoIHRoZSBjb250ZW50IG9mIHRoZSBKc29uUlBDIDIuMCBtZXNzYWdlXG4gKlxuICogQHRocm93cyB7VHlwZUVycm9yfSAtIEludmFsaWQgSnNvblJQQyB2ZXJzaW9uXG4gKlxuICogQHJldHVybiB7T2JqZWN0fSAtIG9iamVjdCBmaWxsZWQgd2l0aCB0aGUgSnNvblJQQyAyLjAgbWVzc2FnZSBjb250ZW50XG4gKi9cbmZ1bmN0aW9uIHVucGFjayhtZXNzYWdlKVxue1xuICB2YXIgcmVzdWx0ID0gbWVzc2FnZTtcblxuICBpZih0eXBlb2YgbWVzc2FnZSA9PT0gJ3N0cmluZycgfHwgbWVzc2FnZSBpbnN0YW5jZW9mIFN0cmluZylcbiAgICByZXN1bHQgPSBKU09OLnBhcnNlKG1lc3NhZ2UpO1xuXG4gIC8vIENoZWNrIGlmIGl0J3MgYSB2YWxpZCBtZXNzYWdlXG5cbiAgdmFyIHZlcnNpb24gPSByZXN1bHQuanNvbnJwYztcbiAgaWYodmVyc2lvbiAhPT0gJzIuMCcpXG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkludmFsaWQgSnNvblJQQyB2ZXJzaW9uICdcIiArIHZlcnNpb24gKyBcIic6IFwiICsgbWVzc2FnZSk7XG5cbiAgLy8gUmVzcG9uc2VcbiAgaWYocmVzdWx0Lm1ldGhvZCA9PSB1bmRlZmluZWQpXG4gIHtcbiAgICBpZihyZXN1bHQuaWQgPT0gdW5kZWZpbmVkKVxuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkludmFsaWQgbWVzc2FnZTogXCIrbWVzc2FnZSk7XG5cbiAgICB2YXIgcmVzdWx0X2RlZmluZWQgPSByZXN1bHQucmVzdWx0ICE9PSB1bmRlZmluZWQ7XG4gICAgdmFyIGVycm9yX2RlZmluZWQgID0gcmVzdWx0LmVycm9yICAhPT0gdW5kZWZpbmVkO1xuXG4gICAgLy8gQ2hlY2sgb25seSByZXN1bHQgb3IgZXJyb3IgaXMgZGVmaW5lZCwgbm90IGJvdGggb3Igbm9uZVxuICAgIGlmKHJlc3VsdF9kZWZpbmVkICYmIGVycm9yX2RlZmluZWQpXG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQm90aCByZXN1bHQgYW5kIGVycm9yIGFyZSBkZWZpbmVkOiBcIittZXNzYWdlKTtcblxuICAgIGlmKCFyZXN1bHRfZGVmaW5lZCAmJiAhZXJyb3JfZGVmaW5lZClcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJObyByZXN1bHQgb3IgZXJyb3IgaXMgZGVmaW5lZDogXCIrbWVzc2FnZSk7XG5cbiAgICByZXN1bHQuYWNrID0gcmVzdWx0LmlkO1xuICAgIGRlbGV0ZSByZXN1bHQuaWQ7XG4gIH1cblxuICAvLyBSZXR1cm4gdW5wYWNrZWQgbWVzc2FnZVxuICByZXR1cm4gcmVzdWx0O1xufTtcblxuXG5leHBvcnRzLnBhY2sgICA9IHBhY2s7XG5leHBvcnRzLnVucGFjayA9IHVucGFjaztcbiIsImZ1bmN0aW9uIHBhY2sobWVzc2FnZSlcbntcbiAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk5vdCB5ZXQgaW1wbGVtZW50ZWRcIik7XG59O1xuXG5mdW5jdGlvbiB1bnBhY2sobWVzc2FnZSlcbntcbiAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk5vdCB5ZXQgaW1wbGVtZW50ZWRcIik7XG59O1xuXG5cbmV4cG9ydHMucGFjayAgID0gcGFjaztcbmV4cG9ydHMudW5wYWNrID0gdW5wYWNrO1xuIiwidmFyIEpzb25SUEMgPSByZXF1aXJlKCcuL0pzb25SUEMnKTtcbnZhciBYbWxSUEMgID0gcmVxdWlyZSgnLi9YbWxSUEMnKTtcblxuXG5leHBvcnRzLkpzb25SUEMgPSBKc29uUlBDO1xuZXhwb3J0cy5YbWxSUEMgID0gWG1sUlBDO1xuIiwiLypcbiAqIChDKSBDb3B5cmlnaHQgMjAxNC0yMDE1IEt1cmVudG8gKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG52YXIgZnJlZWljZSA9IHJlcXVpcmUoJ2ZyZWVpY2UnKVxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxudmFyIFVBUGFyc2VyID0gcmVxdWlyZSgndWEtcGFyc2VyLWpzJylcbnZhciB1dWlkID0gcmVxdWlyZSgndXVpZCcpXG52YXIgaGFyayA9IHJlcXVpcmUoJ2hhcmsnKVxuXG52YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG52YXIgcmVjdXJzaXZlID0gcmVxdWlyZSgnbWVyZ2UnKS5yZWN1cnNpdmUuYmluZCh1bmRlZmluZWQsIHRydWUpXG52YXIgc2RwVHJhbnNsYXRvciA9IHJlcXVpcmUoJ3NkcC10cmFuc2xhdG9yJylcbnZhciBsb2dnZXIgPSB3aW5kb3cuTG9nZ2VyIHx8IGNvbnNvbGVcblxuLy8gdmFyIGdVTSA9IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhIHx8IGZ1bmN0aW9uIChjb25zdHJhaW50cykge1xuLy8gICByZXR1cm4gbmV3IFByb21pc2UobmF2aWdhdG9yLmdldFVzZXJNZWRpYShjb25zdHJhaW50cywgZnVuY3Rpb24gKHN0cmVhbSkge1xuLy8gICAgIHZpZGVvU3RyZWFtID0gc3RyZWFtXG4vLyAgICAgc3RhcnQoKVxuLy8gICB9KS5lcm9yKGNhbGxiYWNrKSk7XG4vLyB9XG5cbnRyeSB7XG4gIHJlcXVpcmUoJ2t1cmVudG8tYnJvd3Nlci1leHRlbnNpb25zJylcbn0gY2F0Y2ggKGVycm9yKSB7XG4gIGlmICh0eXBlb2YgZ2V0U2NyZWVuQ29uc3RyYWludHMgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgbG9nZ2VyLndhcm4oJ3NjcmVlbiBzaGFyaW5nIGlzIG5vdCBhdmFpbGFibGUnKVxuXG4gICAgZ2V0U2NyZWVuQ29uc3RyYWludHMgPSBmdW5jdGlvbiBnZXRTY3JlZW5Db25zdHJhaW50cyhzZW5kU291cmNlLCBjYWxsYmFjaykge1xuICAgICAgY2FsbGJhY2sobmV3IEVycm9yKFwiVGhpcyBsaWJyYXJ5IGlzIG5vdCBlbmFibGVkIGZvciBzY3JlZW4gc2hhcmluZ1wiKSlcbiAgICB9XG4gIH1cbn1cblxudmFyIE1FRElBX0NPTlNUUkFJTlRTID0ge1xuICBhdWRpbzogdHJ1ZSxcbiAgdmlkZW86IHtcbiAgICB3aWR0aDogNjQwLFxuICAgIGZyYW1lcmF0ZTogMTVcbiAgfVxufVxuXG4vLyBTb21laG93LCB0aGUgVUFQYXJzZXIgY29uc3RydWN0b3IgZ2V0cyBhbiBlbXB0eSB3aW5kb3cgb2JqZWN0LlxuLy8gV2UgbmVlZCB0byBwYXNzIHRoZSB1c2VyIGFnZW50IHN0cmluZyBpbiBvcmRlciB0byBnZXQgaW5mb3JtYXRpb25cbnZhciB1YSA9ICh3aW5kb3cgJiYgd2luZG93Lm5hdmlnYXRvcikgPyB3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudCA6ICcnXG52YXIgcGFyc2VyID0gbmV3IFVBUGFyc2VyKHVhKVxudmFyIGJyb3dzZXIgPSBwYXJzZXIuZ2V0QnJvd3NlcigpXG5cbnZhciB1c2VQbGFuQiA9IGZhbHNlXG5pZiAoYnJvd3Nlci5uYW1lID09PSAnQ2hyb21lJyB8fCBicm93c2VyLm5hbWUgPT09ICdDaHJvbWl1bScpIHtcbiAgbG9nZ2VyLmluZm8oYnJvd3Nlci5uYW1lICsgXCI6IHVzaW5nIFNEUCBQbGFuQlwiKVxuICB1c2VQbGFuQiA9IHRydWVcbn1cblxuZnVuY3Rpb24gbm9vcChlcnJvcikge1xuICBpZiAoZXJyb3IpIGxvZ2dlci5lcnJvcihlcnJvcilcbn1cblxuZnVuY3Rpb24gdHJhY2tTdG9wKHRyYWNrKSB7XG4gIHRyYWNrLnN0b3AgJiYgdHJhY2suc3RvcCgpXG59XG5cbmZ1bmN0aW9uIHN0cmVhbVN0b3Aoc3RyZWFtKSB7XG4gIHN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKHRyYWNrU3RvcClcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIGEgU2Vzc2lvbkRlc2NyaXB0aW9uIG9iamVjdC5cbiAqL1xudmFyIGR1bXBTRFAgPSBmdW5jdGlvbiAoZGVzY3JpcHRpb24pIHtcbiAgaWYgKHR5cGVvZiBkZXNjcmlwdGlvbiA9PT0gJ3VuZGVmaW5lZCcgfHwgZGVzY3JpcHRpb24gPT09IG51bGwpIHtcbiAgICByZXR1cm4gJydcbiAgfVxuXG4gIHJldHVybiAndHlwZTogJyArIGRlc2NyaXB0aW9uLnR5cGUgKyAnXFxyXFxuJyArIGRlc2NyaXB0aW9uLnNkcFxufVxuXG5mdW5jdGlvbiBidWZmZXJpemVDYW5kaWRhdGVzKHBjLCBvbmVycm9yKSB7XG4gIHZhciBjYW5kaWRhdGVzUXVldWUgPSBbXVxuXG4gIHBjLmFkZEV2ZW50TGlzdGVuZXIoJ3NpZ25hbGluZ3N0YXRlY2hhbmdlJywgZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLnNpZ25hbGluZ1N0YXRlID09PSAnc3RhYmxlJykge1xuICAgICAgd2hpbGUgKGNhbmRpZGF0ZXNRdWV1ZS5sZW5ndGgpIHtcbiAgICAgICAgdmFyIGVudHJ5ID0gY2FuZGlkYXRlc1F1ZXVlLnNoaWZ0KClcblxuICAgICAgICB0aGlzLmFkZEljZUNhbmRpZGF0ZShlbnRyeS5jYW5kaWRhdGUsIGVudHJ5LmNhbGxiYWNrLCBlbnRyeS5jYWxsYmFjaylcbiAgICAgIH1cbiAgICB9XG4gIH0pXG5cbiAgcmV0dXJuIGZ1bmN0aW9uIChjYW5kaWRhdGUsIGNhbGxiYWNrKSB7XG4gICAgY2FsbGJhY2sgPSBjYWxsYmFjayB8fCBvbmVycm9yXG5cbiAgICBzd2l0Y2ggKHBjLnNpZ25hbGluZ1N0YXRlKSB7XG4gICAgY2FzZSAnY2xvc2VkJzpcbiAgICAgIGNhbGxiYWNrKG5ldyBFcnJvcignUGVlckNvbm5lY3Rpb24gb2JqZWN0IGlzIGNsb3NlZCcpKVxuICAgICAgYnJlYWtcbiAgICBjYXNlICdzdGFibGUnOlxuICAgICAgaWYgKHBjLnJlbW90ZURlc2NyaXB0aW9uKSB7XG4gICAgICAgIHBjLmFkZEljZUNhbmRpZGF0ZShjYW5kaWRhdGUsIGNhbGxiYWNrLCBjYWxsYmFjaylcbiAgICAgICAgYnJlYWtcbiAgICAgIH1cbiAgICBkZWZhdWx0OlxuICAgICAgY2FuZGlkYXRlc1F1ZXVlLnB1c2goe1xuICAgICAgICBjYW5kaWRhdGU6IGNhbmRpZGF0ZSxcbiAgICAgICAgY2FsbGJhY2s6IGNhbGxiYWNrXG4gICAgICB9KVxuICAgIH1cbiAgfVxufVxuXG4vKiBTaW11bGNhc3QgdXRpbGl0aWVzICovXG5cbmZ1bmN0aW9uIHJlbW92ZUZJREZyb21PZmZlcihzZHApIHtcbiAgdmFyIG4gPSBzZHAuaW5kZXhPZihcImE9c3NyYy1ncm91cDpGSURcIik7XG5cbiAgaWYgKG4gPiAwKSB7XG4gICAgcmV0dXJuIHNkcC5zbGljZSgwLCBuKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gc2RwO1xuICB9XG59XG5cbmZ1bmN0aW9uIGdldFNpbXVsY2FzdEluZm8odmlkZW9TdHJlYW0pIHtcbiAgdmFyIHZpZGVvVHJhY2tzID0gdmlkZW9TdHJlYW0uZ2V0VmlkZW9UcmFja3MoKTtcbiAgaWYgKCF2aWRlb1RyYWNrcy5sZW5ndGgpIHtcbiAgICBsb2dnZXIud2FybignTm8gdmlkZW8gdHJhY2tzIGF2YWlsYWJsZSBpbiB0aGUgdmlkZW8gc3RyZWFtJylcbiAgICByZXR1cm4gJydcbiAgfVxuICB2YXIgbGluZXMgPSBbXG4gICAgJ2E9eC1nb29nbGUtZmxhZzpjb25mZXJlbmNlJyxcbiAgICAnYT1zc3JjLWdyb3VwOlNJTSAxIDIgMycsXG4gICAgJ2E9c3NyYzoxIGNuYW1lOmxvY2FsVmlkZW8nLFxuICAgICdhPXNzcmM6MSBtc2lkOicgKyB2aWRlb1N0cmVhbS5pZCArICcgJyArIHZpZGVvVHJhY2tzWzBdLmlkLFxuICAgICdhPXNzcmM6MSBtc2xhYmVsOicgKyB2aWRlb1N0cmVhbS5pZCxcbiAgICAnYT1zc3JjOjEgbGFiZWw6JyArIHZpZGVvVHJhY2tzWzBdLmlkLFxuICAgICdhPXNzcmM6MiBjbmFtZTpsb2NhbFZpZGVvJyxcbiAgICAnYT1zc3JjOjIgbXNpZDonICsgdmlkZW9TdHJlYW0uaWQgKyAnICcgKyB2aWRlb1RyYWNrc1swXS5pZCxcbiAgICAnYT1zc3JjOjIgbXNsYWJlbDonICsgdmlkZW9TdHJlYW0uaWQsXG4gICAgJ2E9c3NyYzoyIGxhYmVsOicgKyB2aWRlb1RyYWNrc1swXS5pZCxcbiAgICAnYT1zc3JjOjMgY25hbWU6bG9jYWxWaWRlbycsXG4gICAgJ2E9c3NyYzozIG1zaWQ6JyArIHZpZGVvU3RyZWFtLmlkICsgJyAnICsgdmlkZW9UcmFja3NbMF0uaWQsXG4gICAgJ2E9c3NyYzozIG1zbGFiZWw6JyArIHZpZGVvU3RyZWFtLmlkLFxuICAgICdhPXNzcmM6MyBsYWJlbDonICsgdmlkZW9UcmFja3NbMF0uaWRcbiAgXTtcblxuICBsaW5lcy5wdXNoKCcnKTtcblxuICByZXR1cm4gbGluZXMuam9pbignXFxuJyk7XG59XG5cbi8qKlxuICogV3JhcHBlciBvYmplY3Qgb2YgYW4gUlRDUGVlckNvbm5lY3Rpb24uIFRoaXMgb2JqZWN0IGlzIGFpbWVkIHRvIHNpbXBsaWZ5IHRoZVxuICogZGV2ZWxvcG1lbnQgb2YgV2ViUlRDLWJhc2VkIGFwcGxpY2F0aW9ucy5cbiAqXG4gKiBAY29uc3RydWN0b3IgbW9kdWxlOmt1cmVudG9VdGlscy5XZWJSdGNQZWVyXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG1vZGUgTW9kZSBpbiB3aGljaCB0aGUgUGVlckNvbm5lY3Rpb24gd2lsbCBiZSBjb25maWd1cmVkLlxuICogIFZhbGlkIHZhbHVlcyBhcmU6ICdyZWN2JywgJ3NlbmQnLCBhbmQgJ3NlbmRSZWN2J1xuICogQHBhcmFtIGxvY2FsVmlkZW8gVmlkZW8gdGFnIGZvciB0aGUgbG9jYWwgc3RyZWFtXG4gKiBAcGFyYW0gcmVtb3RlVmlkZW8gVmlkZW8gdGFnIGZvciB0aGUgcmVtb3RlIHN0cmVhbVxuICogQHBhcmFtIHtNZWRpYVN0cmVhbX0gdmlkZW9TdHJlYW0gU3RyZWFtIHRvIGJlIHVzZWQgYXMgcHJpbWFyeSBzb3VyY2VcbiAqICAodHlwaWNhbGx5IHZpZGVvIGFuZCBhdWRpbywgb3Igb25seSB2aWRlbyBpZiBjb21iaW5lZCB3aXRoIGF1ZGlvU3RyZWFtKSBmb3JcbiAqICBsb2NhbFZpZGVvIGFuZCB0byBiZSBhZGRlZCBhcyBzdHJlYW0gdG8gdGhlIFJUQ1BlZXJDb25uZWN0aW9uXG4gKiBAcGFyYW0ge01lZGlhU3RyZWFtfSBhdWRpb1N0cmVhbSBTdHJlYW0gdG8gYmUgdXNlZCBhcyBzZWNvbmQgc291cmNlXG4gKiAgKHR5cGljYWxseSBmb3IgYXVkaW8pIGZvciBsb2NhbFZpZGVvIGFuZCB0byBiZSBhZGRlZCBhcyBzdHJlYW0gdG8gdGhlXG4gKiAgUlRDUGVlckNvbm5lY3Rpb25cbiAqL1xuZnVuY3Rpb24gV2ViUnRjUGVlcihtb2RlLCBvcHRpb25zLCBjYWxsYmFjaykge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgV2ViUnRjUGVlcikpIHtcbiAgICByZXR1cm4gbmV3IFdlYlJ0Y1BlZXIobW9kZSwgb3B0aW9ucywgY2FsbGJhY2spXG4gIH1cblxuICBXZWJSdGNQZWVyLnN1cGVyXy5jYWxsKHRoaXMpXG5cbiAgaWYgKG9wdGlvbnMgaW5zdGFuY2VvZiBGdW5jdGlvbikge1xuICAgIGNhbGxiYWNrID0gb3B0aW9uc1xuICAgIG9wdGlvbnMgPSB1bmRlZmluZWRcbiAgfVxuXG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9XG4gIGNhbGxiYWNrID0gKGNhbGxiYWNrIHx8IG5vb3ApLmJpbmQodGhpcylcblxuICB2YXIgc2VsZiA9IHRoaXNcbiAgdmFyIGxvY2FsVmlkZW8gPSBvcHRpb25zLmxvY2FsVmlkZW9cbiAgdmFyIHJlbW90ZVZpZGVvID0gb3B0aW9ucy5yZW1vdGVWaWRlb1xuICB2YXIgdmlkZW9TdHJlYW0gPSBvcHRpb25zLnZpZGVvU3RyZWFtXG4gIHZhciBhdWRpb1N0cmVhbSA9IG9wdGlvbnMuYXVkaW9TdHJlYW1cbiAgdmFyIG1lZGlhQ29uc3RyYWludHMgPSBvcHRpb25zLm1lZGlhQ29uc3RyYWludHNcblxuICB2YXIgY29ubmVjdGlvbkNvbnN0cmFpbnRzID0gb3B0aW9ucy5jb25uZWN0aW9uQ29uc3RyYWludHNcbiAgdmFyIHBjID0gb3B0aW9ucy5wZWVyQ29ubmVjdGlvblxuICB2YXIgc2VuZFNvdXJjZSA9IG9wdGlvbnMuc2VuZFNvdXJjZSB8fCAnd2ViY2FtJ1xuXG4gIHZhciBkYXRhQ2hhbm5lbENvbmZpZyA9IG9wdGlvbnMuZGF0YUNoYW5uZWxDb25maWdcbiAgdmFyIHVzZURhdGFDaGFubmVscyA9IG9wdGlvbnMuZGF0YUNoYW5uZWxzIHx8IGZhbHNlXG4gIHZhciBkYXRhQ2hhbm5lbFxuXG4gIHZhciBndWlkID0gdXVpZC52NCgpXG4gIHZhciBjb25maWd1cmF0aW9uID0gcmVjdXJzaXZlKHtcbiAgICAgIGljZVNlcnZlcnM6IGZyZWVpY2UoKVxuICAgIH0sXG4gICAgb3B0aW9ucy5jb25maWd1cmF0aW9uKVxuXG4gIHZhciBvbmljZWNhbmRpZGF0ZSA9IG9wdGlvbnMub25pY2VjYW5kaWRhdGVcbiAgaWYgKG9uaWNlY2FuZGlkYXRlKSB0aGlzLm9uKCdpY2VjYW5kaWRhdGUnLCBvbmljZWNhbmRpZGF0ZSlcblxuICB2YXIgb25jYW5kaWRhdGVnYXRoZXJpbmdkb25lID0gb3B0aW9ucy5vbmNhbmRpZGF0ZWdhdGhlcmluZ2RvbmVcbiAgaWYgKG9uY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZSkge1xuICAgIHRoaXMub24oJ2NhbmRpZGF0ZWdhdGhlcmluZ2RvbmUnLCBvbmNhbmRpZGF0ZWdhdGhlcmluZ2RvbmUpXG4gIH1cblxuICB2YXIgc2ltdWxjYXN0ID0gb3B0aW9ucy5zaW11bGNhc3RcbiAgdmFyIG11bHRpc3RyZWFtID0gb3B0aW9ucy5tdWx0aXN0cmVhbVxuICB2YXIgaW50ZXJvcCA9IG5ldyBzZHBUcmFuc2xhdG9yLkludGVyb3AoKVxuICB2YXIgY2FuZGlkYXRlc1F1ZXVlT3V0ID0gW11cbiAgdmFyIGNhbmRpZGF0ZWdhdGhlcmluZ2RvbmUgPSBmYWxzZVxuXG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRoaXMsIHtcbiAgICAncGVlckNvbm5lY3Rpb24nOiB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHBjXG4gICAgICB9XG4gICAgfSxcblxuICAgICdpZCc6IHtcbiAgICAgIHZhbHVlOiBvcHRpb25zLmlkIHx8IGd1aWQsXG4gICAgICB3cml0YWJsZTogZmFsc2VcbiAgICB9LFxuXG4gICAgJ3JlbW90ZVZpZGVvJzoge1xuICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiByZW1vdGVWaWRlb1xuICAgICAgfVxuICAgIH0sXG5cbiAgICAnbG9jYWxWaWRlbyc6IHtcbiAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gbG9jYWxWaWRlb1xuICAgICAgfVxuICAgIH0sXG5cbiAgICAnZGF0YUNoYW5uZWwnOiB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGRhdGFDaGFubmVsXG4gICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIgeyhleHRlcm5hbDpJbWFnZURhdGF8dW5kZWZpbmVkKX0gY3VycmVudEZyYW1lXG4gICAgICovXG4gICAgJ2N1cnJlbnRGcmFtZSc6IHtcbiAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBbVG9Eb10gRmluZCBzb2x1dGlvbiB3aGVuIHdlIGhhdmUgYSByZW1vdGUgc3RyZWFtIGJ1dCB3ZSBkaWRuJ3Qgc2V0XG4gICAgICAgIC8vIGEgcmVtb3RlVmlkZW8gdGFnXG4gICAgICAgIGlmICghcmVtb3RlVmlkZW8pIHJldHVybjtcblxuICAgICAgICBpZiAocmVtb3RlVmlkZW8ucmVhZHlTdGF0ZSA8IHJlbW90ZVZpZGVvLkhBVkVfQ1VSUkVOVF9EQVRBKVxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdmlkZW8gc3RyZWFtIGRhdGEgYXZhaWxhYmxlJylcblxuICAgICAgICB2YXIgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJylcbiAgICAgICAgY2FudmFzLndpZHRoID0gcmVtb3RlVmlkZW8udmlkZW9XaWR0aFxuICAgICAgICBjYW52YXMuaGVpZ2h0ID0gcmVtb3RlVmlkZW8udmlkZW9IZWlnaHRcblxuICAgICAgICBjYW52YXMuZ2V0Q29udGV4dCgnMmQnKS5kcmF3SW1hZ2UocmVtb3RlVmlkZW8sIDAsIDApXG5cbiAgICAgICAgcmV0dXJuIGNhbnZhc1xuICAgICAgfVxuICAgIH1cbiAgfSlcblxuICAvLyBJbml0IFBlZXJDb25uZWN0aW9uXG4gIGlmICghcGMpIHtcbiAgICBwYyA9IG5ldyBSVENQZWVyQ29ubmVjdGlvbihjb25maWd1cmF0aW9uKTtcbiAgICBpZiAodXNlRGF0YUNoYW5uZWxzICYmICFkYXRhQ2hhbm5lbCkge1xuICAgICAgdmFyIGRjSWQgPSAnV2ViUnRjUGVlci0nICsgc2VsZi5pZFxuICAgICAgdmFyIGRjT3B0aW9ucyA9IHVuZGVmaW5lZFxuICAgICAgaWYgKGRhdGFDaGFubmVsQ29uZmlnKSB7XG4gICAgICAgIGRjSWQgPSBkYXRhQ2hhbm5lbENvbmZpZy5pZCB8fCBkY0lkXG4gICAgICAgIGRjT3B0aW9ucyA9IGRhdGFDaGFubmVsQ29uZmlnLm9wdGlvbnNcbiAgICAgIH1cbiAgICAgIGRhdGFDaGFubmVsID0gcGMuY3JlYXRlRGF0YUNoYW5uZWwoZGNJZCwgZGNPcHRpb25zKTtcbiAgICAgIGlmIChkYXRhQ2hhbm5lbENvbmZpZykge1xuICAgICAgICBkYXRhQ2hhbm5lbC5vbm9wZW4gPSBkYXRhQ2hhbm5lbENvbmZpZy5vbm9wZW47XG4gICAgICAgIGRhdGFDaGFubmVsLm9uY2xvc2UgPSBkYXRhQ2hhbm5lbENvbmZpZy5vbmNsb3NlO1xuICAgICAgICBkYXRhQ2hhbm5lbC5vbm1lc3NhZ2UgPSBkYXRhQ2hhbm5lbENvbmZpZy5vbm1lc3NhZ2U7XG4gICAgICAgIGRhdGFDaGFubmVsLm9uYnVmZmVyZWRhbW91bnRsb3cgPSBkYXRhQ2hhbm5lbENvbmZpZy5vbmJ1ZmZlcmVkYW1vdW50bG93O1xuICAgICAgICBkYXRhQ2hhbm5lbC5vbmVycm9yID0gZGF0YUNoYW5uZWxDb25maWcub25lcnJvciB8fCBub29wO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHBjLmFkZEV2ZW50TGlzdGVuZXIoJ2ljZWNhbmRpZGF0ZScsIGZ1bmN0aW9uIChldmVudCkge1xuICAgIHZhciBjYW5kaWRhdGUgPSBldmVudC5jYW5kaWRhdGVcblxuICAgIGlmIChFdmVudEVtaXR0ZXIubGlzdGVuZXJDb3VudChzZWxmLCAnaWNlY2FuZGlkYXRlJykgfHxcbiAgICAgIEV2ZW50RW1pdHRlci5saXN0ZW5lckNvdW50KFxuICAgICAgICBzZWxmLCAnY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZScpKSB7XG4gICAgICBpZiAoY2FuZGlkYXRlKSB7XG4gICAgICAgIHZhciBjYW5kXG5cbiAgICAgICAgaWYgKG11bHRpc3RyZWFtICYmIHVzZVBsYW5CKSB7XG4gICAgICAgICAgY2FuZCA9IGludGVyb3AuY2FuZGlkYXRlVG9VbmlmaWVkUGxhbihjYW5kaWRhdGUpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY2FuZCA9IGNhbmRpZGF0ZVxuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5lbWl0KCdpY2VjYW5kaWRhdGUnLCBjYW5kKVxuICAgICAgICBjYW5kaWRhdGVnYXRoZXJpbmdkb25lID0gZmFsc2VcbiAgICAgIH0gZWxzZSBpZiAoIWNhbmRpZGF0ZWdhdGhlcmluZ2RvbmUpIHtcbiAgICAgICAgc2VsZi5lbWl0KCdjYW5kaWRhdGVnYXRoZXJpbmdkb25lJylcbiAgICAgICAgY2FuZGlkYXRlZ2F0aGVyaW5nZG9uZSA9IHRydWVcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKCFjYW5kaWRhdGVnYXRoZXJpbmdkb25lKSB7XG4gICAgICAvLyBOb3QgbGlzdGVuaW5nIHRvICdpY2VjYW5kaWRhdGUnIG9yICdjYW5kaWRhdGVnYXRoZXJpbmdkb25lJyBldmVudHMsIHF1ZXVlXG4gICAgICAvLyB0aGUgY2FuZGlkYXRlIHVudGlsIG9uZSBvZiB0aGVtIGlzIGxpc3RlbmVkXG4gICAgICBjYW5kaWRhdGVzUXVldWVPdXQucHVzaChjYW5kaWRhdGUpXG5cbiAgICAgIGlmICghY2FuZGlkYXRlKSBjYW5kaWRhdGVnYXRoZXJpbmdkb25lID0gdHJ1ZVxuICAgIH1cbiAgfSlcblxuICBwYy5vbnRyYWNrID0gb3B0aW9ucy5vbmFkZHN0cmVhbVxuICBwYy5vbm5lZ290aWF0aW9ubmVlZGVkID0gb3B0aW9ucy5vbm5lZ290aWF0aW9ubmVlZGVkXG4gIHRoaXMub24oJ25ld0xpc3RlbmVyJywgZnVuY3Rpb24gKGV2ZW50LCBsaXN0ZW5lcikge1xuICAgIGlmIChldmVudCA9PT0gJ2ljZWNhbmRpZGF0ZScgfHwgZXZlbnQgPT09ICdjYW5kaWRhdGVnYXRoZXJpbmdkb25lJykge1xuICAgICAgd2hpbGUgKGNhbmRpZGF0ZXNRdWV1ZU91dC5sZW5ndGgpIHtcbiAgICAgICAgdmFyIGNhbmRpZGF0ZSA9IGNhbmRpZGF0ZXNRdWV1ZU91dC5zaGlmdCgpXG5cbiAgICAgICAgaWYgKCFjYW5kaWRhdGUgPT09IChldmVudCA9PT0gJ2NhbmRpZGF0ZWdhdGhlcmluZ2RvbmUnKSkge1xuICAgICAgICAgIGxpc3RlbmVyKGNhbmRpZGF0ZSlcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSlcblxuICB2YXIgYWRkSWNlQ2FuZGlkYXRlID0gYnVmZmVyaXplQ2FuZGlkYXRlcyhwYylcblxuICAvKipcbiAgICogQ2FsbGJhY2sgZnVuY3Rpb24gaW52b2tlZCB3aGVuIGFuIElDRSBjYW5kaWRhdGUgaXMgcmVjZWl2ZWQuIERldmVsb3BlcnMgYXJlXG4gICAqIGV4cGVjdGVkIHRvIGludm9rZSB0aGlzIGZ1bmN0aW9uIGluIG9yZGVyIHRvIGNvbXBsZXRlIHRoZSBTRFAgbmVnb3RpYXRpb24uXG4gICAqXG4gICAqIEBmdW5jdGlvbiBtb2R1bGU6a3VyZW50b1V0aWxzLldlYlJ0Y1BlZXIucHJvdG90eXBlLmFkZEljZUNhbmRpZGF0ZVxuICAgKlxuICAgKiBAcGFyYW0gaWNlQ2FuZGlkYXRlIC0gTGl0ZXJhbCBvYmplY3Qgd2l0aCB0aGUgSUNFIGNhbmRpZGF0ZSBkZXNjcmlwdGlvblxuICAgKiBAcGFyYW0gY2FsbGJhY2sgLSBDYWxsZWQgd2hlbiB0aGUgSUNFIGNhbmRpZGF0ZSBoYXMgYmVlbiBhZGRlZC5cbiAgICovXG4gIHRoaXMuYWRkSWNlQ2FuZGlkYXRlID0gZnVuY3Rpb24gKGljZUNhbmRpZGF0ZSwgY2FsbGJhY2spIHtcbiAgICB2YXIgY2FuZGlkYXRlXG5cbiAgICBpZiAobXVsdGlzdHJlYW0gJiYgdXNlUGxhbkIpIHtcbiAgICAgIGNhbmRpZGF0ZSA9IGludGVyb3AuY2FuZGlkYXRlVG9QbGFuQihpY2VDYW5kaWRhdGUpXG4gICAgfSBlbHNlIHtcbiAgICAgIGNhbmRpZGF0ZSA9IG5ldyBSVENJY2VDYW5kaWRhdGUoaWNlQ2FuZGlkYXRlKVxuICAgIH1cblxuICAgIGxvZ2dlci5kZWJ1ZygnUmVtb3RlIElDRSBjYW5kaWRhdGUgcmVjZWl2ZWQnLCBpY2VDYW5kaWRhdGUpXG4gICAgY2FsbGJhY2sgPSAoY2FsbGJhY2sgfHwgbm9vcCkuYmluZCh0aGlzKVxuICAgIGFkZEljZUNhbmRpZGF0ZShjYW5kaWRhdGUsIGNhbGxiYWNrKVxuICB9XG5cbiAgdGhpcy5nZW5lcmF0ZU9mZmVyID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgY2FsbGJhY2sgPSBjYWxsYmFjay5iaW5kKHRoaXMpXG5cbiAgICB2YXIgb2ZmZXJBdWRpbyA9IHRydWVcbiAgICB2YXIgb2ZmZXJWaWRlbyA9IHRydWVcbiAgICAvLyBDb25zdHJhaW50cyBtdXN0IGhhdmUgYm90aCBibG9ja3NcbiAgICBpZiAobWVkaWFDb25zdHJhaW50cykge1xuICAgICAgb2ZmZXJBdWRpbyA9ICh0eXBlb2YgbWVkaWFDb25zdHJhaW50cy5hdWRpbyA9PT0gJ2Jvb2xlYW4nKSA/XG4gICAgICAgIG1lZGlhQ29uc3RyYWludHMuYXVkaW8gOiB0cnVlXG4gICAgICBvZmZlclZpZGVvID0gKHR5cGVvZiBtZWRpYUNvbnN0cmFpbnRzLnZpZGVvID09PSAnYm9vbGVhbicpID9cbiAgICAgICAgbWVkaWFDb25zdHJhaW50cy52aWRlbyA6IHRydWVcbiAgICB9XG5cbiAgICB2YXIgYnJvd3NlckRlcGVuZGFudENvbnN0cmFpbnRzID0ge1xuICAgICAgb2ZmZXJUb1JlY2VpdmVBdWRpbzogKG1vZGUgIT09ICdzZW5kb25seScgJiYgb2ZmZXJBdWRpbyksXG4gICAgICBvZmZlclRvUmVjZWl2ZVZpZGVvOiAobW9kZSAhPT0gJ3NlbmRvbmx5JyAmJiBvZmZlclZpZGVvKVxuICAgIH1cblxuICAgIC8vRklYTUU6IGNsYXJpZnkgcG9zc2libGUgY29uc3RyYWludHMgcGFzc2VkIHRvIGNyZWF0ZU9mZmVyKClcbiAgICAvKnZhciBjb25zdHJhaW50cyA9IHJlY3Vyc2l2ZShicm93c2VyRGVwZW5kYW50Q29uc3RyYWludHMsXG4gICAgICBjb25uZWN0aW9uQ29uc3RyYWludHMpKi9cblxuICAgIHZhciBjb25zdHJhaW50cyA9IGJyb3dzZXJEZXBlbmRhbnRDb25zdHJhaW50cztcblxuICAgIGxvZ2dlci5pbmZvKCdjb25zdHJhaW50czogJyArIEpTT04uc3RyaW5naWZ5KGNvbnN0cmFpbnRzKSlcblxuICAgIHBjLmNyZWF0ZU9mZmVyKGNvbnN0cmFpbnRzKS50aGVuKGZ1bmN0aW9uIChvZmZlcikge1xuICAgICAgbG9nZ2VyLmluZm8oJ0NyZWF0ZWQgU0RQIG9mZmVyJylcbiAgICAgIG9mZmVyID0gbWFuZ2xlU2RwVG9BZGRTaW11bGNhc3Qob2ZmZXIpXG4gICAgICByZXR1cm4gcGMuc2V0TG9jYWxEZXNjcmlwdGlvbihvZmZlcilcbiAgICB9KS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciBsb2NhbERlc2NyaXB0aW9uID0gcGMubG9jYWxEZXNjcmlwdGlvblxuICAgICAgbG9nZ2VyLmluZm8oJ0xvY2FsIGRlc2NyaXB0aW9uIHNldCcsIGxvY2FsRGVzY3JpcHRpb24uc2RwKVxuICAgICAgaWYgKG11bHRpc3RyZWFtICYmIHVzZVBsYW5CKSB7XG4gICAgICAgIGxvY2FsRGVzY3JpcHRpb24gPSBpbnRlcm9wLnRvVW5pZmllZFBsYW4obG9jYWxEZXNjcmlwdGlvbilcbiAgICAgICAgbG9nZ2VyLmluZm8oJ29mZmVyOjpvcmlnUGxhbkItPlVuaWZpZWRQbGFuJywgZHVtcFNEUChcbiAgICAgICAgICBsb2NhbERlc2NyaXB0aW9uKSlcbiAgICAgIH1cbiAgICAgIGNhbGxiYWNrKG51bGwsIGxvY2FsRGVzY3JpcHRpb24uc2RwLCBzZWxmLnByb2Nlc3NBbnN3ZXIuYmluZChcbiAgICAgICAgc2VsZikpXG4gICAgfSkuY2F0Y2goY2FsbGJhY2spXG4gIH1cblxuICB0aGlzLmdldExvY2FsU2Vzc2lvbkRlc2NyaXB0b3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHBjLmxvY2FsRGVzY3JpcHRpb25cbiAgfVxuXG4gIHRoaXMuZ2V0UmVtb3RlU2Vzc2lvbkRlc2NyaXB0b3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHBjLnJlbW90ZURlc2NyaXB0aW9uXG4gIH1cblxuICBmdW5jdGlvbiBzZXRSZW1vdGVWaWRlbygpIHtcbiAgICBpZiAocmVtb3RlVmlkZW8pIHtcbiAgICAgIHZhciBzdHJlYW0gPSBwYy5nZXRSZW1vdGVTdHJlYW1zKClbMF1cbiAgICAgIHZhciB1cmwgPSBzdHJlYW0gPyBVUkwuY3JlYXRlT2JqZWN0VVJMKHN0cmVhbSkgOiAnJ1xuXG4gICAgICByZW1vdGVWaWRlby5wYXVzZSgpXG4gICAgICByZW1vdGVWaWRlby5zcmMgPSB1cmxcbiAgICAgIHJlbW90ZVZpZGVvLmxvYWQoKVxuXG4gICAgICBsb2dnZXIuaW5mbygnUmVtb3RlIFVSTDonLCB1cmwpXG4gICAgfVxuICB9XG5cbiAgdGhpcy5zaG93TG9jYWxWaWRlbyA9IGZ1bmN0aW9uICgpIHtcbiAgICBsb2NhbFZpZGVvLnNyYyA9IFVSTC5jcmVhdGVPYmplY3RVUkwodmlkZW9TdHJlYW0pXG4gICAgbG9jYWxWaWRlby5tdXRlZCA9IHRydWVcbiAgfVxuXG4gIHRoaXMuc2VuZCA9IGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgaWYgKGRhdGFDaGFubmVsICYmIGRhdGFDaGFubmVsLnJlYWR5U3RhdGUgPT09ICdvcGVuJykge1xuICAgICAgZGF0YUNoYW5uZWwuc2VuZChkYXRhKVxuICAgIH0gZWxzZSB7XG4gICAgICBsb2dnZXIud2FybihcbiAgICAgICAgJ1RyeWluZyB0byBzZW5kIGRhdGEgb3ZlciBhIG5vbi1leGlzdGluZyBvciBjbG9zZWQgZGF0YSBjaGFubmVsJylcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2FsbGJhY2sgZnVuY3Rpb24gaW52b2tlZCB3aGVuIGEgU0RQIGFuc3dlciBpcyByZWNlaXZlZC4gRGV2ZWxvcGVycyBhcmVcbiAgICogZXhwZWN0ZWQgdG8gaW52b2tlIHRoaXMgZnVuY3Rpb24gaW4gb3JkZXIgdG8gY29tcGxldGUgdGhlIFNEUCBuZWdvdGlhdGlvbi5cbiAgICpcbiAgICogQGZ1bmN0aW9uIG1vZHVsZTprdXJlbnRvVXRpbHMuV2ViUnRjUGVlci5wcm90b3R5cGUucHJvY2Vzc0Fuc3dlclxuICAgKlxuICAgKiBAcGFyYW0gc2RwQW5zd2VyIC0gRGVzY3JpcHRpb24gb2Ygc2RwQW5zd2VyXG4gICAqIEBwYXJhbSBjYWxsYmFjayAtXG4gICAqICAgICAgICAgICAgSW52b2tlZCBhZnRlciB0aGUgU0RQIGFuc3dlciBpcyBwcm9jZXNzZWQsIG9yIHRoZXJlIGlzIGFuIGVycm9yLlxuICAgKi9cbiAgdGhpcy5wcm9jZXNzQW5zd2VyID0gZnVuY3Rpb24gKHNkcEFuc3dlciwgY2FsbGJhY2spIHtcbiAgICBjYWxsYmFjayA9IChjYWxsYmFjayB8fCBub29wKS5iaW5kKHRoaXMpXG5cbiAgICB2YXIgYW5zd2VyID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICB0eXBlOiAnYW5zd2VyJyxcbiAgICAgIHNkcDogc2RwQW5zd2VyXG4gICAgfSlcblxuICAgIGlmIChtdWx0aXN0cmVhbSAmJiB1c2VQbGFuQikge1xuICAgICAgdmFyIHBsYW5CQW5zd2VyID0gaW50ZXJvcC50b1BsYW5CKGFuc3dlcilcbiAgICAgIGxvZ2dlci5pbmZvKCdhc253ZXI6OnBsYW5CJywgZHVtcFNEUChwbGFuQkFuc3dlcikpXG4gICAgICBhbnN3ZXIgPSBwbGFuQkFuc3dlclxuICAgIH1cblxuICAgIGxvZ2dlci5pbmZvKCdTRFAgYW5zd2VyIHJlY2VpdmVkLCBzZXR0aW5nIHJlbW90ZSBkZXNjcmlwdGlvbicpXG5cbiAgICBpZiAocGMuc2lnbmFsaW5nU3RhdGUgPT09ICdjbG9zZWQnKSB7XG4gICAgICByZXR1cm4gY2FsbGJhY2soJ1BlZXJDb25uZWN0aW9uIGlzIGNsb3NlZCcpXG4gICAgfVxuXG4gICAgcGMuc2V0UmVtb3RlRGVzY3JpcHRpb24oYW5zd2VyLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNldFJlbW90ZVZpZGVvKClcblxuICAgICAgICBjYWxsYmFjaygpXG4gICAgICB9LFxuICAgICAgY2FsbGJhY2spXG4gIH1cblxuICAvKipcbiAgICogQ2FsbGJhY2sgZnVuY3Rpb24gaW52b2tlZCB3aGVuIGEgU0RQIG9mZmVyIGlzIHJlY2VpdmVkLiBEZXZlbG9wZXJzIGFyZVxuICAgKiBleHBlY3RlZCB0byBpbnZva2UgdGhpcyBmdW5jdGlvbiBpbiBvcmRlciB0byBjb21wbGV0ZSB0aGUgU0RQIG5lZ290aWF0aW9uLlxuICAgKlxuICAgKiBAZnVuY3Rpb24gbW9kdWxlOmt1cmVudG9VdGlscy5XZWJSdGNQZWVyLnByb3RvdHlwZS5wcm9jZXNzT2ZmZXJcbiAgICpcbiAgICogQHBhcmFtIHNkcE9mZmVyIC0gRGVzY3JpcHRpb24gb2Ygc2RwT2ZmZXJcbiAgICogQHBhcmFtIGNhbGxiYWNrIC0gQ2FsbGVkIHdoZW4gdGhlIHJlbW90ZSBkZXNjcmlwdGlvbiBoYXMgYmVlbiBzZXRcbiAgICogIHN1Y2Nlc3NmdWxseS5cbiAgICovXG4gIHRoaXMucHJvY2Vzc09mZmVyID0gZnVuY3Rpb24gKHNkcE9mZmVyLCBjYWxsYmFjaykge1xuICAgIGNhbGxiYWNrID0gY2FsbGJhY2suYmluZCh0aGlzKVxuXG4gICAgdmFyIG9mZmVyID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICB0eXBlOiAnb2ZmZXInLFxuICAgICAgc2RwOiBzZHBPZmZlclxuICAgIH0pXG5cbiAgICBpZiAobXVsdGlzdHJlYW0gJiYgdXNlUGxhbkIpIHtcbiAgICAgIHZhciBwbGFuQk9mZmVyID0gaW50ZXJvcC50b1BsYW5CKG9mZmVyKVxuICAgICAgbG9nZ2VyLmluZm8oJ29mZmVyOjpwbGFuQicsIGR1bXBTRFAocGxhbkJPZmZlcikpXG4gICAgICBvZmZlciA9IHBsYW5CT2ZmZXJcbiAgICB9XG5cbiAgICBsb2dnZXIuaW5mbygnU0RQIG9mZmVyIHJlY2VpdmVkLCBzZXR0aW5nIHJlbW90ZSBkZXNjcmlwdGlvbicpXG5cbiAgICBpZiAocGMuc2lnbmFsaW5nU3RhdGUgPT09ICdjbG9zZWQnKSB7XG4gICAgICByZXR1cm4gY2FsbGJhY2soJ1BlZXJDb25uZWN0aW9uIGlzIGNsb3NlZCcpXG4gICAgfVxuXG4gICAgcGMuc2V0UmVtb3RlRGVzY3JpcHRpb24ob2ZmZXIpLnRoZW4oZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIHNldFJlbW90ZVZpZGVvKClcbiAgICB9KS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBwYy5jcmVhdGVBbnN3ZXIoKVxuICAgIH0pLnRoZW4oZnVuY3Rpb24gKGFuc3dlcikge1xuICAgICAgYW5zd2VyID0gbWFuZ2xlU2RwVG9BZGRTaW11bGNhc3QoYW5zd2VyKVxuICAgICAgbG9nZ2VyLmluZm8oJ0NyZWF0ZWQgU0RQIGFuc3dlcicpXG4gICAgICByZXR1cm4gcGMuc2V0TG9jYWxEZXNjcmlwdGlvbihhbnN3ZXIpXG4gICAgfSkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgbG9jYWxEZXNjcmlwdGlvbiA9IHBjLmxvY2FsRGVzY3JpcHRpb25cbiAgICAgIGlmIChtdWx0aXN0cmVhbSAmJiB1c2VQbGFuQikge1xuICAgICAgICBsb2NhbERlc2NyaXB0aW9uID0gaW50ZXJvcC50b1VuaWZpZWRQbGFuKGxvY2FsRGVzY3JpcHRpb24pXG4gICAgICAgIGxvZ2dlci5pbmZvKCdhbnN3ZXI6Om9yaWdQbGFuQi0+VW5pZmllZFBsYW4nLCBkdW1wU0RQKFxuICAgICAgICAgIGxvY2FsRGVzY3JpcHRpb24pKVxuICAgICAgfVxuICAgICAgbG9nZ2VyLmluZm8oJ0xvY2FsIGRlc2NyaXB0aW9uIHNldCcsIGxvY2FsRGVzY3JpcHRpb24uc2RwKVxuICAgICAgY2FsbGJhY2sobnVsbCwgbG9jYWxEZXNjcmlwdGlvbi5zZHApXG4gICAgfSkuY2F0Y2goY2FsbGJhY2spXG4gIH1cblxuICBmdW5jdGlvbiBtYW5nbGVTZHBUb0FkZFNpbXVsY2FzdChhbnN3ZXIpIHtcbiAgICBpZiAoc2ltdWxjYXN0KSB7XG4gICAgICBpZiAoYnJvd3Nlci5uYW1lID09PSAnQ2hyb21lJyB8fCBicm93c2VyLm5hbWUgPT09ICdDaHJvbWl1bScpIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oJ0FkZGluZyBtdWx0aWNhc3QgaW5mbycpXG4gICAgICAgIGFuc3dlciA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgICAgICd0eXBlJzogYW5zd2VyLnR5cGUsXG4gICAgICAgICAgJ3NkcCc6IHJlbW92ZUZJREZyb21PZmZlcihhbnN3ZXIuc2RwKSArIGdldFNpbXVsY2FzdEluZm8oXG4gICAgICAgICAgICB2aWRlb1N0cmVhbSlcbiAgICAgICAgfSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZ2dlci53YXJuKCdTaW11bGNhc3QgaXMgb25seSBhdmFpbGFibGUgaW4gQ2hyb21lIGJyb3dzZXIuJylcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gYW5zd2VyXG4gIH1cblxuICAvKipcbiAgICogVGhpcyBmdW5jdGlvbiBjcmVhdGVzIHRoZSBSVENQZWVyQ29ubmVjdGlvbiBvYmplY3QgdGFraW5nIGludG8gYWNjb3VudCB0aGVcbiAgICogcHJvcGVydGllcyByZWNlaXZlZCBpbiB0aGUgY29uc3RydWN0b3IuIEl0IHN0YXJ0cyB0aGUgU0RQIG5lZ290aWF0aW9uXG4gICAqIHByb2Nlc3M6IGdlbmVyYXRlcyB0aGUgU0RQIG9mZmVyIGFuZCBpbnZva2VzIHRoZSBvbnNkcG9mZmVyIGNhbGxiYWNrLiBUaGlzXG4gICAqIGNhbGxiYWNrIGlzIGV4cGVjdGVkIHRvIHNlbmQgdGhlIFNEUCBvZmZlciwgaW4gb3JkZXIgdG8gb2J0YWluIGFuIFNEUFxuICAgKiBhbnN3ZXIgZnJvbSBhbm90aGVyIHBlZXIuXG4gICAqL1xuICBmdW5jdGlvbiBzdGFydCgpIHtcbiAgICBpZiAocGMuc2lnbmFsaW5nU3RhdGUgPT09ICdjbG9zZWQnKSB7XG4gICAgICBjYWxsYmFjayhcbiAgICAgICAgJ1RoZSBwZWVyIGNvbm5lY3Rpb24gb2JqZWN0IGlzIGluIFwiY2xvc2VkXCIgc3RhdGUuIFRoaXMgaXMgbW9zdCBsaWtlbHkgZHVlIHRvIGFuIGludm9jYXRpb24gb2YgdGhlIGRpc3Bvc2UgbWV0aG9kIGJlZm9yZSBhY2NlcHRpbmcgaW4gdGhlIGRpYWxvZ3VlJ1xuICAgICAgKVxuICAgIH1cblxuICAgIGlmICh2aWRlb1N0cmVhbSAmJiBsb2NhbFZpZGVvKSB7XG4gICAgICBzZWxmLnNob3dMb2NhbFZpZGVvKClcbiAgICB9XG5cbiAgICBpZiAodmlkZW9TdHJlYW0pIHtcbiAgICAgIHBjLmFkZFN0cmVhbSh2aWRlb1N0cmVhbSlcbiAgICB9XG5cbiAgICBpZiAoYXVkaW9TdHJlYW0pIHtcbiAgICAgIHBjLmFkZFN0cmVhbShhdWRpb1N0cmVhbSlcbiAgICB9XG5cbiAgICAvLyBbSGFja10gaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTQ0MzU1OFxuICAgIHZhciBicm93c2VyID0gcGFyc2VyLmdldEJyb3dzZXIoKVxuICAgIGlmIChtb2RlID09PSAnc2VuZG9ubHknICYmXG4gICAgICAoYnJvd3Nlci5uYW1lID09PSAnQ2hyb21lJyB8fCBicm93c2VyLm5hbWUgPT09ICdDaHJvbWl1bScpICYmXG4gICAgICBicm93c2VyLm1ham9yID09PSAzOSkge1xuICAgICAgbW9kZSA9ICdzZW5kcmVjdidcbiAgICB9XG5cbiAgICBjYWxsYmFjaygpXG4gIH1cblxuICBpZiAobW9kZSAhPT0gJ3JlY3Zvbmx5JyAmJiAhdmlkZW9TdHJlYW0gJiYgIWF1ZGlvU3RyZWFtKSB7XG4gICAgZnVuY3Rpb24gZ2V0TWVkaWEoY29uc3RyYWludHMpIHtcbiAgICAgIGlmIChjb25zdHJhaW50cyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNvbnN0cmFpbnRzID0gTUVESUFfQ09OU1RSQUlOVFNcbiAgICAgIH1cblxuICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEoY29uc3RyYWludHMpLnRoZW4oZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICB2aWRlb1N0cmVhbSA9IHN0cmVhbVxuICAgICAgICBzdGFydCgpXG4gICAgICB9KS5jYXRjaChjYWxsYmFjayk7XG4gICAgfVxuICAgIGlmIChzZW5kU291cmNlID09PSAnd2ViY2FtJykge1xuICAgICAgZ2V0TWVkaWEobWVkaWFDb25zdHJhaW50cylcbiAgICB9IGVsc2Uge1xuICAgICAgZ2V0U2NyZWVuQ29uc3RyYWludHMoc2VuZFNvdXJjZSwgZnVuY3Rpb24gKGVycm9yLCBjb25zdHJhaW50c18pIHtcbiAgICAgICAgaWYgKGVycm9yKVxuICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlcnJvcilcblxuICAgICAgICBjb25zdHJhaW50cyA9IFttZWRpYUNvbnN0cmFpbnRzXVxuICAgICAgICBjb25zdHJhaW50cy51bnNoaWZ0KGNvbnN0cmFpbnRzXylcbiAgICAgICAgZ2V0TWVkaWEocmVjdXJzaXZlLmFwcGx5KHVuZGVmaW5lZCwgY29uc3RyYWludHMpKVxuICAgICAgfSwgZ3VpZClcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgc2V0VGltZW91dChzdGFydCwgMClcbiAgfVxuXG4gIHRoaXMub24oJ19kaXNwb3NlJywgZnVuY3Rpb24gKCkge1xuICAgIGlmIChsb2NhbFZpZGVvKSB7XG4gICAgICBsb2NhbFZpZGVvLnBhdXNlKClcbiAgICAgIGxvY2FsVmlkZW8uc3JjID0gJydcbiAgICAgIGxvY2FsVmlkZW8ubG9hZCgpXG4gICAgICAvL1VubXV0ZSBsb2NhbCB2aWRlbyBpbiBjYXNlIHRoZSB2aWRlbyB0YWcgaXMgbGF0ZXIgdXNlZCBmb3IgcmVtb3RlIHZpZGVvXG4gICAgICBsb2NhbFZpZGVvLm11dGVkID0gZmFsc2VcbiAgICB9XG4gICAgaWYgKHJlbW90ZVZpZGVvKSB7XG4gICAgICByZW1vdGVWaWRlby5wYXVzZSgpXG4gICAgICByZW1vdGVWaWRlby5zcmMgPSAnJ1xuICAgICAgcmVtb3RlVmlkZW8ubG9hZCgpXG4gICAgfVxuICAgIHNlbGYucmVtb3ZlQWxsTGlzdGVuZXJzKClcblxuICAgIGlmICh3aW5kb3cuY2FuY2VsQ2hvb3NlRGVza3RvcE1lZGlhICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHdpbmRvdy5jYW5jZWxDaG9vc2VEZXNrdG9wTWVkaWEoZ3VpZClcbiAgICB9XG4gIH0pXG59XG5pbmhlcml0cyhXZWJSdGNQZWVyLCBFdmVudEVtaXR0ZXIpXG5cbmZ1bmN0aW9uIGNyZWF0ZUVuYWJsZURlc2NyaXB0b3IodHlwZSkge1xuICB2YXIgbWV0aG9kID0gJ2dldCcgKyB0eXBlICsgJ1RyYWNrcydcblxuICByZXR1cm4ge1xuICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBbVG9Eb10gU2hvdWxkIHJldHVybiB1bmRlZmluZWQgaWYgbm90IGFsbCB0cmFja3MgaGF2ZSB0aGUgc2FtZSB2YWx1ZT9cblxuICAgICAgaWYgKCF0aGlzLnBlZXJDb25uZWN0aW9uKSByZXR1cm5cblxuICAgICAgdmFyIHN0cmVhbXMgPSB0aGlzLnBlZXJDb25uZWN0aW9uLmdldExvY2FsU3RyZWFtcygpXG4gICAgICBpZiAoIXN0cmVhbXMubGVuZ3RoKSByZXR1cm5cblxuICAgICAgZm9yICh2YXIgaSA9IDAsIHN0cmVhbTsgc3RyZWFtID0gc3RyZWFtc1tpXTsgaSsrKSB7XG4gICAgICAgIHZhciB0cmFja3MgPSBzdHJlYW1bbWV0aG9kXSgpXG4gICAgICAgIGZvciAodmFyIGogPSAwLCB0cmFjazsgdHJhY2sgPSB0cmFja3Nbal07IGorKylcbiAgICAgICAgICBpZiAoIXRyYWNrLmVuYWJsZWQpIHJldHVybiBmYWxzZVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH0sXG4gICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgIGZ1bmN0aW9uIHRyYWNrU2V0RW5hYmxlKHRyYWNrKSB7XG4gICAgICAgIHRyYWNrLmVuYWJsZWQgPSB2YWx1ZVxuICAgICAgfVxuXG4gICAgICB0aGlzLnBlZXJDb25uZWN0aW9uLmdldExvY2FsU3RyZWFtcygpLmZvckVhY2goZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICBzdHJlYW1bbWV0aG9kXSgpLmZvckVhY2godHJhY2tTZXRFbmFibGUpXG4gICAgICB9KVxuICAgIH1cbiAgfVxufVxuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhXZWJSdGNQZWVyLnByb3RvdHlwZSwge1xuICAnZW5hYmxlZCc6IHtcbiAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgcmV0dXJuIHRoaXMuYXVkaW9FbmFibGVkICYmIHRoaXMudmlkZW9FbmFibGVkXG4gICAgfSxcbiAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgdGhpcy5hdWRpb0VuYWJsZWQgPSB0aGlzLnZpZGVvRW5hYmxlZCA9IHZhbHVlXG4gICAgfVxuICB9LFxuICAnYXVkaW9FbmFibGVkJzogY3JlYXRlRW5hYmxlRGVzY3JpcHRvcignQXVkaW8nKSxcbiAgJ3ZpZGVvRW5hYmxlZCc6IGNyZWF0ZUVuYWJsZURlc2NyaXB0b3IoJ1ZpZGVvJylcbn0pXG5cbldlYlJ0Y1BlZXIucHJvdG90eXBlLmdldExvY2FsU3RyZWFtID0gZnVuY3Rpb24gKGluZGV4KSB7XG4gIGlmICh0aGlzLnBlZXJDb25uZWN0aW9uKSB7XG4gICAgcmV0dXJuIHRoaXMucGVlckNvbm5lY3Rpb24uZ2V0TG9jYWxTdHJlYW1zKClbaW5kZXggfHwgMF1cbiAgfVxufVxuXG5XZWJSdGNQZWVyLnByb3RvdHlwZS5nZXRSZW1vdGVTdHJlYW0gPSBmdW5jdGlvbiAoaW5kZXgpIHtcbiAgaWYgKHRoaXMucGVlckNvbm5lY3Rpb24pIHtcbiAgICByZXR1cm4gdGhpcy5wZWVyQ29ubmVjdGlvbi5nZXRSZW1vdGVTdHJlYW1zKClbaW5kZXggfHwgMF1cbiAgfVxufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBUaGlzIG1ldGhvZCBmcmVlcyB0aGUgcmVzb3VyY2VzIHVzZWQgYnkgV2ViUnRjUGVlci5cbiAqXG4gKiBAZnVuY3Rpb24gbW9kdWxlOmt1cmVudG9VdGlscy5XZWJSdGNQZWVyLnByb3RvdHlwZS5kaXNwb3NlXG4gKi9cbldlYlJ0Y1BlZXIucHJvdG90eXBlLmRpc3Bvc2UgPSBmdW5jdGlvbiAoKSB7XG4gIGxvZ2dlci5pbmZvKCdEaXNwb3NpbmcgV2ViUnRjUGVlcicpXG5cbiAgdmFyIHBjID0gdGhpcy5wZWVyQ29ubmVjdGlvblxuICB2YXIgZGMgPSB0aGlzLmRhdGFDaGFubmVsXG4gIHRyeSB7XG4gICAgaWYgKGRjKSB7XG4gICAgICBpZiAoZGMuc2lnbmFsaW5nU3RhdGUgPT09ICdjbG9zZWQnKSByZXR1cm5cblxuICAgICAgZGMuY2xvc2UoKVxuICAgIH1cblxuICAgIGlmIChwYykge1xuICAgICAgaWYgKHBjLnNpZ25hbGluZ1N0YXRlID09PSAnY2xvc2VkJykgcmV0dXJuXG5cbiAgICAgIHBjLmdldExvY2FsU3RyZWFtcygpLmZvckVhY2goc3RyZWFtU3RvcClcblxuICAgICAgLy8gRklYTUUgVGhpcyBpcyBub3QgeWV0IGltcGxlbWVudGVkIGluIGZpcmVmb3hcbiAgICAgIC8vIGlmKHZpZGVvU3RyZWFtKSBwYy5yZW1vdmVTdHJlYW0odmlkZW9TdHJlYW0pO1xuICAgICAgLy8gaWYoYXVkaW9TdHJlYW0pIHBjLnJlbW92ZVN0cmVhbShhdWRpb1N0cmVhbSk7XG5cbiAgICAgIHBjLmNsb3NlKClcbiAgICB9XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci53YXJuKCdFeGNlcHRpb24gZGlzcG9zaW5nIHdlYnJ0YyBwZWVyICcgKyBlcnIpXG4gIH1cblxuICB0aGlzLmVtaXQoJ19kaXNwb3NlJylcbn1cblxuLy9cbi8vIFNwZWNpYWxpemVkIGNoaWxkIGNsYXNzZXNcbi8vXG5cbmZ1bmN0aW9uIFdlYlJ0Y1BlZXJSZWN2b25seShvcHRpb25zLCBjYWxsYmFjaykge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgV2ViUnRjUGVlclJlY3Zvbmx5KSkge1xuICAgIHJldHVybiBuZXcgV2ViUnRjUGVlclJlY3Zvbmx5KG9wdGlvbnMsIGNhbGxiYWNrKVxuICB9XG5cbiAgV2ViUnRjUGVlclJlY3Zvbmx5LnN1cGVyXy5jYWxsKHRoaXMsICdyZWN2b25seScsIG9wdGlvbnMsIGNhbGxiYWNrKVxufVxuaW5oZXJpdHMoV2ViUnRjUGVlclJlY3Zvbmx5LCBXZWJSdGNQZWVyKVxuXG5mdW5jdGlvbiBXZWJSdGNQZWVyU2VuZG9ubHkob3B0aW9ucywgY2FsbGJhY2spIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFdlYlJ0Y1BlZXJTZW5kb25seSkpIHtcbiAgICByZXR1cm4gbmV3IFdlYlJ0Y1BlZXJTZW5kb25seShvcHRpb25zLCBjYWxsYmFjaylcbiAgfVxuXG4gIFdlYlJ0Y1BlZXJTZW5kb25seS5zdXBlcl8uY2FsbCh0aGlzLCAnc2VuZG9ubHknLCBvcHRpb25zLCBjYWxsYmFjaylcbn1cbmluaGVyaXRzKFdlYlJ0Y1BlZXJTZW5kb25seSwgV2ViUnRjUGVlcilcblxuZnVuY3Rpb24gV2ViUnRjUGVlclNlbmRyZWN2KG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBXZWJSdGNQZWVyU2VuZHJlY3YpKSB7XG4gICAgcmV0dXJuIG5ldyBXZWJSdGNQZWVyU2VuZHJlY3Yob3B0aW9ucywgY2FsbGJhY2spXG4gIH1cblxuICBXZWJSdGNQZWVyU2VuZHJlY3Yuc3VwZXJfLmNhbGwodGhpcywgJ3NlbmRyZWN2Jywgb3B0aW9ucywgY2FsbGJhY2spXG59XG5pbmhlcml0cyhXZWJSdGNQZWVyU2VuZHJlY3YsIFdlYlJ0Y1BlZXIpXG5cbmZ1bmN0aW9uIGhhcmtVdGlscyhzdHJlYW0sIG9wdGlvbnMpIHtcbiAgcmV0dXJuIGhhcmsoc3RyZWFtLCBvcHRpb25zKTtcbn1cblxuZXhwb3J0cy5idWZmZXJpemVDYW5kaWRhdGVzID0gYnVmZmVyaXplQ2FuZGlkYXRlc1xuXG5leHBvcnRzLldlYlJ0Y1BlZXJSZWN2b25seSA9IFdlYlJ0Y1BlZXJSZWN2b25seVxuZXhwb3J0cy5XZWJSdGNQZWVyU2VuZG9ubHkgPSBXZWJSdGNQZWVyU2VuZG9ubHlcbmV4cG9ydHMuV2ViUnRjUGVlclNlbmRyZWN2ID0gV2ViUnRjUGVlclNlbmRyZWN2XG5leHBvcnRzLmhhcmsgPSBoYXJrVXRpbHNcbiIsIi8qXG4gKiAoQykgQ29weXJpZ2h0IDIwMTQgS3VyZW50byAoaHR0cDovL2t1cmVudG8ub3JnLylcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICpcbiAqL1xuXG4vKipcbiAqIFRoaXMgbW9kdWxlIGNvbnRhaW5zIGEgc2V0IG9mIHJldXNhYmxlIGNvbXBvbmVudHMgdGhhdCBoYXZlIGJlZW4gZm91bmQgdXNlZnVsXG4gKiBkdXJpbmcgdGhlIGRldmVsb3BtZW50IG9mIHRoZSBXZWJSVEMgYXBwbGljYXRpb25zIHdpdGggS3VyZW50by5cbiAqIFxuICogQG1vZHVsZSBrdXJlbnRvVXRpbHNcbiAqIFxuICogQGNvcHlyaWdodCAyMDE0IEt1cmVudG8gKGh0dHA6Ly9rdXJlbnRvLm9yZy8pXG4gKiBAbGljZW5zZSBBTHYyXG4gKi9cblxudmFyIFdlYlJ0Y1BlZXIgPSByZXF1aXJlKCcuL1dlYlJ0Y1BlZXInKTtcblxuZXhwb3J0cy5XZWJSdGNQZWVyID0gV2ViUnRjUGVlcjtcbiIsIi8qIVxyXG4gKiBAbmFtZSBKYXZhU2NyaXB0L05vZGVKUyBNZXJnZSB2MS4yLjBcclxuICogQGF1dGhvciB5ZWlrb3NcclxuICogQHJlcG9zaXRvcnkgaHR0cHM6Ly9naXRodWIuY29tL3llaWtvcy9qcy5tZXJnZVxyXG5cclxuICogQ29weXJpZ2h0IDIwMTQgeWVpa29zIC0gTUlUIGxpY2Vuc2VcclxuICogaHR0cHM6Ly9yYXcuZ2l0aHViLmNvbS95ZWlrb3MvanMubWVyZ2UvbWFzdGVyL0xJQ0VOU0VcclxuICovXHJcblxyXG47KGZ1bmN0aW9uKGlzTm9kZSkge1xyXG5cclxuXHQvKipcclxuXHQgKiBNZXJnZSBvbmUgb3IgbW9yZSBvYmplY3RzIFxyXG5cdCAqIEBwYXJhbSBib29sPyBjbG9uZVxyXG5cdCAqIEBwYXJhbSBtaXhlZCwuLi4gYXJndW1lbnRzXHJcblx0ICogQHJldHVybiBvYmplY3RcclxuXHQgKi9cclxuXHJcblx0dmFyIFB1YmxpYyA9IGZ1bmN0aW9uKGNsb25lKSB7XHJcblxyXG5cdFx0cmV0dXJuIG1lcmdlKGNsb25lID09PSB0cnVlLCBmYWxzZSwgYXJndW1lbnRzKTtcclxuXHJcblx0fSwgcHVibGljTmFtZSA9ICdtZXJnZSc7XHJcblxyXG5cdC8qKlxyXG5cdCAqIE1lcmdlIHR3byBvciBtb3JlIG9iamVjdHMgcmVjdXJzaXZlbHkgXHJcblx0ICogQHBhcmFtIGJvb2w/IGNsb25lXHJcblx0ICogQHBhcmFtIG1peGVkLC4uLiBhcmd1bWVudHNcclxuXHQgKiBAcmV0dXJuIG9iamVjdFxyXG5cdCAqL1xyXG5cclxuXHRQdWJsaWMucmVjdXJzaXZlID0gZnVuY3Rpb24oY2xvbmUpIHtcclxuXHJcblx0XHRyZXR1cm4gbWVyZ2UoY2xvbmUgPT09IHRydWUsIHRydWUsIGFyZ3VtZW50cyk7XHJcblxyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIENsb25lIHRoZSBpbnB1dCByZW1vdmluZyBhbnkgcmVmZXJlbmNlXHJcblx0ICogQHBhcmFtIG1peGVkIGlucHV0XHJcblx0ICogQHJldHVybiBtaXhlZFxyXG5cdCAqL1xyXG5cclxuXHRQdWJsaWMuY2xvbmUgPSBmdW5jdGlvbihpbnB1dCkge1xyXG5cclxuXHRcdHZhciBvdXRwdXQgPSBpbnB1dCxcclxuXHRcdFx0dHlwZSA9IHR5cGVPZihpbnB1dCksXHJcblx0XHRcdGluZGV4LCBzaXplO1xyXG5cclxuXHRcdGlmICh0eXBlID09PSAnYXJyYXknKSB7XHJcblxyXG5cdFx0XHRvdXRwdXQgPSBbXTtcclxuXHRcdFx0c2l6ZSA9IGlucHV0Lmxlbmd0aDtcclxuXHJcblx0XHRcdGZvciAoaW5kZXg9MDtpbmRleDxzaXplOysraW5kZXgpXHJcblxyXG5cdFx0XHRcdG91dHB1dFtpbmRleF0gPSBQdWJsaWMuY2xvbmUoaW5wdXRbaW5kZXhdKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKHR5cGUgPT09ICdvYmplY3QnKSB7XHJcblxyXG5cdFx0XHRvdXRwdXQgPSB7fTtcclxuXHJcblx0XHRcdGZvciAoaW5kZXggaW4gaW5wdXQpXHJcblxyXG5cdFx0XHRcdG91dHB1dFtpbmRleF0gPSBQdWJsaWMuY2xvbmUoaW5wdXRbaW5kZXhdKTtcclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG91dHB1dDtcclxuXHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogTWVyZ2UgdHdvIG9iamVjdHMgcmVjdXJzaXZlbHlcclxuXHQgKiBAcGFyYW0gbWl4ZWQgaW5wdXRcclxuXHQgKiBAcGFyYW0gbWl4ZWQgZXh0ZW5kXHJcblx0ICogQHJldHVybiBtaXhlZFxyXG5cdCAqL1xyXG5cclxuXHRmdW5jdGlvbiBtZXJnZV9yZWN1cnNpdmUoYmFzZSwgZXh0ZW5kKSB7XHJcblxyXG5cdFx0aWYgKHR5cGVPZihiYXNlKSAhPT0gJ29iamVjdCcpXHJcblxyXG5cdFx0XHRyZXR1cm4gZXh0ZW5kO1xyXG5cclxuXHRcdGZvciAodmFyIGtleSBpbiBleHRlbmQpIHtcclxuXHJcblx0XHRcdGlmICh0eXBlT2YoYmFzZVtrZXldKSA9PT0gJ29iamVjdCcgJiYgdHlwZU9mKGV4dGVuZFtrZXldKSA9PT0gJ29iamVjdCcpIHtcclxuXHJcblx0XHRcdFx0YmFzZVtrZXldID0gbWVyZ2VfcmVjdXJzaXZlKGJhc2Vba2V5XSwgZXh0ZW5kW2tleV0pO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHJcblx0XHRcdFx0YmFzZVtrZXldID0gZXh0ZW5kW2tleV07XHJcblxyXG5cdFx0XHR9XHJcblxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBiYXNlO1xyXG5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIE1lcmdlIHR3byBvciBtb3JlIG9iamVjdHNcclxuXHQgKiBAcGFyYW0gYm9vbCBjbG9uZVxyXG5cdCAqIEBwYXJhbSBib29sIHJlY3Vyc2l2ZVxyXG5cdCAqIEBwYXJhbSBhcnJheSBhcmd2XHJcblx0ICogQHJldHVybiBvYmplY3RcclxuXHQgKi9cclxuXHJcblx0ZnVuY3Rpb24gbWVyZ2UoY2xvbmUsIHJlY3Vyc2l2ZSwgYXJndikge1xyXG5cclxuXHRcdHZhciByZXN1bHQgPSBhcmd2WzBdLFxyXG5cdFx0XHRzaXplID0gYXJndi5sZW5ndGg7XHJcblxyXG5cdFx0aWYgKGNsb25lIHx8IHR5cGVPZihyZXN1bHQpICE9PSAnb2JqZWN0JylcclxuXHJcblx0XHRcdHJlc3VsdCA9IHt9O1xyXG5cclxuXHRcdGZvciAodmFyIGluZGV4PTA7aW5kZXg8c2l6ZTsrK2luZGV4KSB7XHJcblxyXG5cdFx0XHR2YXIgaXRlbSA9IGFyZ3ZbaW5kZXhdLFxyXG5cclxuXHRcdFx0XHR0eXBlID0gdHlwZU9mKGl0ZW0pO1xyXG5cclxuXHRcdFx0aWYgKHR5cGUgIT09ICdvYmplY3QnKSBjb250aW51ZTtcclxuXHJcblx0XHRcdGZvciAodmFyIGtleSBpbiBpdGVtKSB7XHJcblxyXG5cdFx0XHRcdHZhciBzaXRlbSA9IGNsb25lID8gUHVibGljLmNsb25lKGl0ZW1ba2V5XSkgOiBpdGVtW2tleV07XHJcblxyXG5cdFx0XHRcdGlmIChyZWN1cnNpdmUpIHtcclxuXHJcblx0XHRcdFx0XHRyZXN1bHRba2V5XSA9IG1lcmdlX3JlY3Vyc2l2ZShyZXN1bHRba2V5XSwgc2l0ZW0pO1xyXG5cclxuXHRcdFx0XHR9IGVsc2Uge1xyXG5cclxuXHRcdFx0XHRcdHJlc3VsdFtrZXldID0gc2l0ZW07XHJcblxyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdH1cclxuXHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHJlc3VsdDtcclxuXHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBHZXQgdHlwZSBvZiB2YXJpYWJsZVxyXG5cdCAqIEBwYXJhbSBtaXhlZCBpbnB1dFxyXG5cdCAqIEByZXR1cm4gc3RyaW5nXHJcblx0ICpcclxuXHQgKiBAc2VlIGh0dHA6Ly9qc3BlcmYuY29tL3R5cGVvZnZhclxyXG5cdCAqL1xyXG5cclxuXHRmdW5jdGlvbiB0eXBlT2YoaW5wdXQpIHtcclxuXHJcblx0XHRyZXR1cm4gKHt9KS50b1N0cmluZy5jYWxsKGlucHV0KS5zbGljZSg4LCAtMSkudG9Mb3dlckNhc2UoKTtcclxuXHJcblx0fVxyXG5cclxuXHRpZiAoaXNOb2RlKSB7XHJcblxyXG5cdFx0bW9kdWxlLmV4cG9ydHMgPSBQdWJsaWM7XHJcblxyXG5cdH0gZWxzZSB7XHJcblxyXG5cdFx0d2luZG93W3B1YmxpY05hbWVdID0gUHVibGljO1xyXG5cclxuXHR9XHJcblxyXG59KSh0eXBlb2YgbW9kdWxlID09PSAnb2JqZWN0JyAmJiBtb2R1bGUgJiYgdHlwZW9mIG1vZHVsZS5leHBvcnRzID09PSAnb2JqZWN0JyAmJiBtb2R1bGUuZXhwb3J0cyk7IiwiLyoqXG4gKiBIZWxwZXJzLlxuICovXG5cbnZhciBzID0gMTAwMDtcbnZhciBtID0gcyAqIDYwO1xudmFyIGggPSBtICogNjA7XG52YXIgZCA9IGggKiAyNDtcbnZhciB5ID0gZCAqIDM2NS4yNTtcblxuLyoqXG4gKiBQYXJzZSBvciBmb3JtYXQgdGhlIGdpdmVuIGB2YWxgLlxuICpcbiAqIE9wdGlvbnM6XG4gKlxuICogIC0gYGxvbmdgIHZlcmJvc2UgZm9ybWF0dGluZyBbZmFsc2VdXG4gKlxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfSB2YWxcbiAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0aW9uc11cbiAqIEB0aHJvd3Mge0Vycm9yfSB0aHJvdyBhbiBlcnJvciBpZiB2YWwgaXMgbm90IGEgbm9uLWVtcHR5IHN0cmluZyBvciBhIG51bWJlclxuICogQHJldHVybiB7U3RyaW5nfE51bWJlcn1cbiAqIEBhcGkgcHVibGljXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbih2YWwsIG9wdGlvbnMpIHtcbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gIHZhciB0eXBlID0gdHlwZW9mIHZhbDtcbiAgaWYgKHR5cGUgPT09ICdzdHJpbmcnICYmIHZhbC5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIHBhcnNlKHZhbCk7XG4gIH0gZWxzZSBpZiAodHlwZSA9PT0gJ251bWJlcicgJiYgaXNOYU4odmFsKSA9PT0gZmFsc2UpIHtcbiAgICByZXR1cm4gb3B0aW9ucy5sb25nID8gZm10TG9uZyh2YWwpIDogZm10U2hvcnQodmFsKTtcbiAgfVxuICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgJ3ZhbCBpcyBub3QgYSBub24tZW1wdHkgc3RyaW5nIG9yIGEgdmFsaWQgbnVtYmVyLiB2YWw9JyArXG4gICAgICBKU09OLnN0cmluZ2lmeSh2YWwpXG4gICk7XG59O1xuXG4vKipcbiAqIFBhcnNlIHRoZSBnaXZlbiBgc3RyYCBhbmQgcmV0dXJuIG1pbGxpc2Vjb25kcy5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gc3RyXG4gKiBAcmV0dXJuIHtOdW1iZXJ9XG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuXG5mdW5jdGlvbiBwYXJzZShzdHIpIHtcbiAgc3RyID0gU3RyaW5nKHN0cik7XG4gIGlmIChzdHIubGVuZ3RoID4gMTAwKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBtYXRjaCA9IC9eKCg/OlxcZCspP1xcLj9cXGQrKSAqKG1pbGxpc2Vjb25kcz98bXNlY3M/fG1zfHNlY29uZHM/fHNlY3M/fHN8bWludXRlcz98bWlucz98bXxob3Vycz98aHJzP3xofGRheXM/fGR8eWVhcnM/fHlycz98eSk/JC9pLmV4ZWMoXG4gICAgc3RyXG4gICk7XG4gIGlmICghbWF0Y2gpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgdmFyIG4gPSBwYXJzZUZsb2F0KG1hdGNoWzFdKTtcbiAgdmFyIHR5cGUgPSAobWF0Y2hbMl0gfHwgJ21zJykudG9Mb3dlckNhc2UoKTtcbiAgc3dpdGNoICh0eXBlKSB7XG4gICAgY2FzZSAneWVhcnMnOlxuICAgIGNhc2UgJ3llYXInOlxuICAgIGNhc2UgJ3lycyc6XG4gICAgY2FzZSAneXInOlxuICAgIGNhc2UgJ3knOlxuICAgICAgcmV0dXJuIG4gKiB5O1xuICAgIGNhc2UgJ2RheXMnOlxuICAgIGNhc2UgJ2RheSc6XG4gICAgY2FzZSAnZCc6XG4gICAgICByZXR1cm4gbiAqIGQ7XG4gICAgY2FzZSAnaG91cnMnOlxuICAgIGNhc2UgJ2hvdXInOlxuICAgIGNhc2UgJ2hycyc6XG4gICAgY2FzZSAnaHInOlxuICAgIGNhc2UgJ2gnOlxuICAgICAgcmV0dXJuIG4gKiBoO1xuICAgIGNhc2UgJ21pbnV0ZXMnOlxuICAgIGNhc2UgJ21pbnV0ZSc6XG4gICAgY2FzZSAnbWlucyc6XG4gICAgY2FzZSAnbWluJzpcbiAgICBjYXNlICdtJzpcbiAgICAgIHJldHVybiBuICogbTtcbiAgICBjYXNlICdzZWNvbmRzJzpcbiAgICBjYXNlICdzZWNvbmQnOlxuICAgIGNhc2UgJ3NlY3MnOlxuICAgIGNhc2UgJ3NlYyc6XG4gICAgY2FzZSAncyc6XG4gICAgICByZXR1cm4gbiAqIHM7XG4gICAgY2FzZSAnbWlsbGlzZWNvbmRzJzpcbiAgICBjYXNlICdtaWxsaXNlY29uZCc6XG4gICAgY2FzZSAnbXNlY3MnOlxuICAgIGNhc2UgJ21zZWMnOlxuICAgIGNhc2UgJ21zJzpcbiAgICAgIHJldHVybiBuO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbi8qKlxuICogU2hvcnQgZm9ybWF0IGZvciBgbXNgLlxuICpcbiAqIEBwYXJhbSB7TnVtYmVyfSBtc1xuICogQHJldHVybiB7U3RyaW5nfVxuICogQGFwaSBwcml2YXRlXG4gKi9cblxuZnVuY3Rpb24gZm10U2hvcnQobXMpIHtcbiAgaWYgKG1zID49IGQpIHtcbiAgICByZXR1cm4gTWF0aC5yb3VuZChtcyAvIGQpICsgJ2QnO1xuICB9XG4gIGlmIChtcyA+PSBoKSB7XG4gICAgcmV0dXJuIE1hdGgucm91bmQobXMgLyBoKSArICdoJztcbiAgfVxuICBpZiAobXMgPj0gbSkge1xuICAgIHJldHVybiBNYXRoLnJvdW5kKG1zIC8gbSkgKyAnbSc7XG4gIH1cbiAgaWYgKG1zID49IHMpIHtcbiAgICByZXR1cm4gTWF0aC5yb3VuZChtcyAvIHMpICsgJ3MnO1xuICB9XG4gIHJldHVybiBtcyArICdtcyc7XG59XG5cbi8qKlxuICogTG9uZyBmb3JtYXQgZm9yIGBtc2AuXG4gKlxuICogQHBhcmFtIHtOdW1iZXJ9IG1zXG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuXG5mdW5jdGlvbiBmbXRMb25nKG1zKSB7XG4gIHJldHVybiBwbHVyYWwobXMsIGQsICdkYXknKSB8fFxuICAgIHBsdXJhbChtcywgaCwgJ2hvdXInKSB8fFxuICAgIHBsdXJhbChtcywgbSwgJ21pbnV0ZScpIHx8XG4gICAgcGx1cmFsKG1zLCBzLCAnc2Vjb25kJykgfHxcbiAgICBtcyArICcgbXMnO1xufVxuXG4vKipcbiAqIFBsdXJhbGl6YXRpb24gaGVscGVyLlxuICovXG5cbmZ1bmN0aW9uIHBsdXJhbChtcywgbiwgbmFtZSkge1xuICBpZiAobXMgPCBuKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChtcyA8IG4gKiAxLjUpIHtcbiAgICByZXR1cm4gTWF0aC5mbG9vcihtcyAvIG4pICsgJyAnICsgbmFtZTtcbiAgfVxuICByZXR1cm4gTWF0aC5jZWlsKG1zIC8gbikgKyAnICcgKyBuYW1lICsgJ3MnO1xufVxuIiwiLyoqXG4gICMgbm9ybWFsaWNlXG5cbiAgTm9ybWFsaXplIGFuIGljZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QgKG9yIHBsYWluIG9sZCBzdHJpbmcpIGludG8gYSBmb3JtYXRcbiAgdGhhdCBpcyB1c2FibGUgaW4gYWxsIGJyb3dzZXJzIHN1cHBvcnRpbmcgV2ViUlRDLiAgUHJpbWFyaWx5IHRoaXMgbW9kdWxlIGlzIGRlc2lnbmVkXG4gIHRvIGhlbHAgd2l0aCB0aGUgdHJhbnNpdGlvbiBvZiB0aGUgYHVybGAgYXR0cmlidXRlIG9mIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB0b1xuICB0aGUgYHVybHNgIGF0dHJpYnV0ZS5cblxuICAjIyBFeGFtcGxlIFVzYWdlXG5cbiAgPDw8IGV4YW1wbGVzL3NpbXBsZS5qc1xuXG4qKi9cblxudmFyIHByb3RvY29scyA9IFtcbiAgJ3N0dW46JyxcbiAgJ3R1cm46J1xuXTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihpbnB1dCkge1xuICB2YXIgdXJsID0gKGlucHV0IHx8IHt9KS51cmwgfHwgaW5wdXQ7XG4gIHZhciBwcm90b2NvbDtcbiAgdmFyIHBhcnRzO1xuICB2YXIgb3V0cHV0ID0ge307XG5cbiAgLy8gaWYgd2UgZG9uJ3QgaGF2ZSBhIHN0cmluZyB1cmwsIHRoZW4gYWxsb3cgdGhlIGlucHV0IHRvIHBhc3N0aHJvdWdoXG4gIGlmICh0eXBlb2YgdXJsICE9ICdzdHJpbmcnICYmICghICh1cmwgaW5zdGFuY2VvZiBTdHJpbmcpKSkge1xuICAgIHJldHVybiBpbnB1dDtcbiAgfVxuXG4gIC8vIHRyaW0gdGhlIHVybCBzdHJpbmcsIGFuZCBjb252ZXJ0IHRvIGFuIGFycmF5XG4gIHVybCA9IHVybC50cmltKCk7XG5cbiAgLy8gaWYgdGhlIHByb3RvY29sIGlzIG5vdCBrbm93biwgdGhlbiBwYXNzdGhyb3VnaFxuICBwcm90b2NvbCA9IHByb3RvY29sc1twcm90b2NvbHMuaW5kZXhPZih1cmwuc2xpY2UoMCwgNSkpXTtcbiAgaWYgKCEgcHJvdG9jb2wpIHtcbiAgICByZXR1cm4gaW5wdXQ7XG4gIH1cblxuICAvLyBub3cgbGV0J3MgYXR0YWNrIHRoZSByZW1haW5pbmcgdXJsIHBhcnRzXG4gIHVybCA9IHVybC5zbGljZSg1KTtcbiAgcGFydHMgPSB1cmwuc3BsaXQoJ0AnKTtcblxuICBvdXRwdXQudXNlcm5hbWUgPSBpbnB1dC51c2VybmFtZTtcbiAgb3V0cHV0LmNyZWRlbnRpYWwgPSBpbnB1dC5jcmVkZW50aWFsO1xuICAvLyBpZiB3ZSBoYXZlIGFuIGF1dGhlbnRpY2F0aW9uIHBhcnQsIHRoZW4gc2V0IHRoZSBjcmVkZW50aWFsc1xuICBpZiAocGFydHMubGVuZ3RoID4gMSkge1xuICAgIHVybCA9IHBhcnRzWzFdO1xuICAgIHBhcnRzID0gcGFydHNbMF0uc3BsaXQoJzonKTtcblxuICAgIC8vIGFkZCB0aGUgb3V0cHV0IGNyZWRlbnRpYWwgYW5kIHVzZXJuYW1lXG4gICAgb3V0cHV0LnVzZXJuYW1lID0gcGFydHNbMF07XG4gICAgb3V0cHV0LmNyZWRlbnRpYWwgPSAoaW5wdXQgfHwge30pLmNyZWRlbnRpYWwgfHwgcGFydHNbMV0gfHwgJyc7XG4gIH1cblxuICBvdXRwdXQudXJsID0gcHJvdG9jb2wgKyB1cmw7XG4gIG91dHB1dC51cmxzID0gWyBvdXRwdXQudXJsIF07XG5cbiAgcmV0dXJuIG91dHB1dDtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbi8qKlxuICogQ2hlY2sgaWYgd2UncmUgcmVxdWlyZWQgdG8gYWRkIGEgcG9ydCBudW1iZXIuXG4gKlxuICogQHNlZSBodHRwczovL3VybC5zcGVjLndoYXR3Zy5vcmcvI2RlZmF1bHQtcG9ydFxuICogQHBhcmFtIHtOdW1iZXJ8U3RyaW5nfSBwb3J0IFBvcnQgbnVtYmVyIHdlIG5lZWQgdG8gY2hlY2tcbiAqIEBwYXJhbSB7U3RyaW5nfSBwcm90b2NvbCBQcm90b2NvbCB3ZSBuZWVkIHRvIGNoZWNrIGFnYWluc3QuXG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gSXMgaXQgYSBkZWZhdWx0IHBvcnQgZm9yIHRoZSBnaXZlbiBwcm90b2NvbFxuICogQGFwaSBwcml2YXRlXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcmVxdWlyZWQocG9ydCwgcHJvdG9jb2wpIHtcbiAgcHJvdG9jb2wgPSBwcm90b2NvbC5zcGxpdCgnOicpWzBdO1xuICBwb3J0ID0gK3BvcnQ7XG5cbiAgaWYgKCFwb3J0KSByZXR1cm4gZmFsc2U7XG5cbiAgc3dpdGNoIChwcm90b2NvbCkge1xuICAgIGNhc2UgJ2h0dHAnOlxuICAgIGNhc2UgJ3dzJzpcbiAgICByZXR1cm4gcG9ydCAhPT0gODA7XG5cbiAgICBjYXNlICdodHRwcyc6XG4gICAgY2FzZSAnd3NzJzpcbiAgICByZXR1cm4gcG9ydCAhPT0gNDQzO1xuXG4gICAgY2FzZSAnZnRwJzpcbiAgICByZXR1cm4gcG9ydCAhPT0gMjE7XG5cbiAgICBjYXNlICdnb3BoZXInOlxuICAgIHJldHVybiBwb3J0ICE9PSA3MDtcblxuICAgIGNhc2UgJ2ZpbGUnOlxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHJldHVybiBwb3J0ICE9PSAwO1xufTtcbiIsInZhciBncmFtbWFyID0gbW9kdWxlLmV4cG9ydHMgPSB7XG4gIHY6IFt7XG4gICAgICBuYW1lOiAndmVyc2lvbicsXG4gICAgICByZWc6IC9eKFxcZCopJC9cbiAgfV0sXG4gIG86IFt7IC8vbz0tIDIwNTE4IDAgSU4gSVA0IDIwMy4wLjExMy4xXG4gICAgLy8gTkI6IHNlc3Npb25JZCB3aWxsIGJlIGEgU3RyaW5nIGluIG1vc3QgY2FzZXMgYmVjYXVzZSBpdCBpcyBodWdlXG4gICAgbmFtZTogJ29yaWdpbicsXG4gICAgcmVnOiAvXihcXFMqKSAoXFxkKikgKFxcZCopIChcXFMqKSBJUChcXGQpIChcXFMqKS8sXG4gICAgbmFtZXM6IFsndXNlcm5hbWUnLCAnc2Vzc2lvbklkJywgJ3Nlc3Npb25WZXJzaW9uJywgJ25ldFR5cGUnLCAnaXBWZXInLCAnYWRkcmVzcyddLFxuICAgIGZvcm1hdDogXCIlcyAlcyAlZCAlcyBJUCVkICVzXCJcbiAgfV0sXG4gIC8vIGRlZmF1bHQgcGFyc2luZyBvZiB0aGVzZSBvbmx5ICh0aG91Z2ggc29tZSBvZiB0aGVzZSBmZWVsIG91dGRhdGVkKVxuICBzOiBbeyBuYW1lOiAnbmFtZScgfV0sXG4gIGk6IFt7IG5hbWU6ICdkZXNjcmlwdGlvbicgfV0sXG4gIHU6IFt7IG5hbWU6ICd1cmknIH1dLFxuICBlOiBbeyBuYW1lOiAnZW1haWwnIH1dLFxuICBwOiBbeyBuYW1lOiAncGhvbmUnIH1dLFxuICB6OiBbeyBuYW1lOiAndGltZXpvbmVzJyB9XSwgLy8gVE9ETzogdGhpcyBvbmUgY2FuIGFjdHVhbGx5IGJlIHBhcnNlZCBwcm9wZXJseS4uXG4gIHI6IFt7IG5hbWU6ICdyZXBlYXRzJyB9XSwgICAvLyBUT0RPOiB0aGlzIG9uZSBjYW4gYWxzbyBiZSBwYXJzZWQgcHJvcGVybHlcbiAgLy9rOiBbe31dLCAvLyBvdXRkYXRlZCB0aGluZyBpZ25vcmVkXG4gIHQ6IFt7IC8vdD0wIDBcbiAgICBuYW1lOiAndGltaW5nJyxcbiAgICByZWc6IC9eKFxcZCopIChcXGQqKS8sXG4gICAgbmFtZXM6IFsnc3RhcnQnLCAnc3RvcCddLFxuICAgIGZvcm1hdDogXCIlZCAlZFwiXG4gIH1dLFxuICBjOiBbeyAvL2M9SU4gSVA0IDEwLjQ3LjE5Ny4yNlxuICAgICAgbmFtZTogJ2Nvbm5lY3Rpb24nLFxuICAgICAgcmVnOiAvXklOIElQKFxcZCkgKFxcUyopLyxcbiAgICAgIG5hbWVzOiBbJ3ZlcnNpb24nLCAnaXAnXSxcbiAgICAgIGZvcm1hdDogXCJJTiBJUCVkICVzXCJcbiAgfV0sXG4gIGI6IFt7IC8vYj1BUzo0MDAwXG4gICAgICBwdXNoOiAnYmFuZHdpZHRoJyxcbiAgICAgIHJlZzogL14oVElBU3xBU3xDVHxSUnxSUyk6KFxcZCopLyxcbiAgICAgIG5hbWVzOiBbJ3R5cGUnLCAnbGltaXQnXSxcbiAgICAgIGZvcm1hdDogXCIlczolc1wiXG4gIH1dLFxuICBtOiBbeyAvL209dmlkZW8gNTE3NDQgUlRQL0FWUCAxMjYgOTcgOTggMzQgMzFcbiAgICAgIC8vIE5COiBzcGVjaWFsIC0gcHVzaGVzIHRvIHNlc3Npb25cbiAgICAgIC8vIFRPRE86IHJ0cC9mbXRwIHNob3VsZCBiZSBmaWx0ZXJlZCBieSB0aGUgcGF5bG9hZHMgZm91bmQgaGVyZT9cbiAgICAgIHJlZzogL14oXFx3KikgKFxcZCopIChbXFx3XFwvXSopKD86ICguKikpPy8sXG4gICAgICBuYW1lczogWyd0eXBlJywgJ3BvcnQnLCAncHJvdG9jb2wnLCAncGF5bG9hZHMnXSxcbiAgICAgIGZvcm1hdDogXCIlcyAlZCAlcyAlc1wiXG4gIH1dLFxuICBhOiBbXG4gICAgeyAvL2E9cnRwbWFwOjExMCBvcHVzLzQ4MDAwLzJcbiAgICAgIHB1c2g6ICdydHAnLFxuICAgICAgcmVnOiAvXnJ0cG1hcDooXFxkKikgKFtcXHdcXC1dKikoPzpcXHMqXFwvKFxcZCopKD86XFxzKlxcLyhcXFMqKSk/KT8vLFxuICAgICAgbmFtZXM6IFsncGF5bG9hZCcsICdjb2RlYycsICdyYXRlJywgJ2VuY29kaW5nJ10sXG4gICAgICBmb3JtYXQ6IGZ1bmN0aW9uIChvKSB7XG4gICAgICAgIHJldHVybiAoby5lbmNvZGluZykgP1xuICAgICAgICAgIFwicnRwbWFwOiVkICVzLyVzLyVzXCI6XG4gICAgICAgICAgby5yYXRlID9cbiAgICAgICAgICBcInJ0cG1hcDolZCAlcy8lc1wiOlxuICAgICAgICAgIFwicnRwbWFwOiVkICVzXCI7XG4gICAgICB9XG4gICAgfSxcbiAgICB7XG4gICAgICAvL2E9Zm10cDoxMDggcHJvZmlsZS1sZXZlbC1pZD0yNDtvYmplY3Q9MjM7Yml0cmF0ZT02NDAwMFxuICAgICAgLy9hPWZtdHA6MTExIG1pbnB0aW1lPTEwOyB1c2VpbmJhbmRmZWM9MVxuICAgICAgcHVzaDogJ2ZtdHAnLFxuICAgICAgcmVnOiAvXmZtdHA6KFxcZCopIChbXFxTfCBdKikvLFxuICAgICAgbmFtZXM6IFsncGF5bG9hZCcsICdjb25maWcnXSxcbiAgICAgIGZvcm1hdDogXCJmbXRwOiVkICVzXCJcbiAgICB9LFxuICAgIHsgLy9hPWNvbnRyb2w6c3RyZWFtaWQ9MFxuICAgICAgICBuYW1lOiAnY29udHJvbCcsXG4gICAgICAgIHJlZzogL15jb250cm9sOiguKikvLFxuICAgICAgICBmb3JtYXQ6IFwiY29udHJvbDolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1ydGNwOjY1MTc5IElOIElQNCAxOTMuODQuNzcuMTk0XG4gICAgICBuYW1lOiAncnRjcCcsXG4gICAgICByZWc6IC9ecnRjcDooXFxkKikoPzogKFxcUyopIElQKFxcZCkgKFxcUyopKT8vLFxuICAgICAgbmFtZXM6IFsncG9ydCcsICduZXRUeXBlJywgJ2lwVmVyJywgJ2FkZHJlc3MnXSxcbiAgICAgIGZvcm1hdDogZnVuY3Rpb24gKG8pIHtcbiAgICAgICAgcmV0dXJuIChvLmFkZHJlc3MgIT0gbnVsbCkgP1xuICAgICAgICAgIFwicnRjcDolZCAlcyBJUCVkICVzXCI6XG4gICAgICAgICAgXCJydGNwOiVkXCI7XG4gICAgICB9XG4gICAgfSxcbiAgICB7IC8vYT1ydGNwLWZiOjk4IHRyci1pbnQgMTAwXG4gICAgICBwdXNoOiAncnRjcEZiVHJySW50JyxcbiAgICAgIHJlZzogL15ydGNwLWZiOihcXCp8XFxkKikgdHJyLWludCAoXFxkKikvLFxuICAgICAgbmFtZXM6IFsncGF5bG9hZCcsICd2YWx1ZSddLFxuICAgICAgZm9ybWF0OiBcInJ0Y3AtZmI6JWQgdHJyLWludCAlZFwiXG4gICAgfSxcbiAgICB7IC8vYT1ydGNwLWZiOjk4IG5hY2sgcnBzaVxuICAgICAgcHVzaDogJ3J0Y3BGYicsXG4gICAgICByZWc6IC9ecnRjcC1mYjooXFwqfFxcZCopIChbXFx3LV9dKikoPzogKFtcXHctX10qKSk/LyxcbiAgICAgIG5hbWVzOiBbJ3BheWxvYWQnLCAndHlwZScsICdzdWJ0eXBlJ10sXG4gICAgICBmb3JtYXQ6IGZ1bmN0aW9uIChvKSB7XG4gICAgICAgIHJldHVybiAoby5zdWJ0eXBlICE9IG51bGwpID9cbiAgICAgICAgICBcInJ0Y3AtZmI6JXMgJXMgJXNcIjpcbiAgICAgICAgICBcInJ0Y3AtZmI6JXMgJXNcIjtcbiAgICAgIH1cbiAgICB9LFxuICAgIHsgLy9hPWV4dG1hcDoyIHVybjppZXRmOnBhcmFtczpydHAtaGRyZXh0OnRvZmZzZXRcbiAgICAgIC8vYT1leHRtYXA6MS9yZWN2b25seSBVUkktZ3BzLXN0cmluZ1xuICAgICAgcHVzaDogJ2V4dCcsXG4gICAgICByZWc6IC9eZXh0bWFwOihbXFx3X1xcL10qKSAoXFxTKikoPzogKFxcUyopKT8vLFxuICAgICAgbmFtZXM6IFsndmFsdWUnLCAndXJpJywgJ2NvbmZpZyddLCAvLyB2YWx1ZSBtYXkgaW5jbHVkZSBcIi9kaXJlY3Rpb25cIiBzdWZmaXhcbiAgICAgIGZvcm1hdDogZnVuY3Rpb24gKG8pIHtcbiAgICAgICAgcmV0dXJuIChvLmNvbmZpZyAhPSBudWxsKSA/XG4gICAgICAgICAgXCJleHRtYXA6JXMgJXMgJXNcIjpcbiAgICAgICAgICBcImV4dG1hcDolcyAlc1wiO1xuICAgICAgfVxuICAgIH0sXG4gICAge1xuICAgICAgLy9hPWNyeXB0bzoxIEFFU19DTV8xMjhfSE1BQ19TSEExXzgwIGlubGluZTpQUzF1UUNWZWVDRkNhblZtY2prcFB5d2pOV2hjWUQwbVhYdHhhVkJSfDJeMjB8MTozMlxuICAgICAgcHVzaDogJ2NyeXB0bycsXG4gICAgICByZWc6IC9eY3J5cHRvOihcXGQqKSAoW1xcd19dKikgKFxcUyopKD86IChcXFMqKSk/LyxcbiAgICAgIG5hbWVzOiBbJ2lkJywgJ3N1aXRlJywgJ2NvbmZpZycsICdzZXNzaW9uQ29uZmlnJ10sXG4gICAgICBmb3JtYXQ6IGZ1bmN0aW9uIChvKSB7XG4gICAgICAgIHJldHVybiAoby5zZXNzaW9uQ29uZmlnICE9IG51bGwpID9cbiAgICAgICAgICBcImNyeXB0bzolZCAlcyAlcyAlc1wiOlxuICAgICAgICAgIFwiY3J5cHRvOiVkICVzICVzXCI7XG4gICAgICB9XG4gICAgfSxcbiAgICB7IC8vYT1zZXR1cDphY3RwYXNzXG4gICAgICBuYW1lOiAnc2V0dXAnLFxuICAgICAgcmVnOiAvXnNldHVwOihcXHcqKS8sXG4gICAgICBmb3JtYXQ6IFwic2V0dXA6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9bWlkOjFcbiAgICAgIG5hbWU6ICdtaWQnLFxuICAgICAgcmVnOiAvXm1pZDooW15cXHNdKikvLFxuICAgICAgZm9ybWF0OiBcIm1pZDolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1tc2lkOjBjOGIwNjRkLWQ4MDctNDNiNC1iNDM0LWY5MmE4ODlkODU4NyA5ODE3ODY4NS1kNDA5LTQ2ZTAtOGUxNi03ZWYwZGIwZGI2NGFcbiAgICAgIG5hbWU6ICdtc2lkJyxcbiAgICAgIHJlZzogL15tc2lkOiguKikvLFxuICAgICAgZm9ybWF0OiBcIm1zaWQ6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9cHRpbWU6MjBcbiAgICAgIG5hbWU6ICdwdGltZScsXG4gICAgICByZWc6IC9ecHRpbWU6KFxcZCopLyxcbiAgICAgIGZvcm1hdDogXCJwdGltZTolZFwiXG4gICAgfSxcbiAgICB7IC8vYT1tYXhwdGltZTo2MFxuICAgICAgbmFtZTogJ21heHB0aW1lJyxcbiAgICAgIHJlZzogL15tYXhwdGltZTooXFxkKikvLFxuICAgICAgZm9ybWF0OiBcIm1heHB0aW1lOiVkXCJcbiAgICB9LFxuICAgIHsgLy9hPXNlbmRyZWN2XG4gICAgICBuYW1lOiAnZGlyZWN0aW9uJyxcbiAgICAgIHJlZzogL14oc2VuZHJlY3Z8cmVjdm9ubHl8c2VuZG9ubHl8aW5hY3RpdmUpL1xuICAgIH0sXG4gICAgeyAvL2E9aWNlLWxpdGVcbiAgICAgIG5hbWU6ICdpY2VsaXRlJyxcbiAgICAgIHJlZzogL14oaWNlLWxpdGUpL1xuICAgIH0sXG4gICAgeyAvL2E9aWNlLXVmcmFnOkY3Z0lcbiAgICAgIG5hbWU6ICdpY2VVZnJhZycsXG4gICAgICByZWc6IC9eaWNlLXVmcmFnOihcXFMqKS8sXG4gICAgICBmb3JtYXQ6IFwiaWNlLXVmcmFnOiVzXCJcbiAgICB9LFxuICAgIHsgLy9hPWljZS1wd2Q6eDljbWwvWXppY2hWMitYbGhpTXU4Z1xuICAgICAgbmFtZTogJ2ljZVB3ZCcsXG4gICAgICByZWc6IC9eaWNlLXB3ZDooXFxTKikvLFxuICAgICAgZm9ybWF0OiBcImljZS1wd2Q6JXNcIlxuICAgIH0sXG4gICAgeyAvL2E9ZmluZ2VycHJpbnQ6U0hBLTEgMDA6MTE6MjI6MzM6NDQ6NTU6NjY6Nzc6ODg6OTk6QUE6QkI6Q0M6REQ6RUU6RkY6MDA6MTE6MjI6MzNcbiAgICAgIG5hbWU6ICdmaW5nZXJwcmludCcsXG4gICAgICByZWc6IC9eZmluZ2VycHJpbnQ6KFxcUyopIChcXFMqKS8sXG4gICAgICBuYW1lczogWyd0eXBlJywgJ2hhc2gnXSxcbiAgICAgIGZvcm1hdDogXCJmaW5nZXJwcmludDolcyAlc1wiXG4gICAgfSxcbiAgICB7XG4gICAgICAvL2E9Y2FuZGlkYXRlOjAgMSBVRFAgMjExMzY2NzMyNyAyMDMuMC4xMTMuMSA1NDQwMCB0eXAgaG9zdFxuICAgICAgLy9hPWNhbmRpZGF0ZToxMTYyODc1MDgxIDEgdWRwIDIxMTM5MzcxNTEgMTkyLjE2OC4zNC43NSA2MDAxNyB0eXAgaG9zdCBnZW5lcmF0aW9uIDBcbiAgICAgIC8vYT1jYW5kaWRhdGU6MzI4OTkxMjk1NyAyIHVkcCAxODQ1NTAxNjk1IDE5My44NC43Ny4xOTQgNjAwMTcgdHlwIHNyZmx4IHJhZGRyIDE5Mi4xNjguMzQuNzUgcnBvcnQgNjAwMTcgZ2VuZXJhdGlvbiAwXG4gICAgICAvL2E9Y2FuZGlkYXRlOjIyOTgxNTYyMCAxIHRjcCAxNTE4MjgwNDQ3IDE5Mi4xNjguMTUwLjE5IDYwMDE3IHR5cCBob3N0IHRjcHR5cGUgYWN0aXZlIGdlbmVyYXRpb24gMFxuICAgICAgLy9hPWNhbmRpZGF0ZTozMjg5OTEyOTU3IDIgdGNwIDE4NDU1MDE2OTUgMTkzLjg0Ljc3LjE5NCA2MDAxNyB0eXAgc3JmbHggcmFkZHIgMTkyLjE2OC4zNC43NSBycG9ydCA2MDAxNyB0Y3B0eXBlIHBhc3NpdmUgZ2VuZXJhdGlvbiAwXG4gICAgICBwdXNoOidjYW5kaWRhdGVzJyxcbiAgICAgIHJlZzogL15jYW5kaWRhdGU6KFxcUyopIChcXGQqKSAoXFxTKikgKFxcZCopIChcXFMqKSAoXFxkKikgdHlwIChcXFMqKSg/OiByYWRkciAoXFxTKikgcnBvcnQgKFxcZCopKT8oPzogdGNwdHlwZSAoXFxTKikpPyg/OiBnZW5lcmF0aW9uIChcXGQqKSk/LyxcbiAgICAgIG5hbWVzOiBbJ2ZvdW5kYXRpb24nLCAnY29tcG9uZW50JywgJ3RyYW5zcG9ydCcsICdwcmlvcml0eScsICdpcCcsICdwb3J0JywgJ3R5cGUnLCAncmFkZHInLCAncnBvcnQnLCAndGNwdHlwZScsICdnZW5lcmF0aW9uJ10sXG4gICAgICBmb3JtYXQ6IGZ1bmN0aW9uIChvKSB7XG4gICAgICAgIHZhciBzdHIgPSBcImNhbmRpZGF0ZTolcyAlZCAlcyAlZCAlcyAlZCB0eXAgJXNcIjtcblxuICAgICAgICBzdHIgKz0gKG8ucmFkZHIgIT0gbnVsbCkgPyBcIiByYWRkciAlcyBycG9ydCAlZFwiIDogXCIldiV2XCI7XG5cbiAgICAgICAgLy8gTkI6IGNhbmRpZGF0ZSBoYXMgdGhyZWUgb3B0aW9uYWwgY2h1bmtzLCBzbyAldm9pZCBtaWRkbGVzIG9uZSBpZiBpdCdzIG1pc3NpbmdcbiAgICAgICAgc3RyICs9IChvLnRjcHR5cGUgIT0gbnVsbCkgPyBcIiB0Y3B0eXBlICVzXCIgOiBcIiV2XCI7XG5cbiAgICAgICAgaWYgKG8uZ2VuZXJhdGlvbiAhPSBudWxsKSB7XG4gICAgICAgICAgc3RyICs9IFwiIGdlbmVyYXRpb24gJWRcIjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc3RyO1xuICAgICAgfVxuICAgIH0sXG4gICAgeyAvL2E9ZW5kLW9mLWNhbmRpZGF0ZXMgKGtlZXAgYWZ0ZXIgdGhlIGNhbmRpZGF0ZXMgbGluZSBmb3IgcmVhZGFiaWxpdHkpXG4gICAgICBuYW1lOiAnZW5kT2ZDYW5kaWRhdGVzJyxcbiAgICAgIHJlZzogL14oZW5kLW9mLWNhbmRpZGF0ZXMpL1xuICAgIH0sXG4gICAgeyAvL2E9cmVtb3RlLWNhbmRpZGF0ZXM6MSAyMDMuMC4xMTMuMSA1NDQwMCAyIDIwMy4wLjExMy4xIDU0NDAxIC4uLlxuICAgICAgbmFtZTogJ3JlbW90ZUNhbmRpZGF0ZXMnLFxuICAgICAgcmVnOiAvXnJlbW90ZS1jYW5kaWRhdGVzOiguKikvLFxuICAgICAgZm9ybWF0OiBcInJlbW90ZS1jYW5kaWRhdGVzOiVzXCJcbiAgICB9LFxuICAgIHsgLy9hPWljZS1vcHRpb25zOmdvb2dsZS1pY2VcbiAgICAgIG5hbWU6ICdpY2VPcHRpb25zJyxcbiAgICAgIHJlZzogL15pY2Utb3B0aW9uczooXFxTKikvLFxuICAgICAgZm9ybWF0OiBcImljZS1vcHRpb25zOiVzXCJcbiAgICB9LFxuICAgIHsgLy9hPXNzcmM6MjU2NjEwNzU2OSBjbmFtZTp0OVlVOE0xVXhURjhZMUExXG4gICAgICBwdXNoOiBcInNzcmNzXCIsXG4gICAgICByZWc6IC9ec3NyYzooXFxkKikgKFtcXHdfXSopOiguKikvLFxuICAgICAgbmFtZXM6IFsnaWQnLCAnYXR0cmlidXRlJywgJ3ZhbHVlJ10sXG4gICAgICBmb3JtYXQ6IFwic3NyYzolZCAlczolc1wiXG4gICAgfSxcbiAgICB7IC8vYT1zc3JjLWdyb3VwOkZFQyAxIDJcbiAgICAgIHB1c2g6IFwic3NyY0dyb3Vwc1wiLFxuICAgICAgcmVnOiAvXnNzcmMtZ3JvdXA6KFxcdyopICguKikvLFxuICAgICAgbmFtZXM6IFsnc2VtYW50aWNzJywgJ3NzcmNzJ10sXG4gICAgICBmb3JtYXQ6IFwic3NyYy1ncm91cDolcyAlc1wiXG4gICAgfSxcbiAgICB7IC8vYT1tc2lkLXNlbWFudGljOiBXTVMgSnZsYW01WDNTWDFPUDZwbjIweldvZ3ZhS0p6NUhqZjlPbmxWXG4gICAgICBuYW1lOiBcIm1zaWRTZW1hbnRpY1wiLFxuICAgICAgcmVnOiAvXm1zaWQtc2VtYW50aWM6XFxzPyhcXHcqKSAoXFxTKikvLFxuICAgICAgbmFtZXM6IFsnc2VtYW50aWMnLCAndG9rZW4nXSxcbiAgICAgIGZvcm1hdDogXCJtc2lkLXNlbWFudGljOiAlcyAlc1wiIC8vIHNwYWNlIGFmdGVyIFwiOlwiIGlzIG5vdCBhY2NpZGVudGFsXG4gICAgfSxcbiAgICB7IC8vYT1ncm91cDpCVU5ETEUgYXVkaW8gdmlkZW9cbiAgICAgIHB1c2g6ICdncm91cHMnLFxuICAgICAgcmVnOiAvXmdyb3VwOihcXHcqKSAoLiopLyxcbiAgICAgIG5hbWVzOiBbJ3R5cGUnLCAnbWlkcyddLFxuICAgICAgZm9ybWF0OiBcImdyb3VwOiVzICVzXCJcbiAgICB9LFxuICAgIHsgLy9hPXJ0Y3AtbXV4XG4gICAgICBuYW1lOiAncnRjcE11eCcsXG4gICAgICByZWc6IC9eKHJ0Y3AtbXV4KS9cbiAgICB9LFxuICAgIHsgLy9hPXJ0Y3AtcnNpemVcbiAgICAgIG5hbWU6ICdydGNwUnNpemUnLFxuICAgICAgcmVnOiAvXihydGNwLXJzaXplKS9cbiAgICB9LFxuICAgIHsgLy8gYW55IGE9IHRoYXQgd2UgZG9uJ3QgdW5kZXJzdGFuZCBpcyBrZXB0cyB2ZXJiYXRpbSBvbiBtZWRpYS5pbnZhbGlkXG4gICAgICBwdXNoOiAnaW52YWxpZCcsXG4gICAgICBuYW1lczogW1widmFsdWVcIl1cbiAgICB9XG4gIF1cbn07XG5cbi8vIHNldCBzZW5zaWJsZSBkZWZhdWx0cyB0byBhdm9pZCBwb2xsdXRpbmcgdGhlIGdyYW1tYXIgd2l0aCBib3JpbmcgZGV0YWlsc1xuT2JqZWN0LmtleXMoZ3JhbW1hcikuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7XG4gIHZhciBvYmpzID0gZ3JhbW1hcltrZXldO1xuICBvYmpzLmZvckVhY2goZnVuY3Rpb24gKG9iaikge1xuICAgIGlmICghb2JqLnJlZykge1xuICAgICAgb2JqLnJlZyA9IC8oLiopLztcbiAgICB9XG4gICAgaWYgKCFvYmouZm9ybWF0KSB7XG4gICAgICBvYmouZm9ybWF0ID0gXCIlc1wiO1xuICAgIH1cbiAgfSk7XG59KTtcbiIsInZhciBwYXJzZXIgPSByZXF1aXJlKCcuL3BhcnNlcicpO1xudmFyIHdyaXRlciA9IHJlcXVpcmUoJy4vd3JpdGVyJyk7XG5cbmV4cG9ydHMud3JpdGUgPSB3cml0ZXI7XG5leHBvcnRzLnBhcnNlID0gcGFyc2VyLnBhcnNlO1xuZXhwb3J0cy5wYXJzZUZtdHBDb25maWcgPSBwYXJzZXIucGFyc2VGbXRwQ29uZmlnO1xuZXhwb3J0cy5wYXJzZVBheWxvYWRzID0gcGFyc2VyLnBhcnNlUGF5bG9hZHM7XG5leHBvcnRzLnBhcnNlUmVtb3RlQ2FuZGlkYXRlcyA9IHBhcnNlci5wYXJzZVJlbW90ZUNhbmRpZGF0ZXM7XG4iLCJ2YXIgdG9JbnRJZkludCA9IGZ1bmN0aW9uICh2KSB7XG4gIHJldHVybiBTdHJpbmcoTnVtYmVyKHYpKSA9PT0gdiA/IE51bWJlcih2KSA6IHY7XG59O1xuXG52YXIgYXR0YWNoUHJvcGVydGllcyA9IGZ1bmN0aW9uIChtYXRjaCwgbG9jYXRpb24sIG5hbWVzLCByYXdOYW1lKSB7XG4gIGlmIChyYXdOYW1lICYmICFuYW1lcykge1xuICAgIGxvY2F0aW9uW3Jhd05hbWVdID0gdG9JbnRJZkludChtYXRjaFsxXSk7XG4gIH1cbiAgZWxzZSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuYW1lcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgaWYgKG1hdGNoW2krMV0gIT0gbnVsbCkge1xuICAgICAgICBsb2NhdGlvbltuYW1lc1tpXV0gPSB0b0ludElmSW50KG1hdGNoW2krMV0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxufTtcblxudmFyIHBhcnNlUmVnID0gZnVuY3Rpb24gKG9iaiwgbG9jYXRpb24sIGNvbnRlbnQpIHtcbiAgdmFyIG5lZWRzQmxhbmsgPSBvYmoubmFtZSAmJiBvYmoubmFtZXM7XG4gIGlmIChvYmoucHVzaCAmJiAhbG9jYXRpb25bb2JqLnB1c2hdKSB7XG4gICAgbG9jYXRpb25bb2JqLnB1c2hdID0gW107XG4gIH1cbiAgZWxzZSBpZiAobmVlZHNCbGFuayAmJiAhbG9jYXRpb25bb2JqLm5hbWVdKSB7XG4gICAgbG9jYXRpb25bb2JqLm5hbWVdID0ge307XG4gIH1cbiAgdmFyIGtleUxvY2F0aW9uID0gb2JqLnB1c2ggP1xuICAgIHt9IDogIC8vIGJsYW5rIG9iamVjdCB0aGF0IHdpbGwgYmUgcHVzaGVkXG4gICAgbmVlZHNCbGFuayA/IGxvY2F0aW9uW29iai5uYW1lXSA6IGxvY2F0aW9uOyAvLyBvdGhlcndpc2UsIG5hbWVkIGxvY2F0aW9uIG9yIHJvb3RcblxuICBhdHRhY2hQcm9wZXJ0aWVzKGNvbnRlbnQubWF0Y2gob2JqLnJlZyksIGtleUxvY2F0aW9uLCBvYmoubmFtZXMsIG9iai5uYW1lKTtcblxuICBpZiAob2JqLnB1c2gpIHtcbiAgICBsb2NhdGlvbltvYmoucHVzaF0ucHVzaChrZXlMb2NhdGlvbik7XG4gIH1cbn07XG5cbnZhciBncmFtbWFyID0gcmVxdWlyZSgnLi9ncmFtbWFyJyk7XG52YXIgdmFsaWRMaW5lID0gUmVnRXhwLnByb3RvdHlwZS50ZXN0LmJpbmQoL14oW2Etel0pPSguKikvKTtcblxuZXhwb3J0cy5wYXJzZSA9IGZ1bmN0aW9uIChzZHApIHtcbiAgdmFyIHNlc3Npb24gPSB7fVxuICAgICwgbWVkaWEgPSBbXVxuICAgICwgbG9jYXRpb24gPSBzZXNzaW9uOyAvLyBwb2ludHMgYXQgd2hlcmUgcHJvcGVydGllcyBnbyB1bmRlciAob25lIG9mIHRoZSBhYm92ZSlcblxuICAvLyBwYXJzZSBsaW5lcyB3ZSB1bmRlcnN0YW5kXG4gIHNkcC5zcGxpdCgvKFxcclxcbnxcXHJ8XFxuKS8pLmZpbHRlcih2YWxpZExpbmUpLmZvckVhY2goZnVuY3Rpb24gKGwpIHtcbiAgICB2YXIgdHlwZSA9IGxbMF07XG4gICAgdmFyIGNvbnRlbnQgPSBsLnNsaWNlKDIpO1xuICAgIGlmICh0eXBlID09PSAnbScpIHtcbiAgICAgIG1lZGlhLnB1c2goe3J0cDogW10sIGZtdHA6IFtdfSk7XG4gICAgICBsb2NhdGlvbiA9IG1lZGlhW21lZGlhLmxlbmd0aC0xXTsgLy8gcG9pbnQgYXQgbGF0ZXN0IG1lZGlhIGxpbmVcbiAgICB9XG5cbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IChncmFtbWFyW3R5cGVdIHx8IFtdKS5sZW5ndGg7IGogKz0gMSkge1xuICAgICAgdmFyIG9iaiA9IGdyYW1tYXJbdHlwZV1bal07XG4gICAgICBpZiAob2JqLnJlZy50ZXN0KGNvbnRlbnQpKSB7XG4gICAgICAgIHJldHVybiBwYXJzZVJlZyhvYmosIGxvY2F0aW9uLCBjb250ZW50KTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuXG4gIHNlc3Npb24ubWVkaWEgPSBtZWRpYTsgLy8gbGluayBpdCB1cFxuICByZXR1cm4gc2Vzc2lvbjtcbn07XG5cbnZhciBmbXRwUmVkdWNlciA9IGZ1bmN0aW9uIChhY2MsIGV4cHIpIHtcbiAgdmFyIHMgPSBleHByLnNwbGl0KCc9Jyk7XG4gIGlmIChzLmxlbmd0aCA9PT0gMikge1xuICAgIGFjY1tzWzBdXSA9IHRvSW50SWZJbnQoc1sxXSk7XG4gIH1cbiAgcmV0dXJuIGFjYztcbn07XG5cbmV4cG9ydHMucGFyc2VGbXRwQ29uZmlnID0gZnVuY3Rpb24gKHN0cikge1xuICByZXR1cm4gc3RyLnNwbGl0KC9cXDtcXHM/LykucmVkdWNlKGZtdHBSZWR1Y2VyLCB7fSk7XG59O1xuXG5leHBvcnRzLnBhcnNlUGF5bG9hZHMgPSBmdW5jdGlvbiAoc3RyKSB7XG4gIHJldHVybiBzdHIuc3BsaXQoJyAnKS5tYXAoTnVtYmVyKTtcbn07XG5cbmV4cG9ydHMucGFyc2VSZW1vdGVDYW5kaWRhdGVzID0gZnVuY3Rpb24gKHN0cikge1xuICB2YXIgY2FuZGlkYXRlcyA9IFtdO1xuICB2YXIgcGFydHMgPSBzdHIuc3BsaXQoJyAnKS5tYXAodG9JbnRJZkludCk7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgcGFydHMubGVuZ3RoOyBpICs9IDMpIHtcbiAgICBjYW5kaWRhdGVzLnB1c2goe1xuICAgICAgY29tcG9uZW50OiBwYXJ0c1tpXSxcbiAgICAgIGlwOiBwYXJ0c1tpICsgMV0sXG4gICAgICBwb3J0OiBwYXJ0c1tpICsgMl1cbiAgICB9KTtcbiAgfVxuICByZXR1cm4gY2FuZGlkYXRlcztcbn07XG4iLCJ2YXIgZ3JhbW1hciA9IHJlcXVpcmUoJy4vZ3JhbW1hcicpO1xuXG4vLyBjdXN0b21pemVkIHV0aWwuZm9ybWF0IC0gZGlzY2FyZHMgZXhjZXNzIGFyZ3VtZW50cyBhbmQgY2FuIHZvaWQgbWlkZGxlIG9uZXNcbnZhciBmb3JtYXRSZWdFeHAgPSAvJVtzZHYlXS9nO1xudmFyIGZvcm1hdCA9IGZ1bmN0aW9uIChmb3JtYXRTdHIpIHtcbiAgdmFyIGkgPSAxO1xuICB2YXIgYXJncyA9IGFyZ3VtZW50cztcbiAgdmFyIGxlbiA9IGFyZ3MubGVuZ3RoO1xuICByZXR1cm4gZm9ybWF0U3RyLnJlcGxhY2UoZm9ybWF0UmVnRXhwLCBmdW5jdGlvbiAoeCkge1xuICAgIGlmIChpID49IGxlbikge1xuICAgICAgcmV0dXJuIHg7IC8vIG1pc3NpbmcgYXJndW1lbnRcbiAgICB9XG4gICAgdmFyIGFyZyA9IGFyZ3NbaV07XG4gICAgaSArPSAxO1xuICAgIHN3aXRjaCAoeCkge1xuICAgICAgY2FzZSAnJSUnOlxuICAgICAgICByZXR1cm4gJyUnO1xuICAgICAgY2FzZSAnJXMnOlxuICAgICAgICByZXR1cm4gU3RyaW5nKGFyZyk7XG4gICAgICBjYXNlICclZCc6XG4gICAgICAgIHJldHVybiBOdW1iZXIoYXJnKTtcbiAgICAgIGNhc2UgJyV2JzpcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cbiAgfSk7XG4gIC8vIE5COiB3ZSBkaXNjYXJkIGV4Y2VzcyBhcmd1bWVudHMgLSB0aGV5IGFyZSB0eXBpY2FsbHkgdW5kZWZpbmVkIGZyb20gbWFrZUxpbmVcbn07XG5cbnZhciBtYWtlTGluZSA9IGZ1bmN0aW9uICh0eXBlLCBvYmosIGxvY2F0aW9uKSB7XG4gIHZhciBzdHIgPSBvYmouZm9ybWF0IGluc3RhbmNlb2YgRnVuY3Rpb24gP1xuICAgIChvYmouZm9ybWF0KG9iai5wdXNoID8gbG9jYXRpb24gOiBsb2NhdGlvbltvYmoubmFtZV0pKSA6XG4gICAgb2JqLmZvcm1hdDtcblxuICB2YXIgYXJncyA9IFt0eXBlICsgJz0nICsgc3RyXTtcbiAgaWYgKG9iai5uYW1lcykge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgb2JqLm5hbWVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICB2YXIgbiA9IG9iai5uYW1lc1tpXTtcbiAgICAgIGlmIChvYmoubmFtZSkge1xuICAgICAgICBhcmdzLnB1c2gobG9jYXRpb25bb2JqLm5hbWVdW25dKTtcbiAgICAgIH1cbiAgICAgIGVsc2UgeyAvLyBmb3IgbUxpbmUgYW5kIHB1c2ggYXR0cmlidXRlc1xuICAgICAgICBhcmdzLnB1c2gobG9jYXRpb25bb2JqLm5hbWVzW2ldXSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIGVsc2Uge1xuICAgIGFyZ3MucHVzaChsb2NhdGlvbltvYmoubmFtZV0pO1xuICB9XG4gIHJldHVybiBmb3JtYXQuYXBwbHkobnVsbCwgYXJncyk7XG59O1xuXG4vLyBSRkMgc3BlY2lmaWVkIG9yZGVyXG4vLyBUT0RPOiBleHRlbmQgdGhpcyB3aXRoIGFsbCB0aGUgcmVzdFxudmFyIGRlZmF1bHRPdXRlck9yZGVyID0gW1xuICAndicsICdvJywgJ3MnLCAnaScsXG4gICd1JywgJ2UnLCAncCcsICdjJyxcbiAgJ2InLCAndCcsICdyJywgJ3onLCAnYSdcbl07XG52YXIgZGVmYXVsdElubmVyT3JkZXIgPSBbJ2knLCAnYycsICdiJywgJ2EnXTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChzZXNzaW9uLCBvcHRzKSB7XG4gIG9wdHMgPSBvcHRzIHx8IHt9O1xuICAvLyBlbnN1cmUgY2VydGFpbiBwcm9wZXJ0aWVzIGV4aXN0XG4gIGlmIChzZXNzaW9uLnZlcnNpb24gPT0gbnVsbCkge1xuICAgIHNlc3Npb24udmVyc2lvbiA9IDA7IC8vIFwidj0wXCIgbXVzdCBiZSB0aGVyZSAob25seSBkZWZpbmVkIHZlcnNpb24gYXRtKVxuICB9XG4gIGlmIChzZXNzaW9uLm5hbWUgPT0gbnVsbCkge1xuICAgIHNlc3Npb24ubmFtZSA9IFwiIFwiOyAvLyBcInM9IFwiIG11c3QgYmUgdGhlcmUgaWYgbm8gbWVhbmluZ2Z1bCBuYW1lIHNldFxuICB9XG4gIHNlc3Npb24ubWVkaWEuZm9yRWFjaChmdW5jdGlvbiAobUxpbmUpIHtcbiAgICBpZiAobUxpbmUucGF5bG9hZHMgPT0gbnVsbCkge1xuICAgICAgbUxpbmUucGF5bG9hZHMgPSBcIlwiO1xuICAgIH1cbiAgfSk7XG5cbiAgdmFyIG91dGVyT3JkZXIgPSBvcHRzLm91dGVyT3JkZXIgfHwgZGVmYXVsdE91dGVyT3JkZXI7XG4gIHZhciBpbm5lck9yZGVyID0gb3B0cy5pbm5lck9yZGVyIHx8IGRlZmF1bHRJbm5lck9yZGVyO1xuICB2YXIgc2RwID0gW107XG5cbiAgLy8gbG9vcCB0aHJvdWdoIG91dGVyT3JkZXIgZm9yIG1hdGNoaW5nIHByb3BlcnRpZXMgb24gc2Vzc2lvblxuICBvdXRlck9yZGVyLmZvckVhY2goZnVuY3Rpb24gKHR5cGUpIHtcbiAgICBncmFtbWFyW3R5cGVdLmZvckVhY2goZnVuY3Rpb24gKG9iaikge1xuICAgICAgaWYgKG9iai5uYW1lIGluIHNlc3Npb24gJiYgc2Vzc2lvbltvYmoubmFtZV0gIT0gbnVsbCkge1xuICAgICAgICBzZHAucHVzaChtYWtlTGluZSh0eXBlLCBvYmosIHNlc3Npb24pKTtcbiAgICAgIH1cbiAgICAgIGVsc2UgaWYgKG9iai5wdXNoIGluIHNlc3Npb24gJiYgc2Vzc2lvbltvYmoucHVzaF0gIT0gbnVsbCkge1xuICAgICAgICBzZXNzaW9uW29iai5wdXNoXS5mb3JFYWNoKGZ1bmN0aW9uIChlbCkge1xuICAgICAgICAgIHNkcC5wdXNoKG1ha2VMaW5lKHR5cGUsIG9iaiwgZWwpKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xuXG4gIC8vIHRoZW4gZm9yIGVhY2ggbWVkaWEgbGluZSwgZm9sbG93IHRoZSBpbm5lck9yZGVyXG4gIHNlc3Npb24ubWVkaWEuZm9yRWFjaChmdW5jdGlvbiAobUxpbmUpIHtcbiAgICBzZHAucHVzaChtYWtlTGluZSgnbScsIGdyYW1tYXIubVswXSwgbUxpbmUpKTtcblxuICAgIGlubmVyT3JkZXIuZm9yRWFjaChmdW5jdGlvbiAodHlwZSkge1xuICAgICAgZ3JhbW1hclt0eXBlXS5mb3JFYWNoKGZ1bmN0aW9uIChvYmopIHtcbiAgICAgICAgaWYgKG9iai5uYW1lIGluIG1MaW5lICYmIG1MaW5lW29iai5uYW1lXSAhPSBudWxsKSB7XG4gICAgICAgICAgc2RwLnB1c2gobWFrZUxpbmUodHlwZSwgb2JqLCBtTGluZSkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKG9iai5wdXNoIGluIG1MaW5lICYmIG1MaW5lW29iai5wdXNoXSAhPSBudWxsKSB7XG4gICAgICAgICAgbUxpbmVbb2JqLnB1c2hdLmZvckVhY2goZnVuY3Rpb24gKGVsKSB7XG4gICAgICAgICAgICBzZHAucHVzaChtYWtlTGluZSh0eXBlLCBvYmosIGVsKSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICByZXR1cm4gc2RwLmpvaW4oJ1xcclxcbicpICsgJ1xcclxcbic7XG59O1xuIiwiLyogQ29weXJpZ2h0IEAgMjAxNSBBdGxhc3NpYW4gUHR5IEx0ZFxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGFycmF5RXF1YWxzKGFycmF5KSB7XG4gICAgLy8gaWYgdGhlIG90aGVyIGFycmF5IGlzIGEgZmFsc3kgdmFsdWUsIHJldHVyblxuICAgIGlmICghYXJyYXkpXG4gICAgICAgIHJldHVybiBmYWxzZTtcblxuICAgIC8vIGNvbXBhcmUgbGVuZ3RocyAtIGNhbiBzYXZlIGEgbG90IG9mIHRpbWVcbiAgICBpZiAodGhpcy5sZW5ndGggIT0gYXJyYXkubGVuZ3RoKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgbCA9IHRoaXMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgIC8vIENoZWNrIGlmIHdlIGhhdmUgbmVzdGVkIGFycmF5c1xuICAgICAgICBpZiAodGhpc1tpXSBpbnN0YW5jZW9mIEFycmF5ICYmIGFycmF5W2ldIGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICAgICAgICAgIC8vIHJlY3Vyc2UgaW50byB0aGUgbmVzdGVkIGFycmF5c1xuICAgICAgICAgICAgaWYgKCFhcnJheUVxdWFscy5hcHBseSh0aGlzW2ldLCBbYXJyYXlbaV1dKSlcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpc1tpXSAhPSBhcnJheVtpXSkge1xuICAgICAgICAgICAgLy8gV2FybmluZyAtIHR3byBkaWZmZXJlbnQgb2JqZWN0IGluc3RhbmNlcyB3aWxsIG5ldmVyIGJlIGVxdWFsOlxuICAgICAgICAgICAgLy8ge3g6MjB9ICE9IHt4OjIwfVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufTtcblxuIiwiLyogQ29weXJpZ2h0IEAgMjAxNSBBdGxhc3NpYW4gUHR5IEx0ZFxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG5leHBvcnRzLkludGVyb3AgPSByZXF1aXJlKCcuL2ludGVyb3AnKTtcbiIsIi8qIENvcHlyaWdodCBAIDIwMTUgQXRsYXNzaWFuIFB0eSBMdGRcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuLyogZ2xvYmFsIFJUQ1Nlc3Npb25EZXNjcmlwdGlvbiAqL1xuLyogZ2xvYmFsIFJUQ0ljZUNhbmRpZGF0ZSAqL1xuLyoganNoaW50IC1XMDk3ICovXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIHRyYW5zZm9ybSA9IHJlcXVpcmUoJy4vdHJhbnNmb3JtJyk7XG52YXIgYXJyYXlFcXVhbHMgPSByZXF1aXJlKCcuL2FycmF5LWVxdWFscycpO1xuXG5mdW5jdGlvbiBJbnRlcm9wKCkge1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBtYXAgaG9sZHMgdGhlIG1vc3QgcmVjZW50IFVuaWZpZWQgUGxhbiBvZmZlci9hbnN3ZXIgU0RQIHRoYXQgd2FzXG4gICAgICogY29udmVydGVkIHRvIFBsYW4gQiwgd2l0aCB0aGUgU0RQIHR5cGUgKCdvZmZlcicgb3IgJ2Fuc3dlcicpIGFzIGtleXMgYW5kXG4gICAgICogdGhlIFNEUCBzdHJpbmcgYXMgdmFsdWVzLlxuICAgICAqXG4gICAgICogQHR5cGUge3t9fVxuICAgICAqL1xuICAgIHRoaXMuY2FjaGUgPSB7XG4gICAgICAgIG1sQjJVTWFwIDoge30sXG4gICAgICAgIG1sVTJCTWFwIDoge31cbiAgICB9O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IEludGVyb3A7XG5cbi8qKlxuICogQ2hhbmdlcyB0aGUgY2FuZGlkYXRlIGFyZ3MgdG8gbWF0Y2ggd2l0aCB0aGUgcmVsYXRlZCBVbmlmaWVkIFBsYW5cbiAqL1xuSW50ZXJvcC5wcm90b3R5cGUuY2FuZGlkYXRlVG9VbmlmaWVkUGxhbiA9IGZ1bmN0aW9uKGNhbmRpZGF0ZSkge1xuICAgIHZhciBjYW5kID0gbmV3IFJUQ0ljZUNhbmRpZGF0ZShjYW5kaWRhdGUpO1xuXG4gICAgY2FuZC5zZHBNTGluZUluZGV4ID0gdGhpcy5jYWNoZS5tbEIyVU1hcFtjYW5kLnNkcE1MaW5lSW5kZXhdO1xuICAgIC8qIFRPRE86IGNoYW5nZSBzZHBNaWQgdG8gKGF1ZGlvfHZpZGVvKS1TU1JDICovXG5cbiAgICByZXR1cm4gY2FuZDtcbn07XG5cbi8qKlxuICogQ2hhbmdlcyB0aGUgY2FuZGlkYXRlIGFyZ3MgdG8gbWF0Y2ggd2l0aCB0aGUgcmVsYXRlZCBQbGFuIEJcbiAqL1xuSW50ZXJvcC5wcm90b3R5cGUuY2FuZGlkYXRlVG9QbGFuQiA9IGZ1bmN0aW9uKGNhbmRpZGF0ZSkge1xuICAgIHZhciBjYW5kID0gbmV3IFJUQ0ljZUNhbmRpZGF0ZShjYW5kaWRhdGUpO1xuXG4gICAgaWYgKGNhbmQuc2RwTWlkLmluZGV4T2YoJ2F1ZGlvJykgPT09IDApIHtcbiAgICAgIGNhbmQuc2RwTWlkID0gJ2F1ZGlvJztcbiAgICB9IGVsc2UgaWYgKGNhbmQuc2RwTWlkLmluZGV4T2YoJ3ZpZGVvJykgPT09IDApIHtcbiAgICAgIGNhbmQuc2RwTWlkID0gJ3ZpZGVvJztcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5kaWRhdGUgd2l0aCAnICsgY2FuZC5zZHBNaWQgKyAnIG5vdCBhbGxvd2VkJyk7XG4gICAgfVxuXG4gICAgY2FuZC5zZHBNTGluZUluZGV4ID0gdGhpcy5jYWNoZS5tbFUyQk1hcFtjYW5kLnNkcE1MaW5lSW5kZXhdO1xuXG4gICAgcmV0dXJuIGNhbmQ7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGluZGV4IG9mIHRoZSBmaXJzdCBtLWxpbmUgd2l0aCB0aGUgZ2l2ZW4gbWVkaWEgdHlwZSBhbmQgd2l0aCBhXG4gKiBkaXJlY3Rpb24gd2hpY2ggYWxsb3dzIHNlbmRpbmcsIGluIHRoZSBsYXN0IFVuaWZpZWQgUGxhbiBkZXNjcmlwdGlvbiB3aXRoXG4gKiB0eXBlIFwiYW5zd2VyXCIgY29udmVydGVkIHRvIFBsYW4gQi4gUmV0dXJucyB7bnVsbH0gaWYgdGhlcmUgaXMgbm8gc2F2ZWRcbiAqIGFuc3dlciwgb3IgaWYgbm9uZSBvZiBpdHMgbS1saW5lcyB3aXRoIHRoZSBnaXZlbiB0eXBlIGFsbG93IHNlbmRpbmcuXG4gKiBAcGFyYW0gdHlwZSB0aGUgbWVkaWEgdHlwZSAoXCJhdWRpb1wiIG9yIFwidmlkZW9cIikuXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuSW50ZXJvcC5wcm90b3R5cGUuZ2V0Rmlyc3RTZW5kaW5nSW5kZXhGcm9tQW5zd2VyID0gZnVuY3Rpb24odHlwZSkge1xuICAgIGlmICghdGhpcy5jYWNoZS5hbnN3ZXIpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgdmFyIHNlc3Npb24gPSB0cmFuc2Zvcm0ucGFyc2UodGhpcy5jYWNoZS5hbnN3ZXIpO1xuICAgIGlmIChzZXNzaW9uICYmIHNlc3Npb24ubWVkaWEgJiYgQXJyYXkuaXNBcnJheShzZXNzaW9uLm1lZGlhKSl7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2Vzc2lvbi5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKHNlc3Npb24ubWVkaWFbaV0udHlwZSA9PSB0eXBlICYmXG4gICAgICAgICAgICAgICAgKCFzZXNzaW9uLm1lZGlhW2ldLmRpcmVjdGlvbiAvKiBkZWZhdWx0IHRvIHNlbmRyZWN2ICovIHx8XG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb24ubWVkaWFbaV0uZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnIHx8XG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb24ubWVkaWFbaV0uZGlyZWN0aW9uID09PSAnc2VuZG9ubHknKSl7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2QgdHJhbnNmb3JtcyBhIFVuaWZpZWQgUGxhbiBTRFAgdG8gYW4gZXF1aXZhbGVudCBQbGFuIEIgU0RQLiBBXG4gKiBQZWVyQ29ubmVjdGlvbiB3cmFwcGVyIHRyYW5zZm9ybXMgdGhlIFNEUCB0byBQbGFuIEIgYmVmb3JlIHBhc3NpbmcgaXQgdG8gdGhlXG4gKiBhcHBsaWNhdGlvbi5cbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cbkludGVyb3AucHJvdG90eXBlLnRvUGxhbkIgPSBmdW5jdGlvbihkZXNjKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIC8vI3JlZ2lvbiBQcmVsaW1pbmFyeSBpbnB1dCB2YWxpZGF0aW9uLlxuXG4gICAgaWYgKHR5cGVvZiBkZXNjICE9PSAnb2JqZWN0JyB8fCBkZXNjID09PSBudWxsIHx8XG4gICAgICAgIHR5cGVvZiBkZXNjLnNkcCAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdBbiBlbXB0eSBkZXNjcmlwdGlvbiB3YXMgcGFzc2VkIGFzIGFuIGFyZ3VtZW50LicpO1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICAvLyBPYmplY3RpZnkgdGhlIFNEUCBmb3IgZWFzaWVyIG1hbmlwdWxhdGlvbi5cbiAgICB2YXIgc2Vzc2lvbiA9IHRyYW5zZm9ybS5wYXJzZShkZXNjLnNkcCk7XG5cbiAgICAvLyBJZiB0aGUgU0RQIGNvbnRhaW5zIG5vIG1lZGlhLCB0aGVyZSdzIG5vdGhpbmcgdG8gdHJhbnNmb3JtLlxuICAgIGlmICh0eXBlb2Ygc2Vzc2lvbi5tZWRpYSA9PT0gJ3VuZGVmaW5lZCcgfHxcbiAgICAgICAgIUFycmF5LmlzQXJyYXkoc2Vzc2lvbi5tZWRpYSkgfHwgc2Vzc2lvbi5tZWRpYS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdUaGUgZGVzY3JpcHRpb24gaGFzIG5vIG1lZGlhLicpO1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICAvLyBUcnkgc29tZSBoZXVyaXN0aWNzIHRvIFwibWFrZSBzdXJlXCIgdGhpcyBpcyBhIFVuaWZpZWQgUGxhbiBTRFAuIFBsYW4gQlxuICAgIC8vIFNEUCBoYXMgYSB2aWRlbywgYW4gYXVkaW8gYW5kIGEgZGF0YSBcImNoYW5uZWxcIiBhdCBtb3N0LlxuICAgIGlmIChzZXNzaW9uLm1lZGlhLmxlbmd0aCA8PSAzICYmIHNlc3Npb24ubWVkaWEuZXZlcnkoZnVuY3Rpb24obSkge1xuICAgICAgICAgICAgcmV0dXJuIFsndmlkZW8nLCAnYXVkaW8nLCAnZGF0YSddLmluZGV4T2YobS5taWQpICE9PSAtMTtcbiAgICAgICAgfSkpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdUaGlzIGRlc2NyaXB0aW9uIGRvZXMgbm90IGxvb2sgbGlrZSBVbmlmaWVkIFBsYW4uJyk7XG4gICAgICAgIHJldHVybiBkZXNjO1xuICAgIH1cblxuICAgIC8vI2VuZHJlZ2lvblxuXG4gICAgLy8gSEFDSyBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD0xMTEzNDQzXG4gICAgdmFyIHNkcCA9IGRlc2Muc2RwO1xuICAgIHZhciByZXdyaXRlID0gZmFsc2U7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzZXNzaW9uLm1lZGlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciB1TGluZSA9IHNlc3Npb24ubWVkaWFbaV07XG4gICAgICAgIHVMaW5lLnJ0cC5mb3JFYWNoKGZ1bmN0aW9uKHJ0cCkge1xuICAgICAgICAgICAgaWYgKHJ0cC5jb2RlYyA9PT0gJ05VTEwnKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHJld3JpdGUgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHZhciBvZmZlciA9IHRyYW5zZm9ybS5wYXJzZShzZWxmLmNhY2hlLm9mZmVyKTtcbiAgICAgICAgICAgICAgICBydHAuY29kZWMgPSBvZmZlci5tZWRpYVtpXS5ydHBbMF0uY29kZWM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBpZiAocmV3cml0ZSkge1xuICAgICAgICBzZHAgPSB0cmFuc2Zvcm0ud3JpdGUoc2Vzc2lvbik7XG4gICAgfVxuXG4gICAgLy8gVW5pZmllZCBQbGFuIFNEUCBpcyBvdXIgXCJwcmVjaW91c1wiLiBDYWNoZSBpdCBmb3IgbGF0ZXIgdXNlIGluIHRoZSBQbGFuIEJcbiAgICAvLyAtPiBVbmlmaWVkIFBsYW4gdHJhbnNmb3JtYXRpb24uXG4gICAgdGhpcy5jYWNoZVtkZXNjLnR5cGVdID0gc2RwO1xuXG4gICAgLy8jcmVnaW9uIENvbnZlcnQgZnJvbSBVbmlmaWVkIFBsYW4gdG8gUGxhbiBCLlxuXG4gICAgLy8gV2UgcmVidWlsZCB0aGUgc2Vzc2lvbi5tZWRpYSBhcnJheS5cbiAgICB2YXIgbWVkaWEgPSBzZXNzaW9uLm1lZGlhO1xuICAgIHNlc3Npb24ubWVkaWEgPSBbXTtcblxuICAgIC8vIEFzc29jaWF0aXZlIGFycmF5IHRoYXQgbWFwcyBjaGFubmVsIHR5cGVzIHRvIGNoYW5uZWwgb2JqZWN0cyBmb3IgZmFzdFxuICAgIC8vIGFjY2VzcyB0byBjaGFubmVsIG9iamVjdHMgYnkgdGhlaXIgdHlwZSwgZS5nLiB0eXBlMmJsWydhdWRpbyddLT5jaGFubmVsXG4gICAgLy8gb2JqLlxuICAgIHZhciB0eXBlMmJsID0ge307XG5cbiAgICAvLyBVc2VkIHRvIGJ1aWxkIHRoZSBncm91cDpCVU5ETEUgdmFsdWUgYWZ0ZXIgdGhlIGNoYW5uZWxzIGNvbnN0cnVjdGlvblxuICAgIC8vIGxvb3AuXG4gICAgdmFyIHR5cGVzID0gW107XG5cbiAgICBtZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKHVMaW5lKSB7XG4gICAgICAgIC8vIHJ0Y3AtbXV4IGlzIHJlcXVpcmVkIGluIHRoZSBQbGFuIEIgU0RQLlxuICAgICAgICBpZiAoKHR5cGVvZiB1TGluZS5ydGNwTXV4ICE9PSAnc3RyaW5nJyB8fFxuICAgICAgICAgICAgdUxpbmUucnRjcE11eCAhPT0gJ3J0Y3AtbXV4JykgJiZcbiAgICAgICAgICAgIHVMaW5lLmRpcmVjdGlvbiAhPT0gJ2luYWN0aXZlJykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgY29udmVydCB0byBQbGFuIEIgYmVjYXVzZSBtLWxpbmVzICcgK1xuICAgICAgICAgICAgICAgICd3aXRob3V0IHRoZSBydGNwLW11eCBhdHRyaWJ1dGUgd2VyZSBmb3VuZC4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIHdlIGRvbid0IGhhdmUgYSBjaGFubmVsIGZvciB0aGlzIHVMaW5lLnR5cGUgT1IgdGhlIHNlbGVjdGVkIGlzXG4gICAgICAgIC8vIGluYWN0aXZlLCB0aGVuIHNlbGVjdCB0aGlzIHVMaW5lIGFzIHRoZSBjaGFubmVsIGJhc2lzLlxuICAgICAgICBpZiAodHlwZW9mIHR5cGUyYmxbdUxpbmUudHlwZV0gPT09ICd1bmRlZmluZWQnIHx8XG4gICAgICAgICAgICB0eXBlMmJsW3VMaW5lLnR5cGVdLmRpcmVjdGlvbiA9PT0gJ2luYWN0aXZlJykge1xuICAgICAgICAgICAgdHlwZTJibFt1TGluZS50eXBlXSA9IHVMaW5lO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHVMaW5lLnByb3RvY29sICE9IHR5cGUyYmxbdUxpbmUudHlwZV0ucHJvdG9jb2wpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBjb252ZXJ0IHRvIFBsYW4gQiBiZWNhdXNlIG0tbGluZXMgJyArXG4gICAgICAgICAgICAgICdoYXZlIGRpZmZlcmVudCBwcm90b2NvbHMgYW5kIHRoaXMgbGlicmFyeSBkb2VzIG5vdCBoYXZlICcgK1xuICAgICAgICAgICAgICAnc3VwcG9ydCBmb3IgdGhhdCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHVMaW5lLnBheWxvYWRzICE9IHR5cGUyYmxbdUxpbmUudHlwZV0ucGF5bG9hZHMpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBjb252ZXJ0IHRvIFBsYW4gQiBiZWNhdXNlIG0tbGluZXMgJyArXG4gICAgICAgICAgICAgICdoYXZlIGRpZmZlcmVudCBwYXlsb2FkcyBhbmQgdGhpcyBsaWJyYXJ5IGRvZXMgbm90IGhhdmUgJyArXG4gICAgICAgICAgICAgICdzdXBwb3J0IGZvciB0aGF0Jyk7XG4gICAgICAgIH1cblxuICAgIH0pO1xuXG4gICAgLy8gSW1wbG9kZSB0aGUgVW5pZmllZCBQbGFuIG0tbGluZXMvdHJhY2tzIGludG8gUGxhbiBCIGNoYW5uZWxzLlxuICAgIG1lZGlhLmZvckVhY2goZnVuY3Rpb24odUxpbmUpIHtcbiAgICAgICAgaWYgKHVMaW5lLnR5cGUgPT09ICdhcHBsaWNhdGlvbicpIHtcbiAgICAgICAgICAgIHNlc3Npb24ubWVkaWEucHVzaCh1TGluZSk7XG4gICAgICAgICAgICB0eXBlcy5wdXNoKHVMaW5lLm1pZCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBZGQgc291cmNlcyB0byB0aGUgY2hhbm5lbCBhbmQgaGFuZGxlIGE9bXNpZC5cbiAgICAgICAgaWYgKHR5cGVvZiB1TGluZS5zb3VyY2VzID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgT2JqZWN0LmtleXModUxpbmUuc291cmNlcykuZm9yRWFjaChmdW5jdGlvbihzc3JjKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB0eXBlMmJsW3VMaW5lLnR5cGVdLnNvdXJjZXMgIT09ICdvYmplY3QnKVxuICAgICAgICAgICAgICAgICAgICB0eXBlMmJsW3VMaW5lLnR5cGVdLnNvdXJjZXMgPSB7fTtcblxuICAgICAgICAgICAgICAgIC8vIEFzc2lnbiB0aGUgc291cmNlcyB0byB0aGUgY2hhbm5lbC5cbiAgICAgICAgICAgICAgICB0eXBlMmJsW3VMaW5lLnR5cGVdLnNvdXJjZXNbc3NyY10gPVxuICAgICAgICAgICAgICAgICAgICB1TGluZS5zb3VyY2VzW3NzcmNdO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB1TGluZS5tc2lkICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgICAgICAvLyBJbiBQbGFuIEIgdGhlIG1zaWQgaXMgYW4gU1NSQyBhdHRyaWJ1dGUuIEFsc28sIHdlIGRvbid0XG4gICAgICAgICAgICAgICAgICAgIC8vIGNhcmUgYWJvdXQgdGhlIG9ic29sZXRlIGxhYmVsIGFuZCBtc2xhYmVsIGF0dHJpYnV0ZXMuXG4gICAgICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgICAgIC8vIE5vdGUgdGhhdCBpdCBpcyBub3QgZ3VhcmFudGVlZCB0aGF0IHRoZSB1TGluZSB3aWxsXG4gICAgICAgICAgICAgICAgICAgIC8vIGhhdmUgYW4gbXNpZC4gcmVjdm9ubHkgY2hhbm5lbHMgaW4gcGFydGljdWxhciBkb24ndCBoYXZlXG4gICAgICAgICAgICAgICAgICAgIC8vIG9uZS5cbiAgICAgICAgICAgICAgICAgICAgdHlwZTJibFt1TGluZS50eXBlXS5zb3VyY2VzW3NzcmNdLm1zaWQgPVxuICAgICAgICAgICAgICAgICAgICAgICAgdUxpbmUubXNpZDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gTk9URSBzc3JjcyBpbiBzc3JjIGdyb3VwcyB3aWxsIHNoYXJlIG1zaWRzLCBhc1xuICAgICAgICAgICAgICAgIC8vIGRyYWZ0LXViZXJ0aS1ydGN3ZWItcGxhbi0wMCBtYW5kYXRlcy5cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQWRkIHNzcmMgZ3JvdXBzIHRvIHRoZSBjaGFubmVsLlxuICAgICAgICBpZiAodHlwZW9mIHVMaW5lLnNzcmNHcm91cHMgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICAgICAgQXJyYXkuaXNBcnJheSh1TGluZS5zc3JjR3JvdXBzKSkge1xuXG4gICAgICAgICAgICAvLyBDcmVhdGUgdGhlIHNzcmNHcm91cHMgYXJyYXksIGlmIGl0J3Mgbm90IGRlZmluZWQuXG4gICAgICAgICAgICBpZiAodHlwZW9mIHR5cGUyYmxbdUxpbmUudHlwZV0uc3NyY0dyb3VwcyA9PT0gJ3VuZGVmaW5lZCcgfHxcbiAgICAgICAgICAgICAgICAgICAgIUFycmF5LmlzQXJyYXkodHlwZTJibFt1TGluZS50eXBlXS5zc3JjR3JvdXBzKSkge1xuICAgICAgICAgICAgICAgIHR5cGUyYmxbdUxpbmUudHlwZV0uc3NyY0dyb3VwcyA9IFtdO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0eXBlMmJsW3VMaW5lLnR5cGVdLnNzcmNHcm91cHMgPVxuICAgICAgICAgICAgICAgIHR5cGUyYmxbdUxpbmUudHlwZV0uc3NyY0dyb3Vwcy5jb25jYXQoXG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLnNzcmNHcm91cHMpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGUyYmxbdUxpbmUudHlwZV0gPT09IHVMaW5lKSB7XG4gICAgICAgICAgICAvLyBQbGFuIEIgbWlkcyBhcmUgaW4gWydhdWRpbycsICd2aWRlbycsICdkYXRhJ11cbiAgICAgICAgICAgIHVMaW5lLm1pZCA9IHVMaW5lLnR5cGU7XG5cbiAgICAgICAgICAgIC8vIFBsYW4gQiBkb2Vzbid0IHN1cHBvcnQvbmVlZCB0aGUgYnVuZGxlLW9ubHkgYXR0cmlidXRlLlxuICAgICAgICAgICAgZGVsZXRlIHVMaW5lLmJ1bmRsZU9ubHk7XG5cbiAgICAgICAgICAgIC8vIEluIFBsYW4gQiB0aGUgbXNpZCBpcyBhbiBTU1JDIGF0dHJpYnV0ZS5cbiAgICAgICAgICAgIGRlbGV0ZSB1TGluZS5tc2lkO1xuXG5cdCAgICBpZiAodUxpbmUudHlwZSA9PSBtZWRpYVswXS50eXBlKSB7XG5cdCAgICAgIHR5cGVzLnVuc2hpZnQodUxpbmUudHlwZSk7XG5cdCAgICAgIC8vIEFkZCB0aGUgY2hhbm5lbCB0byB0aGUgbmV3IG1lZGlhIGFycmF5LlxuXHQgICAgICBzZXNzaW9uLm1lZGlhLnVuc2hpZnQodUxpbmUpO1xuXHQgICAgfSBlbHNlIHtcblx0ICAgICAgdHlwZXMucHVzaCh1TGluZS50eXBlKTtcblx0ICAgICAgLy8gQWRkIHRoZSBjaGFubmVsIHRvIHRoZSBuZXcgbWVkaWEgYXJyYXkuXG5cdCAgICAgIHNlc3Npb24ubWVkaWEucHVzaCh1TGluZSk7XG5cdCAgICB9XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIGlmICh0eXBlb2Ygc2Vzc2lvbi5ncm91cHMgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAvLyBXZSByZWdlbmVyYXRlIHRoZSBCVU5ETEUgZ3JvdXAgd2l0aCB0aGUgbmV3IG1pZHMuXG4gICAgICBzZXNzaW9uLmdyb3Vwcy5zb21lKGZ1bmN0aW9uKGdyb3VwKSB7XG5cdCAgaWYgKGdyb3VwLnR5cGUgPT09ICdCVU5ETEUnKSB7XG5cdCAgICAgIGdyb3VwLm1pZHMgPSB0eXBlcy5qb2luKCcgJyk7XG5cdCAgICAgIHJldHVybiB0cnVlO1xuXHQgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIG1zaWQgc2VtYW50aWNcbiAgICBzZXNzaW9uLm1zaWRTZW1hbnRpYyA9IHtcbiAgICAgICAgc2VtYW50aWM6ICdXTVMnLFxuICAgICAgICB0b2tlbjogJyonXG4gICAgfTtcblxuICAgIHZhciByZXNTdHIgPSB0cmFuc2Zvcm0ud3JpdGUoc2Vzc2lvbik7XG5cbiAgICByZXR1cm4gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICAgIHR5cGU6IGRlc2MudHlwZSxcbiAgICAgICAgc2RwOiByZXNTdHJcbiAgICB9KTtcblxuICAgIC8vI2VuZHJlZ2lvblxufTtcblxuLyogZm9sbG93IHJ1bGVzIGRlZmluZWQgaW4gUkZDNDE0NSAqL1xuZnVuY3Rpb24gYWRkU2V0dXBBdHRyKHVMaW5lKSB7XG4gICAgaWYgKHR5cGVvZiB1TGluZS5zZXR1cCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh1TGluZS5zZXR1cCA9PT0gXCJhY3RpdmVcIikge1xuICAgICAgICAgICAgdUxpbmUuc2V0dXAgPSBcInBhc3NpdmVcIjtcbiAgICB9IGVsc2UgaWYgKHVMaW5lLnNldHVwID09PSBcInBhc3NpdmVcIikge1xuICAgICAgICB1TGluZS5zZXR1cCA9IFwiYWN0aXZlXCI7XG4gICAgfVxufVxuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHRyYW5zZm9ybXMgYSBQbGFuIEIgU0RQIHRvIGFuIGVxdWl2YWxlbnQgVW5pZmllZCBQbGFuIFNEUC4gQVxuICogUGVlckNvbm5lY3Rpb24gd3JhcHBlciB0cmFuc2Zvcm1zIHRoZSBTRFAgdG8gVW5pZmllZCBQbGFuIGJlZm9yZSBwYXNzaW5nIGl0XG4gKiB0byBGRi5cbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cbkludGVyb3AucHJvdG90eXBlLnRvVW5pZmllZFBsYW4gPSBmdW5jdGlvbihkZXNjKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIC8vI3JlZ2lvbiBQcmVsaW1pbmFyeSBpbnB1dCB2YWxpZGF0aW9uLlxuXG4gICAgaWYgKHR5cGVvZiBkZXNjICE9PSAnb2JqZWN0JyB8fCBkZXNjID09PSBudWxsIHx8XG4gICAgICAgIHR5cGVvZiBkZXNjLnNkcCAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdBbiBlbXB0eSBkZXNjcmlwdGlvbiB3YXMgcGFzc2VkIGFzIGFuIGFyZ3VtZW50LicpO1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICB2YXIgc2Vzc2lvbiA9IHRyYW5zZm9ybS5wYXJzZShkZXNjLnNkcCk7XG5cbiAgICAvLyBJZiB0aGUgU0RQIGNvbnRhaW5zIG5vIG1lZGlhLCB0aGVyZSdzIG5vdGhpbmcgdG8gdHJhbnNmb3JtLlxuICAgIGlmICh0eXBlb2Ygc2Vzc2lvbi5tZWRpYSA9PT0gJ3VuZGVmaW5lZCcgfHxcbiAgICAgICAgIUFycmF5LmlzQXJyYXkoc2Vzc2lvbi5tZWRpYSkgfHwgc2Vzc2lvbi5tZWRpYS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdUaGUgZGVzY3JpcHRpb24gaGFzIG5vIG1lZGlhLicpO1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICAvLyBUcnkgc29tZSBoZXVyaXN0aWNzIHRvIFwibWFrZSBzdXJlXCIgdGhpcyBpcyBhIFBsYW4gQiBTRFAuIFBsYW4gQiBTRFAgaGFzXG4gICAgLy8gYSB2aWRlbywgYW4gYXVkaW8gYW5kIGEgZGF0YSBcImNoYW5uZWxcIiBhdCBtb3N0LlxuICAgIGlmIChzZXNzaW9uLm1lZGlhLmxlbmd0aCA+IDMgfHwgIXNlc3Npb24ubWVkaWEuZXZlcnkoZnVuY3Rpb24obSkge1xuICAgICAgICAgICAgcmV0dXJuIFsndmlkZW8nLCAnYXVkaW8nLCAnZGF0YSddLmluZGV4T2YobS5taWQpICE9PSAtMTtcbiAgICAgICAgfSkpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdUaGlzIGRlc2NyaXB0aW9uIGRvZXMgbm90IGxvb2sgbGlrZSBQbGFuIEIuJyk7XG4gICAgICAgIHJldHVybiBkZXNjO1xuICAgIH1cblxuICAgIC8vIE1ha2Ugc3VyZSB0aGlzIFBsYW4gQiBTRFAgY2FuIGJlIGNvbnZlcnRlZCB0byBhIFVuaWZpZWQgUGxhbiBTRFAuXG4gICAgdmFyIG1pZHMgPSBbXTtcbiAgICBzZXNzaW9uLm1lZGlhLmZvckVhY2goZnVuY3Rpb24obSkge1xuICAgICAgICBtaWRzLnB1c2gobS5taWQpO1xuICAgIH0pO1xuXG4gICAgdmFyIGhhc0J1bmRsZSA9IGZhbHNlO1xuICAgIGlmICh0eXBlb2Ygc2Vzc2lvbi5ncm91cHMgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgIEFycmF5LmlzQXJyYXkoc2Vzc2lvbi5ncm91cHMpKSB7XG4gICAgICAgIGhhc0J1bmRsZSA9IHNlc3Npb24uZ3JvdXBzLmV2ZXJ5KGZ1bmN0aW9uKGcpIHtcbiAgICAgICAgICAgIHJldHVybiBnLnR5cGUgIT09ICdCVU5ETEUnIHx8XG4gICAgICAgICAgICAgICAgYXJyYXlFcXVhbHMuYXBwbHkoZy5taWRzLnNvcnQoKSwgW21pZHMuc29ydCgpXSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICghaGFzQnVuZGxlKSB7XG4gICAgICAgIHZhciBtdXN0QmVCdW5kbGUgPSBmYWxzZTtcblxuICAgICAgICBzZXNzaW9uLm1lZGlhLmZvckVhY2goZnVuY3Rpb24obSkge1xuICAgICAgICAgICAgaWYgKG0uZGlyZWN0aW9uICE9PSAnaW5hY3RpdmUnKSB7XG4gICAgICAgICAgICAgICAgbXVzdEJlQnVuZGxlID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKG11c3RCZUJ1bmRsZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGNvbnZlcnQgdG8gVW5pZmllZCBQbGFuIGJlY2F1c2UgbS1saW5lcyB0aGF0XCIgK1xuICAgICAgICAgICAgICBcIiBhcmUgbm90IGJ1bmRsZWQgd2VyZSBmb3VuZC5cIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyNlbmRyZWdpb25cblxuXG4gICAgLy8jcmVnaW9uIENvbnZlcnQgZnJvbSBQbGFuIEIgdG8gVW5pZmllZCBQbGFuLlxuXG4gICAgLy8gVW5mb3J0dW5hdGVseSwgYSBQbGFuIEIgb2ZmZXIvYW5zd2VyIGRvZXNuJ3QgaGF2ZSBlbm91Z2ggaW5mb3JtYXRpb24gdG9cbiAgICAvLyByZWJ1aWxkIGFuIGVxdWl2YWxlbnQgVW5pZmllZCBQbGFuIG9mZmVyL2Fuc3dlci5cbiAgICAvL1xuICAgIC8vIEZvciBleGFtcGxlLCBpZiB0aGlzIGlzIGEgbG9jYWwgYW5zd2VyIChpbiBVbmlmaWVkIFBsYW4gc3R5bGUpIHRoYXQgd2VcbiAgICAvLyBjb252ZXJ0IHRvIFBsYW4gQiBwcmlvciB0byBoYW5kaW5nIGl0IG92ZXIgdG8gdGhlIGFwcGxpY2F0aW9uICh0aGVcbiAgICAvLyBQZWVyQ29ubmVjdGlvbiB3cmFwcGVyIGNhbGxlZCB1cywgZm9yIGluc3RhbmNlLCBhZnRlciBhIHN1Y2Nlc3NmdWxcbiAgICAvLyBjcmVhdGVBbnN3ZXIpLCB3ZSB3YW50IHRvIHJlbWVtYmVyIHRoZSBtLWxpbmUgYXQgd2hpY2ggd2UndmUgc2VlbiB0aGVcbiAgICAvLyAobG9jYWwpIFNTUkMuIFRoYXQncyBiZWNhdXNlIHdoZW4gdGhlIGFwcGxpY2F0aW9uIHdhbnRzIHRvIGRvIGNhbGwgdGhlXG4gICAgLy8gU0xEIG1ldGhvZCwgZm9yY2luZyB1cyB0byBkbyB0aGUgaW52ZXJzZSB0cmFuc2Zvcm1hdGlvbiAoZnJvbSBQbGFuIEIgdG9cbiAgICAvLyBVbmlmaWVkIFBsYW4pLCB3ZSBuZWVkIHRvIGtub3cgdG8gd2hpY2ggbS1saW5lIHRvIGFzc2lnbiB0aGUgKGxvY2FsKVxuICAgIC8vIFNTUkMuIFdlIGFsc28gbmVlZCB0byBrbm93IGFsbCB0aGUgb3RoZXIgbS1saW5lcyB0aGF0IHRoZSBvcmlnaW5hbFxuICAgIC8vIGFuc3dlciBoYWQgYW5kIGluY2x1ZGUgdGhlbSBpbiB0aGUgdHJhbnNmb3JtZWQgYW5zd2VyIGFzIHdlbGwuXG4gICAgLy9cbiAgICAvLyBBbm90aGVyIGV4YW1wbGUgaXMgaWYgdGhpcyBpcyBhIHJlbW90ZSBvZmZlciB0aGF0IHdlIGNvbnZlcnQgdG8gUGxhbiBCXG4gICAgLy8gcHJpb3IgdG8gZ2l2aW5nIGl0IHRvIHRoZSBhcHBsaWNhdGlvbiwgd2Ugd2FudCB0byByZW1lbWJlciB0aGUgbWlkIGF0XG4gICAgLy8gd2hpY2ggd2UndmUgc2VlbiB0aGUgKHJlbW90ZSkgU1NSQy5cbiAgICAvL1xuICAgIC8vIEluIHRoZSBpdGVyYXRpb24gdGhhdCBmb2xsb3dzLCB3ZSB1c2UgdGhlIGNhY2hlZCBVbmlmaWVkIFBsYW4gKGlmIGl0XG4gICAgLy8gZXhpc3RzKSB0byBhc3NpZ24gbWlkcyB0byBzc3Jjcy5cblxuICAgIHZhciB0eXBlO1xuICAgIGlmIChkZXNjLnR5cGUgPT09ICdhbnN3ZXInKSB7XG4gICAgICAgIHR5cGUgPSAnb2ZmZXInO1xuICAgIH0gZWxzZSBpZiAoZGVzYy50eXBlID09PSAnb2ZmZXInKSB7XG4gICAgICAgIHR5cGUgPSAnYW5zd2VyJztcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUeXBlICdcIiArIGRlc2MudHlwZSArIFwiJyBub3Qgc3VwcG9ydGVkLlwiKTtcbiAgICB9XG5cbiAgICB2YXIgY2FjaGVkO1xuICAgIGlmICh0eXBlb2YgdGhpcy5jYWNoZVt0eXBlXSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgY2FjaGVkID0gdHJhbnNmb3JtLnBhcnNlKHRoaXMuY2FjaGVbdHlwZV0pO1xuICAgIH1cblxuICAgIHZhciByZWN2b25seVNzcmNzID0ge1xuICAgICAgICBhdWRpbzoge30sXG4gICAgICAgIHZpZGVvOiB7fVxuICAgIH07XG5cbiAgICAvLyBBIGhlbHBlciBtYXAgdGhhdCBzZW5kcyBtaWRzIHRvIG0tbGluZSBvYmplY3RzLiBXZSB1c2UgaXQgbGF0ZXIgdG9cbiAgICAvLyByZWJ1aWxkIHRoZSBVbmlmaWVkIFBsYW4gc3R5bGUgc2Vzc2lvbi5tZWRpYSBhcnJheS5cbiAgICB2YXIgbWlkMnVsID0ge307XG4gICAgdmFyIGJJZHggPSAwO1xuICAgIHZhciB1SWR4ID0gMDtcblxuICAgIHZhciBzb3VyY2VzMnVsID0ge307XG5cbiAgICB2YXIgY2FuZGlkYXRlcztcbiAgICB2YXIgaWNlVWZyYWc7XG4gICAgdmFyIGljZVB3ZDtcbiAgICB2YXIgZmluZ2VycHJpbnQ7XG4gICAgdmFyIHBheWxvYWRzID0ge307XG4gICAgdmFyIHJ0Y3BGYiA9IHt9O1xuICAgIHZhciBydHAgPSB7fTtcblxuICAgIHNlc3Npb24ubWVkaWEuZm9yRWFjaChmdW5jdGlvbihiTGluZSkge1xuICAgICAgICBpZiAoKHR5cGVvZiBiTGluZS5ydGNwTXV4ICE9PSAnc3RyaW5nJyB8fFxuICAgICAgICAgICAgYkxpbmUucnRjcE11eCAhPT0gJ3J0Y3AtbXV4JykgJiZcbiAgICAgICAgICAgIGJMaW5lLmRpcmVjdGlvbiAhPT0gJ2luYWN0aXZlJykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGNvbnZlcnQgdG8gVW5pZmllZCBQbGFuIGJlY2F1c2UgbS1saW5lcyBcIiArXG4gICAgICAgICAgICAgICAgXCJ3aXRob3V0IHRoZSBydGNwLW11eCBhdHRyaWJ1dGUgd2VyZSBmb3VuZC5cIik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYkxpbmUudHlwZSA9PT0gJ2FwcGxpY2F0aW9uJykge1xuICAgICAgICAgICAgbWlkMnVsW2JMaW5lLm1pZF0gPSBiTGluZTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFdpdGggcnRjcC1tdXggYW5kIGJ1bmRsZSBhbGwgdGhlIGNoYW5uZWxzIHNob3VsZCBoYXZlIHRoZSBzYW1lIElDRVxuICAgICAgICAvLyBzdHVmZi5cbiAgICAgICAgdmFyIHNvdXJjZXMgPSBiTGluZS5zb3VyY2VzO1xuICAgICAgICB2YXIgc3NyY0dyb3VwcyA9IGJMaW5lLnNzcmNHcm91cHM7XG4gICAgICAgIHZhciBwb3J0ID0gYkxpbmUucG9ydDtcblxuICAgICAgICAvKiBDaHJvbWUgYWRkcyBkaWZmZXJlbnQgY2FuZGlkYXRlcyBldmVuIHVzaW5nIGJ1bmRsZSwgc28gd2UgY29uY2F0IHRoZSBjYW5kaWRhdGVzIGxpc3QgKi9cbiAgICAgICAgaWYgKHR5cGVvZiBiTGluZS5jYW5kaWRhdGVzICE9ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGNhbmRpZGF0ZXMgIT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICBjYW5kaWRhdGVzID0gY2FuZGlkYXRlcy5jb25jYXQoYkxpbmUuY2FuZGlkYXRlcyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNhbmRpZGF0ZXMgPSBiTGluZS5jYW5kaWRhdGVzO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCh0eXBlb2YgaWNlVWZyYWcgIT0gJ3VuZGVmaW5lZCcpICYmICh0eXBlb2YgYkxpbmUuaWNlVWZyYWcgIT0gJ3VuZGVmaW5lZCcpICYmIChpY2VVZnJhZyAhPSBiTGluZS5pY2VVZnJhZykpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk9ubHkgQlVORExFIHN1cHBvcnRlZCwgaWNlVWZyYWcgbXVzdCBiZSB0aGUgc2FtZSBmb3IgYWxsIG0tbGluZXMuXFxuXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiXFx0TGFzdCBpY2VVZnJhZzogXCIgKyBpY2VVZnJhZyArIFwiXFxuXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiXFx0TmV3IGljZVVmcmFnOiBcIiArIGJMaW5lLmljZVVmcmFnXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBiTGluZS5pY2VVZnJhZyAhPSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIGljZVVmcmFnID0gYkxpbmUuaWNlVWZyYWc7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoKHR5cGVvZiBpY2VQd2QgIT0gJ3VuZGVmaW5lZCcpICYmICh0eXBlb2YgYkxpbmUuaWNlUHdkICE9ICd1bmRlZmluZWQnKSAmJiAoaWNlUHdkICE9IGJMaW5lLmljZVB3ZCkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk9ubHkgQlVORExFIHN1cHBvcnRlZCwgaWNlUHdkIG11c3QgYmUgdGhlIHNhbWUgZm9yIGFsbCBtLWxpbmVzLlxcblwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIlxcdExhc3QgaWNlUHdkOiBcIiArIGljZVB3ZCArIFwiXFxuXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiXFx0TmV3IGljZVB3ZDogXCIgKyBiTGluZS5pY2VQd2RcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIGJMaW5lLmljZVB3ZCAhPSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIGljZVB3ZCA9IGJMaW5lLmljZVB3ZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgodHlwZW9mIGZpbmdlcnByaW50ICE9ICd1bmRlZmluZWQnKSAmJiAodHlwZW9mIGJMaW5lLmZpbmdlcnByaW50ICE9ICd1bmRlZmluZWQnKSAmJlxuICAgICAgICAgICAgKGZpbmdlcnByaW50LnR5cGUgIT0gYkxpbmUuZmluZ2VycHJpbnQudHlwZSB8fCBmaW5nZXJwcmludC5oYXNoICE9IGJMaW5lLmZpbmdlcnByaW50Lmhhc2gpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJPbmx5IEJVTkRMRSBzdXBwb3J0ZWQsIGZpbmdlcnByaW50IG11c3QgYmUgdGhlIHNhbWUgZm9yIGFsbCBtLWxpbmVzLlxcblwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIlxcdExhc3QgZmluZ2VycHJpbnQ6IFwiICsgSlNPTi5zdHJpbmdpZnkoZmluZ2VycHJpbnQpICsgXCJcXG5cIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJcXHROZXcgZmluZ2VycHJpbnQ6IFwiICsgSlNPTi5zdHJpbmdpZnkoYkxpbmUuZmluZ2VycHJpbnQpXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBiTGluZS5maW5nZXJwcmludCAhPSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIGZpbmdlcnByaW50ID0gYkxpbmUuZmluZ2VycHJpbnQ7XG4gICAgICAgIH1cblxuICAgICAgICBwYXlsb2Fkc1tiTGluZS50eXBlXSA9IGJMaW5lLnBheWxvYWRzO1xuICAgICAgICBydGNwRmJbYkxpbmUudHlwZV0gPSBiTGluZS5ydGNwRmI7XG4gICAgICAgIHJ0cFtiTGluZS50eXBlXSA9IGJMaW5lLnJ0cDtcblxuICAgICAgICAvLyBpbnZlcnRlZCBzc3JjIGdyb3VwIG1hcFxuICAgICAgICB2YXIgc3NyYzJncm91cCA9IHt9O1xuICAgICAgICBpZiAodHlwZW9mIHNzcmNHcm91cHMgIT09ICd1bmRlZmluZWQnICYmIEFycmF5LmlzQXJyYXkoc3NyY0dyb3VwcykpIHtcbiAgICAgICAgICAgIHNzcmNHcm91cHMuZm9yRWFjaChmdW5jdGlvbiAoc3NyY0dyb3VwKSB7XG4gICAgICAgICAgICAgICAgLy8gWFhYIFRoaXMgbWlnaHQgYnJha2UgaWYgYW4gU1NSQyBpcyBpbiBtb3JlIHRoYW4gb25lIGdyb3VwXG4gICAgICAgICAgICAgICAgLy8gZm9yIHNvbWUgcmVhc29uLlxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygc3NyY0dyb3VwLnNzcmNzICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgICAgICAgICBBcnJheS5pc0FycmF5KHNzcmNHcm91cC5zc3JjcykpIHtcbiAgICAgICAgICAgICAgICAgICAgc3NyY0dyb3VwLnNzcmNzLmZvckVhY2goZnVuY3Rpb24gKHNzcmMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygc3NyYzJncm91cFtzc3JjXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzc3JjMmdyb3VwW3NzcmNdID0gW107XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHNzcmMyZ3JvdXBbc3NyY10ucHVzaChzc3JjR3JvdXApO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNzcmMgdG8gbS1saW5lIGluZGV4LlxuICAgICAgICB2YXIgc3NyYzJtbCA9IHt9O1xuXG4gICAgICAgIGlmICh0eXBlb2Ygc291cmNlcyA9PT0gJ29iamVjdCcpIHtcblxuICAgICAgICAgICAgLy8gV2UnbGwgdXNlIHRoZSBcImJMaW5lXCIgb2JqZWN0IGFzIGEgcHJvdG90eXBlIGZvciBlYWNoIG5ldyBcIm1MaW5lXCJcbiAgICAgICAgICAgIC8vIHRoYXQgd2UgY3JlYXRlLCBidXQgZmlyc3Qgd2UgbmVlZCB0byBjbGVhbiBpdCB1cCBhIGJpdC5cbiAgICAgICAgICAgIGRlbGV0ZSBiTGluZS5zb3VyY2VzO1xuICAgICAgICAgICAgZGVsZXRlIGJMaW5lLnNzcmNHcm91cHM7XG4gICAgICAgICAgICBkZWxldGUgYkxpbmUuY2FuZGlkYXRlcztcbiAgICAgICAgICAgIGRlbGV0ZSBiTGluZS5pY2VVZnJhZztcbiAgICAgICAgICAgIGRlbGV0ZSBiTGluZS5pY2VQd2Q7XG4gICAgICAgICAgICBkZWxldGUgYkxpbmUuZmluZ2VycHJpbnQ7XG4gICAgICAgICAgICBkZWxldGUgYkxpbmUucG9ydDtcbiAgICAgICAgICAgIGRlbGV0ZSBiTGluZS5taWQ7XG5cbiAgICAgICAgICAgIC8vIEV4cGxvZGUgdGhlIFBsYW4gQiBjaGFubmVsIHNvdXJjZXMgd2l0aCBvbmUgbS1saW5lIHBlciBzb3VyY2UuXG4gICAgICAgICAgICBPYmplY3Qua2V5cyhzb3VyY2VzKS5mb3JFYWNoKGZ1bmN0aW9uKHNzcmMpIHtcblxuICAgICAgICAgICAgICAgIC8vIFRoZSAodW5pZmllZCkgbS1saW5lIGZvciB0aGlzIFNTUkMuIFdlIGVpdGhlciBjcmVhdGUgaXQgZnJvbVxuICAgICAgICAgICAgICAgIC8vIHNjcmF0Y2ggb3IsIGlmIGl0J3MgYSBncm91cGVkIFNTUkMsIHdlIHJlLXVzZSBhIHJlbGF0ZWRcbiAgICAgICAgICAgICAgICAvLyBtbGluZS4gSW4gb3RoZXIgd29yZHMsIGlmIHRoZSBzb3VyY2UgaXMgZ3JvdXBlZCB3aXRoIGFub3RoZXJcbiAgICAgICAgICAgICAgICAvLyBzb3VyY2UsIHB1dCB0aGUgdHdvIHRvZ2V0aGVyIGluIHRoZSBzYW1lIG0tbGluZS5cbiAgICAgICAgICAgICAgICB2YXIgdUxpbmU7XG5cbiAgICAgICAgICAgICAgICAvLyBXZSBhc3N1bWUgaGVyZSB0aGF0IHdlIGFyZSB0aGUgYW5zd2VyZXIgaW4gdGhlIE8vQSwgc28gYW55XG4gICAgICAgICAgICAgICAgLy8gb2ZmZXJzIHdoaWNoIHdlIHRyYW5zbGF0ZSBjb21lIGZyb20gdGhlIHJlbW90ZSBzaWRlLCB3aGlsZVxuICAgICAgICAgICAgICAgIC8vIGFuc3dlcnMgYXJlIGxvY2FsLiBTbyB0aGUgY2hlY2sgYmVsb3cgaXMgdG8gbWFrZSB0aGF0IHdlXG4gICAgICAgICAgICAgICAgLy8gaGFuZGxlIHJlY2VpdmUtb25seSBTU1JDcyBpbiBhIHNwZWNpYWwgd2F5IG9ubHkgaWYgdGhleSBjb21lXG4gICAgICAgICAgICAgICAgLy8gZnJvbSB0aGUgcmVtb3RlIHNpZGUuXG4gICAgICAgICAgICAgICAgaWYgKGRlc2MudHlwZT09PSdvZmZlcicpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gV2Ugd2FudCB0byBkZXRlY3QgU1NSQ3Mgd2hpY2ggYXJlIHVzZWQgYnkgYSByZW1vdGUgcGVlclxuICAgICAgICAgICAgICAgICAgICAvLyBpbiBhbiBtLWxpbmUgd2l0aCBkaXJlY3Rpb249cmVjdm9ubHkgKGkuZS4gdGhleSBhcmVcbiAgICAgICAgICAgICAgICAgICAgLy8gYmVpbmcgdXNlZCBmb3IgUlRDUCBvbmx5KS5cbiAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyBpbmZvcm1hdGlvbiB3b3VsZCBoYXZlIGdvdHRlbiBsb3N0IGlmIHRoZSByZW1vdGVcbiAgICAgICAgICAgICAgICAgICAgLy8gcGVlciB1c2VkIFVuaWZpZWQgUGxhbiBhbmQgdGhlaXIgbG9jYWwgZGVzY3JpcHRpb24gd2FzXG4gICAgICAgICAgICAgICAgICAgIC8vIHRyYW5zbGF0ZWQgdG8gUGxhbiBCLiBTbyB3ZSB1c2UgdGhlIGxhY2sgb2YgYW4gTVNJRFxuICAgICAgICAgICAgICAgICAgICAvLyBhdHRyaWJ1dGUgdG8gZGVkdWNlIGEgXCJyZWNlaXZlIG9ubHlcIiBTU1JDLlxuICAgICAgICAgICAgICAgICAgICBpZiAoIXNvdXJjZXNbc3NyY10ubXNpZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVjdm9ubHlTc3Jjc1tiTGluZS50eXBlXVtzc3JjXSA9IHNvdXJjZXNbc3NyY107XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBSZWNlaXZlLW9ubHkgU1NSQ3MgbXVzdCBub3QgY3JlYXRlIG5ldyBtLWxpbmVzLiBXZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2lsbCBhc3NpZ24gdGhlbSB0byBhbiBleGlzdGluZyBtLWxpbmUgbGF0ZXIuXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHNzcmMyZ3JvdXBbc3NyY10gIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICAgICAgICAgIEFycmF5LmlzQXJyYXkoc3NyYzJncm91cFtzc3JjXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgc3NyYzJncm91cFtzc3JjXS5zb21lKGZ1bmN0aW9uIChzc3JjR3JvdXApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNzcmNHcm91cC5zc3JjcyAqaXMqIGFuIEFycmF5LCBubyBuZWVkIHRvIGNoZWNrXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhZ2FpbiBoZXJlLlxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNzcmNHcm91cC5zc3Jjcy5zb21lKGZ1bmN0aW9uIChyZWxhdGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBzc3JjMm1sW3JlbGF0ZWRdID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1TGluZSA9IHNzcmMybWxbcmVsYXRlZF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHVMaW5lID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgbS1saW5lIGFscmVhZHkgZXhpc3RzLiBKdXN0IGFkZCB0aGUgc291cmNlLlxuICAgICAgICAgICAgICAgICAgICB1TGluZS5zb3VyY2VzW3NzcmNdID0gc291cmNlc1tzc3JjXTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHNvdXJjZXNbc3NyY10ubXNpZDtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBVc2UgdGhlIFwiYkxpbmVcIiBhcyBhIHByb3RvdHlwZSBmb3IgdGhlIFwidUxpbmVcIi5cbiAgICAgICAgICAgICAgICAgICAgdUxpbmUgPSBPYmplY3QuY3JlYXRlKGJMaW5lKTtcbiAgICAgICAgICAgICAgICAgICAgc3NyYzJtbFtzc3JjXSA9IHVMaW5lO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygc291cmNlc1tzc3JjXS5tc2lkICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQXNzaWduIHRoZSBtc2lkIG9mIHRoZSBzb3VyY2UgdG8gdGhlIG0tbGluZS4gTm90ZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhhdCBpdCBpcyBub3QgZ3VhcmFudGVlZCB0aGF0IHRoZSBzb3VyY2Ugd2lsbCBoYXZlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBtc2lkLiBJbiBwYXJ0aWN1bGFyIFwicmVjdm9ubHlcIiBzb3VyY2VzIGRvbid0IGhhdmUgYW5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1zaWQuIE5vdGUgdGhhdCBcInJlY3Zvbmx5XCIgaXMgYSB0ZXJtIG9ubHkgZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZm9yIG0tbGluZXMuXG4gICAgICAgICAgICAgICAgICAgICAgICB1TGluZS5tc2lkID0gc291cmNlc1tzc3JjXS5tc2lkO1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHNvdXJjZXNbc3NyY10ubXNpZDtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFdlIGFzc2lnbiBvbmUgU1NSQyBwZXIgbWVkaWEgbGluZS5cbiAgICAgICAgICAgICAgICAgICAgdUxpbmUuc291cmNlcyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICB1TGluZS5zb3VyY2VzW3NzcmNdID0gc291cmNlc1tzc3JjXTtcbiAgICAgICAgICAgICAgICAgICAgdUxpbmUuc3NyY0dyb3VwcyA9IHNzcmMyZ3JvdXBbc3NyY107XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gVXNlIHRoZSBjYWNoZWQgVW5pZmllZCBQbGFuIFNEUCAoaWYgaXQgZXhpc3RzKSB0byBhc3NpZ25cbiAgICAgICAgICAgICAgICAgICAgLy8gU1NSQ3MgdG8gbWlkcy5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBjYWNoZWQgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlb2YgY2FjaGVkLm1lZGlhICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgQXJyYXkuaXNBcnJheShjYWNoZWQubWVkaWEpKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNhY2hlZC5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uIChtKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBtLnNvdXJjZXMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9iamVjdC5rZXlzKG0uc291cmNlcykuZm9yRWFjaChmdW5jdGlvbiAocykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHMgPT09IHNzcmMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1TGluZS5taWQgPSBtLm1pZDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHVMaW5lLm1pZCA9PT0gJ3VuZGVmaW5lZCcpIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhpcyBpcyBhbiBTU1JDIHRoYXQgd2Ugc2VlIGZvciB0aGUgZmlyc3QgdGltZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXNzaWduIGl0IGEgbmV3IG1pZC4gVGhpcyBpcyB0eXBpY2FsbHkgdGhlIGNhc2Ugd2hlblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhpcyBtZXRob2QgaXMgY2FsbGVkIHRvIHRyYW5zZm9ybSBhIHJlbW90ZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGVzY3JpcHRpb24gZm9yIHRoZSBmaXJzdCB0aW1lIG9yIHdoZW4gdGhlcmUgaXMgYVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbmV3IFNTUkMgaW4gdGhlIHJlbW90ZSBkZXNjcmlwdGlvbiBiZWNhdXNlIGEgbmV3XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBwZWVyIGhhcyBqb2luZWQgdGhlIGNvbmZlcmVuY2UuIExvY2FsIFNTUkNzIHNob3VsZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaGF2ZSBhbHJlYWR5IGJlZW4gYWRkZWQgdG8gdGhlIG1hcCBpbiB0aGUgdG9QbGFuQlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbWV0aG9kLlxuICAgICAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEJlY2F1c2UgRkYgZ2VuZXJhdGVzIGFuc3dlcnMgaW4gVW5pZmllZCBQbGFuIHN0eWxlLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2UgTVVTVCBhbHJlYWR5IGhhdmUgYSBjYWNoZWQgYW5zd2VyIHdpdGggYWxsIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbG9jYWwgU1NSQ3MgbWFwcGVkIHRvIHNvbWUgbS1saW5lL21pZC5cblxuICAgICAgICAgICAgICAgICAgICAgICAgdUxpbmUubWlkID0gW2JMaW5lLnR5cGUsICctJywgc3NyY10uam9pbignJyk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBJbmNsdWRlIHRoZSBjYW5kaWRhdGVzIGluIHRoZSAxc3QgbWVkaWEgbGluZS5cbiAgICAgICAgICAgICAgICAgICAgdUxpbmUuY2FuZGlkYXRlcyA9IGNhbmRpZGF0ZXM7XG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLmljZVVmcmFnID0gaWNlVWZyYWc7XG4gICAgICAgICAgICAgICAgICAgIHVMaW5lLmljZVB3ZCA9IGljZVB3ZDtcbiAgICAgICAgICAgICAgICAgICAgdUxpbmUuZmluZ2VycHJpbnQgPSBmaW5nZXJwcmludDtcbiAgICAgICAgICAgICAgICAgICAgdUxpbmUucG9ydCA9IHBvcnQ7XG5cbiAgICAgICAgICAgICAgICAgICAgbWlkMnVsW3VMaW5lLm1pZF0gPSB1TGluZTtcbiAgICAgICAgICAgICAgICAgICAgc291cmNlczJ1bFt1SWR4XSA9IHVMaW5lLnNvdXJjZXM7XG5cbiAgICAgICAgICAgICAgICAgICAgc2VsZi5jYWNoZS5tbFUyQk1hcFt1SWR4XSA9IGJJZHg7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygc2VsZi5jYWNoZS5tbEIyVU1hcFtiSWR4XSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICBzZWxmLmNhY2hlLm1sQjJVTWFwW2JJZHhdID0gdUlkeDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB1SWR4Kys7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdmFyIHVMaW5lID0gYkxpbmU7XG5cbiAgICAgICAgICB1TGluZS5jYW5kaWRhdGVzID0gY2FuZGlkYXRlcztcbiAgICAgICAgICB1TGluZS5pY2VVZnJhZyA9IGljZVVmcmFnO1xuICAgICAgICAgIHVMaW5lLmljZVB3ZCA9IGljZVB3ZDtcbiAgICAgICAgICB1TGluZS5maW5nZXJwcmludCA9IGZpbmdlcnByaW50O1xuICAgICAgICAgIHVMaW5lLnBvcnQgPSBwb3J0O1xuXG4gICAgICAgICAgbWlkMnVsW3VMaW5lLm1pZF0gPSB1TGluZTtcblxuICAgICAgICAgIHNlbGYuY2FjaGUubWxVMkJNYXBbdUlkeF0gPSBiSWR4O1xuICAgICAgICAgIGlmICh0eXBlb2Ygc2VsZi5jYWNoZS5tbEIyVU1hcFtiSWR4XSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHNlbGYuY2FjaGUubWxCMlVNYXBbYklkeF0gPSB1SWR4O1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGJJZHgrKztcbiAgICB9KTtcblxuICAgIC8vIFJlYnVpbGQgdGhlIG1lZGlhIGFycmF5IGluIHRoZSByaWdodCBvcmRlciBhbmQgYWRkIHRoZSBtaXNzaW5nIG1MaW5lc1xuICAgIC8vIChtaXNzaW5nIGZyb20gdGhlIFBsYW4gQiBTRFApLlxuICAgIHNlc3Npb24ubWVkaWEgPSBbXTtcbiAgICBtaWRzID0gW107IC8vIHJldXNlXG5cbiAgICBpZiAoZGVzYy50eXBlID09PSAnYW5zd2VyJykge1xuXG4gICAgICAgIC8vIFRoZSBtZWRpYSBsaW5lcyBpbiB0aGUgYW5zd2VyIG11c3QgbWF0Y2ggdGhlIG1lZGlhIGxpbmVzIGluIHRoZVxuICAgICAgICAvLyBvZmZlci4gVGhlIG9yZGVyIGlzIGltcG9ydGFudCB0b28uIEhlcmUgd2UgYXNzdW1lIHRoYXQgRmlyZWZveCBpc1xuICAgICAgICAvLyB0aGUgYW5zd2VyZXIsIHNvIHdlIG1lcmVseSBoYXZlIHRvIHVzZSB0aGUgcmVjb25zdHJ1Y3RlZCAodW5pZmllZClcbiAgICAgICAgLy8gYW5zd2VyIHRvIHVwZGF0ZSB0aGUgY2FjaGVkICh1bmlmaWVkKSBhbnN3ZXIgYWNjb3JkaW5nbHkuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIEluIHRoZSBnZW5lcmFsIGNhc2UsIG9uZSB3b3VsZCBoYXZlIHRvIHVzZSB0aGUgY2FjaGVkICh1bmlmaWVkKVxuICAgICAgICAvLyBvZmZlciB0byBmaW5kIHRoZSBtLWxpbmVzIHRoYXQgYXJlIG1pc3NpbmcgZnJvbSB0aGUgcmVjb25zdHJ1Y3RlZFxuICAgICAgICAvLyBhbnN3ZXIsIHBvdGVudGlhbGx5IGdyYWJiaW5nIHRoZW0gZnJvbSB0aGUgY2FjaGVkICh1bmlmaWVkKSBhbnN3ZXIuXG4gICAgICAgIC8vIE9uZSBoYXMgdG8gYmUgY2FyZWZ1bCB3aXRoIHRoaXMgYXBwcm9hY2ggYmVjYXVzZSBpbmFjdGl2ZSBtLWxpbmVzIGRvXG4gICAgICAgIC8vIG5vdCBhbHdheXMgaGF2ZSBhbiBtaWQsIG1ha2luZyBpdCB0cmlja3kgKGltcG9zc2libGU/KSB0byBmaW5kIHdoZXJlXG4gICAgICAgIC8vIGV4YWN0bHkgYW5kIHdoaWNoIG0tbGluZXMgYXJlIG1pc3NpbmcgZnJvbSB0aGUgcmVjb25zdHJ1Y3RlZCBhbnN3ZXIuXG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjYWNoZWQubWVkaWEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHZhciB1TGluZSA9IGNhY2hlZC5tZWRpYVtpXTtcblxuICAgICAgICAgICAgZGVsZXRlIHVMaW5lLm1zaWQ7XG4gICAgICAgICAgICBkZWxldGUgdUxpbmUuc291cmNlcztcbiAgICAgICAgICAgIGRlbGV0ZSB1TGluZS5zc3JjR3JvdXBzO1xuXG4gICAgICAgICAgICBpZiAodHlwZW9mIHNvdXJjZXMydWxbaV0gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgIGlmICghdUxpbmUuZGlyZWN0aW9uXG4gICAgICAgICAgICAgICAgICB8fCB1TGluZS5kaXJlY3Rpb24gPT09ICdzZW5kcmVjdicpXG4gICAgICAgICAgICAgICAgICB1TGluZS5kaXJlY3Rpb24gPSAncmVjdm9ubHknO1xuICAgICAgICAgICAgICBlbHNlIGlmICh1TGluZS5kaXJlY3Rpb24gPT09ICdzZW5kb25seScpXG4gICAgICAgICAgICAgICAgICB1TGluZS5kaXJlY3Rpb24gPSAnaW5hY3RpdmUnO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgaWYgKCF1TGluZS5kaXJlY3Rpb25cbiAgICAgICAgICAgICAgICAgIHx8IHVMaW5lLmRpcmVjdGlvbiA9PT0gJ3NlbmRyZWN2JylcbiAgICAgICAgICAgICAgICAgIHVMaW5lLmRpcmVjdGlvbiA9ICdzZW5kcmVjdic7XG4gICAgICAgICAgICAgIGVsc2UgaWYgKHVMaW5lLmRpcmVjdGlvbiA9PT0gJ3JlY3Zvbmx5JylcbiAgICAgICAgICAgICAgICAgIHVMaW5lLmRpcmVjdGlvbiA9ICdzZW5kb25seSc7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHVMaW5lLnNvdXJjZXMgPSBzb3VyY2VzMnVsW2ldO1xuICAgICAgICAgICAgdUxpbmUuY2FuZGlkYXRlcyA9IGNhbmRpZGF0ZXM7XG4gICAgICAgICAgICB1TGluZS5pY2VVZnJhZyA9IGljZVVmcmFnO1xuICAgICAgICAgICAgdUxpbmUuaWNlUHdkID0gaWNlUHdkO1xuICAgICAgICAgICAgdUxpbmUuZmluZ2VycHJpbnQgPSBmaW5nZXJwcmludDtcblxuICAgICAgICAgICAgdUxpbmUucnRwID0gcnRwW3VMaW5lLnR5cGVdO1xuICAgICAgICAgICAgdUxpbmUucGF5bG9hZHMgPSBwYXlsb2Fkc1t1TGluZS50eXBlXTtcbiAgICAgICAgICAgIHVMaW5lLnJ0Y3BGYiA9IHJ0Y3BGYlt1TGluZS50eXBlXTtcblxuICAgICAgICAgICAgc2Vzc2lvbi5tZWRpYS5wdXNoKHVMaW5lKTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB1TGluZS5taWQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gaW5hY3RpdmUgbGluZXMgZG9uJ3QvbWF5IG5vdCBoYXZlIGFuIG1pZC5cbiAgICAgICAgICAgICAgICBtaWRzLnB1c2godUxpbmUubWlkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0gZWxzZSB7XG5cbiAgICAgICAgLy8gU0RQIG9mZmVyL2Fuc3dlciAoYW5kIHRoZSBKU0VQIHNwZWMpIGZvcmJpZHMgcmVtb3ZpbmcgYW4gbS1zZWN0aW9uXG4gICAgICAgIC8vIHVuZGVyIGFueSBjaXJjdW1zdGFuY2VzLiBJZiB3ZSBhcmUgbm8gbG9uZ2VyIGludGVyZXN0ZWQgaW4gc2VuZGluZyBhXG4gICAgICAgIC8vIHRyYWNrLCB3ZSBqdXN0IHJlbW92ZSB0aGUgbXNpZCBhbmQgc3NyYyBhdHRyaWJ1dGVzIGFuZCBzZXQgaXQgdG9cbiAgICAgICAgLy8gZWl0aGVyIGE9cmVjdm9ubHkgKGFzIHRoZSByZW9mZmVyZXIsIHdlIG11c3QgdXNlIHJlY3Zvbmx5IGlmIHRoZVxuICAgICAgICAvLyBvdGhlciBzaWRlIHdhcyBwcmV2aW91c2x5IHNlbmRpbmcgb24gdGhlIG0tc2VjdGlvbiwgYnV0IHdlIGNhbiBhbHNvXG4gICAgICAgIC8vIGxlYXZlIHRoZSBwb3NzaWJpbGl0eSBvcGVuIGlmIGl0IHdhc24ndCBwcmV2aW91c2x5IGluIHVzZSksIG9yXG4gICAgICAgIC8vIGE9aW5hY3RpdmUuXG5cbiAgICAgICAgaWYgKHR5cGVvZiBjYWNoZWQgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICB0eXBlb2YgY2FjaGVkLm1lZGlhICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgICAgICAgQXJyYXkuaXNBcnJheShjYWNoZWQubWVkaWEpKSB7XG4gICAgICAgICAgICBjYWNoZWQubWVkaWEuZm9yRWFjaChmdW5jdGlvbih1TGluZSkge1xuICAgICAgICAgICAgICAgIG1pZHMucHVzaCh1TGluZS5taWQpO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgbWlkMnVsW3VMaW5lLm1pZF0gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb24ubWVkaWEucHVzaChtaWQydWxbdUxpbmUubWlkXSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHVMaW5lLm1zaWQ7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB1TGluZS5zb3VyY2VzO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdUxpbmUuc3NyY0dyb3VwcztcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIXVMaW5lLmRpcmVjdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgfHwgdUxpbmUuZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB1TGluZS5kaXJlY3Rpb24gPSAnc2VuZG9ubHknO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmICghdUxpbmUuZGlyZWN0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgICB8fCB1TGluZS5kaXJlY3Rpb24gPT09ICdyZWN2b25seScpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHVMaW5lLmRpcmVjdGlvbiA9ICdpbmFjdGl2ZSc7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBhZGRTZXR1cEF0dHIgKHVMaW5lKTtcbiAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbi5tZWRpYS5wdXNoKHVMaW5lKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFkZCBhbGwgdGhlIHJlbWFpbmluZyAobmV3KSBtLWxpbmVzIG9mIHRoZSB0cmFuc2Zvcm1lZCBTRFAuXG4gICAgICAgIE9iamVjdC5rZXlzKG1pZDJ1bCkuZm9yRWFjaChmdW5jdGlvbihtaWQpIHtcbiAgICAgICAgICAgIGlmIChtaWRzLmluZGV4T2YobWlkKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICBtaWRzLnB1c2gobWlkKTtcbiAgICAgICAgICAgICAgICBpZiAobWlkMnVsW21pZF0uZGlyZWN0aW9uID09PSAncmVjdm9ubHknKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRoaXMgaXMgYSByZW1vdGUgcmVjdm9ubHkgY2hhbm5lbC4gQWRkIGl0cyBTU1JDIHRvIHRoZVxuICAgICAgICAgICAgICAgICAgICAvLyBhcHByb3ByaWF0ZSBzZW5kcmVjdiBvciBzZW5kb25seSBjaGFubmVsLlxuICAgICAgICAgICAgICAgICAgICAvLyBUT0RPKGdwKSB3aGF0IGlmIHdlIGRvbid0IGhhdmUgc2VuZHJlY3Yvc2VuZG9ubHlcbiAgICAgICAgICAgICAgICAgICAgLy8gY2hhbm5lbD9cblxuICAgICAgICAgICAgICAgICAgICB2YXIgZG9uZSA9IGZhbHNlO1xuXG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb24ubWVkaWEuc29tZShmdW5jdGlvbiAodUxpbmUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICgodUxpbmUuZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdUxpbmUuZGlyZWN0aW9uID09PSAnc2VuZG9ubHknKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVMaW5lLnR5cGUgPT09IG1pZDJ1bFttaWRdLnR5cGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBtaWQydWxbbWlkXSBzaG91bGRuJ3QgaGF2ZSBhbnkgc3NyYy1ncm91cHNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBPYmplY3Qua2V5cyhtaWQydWxbbWlkXS5zb3VyY2VzKS5mb3JFYWNoKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoc3NyYykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1TGluZS5zb3VyY2VzW3NzcmNdID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pZDJ1bFttaWRdLnNvdXJjZXNbc3NyY107XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb25lID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFkb25lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXNzaW9uLm1lZGlhLnB1c2gobWlkMnVsW21pZF0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgc2Vzc2lvbi5tZWRpYS5wdXNoKG1pZDJ1bFttaWRdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIEFmdGVyIHdlIGhhdmUgY29uc3RydWN0ZWQgdGhlIFBsYW4gVW5pZmllZCBtLWxpbmVzIHdlIGNhbiBmaWd1cmUgb3V0XG4gICAgLy8gd2hlcmUgKGluIHdoaWNoIG0tbGluZSkgdG8gcGxhY2UgdGhlICdyZWN2b25seSBTU1JDcycuXG4gICAgLy8gTm90ZTogd2UgYXNzdW1lIGhlcmUgdGhhdCB3ZSBhcmUgdGhlIGFuc3dlcmVyIGluIHRoZSBPL0EsIHNvIGFueSBvZmZlcnNcbiAgICAvLyB3aGljaCB3ZSB0cmFuc2xhdGUgY29tZSBmcm9tIHRoZSByZW1vdGUgc2lkZSwgd2hpbGUgYW5zd2VycyBhcmUgbG9jYWxcbiAgICAvLyAoYW5kIHNvIG91ciBsYXN0IGxvY2FsIGRlc2NyaXB0aW9uIGlzIGNhY2hlZCBhcyBhbiAnYW5zd2VyJykuXG4gICAgW1wiYXVkaW9cIiwgXCJ2aWRlb1wiXS5mb3JFYWNoKGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgICAgIGlmICghc2Vzc2lvbiB8fCAhc2Vzc2lvbi5tZWRpYSB8fCAhQXJyYXkuaXNBcnJheShzZXNzaW9uLm1lZGlhKSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB2YXIgaWR4ID0gbnVsbDtcbiAgICAgICAgaWYgKE9iamVjdC5rZXlzKHJlY3Zvbmx5U3NyY3NbdHlwZV0pLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGlkeCA9IHNlbGYuZ2V0Rmlyc3RTZW5kaW5nSW5kZXhGcm9tQW5zd2VyKHR5cGUpO1xuICAgICAgICAgICAgaWYgKGlkeCA9PT0gbnVsbCl7XG4gICAgICAgICAgICAgICAgLy8gSWYgdGhpcyBpcyB0aGUgZmlyc3Qgb2ZmZXIgd2UgcmVjZWl2ZSwgd2UgZG9uJ3QgaGF2ZSBhXG4gICAgICAgICAgICAgICAgLy8gY2FjaGVkIGFuc3dlci4gQXNzdW1lIHRoYXQgd2Ugd2lsbCBiZSBzZW5kaW5nIG1lZGlhIHVzaW5nXG4gICAgICAgICAgICAgICAgLy8gdGhlIGZpcnN0IG0tbGluZSBmb3IgZWFjaCBtZWRpYSB0eXBlLlxuXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzZXNzaW9uLm1lZGlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChzZXNzaW9uLm1lZGlhW2ldLnR5cGUgPT09IHR5cGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlkeCA9IGk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpZHggJiYgc2Vzc2lvbi5tZWRpYS5sZW5ndGggPiBpZHgpIHtcbiAgICAgICAgICAgIHZhciBtTGluZSA9IHNlc3Npb24ubWVkaWFbaWR4XTtcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKHJlY3Zvbmx5U3NyY3NbdHlwZV0pLmZvckVhY2goZnVuY3Rpb24oc3NyYykge1xuICAgICAgICAgICAgICAgIGlmIChtTGluZS5zb3VyY2VzICYmIG1MaW5lLnNvdXJjZXNbc3NyY10pIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiUmVwbGFjaW5nIGFuIGV4aXN0aW5nIFNTUkMuXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoIW1MaW5lLnNvdXJjZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgbUxpbmUuc291cmNlcyA9IHt9O1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIG1MaW5lLnNvdXJjZXNbc3NyY10gPSByZWN2b25seVNzcmNzW3R5cGVdW3NzcmNdO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIGlmICh0eXBlb2Ygc2Vzc2lvbi5ncm91cHMgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAvLyBXZSByZWdlbmVyYXRlIHRoZSBCVU5ETEUgZ3JvdXAgKHNpbmNlIHdlIHJlZ2VuZXJhdGVkIHRoZSBtaWRzKVxuICAgICAgc2Vzc2lvbi5ncm91cHMuc29tZShmdW5jdGlvbihncm91cCkge1xuXHQgIGlmIChncm91cC50eXBlID09PSAnQlVORExFJykge1xuXHQgICAgICBncm91cC5taWRzID0gbWlkcy5qb2luKCcgJyk7XG5cdCAgICAgIHJldHVybiB0cnVlO1xuXHQgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIG1zaWQgc2VtYW50aWNcbiAgICBzZXNzaW9uLm1zaWRTZW1hbnRpYyA9IHtcbiAgICAgICAgc2VtYW50aWM6ICdXTVMnLFxuICAgICAgICB0b2tlbjogJyonXG4gICAgfTtcblxuICAgIHZhciByZXNTdHIgPSB0cmFuc2Zvcm0ud3JpdGUoc2Vzc2lvbik7XG5cbiAgICAvLyBDYWNoZSB0aGUgdHJhbnNmb3JtZWQgU0RQIChVbmlmaWVkIFBsYW4pIGZvciBsYXRlciByZS11c2UgaW4gdGhpc1xuICAgIC8vIGZ1bmN0aW9uLlxuICAgIHRoaXMuY2FjaGVbZGVzYy50eXBlXSA9IHJlc1N0cjtcblxuICAgIHJldHVybiBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgICAgdHlwZTogZGVzYy50eXBlLFxuICAgICAgICBzZHA6IHJlc1N0clxuICAgIH0pO1xuXG4gICAgLy8jZW5kcmVnaW9uXG59O1xuIiwiLyogQ29weXJpZ2h0IEAgMjAxNSBBdGxhc3NpYW4gUHR5IEx0ZFxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG52YXIgdHJhbnNmb3JtID0gcmVxdWlyZSgnc2RwLXRyYW5zZm9ybScpO1xuXG5leHBvcnRzLndyaXRlID0gZnVuY3Rpb24oc2Vzc2lvbiwgb3B0cykge1xuXG4gIGlmICh0eXBlb2Ygc2Vzc2lvbiAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgIHR5cGVvZiBzZXNzaW9uLm1lZGlhICE9PSAndW5kZWZpbmVkJyAmJlxuICAgICAgQXJyYXkuaXNBcnJheShzZXNzaW9uLm1lZGlhKSkge1xuXG4gICAgc2Vzc2lvbi5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uIChtTGluZSkge1xuICAgICAgLy8gZXhwYW5kIHNvdXJjZXMgdG8gc3NyY3NcbiAgICAgIGlmICh0eXBlb2YgbUxpbmUuc291cmNlcyAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgT2JqZWN0LmtleXMobUxpbmUuc291cmNlcykubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgICAgbUxpbmUuc3NyY3MgPSBbXTtcbiAgICAgICAgICBPYmplY3Qua2V5cyhtTGluZS5zb3VyY2VzKS5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgICB2YXIgc291cmNlID0gbUxpbmUuc291cmNlc1tzc3JjXTtcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKHNvdXJjZSkuZm9yRWFjaChmdW5jdGlvbiAoYXR0cmlidXRlKSB7XG4gICAgICAgICAgICAgIG1MaW5lLnNzcmNzLnB1c2goe1xuICAgICAgICAgICAgICAgIGlkOiBzc3JjLFxuICAgICAgICAgICAgICAgIGF0dHJpYnV0ZTogYXR0cmlidXRlLFxuICAgICAgICAgICAgICAgIHZhbHVlOiBzb3VyY2VbYXR0cmlidXRlXVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIGRlbGV0ZSBtTGluZS5zb3VyY2VzO1xuICAgICAgICB9XG5cbiAgICAgIC8vIGpvaW4gc3NyY3MgaW4gc3NyYyBncm91cHNcbiAgICAgIGlmICh0eXBlb2YgbUxpbmUuc3NyY0dyb3VwcyAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgQXJyYXkuaXNBcnJheShtTGluZS5zc3JjR3JvdXBzKSkge1xuICAgICAgICAgIG1MaW5lLnNzcmNHcm91cHMuZm9yRWFjaChmdW5jdGlvbiAoc3NyY0dyb3VwKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHNzcmNHcm91cC5zc3JjcyAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgICAgICAgICBBcnJheS5pc0FycmF5KHNzcmNHcm91cC5zc3JjcykpIHtcbiAgICAgICAgICAgICAgc3NyY0dyb3VwLnNzcmNzID0gc3NyY0dyb3VwLnNzcmNzLmpvaW4oJyAnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLy8gam9pbiBncm91cCBtaWRzXG4gIGlmICh0eXBlb2Ygc2Vzc2lvbiAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgIHR5cGVvZiBzZXNzaW9uLmdyb3VwcyAhPT0gJ3VuZGVmaW5lZCcgJiYgQXJyYXkuaXNBcnJheShzZXNzaW9uLmdyb3VwcykpIHtcblxuICAgIHNlc3Npb24uZ3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKGcpIHtcbiAgICAgIGlmICh0eXBlb2YgZy5taWRzICE9PSAndW5kZWZpbmVkJyAmJiBBcnJheS5pc0FycmF5KGcubWlkcykpIHtcbiAgICAgICAgZy5taWRzID0gZy5taWRzLmpvaW4oJyAnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiB0cmFuc2Zvcm0ud3JpdGUoc2Vzc2lvbiwgb3B0cyk7XG59O1xuXG5leHBvcnRzLnBhcnNlID0gZnVuY3Rpb24oc2RwKSB7XG4gIHZhciBzZXNzaW9uID0gdHJhbnNmb3JtLnBhcnNlKHNkcCk7XG5cbiAgaWYgKHR5cGVvZiBzZXNzaW9uICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2Ygc2Vzc2lvbi5tZWRpYSAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgIEFycmF5LmlzQXJyYXkoc2Vzc2lvbi5tZWRpYSkpIHtcblxuICAgIHNlc3Npb24ubWVkaWEuZm9yRWFjaChmdW5jdGlvbiAobUxpbmUpIHtcbiAgICAgIC8vIGdyb3VwIHNvdXJjZXMgYXR0cmlidXRlcyBieSBzc3JjXG4gICAgICBpZiAodHlwZW9mIG1MaW5lLnNzcmNzICE9PSAndW5kZWZpbmVkJyAmJiBBcnJheS5pc0FycmF5KG1MaW5lLnNzcmNzKSkge1xuICAgICAgICBtTGluZS5zb3VyY2VzID0ge307XG4gICAgICAgIG1MaW5lLnNzcmNzLmZvckVhY2goZnVuY3Rpb24gKHNzcmMpIHtcbiAgICAgICAgICBpZiAoIW1MaW5lLnNvdXJjZXNbc3NyYy5pZF0pXG4gICAgICAgICAgbUxpbmUuc291cmNlc1tzc3JjLmlkXSA9IHt9O1xuICAgICAgICBtTGluZS5zb3VyY2VzW3NzcmMuaWRdW3NzcmMuYXR0cmlidXRlXSA9IHNzcmMudmFsdWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGRlbGV0ZSBtTGluZS5zc3JjcztcbiAgICAgIH1cblxuICAgICAgLy8gc3BsaXQgc3NyY3MgaW4gc3NyYyBncm91cHNcbiAgICAgIGlmICh0eXBlb2YgbUxpbmUuc3NyY0dyb3VwcyAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgICAgQXJyYXkuaXNBcnJheShtTGluZS5zc3JjR3JvdXBzKSkge1xuICAgICAgICAgIG1MaW5lLnNzcmNHcm91cHMuZm9yRWFjaChmdW5jdGlvbiAoc3NyY0dyb3VwKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHNzcmNHcm91cC5zc3JjcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgc3NyY0dyb3VwLnNzcmNzID0gc3NyY0dyb3VwLnNzcmNzLnNwbGl0KCcgJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9KTtcbiAgfVxuICAvLyBzcGxpdCBncm91cCBtaWRzXG4gIGlmICh0eXBlb2Ygc2Vzc2lvbiAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgIHR5cGVvZiBzZXNzaW9uLmdyb3VwcyAhPT0gJ3VuZGVmaW5lZCcgJiYgQXJyYXkuaXNBcnJheShzZXNzaW9uLmdyb3VwcykpIHtcblxuICAgIHNlc3Npb24uZ3JvdXBzLmZvckVhY2goZnVuY3Rpb24gKGcpIHtcbiAgICAgIGlmICh0eXBlb2YgZy5taWRzID09PSAnc3RyaW5nJykge1xuICAgICAgICBnLm1pZHMgPSBnLm1pZHMuc3BsaXQoJyAnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiBzZXNzaW9uO1xufTtcblxuIiwiIC8qIGVzbGludC1lbnYgbm9kZSAqL1xuJ3VzZSBzdHJpY3QnO1xuXG4vLyBTRFAgaGVscGVycy5cbnZhciBTRFBVdGlscyA9IHt9O1xuXG4vLyBHZW5lcmF0ZSBhbiBhbHBoYW51bWVyaWMgaWRlbnRpZmllciBmb3IgY25hbWUgb3IgbWlkcy5cbi8vIFRPRE86IHVzZSBVVUlEcyBpbnN0ZWFkPyBodHRwczovL2dpc3QuZ2l0aHViLmNvbS9qZWQvOTgyODgzXG5TRFBVdGlscy5nZW5lcmF0ZUlkZW50aWZpZXIgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cigyLCAxMCk7XG59O1xuXG4vLyBUaGUgUlRDUCBDTkFNRSB1c2VkIGJ5IGFsbCBwZWVyY29ubmVjdGlvbnMgZnJvbSB0aGUgc2FtZSBKUy5cblNEUFV0aWxzLmxvY2FsQ05hbWUgPSBTRFBVdGlscy5nZW5lcmF0ZUlkZW50aWZpZXIoKTtcblxuLy8gU3BsaXRzIFNEUCBpbnRvIGxpbmVzLCBkZWFsaW5nIHdpdGggYm90aCBDUkxGIGFuZCBMRi5cblNEUFV0aWxzLnNwbGl0TGluZXMgPSBmdW5jdGlvbihibG9iKSB7XG4gIHJldHVybiBibG9iLnRyaW0oKS5zcGxpdCgnXFxuJykubWFwKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICByZXR1cm4gbGluZS50cmltKCk7XG4gIH0pO1xufTtcbi8vIFNwbGl0cyBTRFAgaW50byBzZXNzaW9ucGFydCBhbmQgbWVkaWFzZWN0aW9ucy4gRW5zdXJlcyBDUkxGLlxuU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyA9IGZ1bmN0aW9uKGJsb2IpIHtcbiAgdmFyIHBhcnRzID0gYmxvYi5zcGxpdCgnXFxubT0nKTtcbiAgcmV0dXJuIHBhcnRzLm1hcChmdW5jdGlvbihwYXJ0LCBpbmRleCkge1xuICAgIHJldHVybiAoaW5kZXggPiAwID8gJ209JyArIHBhcnQgOiBwYXJ0KS50cmltKCkgKyAnXFxyXFxuJztcbiAgfSk7XG59O1xuXG4vLyBSZXR1cm5zIGxpbmVzIHRoYXQgc3RhcnQgd2l0aCBhIGNlcnRhaW4gcHJlZml4LlxuU0RQVXRpbHMubWF0Y2hQcmVmaXggPSBmdW5jdGlvbihibG9iLCBwcmVmaXgpIHtcbiAgcmV0dXJuIFNEUFV0aWxzLnNwbGl0TGluZXMoYmxvYikuZmlsdGVyKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICByZXR1cm4gbGluZS5pbmRleE9mKHByZWZpeCkgPT09IDA7XG4gIH0pO1xufTtcblxuLy8gUGFyc2VzIGFuIElDRSBjYW5kaWRhdGUgbGluZS4gU2FtcGxlIGlucHV0OlxuLy8gY2FuZGlkYXRlOjcwMjc4NjM1MCAyIHVkcCA0MTgxOTkwMiA4LjguOC44IDYwNzY5IHR5cCByZWxheSByYWRkciA4LjguOC44XG4vLyBycG9ydCA1NTk5NlwiXG5TRFBVdGlscy5wYXJzZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgdmFyIHBhcnRzO1xuICAvLyBQYXJzZSBib3RoIHZhcmlhbnRzLlxuICBpZiAobGluZS5pbmRleE9mKCdhPWNhbmRpZGF0ZTonKSA9PT0gMCkge1xuICAgIHBhcnRzID0gbGluZS5zdWJzdHJpbmcoMTIpLnNwbGl0KCcgJyk7XG4gIH0gZWxzZSB7XG4gICAgcGFydHMgPSBsaW5lLnN1YnN0cmluZygxMCkuc3BsaXQoJyAnKTtcbiAgfVxuXG4gIHZhciBjYW5kaWRhdGUgPSB7XG4gICAgZm91bmRhdGlvbjogcGFydHNbMF0sXG4gICAgY29tcG9uZW50OiBwYXJ0c1sxXSxcbiAgICBwcm90b2NvbDogcGFydHNbMl0udG9Mb3dlckNhc2UoKSxcbiAgICBwcmlvcml0eTogcGFyc2VJbnQocGFydHNbM10sIDEwKSxcbiAgICBpcDogcGFydHNbNF0sXG4gICAgcG9ydDogcGFyc2VJbnQocGFydHNbNV0sIDEwKSxcbiAgICAvLyBza2lwIHBhcnRzWzZdID09ICd0eXAnXG4gICAgdHlwZTogcGFydHNbN11cbiAgfTtcblxuICBmb3IgKHZhciBpID0gODsgaSA8IHBhcnRzLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgc3dpdGNoIChwYXJ0c1tpXSkge1xuICAgICAgY2FzZSAncmFkZHInOlxuICAgICAgICBjYW5kaWRhdGUucmVsYXRlZEFkZHJlc3MgPSBwYXJ0c1tpICsgMV07XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAncnBvcnQnOlxuICAgICAgICBjYW5kaWRhdGUucmVsYXRlZFBvcnQgPSBwYXJzZUludChwYXJ0c1tpICsgMV0sIDEwKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICd0Y3B0eXBlJzpcbiAgICAgICAgY2FuZGlkYXRlLnRjcFR5cGUgPSBwYXJ0c1tpICsgMV07XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDogLy8gZXh0ZW5zaW9uIGhhbmRsaW5nLCBpbiBwYXJ0aWN1bGFyIHVmcmFnXG4gICAgICAgIGNhbmRpZGF0ZVtwYXJ0c1tpXV0gPSBwYXJ0c1tpICsgMV07XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuICByZXR1cm4gY2FuZGlkYXRlO1xufTtcblxuLy8gVHJhbnNsYXRlcyBhIGNhbmRpZGF0ZSBvYmplY3QgaW50byBTRFAgY2FuZGlkYXRlIGF0dHJpYnV0ZS5cblNEUFV0aWxzLndyaXRlQ2FuZGlkYXRlID0gZnVuY3Rpb24oY2FuZGlkYXRlKSB7XG4gIHZhciBzZHAgPSBbXTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLmZvdW5kYXRpb24pO1xuICBzZHAucHVzaChjYW5kaWRhdGUuY29tcG9uZW50KTtcbiAgc2RwLnB1c2goY2FuZGlkYXRlLnByb3RvY29sLnRvVXBwZXJDYXNlKCkpO1xuICBzZHAucHVzaChjYW5kaWRhdGUucHJpb3JpdHkpO1xuICBzZHAucHVzaChjYW5kaWRhdGUuaXApO1xuICBzZHAucHVzaChjYW5kaWRhdGUucG9ydCk7XG5cbiAgdmFyIHR5cGUgPSBjYW5kaWRhdGUudHlwZTtcbiAgc2RwLnB1c2goJ3R5cCcpO1xuICBzZHAucHVzaCh0eXBlKTtcbiAgaWYgKHR5cGUgIT09ICdob3N0JyAmJiBjYW5kaWRhdGUucmVsYXRlZEFkZHJlc3MgJiZcbiAgICAgIGNhbmRpZGF0ZS5yZWxhdGVkUG9ydCkge1xuICAgIHNkcC5wdXNoKCdyYWRkcicpO1xuICAgIHNkcC5wdXNoKGNhbmRpZGF0ZS5yZWxhdGVkQWRkcmVzcyk7IC8vIHdhczogcmVsQWRkclxuICAgIHNkcC5wdXNoKCdycG9ydCcpO1xuICAgIHNkcC5wdXNoKGNhbmRpZGF0ZS5yZWxhdGVkUG9ydCk7IC8vIHdhczogcmVsUG9ydFxuICB9XG4gIGlmIChjYW5kaWRhdGUudGNwVHlwZSAmJiBjYW5kaWRhdGUucHJvdG9jb2wudG9Mb3dlckNhc2UoKSA9PT0gJ3RjcCcpIHtcbiAgICBzZHAucHVzaCgndGNwdHlwZScpO1xuICAgIHNkcC5wdXNoKGNhbmRpZGF0ZS50Y3BUeXBlKTtcbiAgfVxuICByZXR1cm4gJ2NhbmRpZGF0ZTonICsgc2RwLmpvaW4oJyAnKTtcbn07XG5cbi8vIFBhcnNlcyBhbiBpY2Utb3B0aW9ucyBsaW5lLCByZXR1cm5zIGFuIGFycmF5IG9mIG9wdGlvbiB0YWdzLlxuLy8gYT1pY2Utb3B0aW9uczpmb28gYmFyXG5TRFBVdGlscy5wYXJzZUljZU9wdGlvbnMgPSBmdW5jdGlvbihsaW5lKSB7XG4gIHJldHVybiBsaW5lLnN1YnN0cigxNCkuc3BsaXQoJyAnKTtcbn1cblxuLy8gUGFyc2VzIGFuIHJ0cG1hcCBsaW5lLCByZXR1cm5zIFJUQ1J0cENvZGRlY1BhcmFtZXRlcnMuIFNhbXBsZSBpbnB1dDpcbi8vIGE9cnRwbWFwOjExMSBvcHVzLzQ4MDAwLzJcblNEUFV0aWxzLnBhcnNlUnRwTWFwID0gZnVuY3Rpb24obGluZSkge1xuICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cig5KS5zcGxpdCgnICcpO1xuICB2YXIgcGFyc2VkID0ge1xuICAgIHBheWxvYWRUeXBlOiBwYXJzZUludChwYXJ0cy5zaGlmdCgpLCAxMCkgLy8gd2FzOiBpZFxuICB9O1xuXG4gIHBhcnRzID0gcGFydHNbMF0uc3BsaXQoJy8nKTtcblxuICBwYXJzZWQubmFtZSA9IHBhcnRzWzBdO1xuICBwYXJzZWQuY2xvY2tSYXRlID0gcGFyc2VJbnQocGFydHNbMV0sIDEwKTsgLy8gd2FzOiBjbG9ja3JhdGVcbiAgLy8gd2FzOiBjaGFubmVsc1xuICBwYXJzZWQubnVtQ2hhbm5lbHMgPSBwYXJ0cy5sZW5ndGggPT09IDMgPyBwYXJzZUludChwYXJ0c1syXSwgMTApIDogMTtcbiAgcmV0dXJuIHBhcnNlZDtcbn07XG5cbi8vIEdlbmVyYXRlIGFuIGE9cnRwbWFwIGxpbmUgZnJvbSBSVENSdHBDb2RlY0NhcGFiaWxpdHkgb3Jcbi8vIFJUQ1J0cENvZGVjUGFyYW1ldGVycy5cblNEUFV0aWxzLndyaXRlUnRwTWFwID0gZnVuY3Rpb24oY29kZWMpIHtcbiAgdmFyIHB0ID0gY29kZWMucGF5bG9hZFR5cGU7XG4gIGlmIChjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcHQgPSBjb2RlYy5wcmVmZXJyZWRQYXlsb2FkVHlwZTtcbiAgfVxuICByZXR1cm4gJ2E9cnRwbWFwOicgKyBwdCArICcgJyArIGNvZGVjLm5hbWUgKyAnLycgKyBjb2RlYy5jbG9ja1JhdGUgK1xuICAgICAgKGNvZGVjLm51bUNoYW5uZWxzICE9PSAxID8gJy8nICsgY29kZWMubnVtQ2hhbm5lbHMgOiAnJykgKyAnXFxyXFxuJztcbn07XG5cbi8vIFBhcnNlcyBhbiBhPWV4dG1hcCBsaW5lIChoZWFkZXJleHRlbnNpb24gZnJvbSBSRkMgNTI4NSkuIFNhbXBsZSBpbnB1dDpcbi8vIGE9ZXh0bWFwOjIgdXJuOmlldGY6cGFyYW1zOnJ0cC1oZHJleHQ6dG9mZnNldFxuLy8gYT1leHRtYXA6Mi9zZW5kb25seSB1cm46aWV0ZjpwYXJhbXM6cnRwLWhkcmV4dDp0b2Zmc2V0XG5TRFBVdGlscy5wYXJzZUV4dG1hcCA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgdmFyIHBhcnRzID0gbGluZS5zdWJzdHIoOSkuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICBpZDogcGFyc2VJbnQocGFydHNbMF0sIDEwKSxcbiAgICBkaXJlY3Rpb246IHBhcnRzWzBdLmluZGV4T2YoJy8nKSA+IDAgPyBwYXJ0c1swXS5zcGxpdCgnLycpWzFdIDogJ3NlbmRyZWN2JyxcbiAgICB1cmk6IHBhcnRzWzFdXG4gIH07XG59O1xuXG4vLyBHZW5lcmF0ZXMgYT1leHRtYXAgbGluZSBmcm9tIFJUQ1J0cEhlYWRlckV4dGVuc2lvblBhcmFtZXRlcnMgb3Jcbi8vIFJUQ1J0cEhlYWRlckV4dGVuc2lvbi5cblNEUFV0aWxzLndyaXRlRXh0bWFwID0gZnVuY3Rpb24oaGVhZGVyRXh0ZW5zaW9uKSB7XG4gIHJldHVybiAnYT1leHRtYXA6JyArIChoZWFkZXJFeHRlbnNpb24uaWQgfHwgaGVhZGVyRXh0ZW5zaW9uLnByZWZlcnJlZElkKSArXG4gICAgICAoaGVhZGVyRXh0ZW5zaW9uLmRpcmVjdGlvbiAmJiBoZWFkZXJFeHRlbnNpb24uZGlyZWN0aW9uICE9PSAnc2VuZHJlY3YnXG4gICAgICAgICAgPyAnLycgKyBoZWFkZXJFeHRlbnNpb24uZGlyZWN0aW9uXG4gICAgICAgICAgOiAnJykgK1xuICAgICAgJyAnICsgaGVhZGVyRXh0ZW5zaW9uLnVyaSArICdcXHJcXG4nO1xufTtcblxuLy8gUGFyc2VzIGFuIGZ0bXAgbGluZSwgcmV0dXJucyBkaWN0aW9uYXJ5LiBTYW1wbGUgaW5wdXQ6XG4vLyBhPWZtdHA6OTYgdmJyPW9uO2NuZz1vblxuLy8gQWxzbyBkZWFscyB3aXRoIHZicj1vbjsgY25nPW9uXG5TRFBVdGlscy5wYXJzZUZtdHAgPSBmdW5jdGlvbihsaW5lKSB7XG4gIHZhciBwYXJzZWQgPSB7fTtcbiAgdmFyIGt2O1xuICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cihsaW5lLmluZGV4T2YoJyAnKSArIDEpLnNwbGl0KCc7Jyk7XG4gIGZvciAodmFyIGogPSAwOyBqIDwgcGFydHMubGVuZ3RoOyBqKyspIHtcbiAgICBrdiA9IHBhcnRzW2pdLnRyaW0oKS5zcGxpdCgnPScpO1xuICAgIHBhcnNlZFtrdlswXS50cmltKCldID0ga3ZbMV07XG4gIH1cbiAgcmV0dXJuIHBhcnNlZDtcbn07XG5cbi8vIEdlbmVyYXRlcyBhbiBhPWZ0bXAgbGluZSBmcm9tIFJUQ1J0cENvZGVjQ2FwYWJpbGl0eSBvciBSVENSdHBDb2RlY1BhcmFtZXRlcnMuXG5TRFBVdGlscy53cml0ZUZtdHAgPSBmdW5jdGlvbihjb2RlYykge1xuICB2YXIgbGluZSA9ICcnO1xuICB2YXIgcHQgPSBjb2RlYy5wYXlsb2FkVHlwZTtcbiAgaWYgKGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlICE9PSB1bmRlZmluZWQpIHtcbiAgICBwdCA9IGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlO1xuICB9XG4gIGlmIChjb2RlYy5wYXJhbWV0ZXJzICYmIE9iamVjdC5rZXlzKGNvZGVjLnBhcmFtZXRlcnMpLmxlbmd0aCkge1xuICAgIHZhciBwYXJhbXMgPSBbXTtcbiAgICBPYmplY3Qua2V5cyhjb2RlYy5wYXJhbWV0ZXJzKS5mb3JFYWNoKGZ1bmN0aW9uKHBhcmFtKSB7XG4gICAgICBwYXJhbXMucHVzaChwYXJhbSArICc9JyArIGNvZGVjLnBhcmFtZXRlcnNbcGFyYW1dKTtcbiAgICB9KTtcbiAgICBsaW5lICs9ICdhPWZtdHA6JyArIHB0ICsgJyAnICsgcGFyYW1zLmpvaW4oJzsnKSArICdcXHJcXG4nO1xuICB9XG4gIHJldHVybiBsaW5lO1xufTtcblxuLy8gUGFyc2VzIGFuIHJ0Y3AtZmIgbGluZSwgcmV0dXJucyBSVENQUnRjcEZlZWRiYWNrIG9iamVjdC4gU2FtcGxlIGlucHV0OlxuLy8gYT1ydGNwLWZiOjk4IG5hY2sgcnBzaVxuU0RQVXRpbHMucGFyc2VSdGNwRmIgPSBmdW5jdGlvbihsaW5lKSB7XG4gIHZhciBwYXJ0cyA9IGxpbmUuc3Vic3RyKGxpbmUuaW5kZXhPZignICcpICsgMSkuc3BsaXQoJyAnKTtcbiAgcmV0dXJuIHtcbiAgICB0eXBlOiBwYXJ0cy5zaGlmdCgpLFxuICAgIHBhcmFtZXRlcjogcGFydHMuam9pbignICcpXG4gIH07XG59O1xuLy8gR2VuZXJhdGUgYT1ydGNwLWZiIGxpbmVzIGZyb20gUlRDUnRwQ29kZWNDYXBhYmlsaXR5IG9yIFJUQ1J0cENvZGVjUGFyYW1ldGVycy5cblNEUFV0aWxzLndyaXRlUnRjcEZiID0gZnVuY3Rpb24oY29kZWMpIHtcbiAgdmFyIGxpbmVzID0gJyc7XG4gIHZhciBwdCA9IGNvZGVjLnBheWxvYWRUeXBlO1xuICBpZiAoY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGUgIT09IHVuZGVmaW5lZCkge1xuICAgIHB0ID0gY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGU7XG4gIH1cbiAgaWYgKGNvZGVjLnJ0Y3BGZWVkYmFjayAmJiBjb2RlYy5ydGNwRmVlZGJhY2subGVuZ3RoKSB7XG4gICAgLy8gRklYTUU6IHNwZWNpYWwgaGFuZGxpbmcgZm9yIHRyci1pbnQ/XG4gICAgY29kZWMucnRjcEZlZWRiYWNrLmZvckVhY2goZnVuY3Rpb24oZmIpIHtcbiAgICAgIGxpbmVzICs9ICdhPXJ0Y3AtZmI6JyArIHB0ICsgJyAnICsgZmIudHlwZSArXG4gICAgICAoZmIucGFyYW1ldGVyICYmIGZiLnBhcmFtZXRlci5sZW5ndGggPyAnICcgKyBmYi5wYXJhbWV0ZXIgOiAnJykgK1xuICAgICAgICAgICdcXHJcXG4nO1xuICAgIH0pO1xuICB9XG4gIHJldHVybiBsaW5lcztcbn07XG5cbi8vIFBhcnNlcyBhbiBSRkMgNTU3NiBzc3JjIG1lZGlhIGF0dHJpYnV0ZS4gU2FtcGxlIGlucHV0OlxuLy8gYT1zc3JjOjM3MzU5Mjg1NTkgY25hbWU6c29tZXRoaW5nXG5TRFBVdGlscy5wYXJzZVNzcmNNZWRpYSA9IGZ1bmN0aW9uKGxpbmUpIHtcbiAgdmFyIHNwID0gbGluZS5pbmRleE9mKCcgJyk7XG4gIHZhciBwYXJ0cyA9IHtcbiAgICBzc3JjOiBwYXJzZUludChsaW5lLnN1YnN0cig3LCBzcCAtIDcpLCAxMClcbiAgfTtcbiAgdmFyIGNvbG9uID0gbGluZS5pbmRleE9mKCc6Jywgc3ApO1xuICBpZiAoY29sb24gPiAtMSkge1xuICAgIHBhcnRzLmF0dHJpYnV0ZSA9IGxpbmUuc3Vic3RyKHNwICsgMSwgY29sb24gLSBzcCAtIDEpO1xuICAgIHBhcnRzLnZhbHVlID0gbGluZS5zdWJzdHIoY29sb24gKyAxKTtcbiAgfSBlbHNlIHtcbiAgICBwYXJ0cy5hdHRyaWJ1dGUgPSBsaW5lLnN1YnN0cihzcCArIDEpO1xuICB9XG4gIHJldHVybiBwYXJ0cztcbn07XG5cbi8vIEV4dHJhY3RzIHRoZSBNSUQgKFJGQyA1ODg4KSBmcm9tIGEgbWVkaWEgc2VjdGlvbi5cbi8vIHJldHVybnMgdGhlIE1JRCBvciB1bmRlZmluZWQgaWYgbm8gbWlkIGxpbmUgd2FzIGZvdW5kLlxuU0RQVXRpbHMuZ2V0TWlkID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHZhciBtaWQgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPW1pZDonKVswXTtcbiAgaWYgKG1pZCkge1xuICAgIHJldHVybiBtaWQuc3Vic3RyKDYpO1xuICB9XG59XG5cblNEUFV0aWxzLnBhcnNlRmluZ2VycHJpbnQgPSBmdW5jdGlvbihsaW5lKSB7XG4gIHZhciBwYXJ0cyA9IGxpbmUuc3Vic3RyKDE0KS5zcGxpdCgnICcpO1xuICByZXR1cm4ge1xuICAgIGFsZ29yaXRobTogcGFydHNbMF0udG9Mb3dlckNhc2UoKSwgLy8gYWxnb3JpdGhtIGlzIGNhc2Utc2Vuc2l0aXZlIGluIEVkZ2UuXG4gICAgdmFsdWU6IHBhcnRzWzFdXG4gIH07XG59O1xuXG4vLyBFeHRyYWN0cyBEVExTIHBhcmFtZXRlcnMgZnJvbSBTRFAgbWVkaWEgc2VjdGlvbiBvciBzZXNzaW9ucGFydC5cbi8vIEZJWE1FOiBmb3IgY29uc2lzdGVuY3kgd2l0aCBvdGhlciBmdW5jdGlvbnMgdGhpcyBzaG91bGQgb25seVxuLy8gICBnZXQgdGhlIGZpbmdlcnByaW50IGxpbmUgYXMgaW5wdXQuIFNlZSBhbHNvIGdldEljZVBhcmFtZXRlcnMuXG5TRFBVdGlscy5nZXREdGxzUGFyYW1ldGVycyA9IGZ1bmN0aW9uKG1lZGlhU2VjdGlvbiwgc2Vzc2lvbnBhcnQpIHtcbiAgdmFyIGxpbmVzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uICsgc2Vzc2lvbnBhcnQsXG4gICAgICAnYT1maW5nZXJwcmludDonKTtcbiAgLy8gTm90ZTogYT1zZXR1cCBsaW5lIGlzIGlnbm9yZWQgc2luY2Ugd2UgdXNlIHRoZSAnYXV0bycgcm9sZS5cbiAgLy8gTm90ZTI6ICdhbGdvcml0aG0nIGlzIG5vdCBjYXNlIHNlbnNpdGl2ZSBleGNlcHQgaW4gRWRnZS5cbiAgcmV0dXJuIHtcbiAgICByb2xlOiAnYXV0bycsXG4gICAgZmluZ2VycHJpbnRzOiBsaW5lcy5tYXAoU0RQVXRpbHMucGFyc2VGaW5nZXJwcmludClcbiAgfTtcbn07XG5cbi8vIFNlcmlhbGl6ZXMgRFRMUyBwYXJhbWV0ZXJzIHRvIFNEUC5cblNEUFV0aWxzLndyaXRlRHRsc1BhcmFtZXRlcnMgPSBmdW5jdGlvbihwYXJhbXMsIHNldHVwVHlwZSkge1xuICB2YXIgc2RwID0gJ2E9c2V0dXA6JyArIHNldHVwVHlwZSArICdcXHJcXG4nO1xuICBwYXJhbXMuZmluZ2VycHJpbnRzLmZvckVhY2goZnVuY3Rpb24oZnApIHtcbiAgICBzZHAgKz0gJ2E9ZmluZ2VycHJpbnQ6JyArIGZwLmFsZ29yaXRobSArICcgJyArIGZwLnZhbHVlICsgJ1xcclxcbic7XG4gIH0pO1xuICByZXR1cm4gc2RwO1xufTtcbi8vIFBhcnNlcyBJQ0UgaW5mb3JtYXRpb24gZnJvbSBTRFAgbWVkaWEgc2VjdGlvbiBvciBzZXNzaW9ucGFydC5cbi8vIEZJWE1FOiBmb3IgY29uc2lzdGVuY3kgd2l0aCBvdGhlciBmdW5jdGlvbnMgdGhpcyBzaG91bGQgb25seVxuLy8gICBnZXQgdGhlIGljZS11ZnJhZyBhbmQgaWNlLXB3ZCBsaW5lcyBhcyBpbnB1dC5cblNEUFV0aWxzLmdldEljZVBhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KSB7XG4gIHZhciBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMobWVkaWFTZWN0aW9uKTtcbiAgLy8gU2VhcmNoIGluIHNlc3Npb24gcGFydCwgdG9vLlxuICBsaW5lcyA9IGxpbmVzLmNvbmNhdChTRFBVdGlscy5zcGxpdExpbmVzKHNlc3Npb25wYXJ0KSk7XG4gIHZhciBpY2VQYXJhbWV0ZXJzID0ge1xuICAgIHVzZXJuYW1lRnJhZ21lbnQ6IGxpbmVzLmZpbHRlcihmdW5jdGlvbihsaW5lKSB7XG4gICAgICByZXR1cm4gbGluZS5pbmRleE9mKCdhPWljZS11ZnJhZzonKSA9PT0gMDtcbiAgICB9KVswXS5zdWJzdHIoMTIpLFxuICAgIHBhc3N3b3JkOiBsaW5lcy5maWx0ZXIoZnVuY3Rpb24obGluZSkge1xuICAgICAgcmV0dXJuIGxpbmUuaW5kZXhPZignYT1pY2UtcHdkOicpID09PSAwO1xuICAgIH0pWzBdLnN1YnN0cigxMClcbiAgfTtcbiAgcmV0dXJuIGljZVBhcmFtZXRlcnM7XG59O1xuXG4vLyBTZXJpYWxpemVzIElDRSBwYXJhbWV0ZXJzIHRvIFNEUC5cblNEUFV0aWxzLndyaXRlSWNlUGFyYW1ldGVycyA9IGZ1bmN0aW9uKHBhcmFtcykge1xuICByZXR1cm4gJ2E9aWNlLXVmcmFnOicgKyBwYXJhbXMudXNlcm5hbWVGcmFnbWVudCArICdcXHJcXG4nICtcbiAgICAgICdhPWljZS1wd2Q6JyArIHBhcmFtcy5wYXNzd29yZCArICdcXHJcXG4nO1xufTtcblxuLy8gUGFyc2VzIHRoZSBTRFAgbWVkaWEgc2VjdGlvbiBhbmQgcmV0dXJucyBSVENSdHBQYXJhbWV0ZXJzLlxuU0RQVXRpbHMucGFyc2VSdHBQYXJhbWV0ZXJzID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHZhciBkZXNjcmlwdGlvbiA9IHtcbiAgICBjb2RlY3M6IFtdLFxuICAgIGhlYWRlckV4dGVuc2lvbnM6IFtdLFxuICAgIGZlY01lY2hhbmlzbXM6IFtdLFxuICAgIHJ0Y3A6IFtdXG4gIH07XG4gIHZhciBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMobWVkaWFTZWN0aW9uKTtcbiAgdmFyIG1saW5lID0gbGluZXNbMF0uc3BsaXQoJyAnKTtcbiAgZm9yICh2YXIgaSA9IDM7IGkgPCBtbGluZS5sZW5ndGg7IGkrKykgeyAvLyBmaW5kIGFsbCBjb2RlY3MgZnJvbSBtbGluZVszLi5dXG4gICAgdmFyIHB0ID0gbWxpbmVbaV07XG4gICAgdmFyIHJ0cG1hcGxpbmUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChcbiAgICAgICAgbWVkaWFTZWN0aW9uLCAnYT1ydHBtYXA6JyArIHB0ICsgJyAnKVswXTtcbiAgICBpZiAocnRwbWFwbGluZSkge1xuICAgICAgdmFyIGNvZGVjID0gU0RQVXRpbHMucGFyc2VSdHBNYXAocnRwbWFwbGluZSk7XG4gICAgICB2YXIgZm10cHMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChcbiAgICAgICAgICBtZWRpYVNlY3Rpb24sICdhPWZtdHA6JyArIHB0ICsgJyAnKTtcbiAgICAgIC8vIE9ubHkgdGhlIGZpcnN0IGE9Zm10cDo8cHQ+IGlzIGNvbnNpZGVyZWQuXG4gICAgICBjb2RlYy5wYXJhbWV0ZXJzID0gZm10cHMubGVuZ3RoID8gU0RQVXRpbHMucGFyc2VGbXRwKGZtdHBzWzBdKSA6IHt9O1xuICAgICAgY29kZWMucnRjcEZlZWRiYWNrID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoXG4gICAgICAgICAgbWVkaWFTZWN0aW9uLCAnYT1ydGNwLWZiOicgKyBwdCArICcgJylcbiAgICAgICAgLm1hcChTRFBVdGlscy5wYXJzZVJ0Y3BGYik7XG4gICAgICBkZXNjcmlwdGlvbi5jb2RlY3MucHVzaChjb2RlYyk7XG4gICAgICAvLyBwYXJzZSBGRUMgbWVjaGFuaXNtcyBmcm9tIHJ0cG1hcCBsaW5lcy5cbiAgICAgIHN3aXRjaCAoY29kZWMubmFtZS50b1VwcGVyQ2FzZSgpKSB7XG4gICAgICAgIGNhc2UgJ1JFRCc6XG4gICAgICAgIGNhc2UgJ1VMUEZFQyc6XG4gICAgICAgICAgZGVzY3JpcHRpb24uZmVjTWVjaGFuaXNtcy5wdXNoKGNvZGVjLm5hbWUudG9VcHBlckNhc2UoKSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6IC8vIG9ubHkgUkVEIGFuZCBVTFBGRUMgYXJlIHJlY29nbml6ZWQgYXMgRkVDIG1lY2hhbmlzbXMuXG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9ZXh0bWFwOicpLmZvckVhY2goZnVuY3Rpb24obGluZSkge1xuICAgIGRlc2NyaXB0aW9uLmhlYWRlckV4dGVuc2lvbnMucHVzaChTRFBVdGlscy5wYXJzZUV4dG1hcChsaW5lKSk7XG4gIH0pO1xuICAvLyBGSVhNRTogcGFyc2UgcnRjcC5cbiAgcmV0dXJuIGRlc2NyaXB0aW9uO1xufTtcblxuLy8gR2VuZXJhdGVzIHBhcnRzIG9mIHRoZSBTRFAgbWVkaWEgc2VjdGlvbiBkZXNjcmliaW5nIHRoZSBjYXBhYmlsaXRpZXMgL1xuLy8gcGFyYW1ldGVycy5cblNEUFV0aWxzLndyaXRlUnRwRGVzY3JpcHRpb24gPSBmdW5jdGlvbihraW5kLCBjYXBzKSB7XG4gIHZhciBzZHAgPSAnJztcblxuICAvLyBCdWlsZCB0aGUgbWxpbmUuXG4gIHNkcCArPSAnbT0nICsga2luZCArICcgJztcbiAgc2RwICs9IGNhcHMuY29kZWNzLmxlbmd0aCA+IDAgPyAnOScgOiAnMCc7IC8vIHJlamVjdCBpZiBubyBjb2RlY3MuXG4gIHNkcCArPSAnIFVEUC9UTFMvUlRQL1NBVlBGICc7XG4gIHNkcCArPSBjYXBzLmNvZGVjcy5tYXAoZnVuY3Rpb24oY29kZWMpIHtcbiAgICBpZiAoY29kZWMucHJlZmVycmVkUGF5bG9hZFR5cGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIGNvZGVjLnByZWZlcnJlZFBheWxvYWRUeXBlO1xuICAgIH1cbiAgICByZXR1cm4gY29kZWMucGF5bG9hZFR5cGU7XG4gIH0pLmpvaW4oJyAnKSArICdcXHJcXG4nO1xuXG4gIHNkcCArPSAnYz1JTiBJUDQgMC4wLjAuMFxcclxcbic7XG4gIHNkcCArPSAnYT1ydGNwOjkgSU4gSVA0IDAuMC4wLjBcXHJcXG4nO1xuXG4gIC8vIEFkZCBhPXJ0cG1hcCBsaW5lcyBmb3IgZWFjaCBjb2RlYy4gQWxzbyBmbXRwIGFuZCBydGNwLWZiLlxuICBjYXBzLmNvZGVjcy5mb3JFYWNoKGZ1bmN0aW9uKGNvZGVjKSB7XG4gICAgc2RwICs9IFNEUFV0aWxzLndyaXRlUnRwTWFwKGNvZGVjKTtcbiAgICBzZHAgKz0gU0RQVXRpbHMud3JpdGVGbXRwKGNvZGVjKTtcbiAgICBzZHAgKz0gU0RQVXRpbHMud3JpdGVSdGNwRmIoY29kZWMpO1xuICB9KTtcbiAgdmFyIG1heHB0aW1lID0gMDtcbiAgY2Fwcy5jb2RlY3MuZm9yRWFjaChmdW5jdGlvbihjb2RlYykge1xuICAgIGlmIChjb2RlYy5tYXhwdGltZSA+IG1heHB0aW1lKSB7XG4gICAgICBtYXhwdGltZSA9IGNvZGVjLm1heHB0aW1lO1xuICAgIH1cbiAgfSk7XG4gIGlmIChtYXhwdGltZSA+IDApIHtcbiAgICBzZHAgKz0gJ2E9bWF4cHRpbWU6JyArIG1heHB0aW1lICsgJ1xcclxcbic7XG4gIH1cbiAgc2RwICs9ICdhPXJ0Y3AtbXV4XFxyXFxuJztcblxuICBjYXBzLmhlYWRlckV4dGVuc2lvbnMuZm9yRWFjaChmdW5jdGlvbihleHRlbnNpb24pIHtcbiAgICBzZHAgKz0gU0RQVXRpbHMud3JpdGVFeHRtYXAoZXh0ZW5zaW9uKTtcbiAgfSk7XG4gIC8vIEZJWE1FOiB3cml0ZSBmZWNNZWNoYW5pc21zLlxuICByZXR1cm4gc2RwO1xufTtcblxuLy8gUGFyc2VzIHRoZSBTRFAgbWVkaWEgc2VjdGlvbiBhbmQgcmV0dXJucyBhbiBhcnJheSBvZlxuLy8gUlRDUnRwRW5jb2RpbmdQYXJhbWV0ZXJzLlxuU0RQVXRpbHMucGFyc2VSdHBFbmNvZGluZ1BhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgdmFyIGVuY29kaW5nUGFyYW1ldGVycyA9IFtdO1xuICB2YXIgZGVzY3JpcHRpb24gPSBTRFBVdGlscy5wYXJzZVJ0cFBhcmFtZXRlcnMobWVkaWFTZWN0aW9uKTtcbiAgdmFyIGhhc1JlZCA9IGRlc2NyaXB0aW9uLmZlY01lY2hhbmlzbXMuaW5kZXhPZignUkVEJykgIT09IC0xO1xuICB2YXIgaGFzVWxwZmVjID0gZGVzY3JpcHRpb24uZmVjTWVjaGFuaXNtcy5pbmRleE9mKCdVTFBGRUMnKSAhPT0gLTE7XG5cbiAgLy8gZmlsdGVyIGE9c3NyYzouLi4gY25hbWU6LCBpZ25vcmUgUGxhbkItbXNpZFxuICB2YXIgc3NyY3MgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXNzcmM6JylcbiAgLm1hcChmdW5jdGlvbihsaW5lKSB7XG4gICAgcmV0dXJuIFNEUFV0aWxzLnBhcnNlU3NyY01lZGlhKGxpbmUpO1xuICB9KVxuICAuZmlsdGVyKGZ1bmN0aW9uKHBhcnRzKSB7XG4gICAgcmV0dXJuIHBhcnRzLmF0dHJpYnV0ZSA9PT0gJ2NuYW1lJztcbiAgfSk7XG4gIHZhciBwcmltYXJ5U3NyYyA9IHNzcmNzLmxlbmd0aCA+IDAgJiYgc3NyY3NbMF0uc3NyYztcbiAgdmFyIHNlY29uZGFyeVNzcmM7XG5cbiAgdmFyIGZsb3dzID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zc3JjLWdyb3VwOkZJRCcpXG4gIC5tYXAoZnVuY3Rpb24obGluZSkge1xuICAgIHZhciBwYXJ0cyA9IGxpbmUuc3BsaXQoJyAnKTtcbiAgICBwYXJ0cy5zaGlmdCgpO1xuICAgIHJldHVybiBwYXJ0cy5tYXAoZnVuY3Rpb24ocGFydCkge1xuICAgICAgcmV0dXJuIHBhcnNlSW50KHBhcnQsIDEwKTtcbiAgICB9KTtcbiAgfSk7XG4gIGlmIChmbG93cy5sZW5ndGggPiAwICYmIGZsb3dzWzBdLmxlbmd0aCA+IDEgJiYgZmxvd3NbMF1bMF0gPT09IHByaW1hcnlTc3JjKSB7XG4gICAgc2Vjb25kYXJ5U3NyYyA9IGZsb3dzWzBdWzFdO1xuICB9XG5cbiAgZGVzY3JpcHRpb24uY29kZWNzLmZvckVhY2goZnVuY3Rpb24oY29kZWMpIHtcbiAgICBpZiAoY29kZWMubmFtZS50b1VwcGVyQ2FzZSgpID09PSAnUlRYJyAmJiBjb2RlYy5wYXJhbWV0ZXJzLmFwdCkge1xuICAgICAgdmFyIGVuY1BhcmFtID0ge1xuICAgICAgICBzc3JjOiBwcmltYXJ5U3NyYyxcbiAgICAgICAgY29kZWNQYXlsb2FkVHlwZTogcGFyc2VJbnQoY29kZWMucGFyYW1ldGVycy5hcHQsIDEwKSxcbiAgICAgICAgcnR4OiB7XG4gICAgICAgICAgc3NyYzogc2Vjb25kYXJ5U3NyY1xuICAgICAgICB9XG4gICAgICB9O1xuICAgICAgZW5jb2RpbmdQYXJhbWV0ZXJzLnB1c2goZW5jUGFyYW0pO1xuICAgICAgaWYgKGhhc1JlZCkge1xuICAgICAgICBlbmNQYXJhbSA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoZW5jUGFyYW0pKTtcbiAgICAgICAgZW5jUGFyYW0uZmVjID0ge1xuICAgICAgICAgIHNzcmM6IHNlY29uZGFyeVNzcmMsXG4gICAgICAgICAgbWVjaGFuaXNtOiBoYXNVbHBmZWMgPyAncmVkK3VscGZlYycgOiAncmVkJ1xuICAgICAgICB9O1xuICAgICAgICBlbmNvZGluZ1BhcmFtZXRlcnMucHVzaChlbmNQYXJhbSk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcbiAgaWYgKGVuY29kaW5nUGFyYW1ldGVycy5sZW5ndGggPT09IDAgJiYgcHJpbWFyeVNzcmMpIHtcbiAgICBlbmNvZGluZ1BhcmFtZXRlcnMucHVzaCh7XG4gICAgICBzc3JjOiBwcmltYXJ5U3NyY1xuICAgIH0pO1xuICB9XG5cbiAgLy8gd2Ugc3VwcG9ydCBib3RoIGI9QVMgYW5kIGI9VElBUyBidXQgaW50ZXJwcmV0IEFTIGFzIFRJQVMuXG4gIHZhciBiYW5kd2lkdGggPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdiPScpO1xuICBpZiAoYmFuZHdpZHRoLmxlbmd0aCkge1xuICAgIGlmIChiYW5kd2lkdGhbMF0uaW5kZXhPZignYj1USUFTOicpID09PSAwKSB7XG4gICAgICBiYW5kd2lkdGggPSBwYXJzZUludChiYW5kd2lkdGhbMF0uc3Vic3RyKDcpLCAxMCk7XG4gICAgfSBlbHNlIGlmIChiYW5kd2lkdGhbMF0uaW5kZXhPZignYj1BUzonKSA9PT0gMCkge1xuICAgICAgYmFuZHdpZHRoID0gcGFyc2VJbnQoYmFuZHdpZHRoWzBdLnN1YnN0cig1KSwgMTApO1xuICAgIH1cbiAgICBlbmNvZGluZ1BhcmFtZXRlcnMuZm9yRWFjaChmdW5jdGlvbihwYXJhbXMpIHtcbiAgICAgIHBhcmFtcy5tYXhCaXRyYXRlID0gYmFuZHdpZHRoO1xuICAgIH0pO1xuICB9XG4gIHJldHVybiBlbmNvZGluZ1BhcmFtZXRlcnM7XG59O1xuXG4vLyBwYXJzZXMgaHR0cDovL2RyYWZ0Lm9ydGMub3JnLyNydGNydGNwcGFyYW1ldGVycypcblNEUFV0aWxzLnBhcnNlUnRjcFBhcmFtZXRlcnMgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgdmFyIHJ0Y3BQYXJhbWV0ZXJzID0ge307XG5cbiAgdmFyIGNuYW1lO1xuICAvLyBHZXRzIHRoZSBmaXJzdCBTU1JDLiBOb3RlIHRoYXQgd2l0aCBSVFggdGhlcmUgbWlnaHQgYmUgbXVsdGlwbGVcbiAgLy8gU1NSQ3MuXG4gIHZhciByZW1vdGVTc3JjID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zc3JjOicpXG4gICAgICAubWFwKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgICAgcmV0dXJuIFNEUFV0aWxzLnBhcnNlU3NyY01lZGlhKGxpbmUpO1xuICAgICAgfSlcbiAgICAgIC5maWx0ZXIoZnVuY3Rpb24ob2JqKSB7XG4gICAgICAgIHJldHVybiBvYmouYXR0cmlidXRlID09PSAnY25hbWUnO1xuICAgICAgfSlbMF07XG4gIGlmIChyZW1vdGVTc3JjKSB7XG4gICAgcnRjcFBhcmFtZXRlcnMuY25hbWUgPSByZW1vdGVTc3JjLnZhbHVlO1xuICAgIHJ0Y3BQYXJhbWV0ZXJzLnNzcmMgPSByZW1vdGVTc3JjLnNzcmM7XG4gIH1cblxuICAvLyBFZGdlIHVzZXMgdGhlIGNvbXBvdW5kIGF0dHJpYnV0ZSBpbnN0ZWFkIG9mIHJlZHVjZWRTaXplXG4gIC8vIGNvbXBvdW5kIGlzICFyZWR1Y2VkU2l6ZVxuICB2YXIgcnNpemUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPXJ0Y3AtcnNpemUnKTtcbiAgcnRjcFBhcmFtZXRlcnMucmVkdWNlZFNpemUgPSByc2l6ZS5sZW5ndGggPiAwO1xuICBydGNwUGFyYW1ldGVycy5jb21wb3VuZCA9IHJzaXplLmxlbmd0aCA9PT0gMDtcblxuICAvLyBwYXJzZXMgdGhlIHJ0Y3AtbXV4IGF0dHLRlmJ1dGUuXG4gIC8vIE5vdGUgdGhhdCBFZGdlIGRvZXMgbm90IHN1cHBvcnQgdW5tdXhlZCBSVENQLlxuICB2YXIgbXV4ID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1ydGNwLW11eCcpO1xuICBydGNwUGFyYW1ldGVycy5tdXggPSBtdXgubGVuZ3RoID4gMDtcblxuICByZXR1cm4gcnRjcFBhcmFtZXRlcnM7XG59O1xuXG4vLyBwYXJzZXMgZWl0aGVyIGE9bXNpZDogb3IgYT1zc3JjOi4uLiBtc2lkIGxpbmVzIGFuZCByZXR1cm5zXG4vLyB0aGUgaWQgb2YgdGhlIE1lZGlhU3RyZWFtIGFuZCBNZWRpYVN0cmVhbVRyYWNrLlxuU0RQVXRpbHMucGFyc2VNc2lkID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHZhciBwYXJ0cztcbiAgdmFyIHNwZWMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPW1zaWQ6Jyk7XG4gIGlmIChzcGVjLmxlbmd0aCA9PT0gMSkge1xuICAgIHBhcnRzID0gc3BlY1swXS5zdWJzdHIoNykuc3BsaXQoJyAnKTtcbiAgICByZXR1cm4ge3N0cmVhbTogcGFydHNbMF0sIHRyYWNrOiBwYXJ0c1sxXX07XG4gIH1cbiAgdmFyIHBsYW5CID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgobWVkaWFTZWN0aW9uLCAnYT1zc3JjOicpXG4gIC5tYXAoZnVuY3Rpb24obGluZSkge1xuICAgIHJldHVybiBTRFBVdGlscy5wYXJzZVNzcmNNZWRpYShsaW5lKTtcbiAgfSlcbiAgLmZpbHRlcihmdW5jdGlvbihwYXJ0cykge1xuICAgIHJldHVybiBwYXJ0cy5hdHRyaWJ1dGUgPT09ICdtc2lkJztcbiAgfSk7XG4gIGlmIChwbGFuQi5sZW5ndGggPiAwKSB7XG4gICAgcGFydHMgPSBwbGFuQlswXS52YWx1ZS5zcGxpdCgnICcpO1xuICAgIHJldHVybiB7c3RyZWFtOiBwYXJ0c1swXSwgdHJhY2s6IHBhcnRzWzFdfTtcbiAgfVxufTtcblxuU0RQVXRpbHMud3JpdGVTZXNzaW9uQm9pbGVycGxhdGUgPSBmdW5jdGlvbigpIHtcbiAgLy8gRklYTUU6IHNlc3MtaWQgc2hvdWxkIGJlIGFuIE5UUCB0aW1lc3RhbXAuXG4gIHJldHVybiAndj0wXFxyXFxuJyArXG4gICAgICAnbz10aGlzaXNhZGFwdGVyb3J0YyA4MTY5NjM5OTE1NjQ2OTQzMTM3IDIgSU4gSVA0IDEyNy4wLjAuMVxcclxcbicgK1xuICAgICAgJ3M9LVxcclxcbicgK1xuICAgICAgJ3Q9MCAwXFxyXFxuJztcbn07XG5cblNEUFV0aWxzLndyaXRlTWVkaWFTZWN0aW9uID0gZnVuY3Rpb24odHJhbnNjZWl2ZXIsIGNhcHMsIHR5cGUsIHN0cmVhbSkge1xuICB2YXIgc2RwID0gU0RQVXRpbHMud3JpdGVSdHBEZXNjcmlwdGlvbih0cmFuc2NlaXZlci5raW5kLCBjYXBzKTtcblxuICAvLyBNYXAgSUNFIHBhcmFtZXRlcnMgKHVmcmFnLCBwd2QpIHRvIFNEUC5cbiAgc2RwICs9IFNEUFV0aWxzLndyaXRlSWNlUGFyYW1ldGVycyhcbiAgICAgIHRyYW5zY2VpdmVyLmljZUdhdGhlcmVyLmdldExvY2FsUGFyYW1ldGVycygpKTtcblxuICAvLyBNYXAgRFRMUyBwYXJhbWV0ZXJzIHRvIFNEUC5cbiAgc2RwICs9IFNEUFV0aWxzLndyaXRlRHRsc1BhcmFtZXRlcnMoXG4gICAgICB0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0LmdldExvY2FsUGFyYW1ldGVycygpLFxuICAgICAgdHlwZSA9PT0gJ29mZmVyJyA/ICdhY3RwYXNzJyA6ICdhY3RpdmUnKTtcblxuICBzZHAgKz0gJ2E9bWlkOicgKyB0cmFuc2NlaXZlci5taWQgKyAnXFxyXFxuJztcblxuICBpZiAodHJhbnNjZWl2ZXIuZGlyZWN0aW9uKSB7XG4gICAgc2RwICs9ICdhPScgKyB0cmFuc2NlaXZlci5kaXJlY3Rpb24gKyAnXFxyXFxuJztcbiAgfSBlbHNlIGlmICh0cmFuc2NlaXZlci5ydHBTZW5kZXIgJiYgdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXIpIHtcbiAgICBzZHAgKz0gJ2E9c2VuZHJlY3ZcXHJcXG4nO1xuICB9IGVsc2UgaWYgKHRyYW5zY2VpdmVyLnJ0cFNlbmRlcikge1xuICAgIHNkcCArPSAnYT1zZW5kb25seVxcclxcbic7XG4gIH0gZWxzZSBpZiAodHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXIpIHtcbiAgICBzZHAgKz0gJ2E9cmVjdm9ubHlcXHJcXG4nO1xuICB9IGVsc2Uge1xuICAgIHNkcCArPSAnYT1pbmFjdGl2ZVxcclxcbic7XG4gIH1cblxuICBpZiAodHJhbnNjZWl2ZXIucnRwU2VuZGVyKSB7XG4gICAgLy8gc3BlYy5cbiAgICB2YXIgbXNpZCA9ICdtc2lkOicgKyBzdHJlYW0uaWQgKyAnICcgK1xuICAgICAgICB0cmFuc2NlaXZlci5ydHBTZW5kZXIudHJhY2suaWQgKyAnXFxyXFxuJztcbiAgICBzZHAgKz0gJ2E9JyArIG1zaWQ7XG5cbiAgICAvLyBmb3IgQ2hyb21lLlxuICAgIHNkcCArPSAnYT1zc3JjOicgKyB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnNzcmMgK1xuICAgICAgICAnICcgKyBtc2lkO1xuICAgIGlmICh0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eCkge1xuICAgICAgc2RwICs9ICdhPXNzcmM6JyArIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0ucnR4LnNzcmMgK1xuICAgICAgICAgICcgJyArIG1zaWQ7XG4gICAgICBzZHAgKz0gJ2E9c3NyYy1ncm91cDpGSUQgJyArXG4gICAgICAgICAgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5zc3JjICsgJyAnICtcbiAgICAgICAgICB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eC5zc3JjICtcbiAgICAgICAgICAnXFxyXFxuJztcbiAgICB9XG4gIH1cbiAgLy8gRklYTUU6IHRoaXMgc2hvdWxkIGJlIHdyaXR0ZW4gYnkgd3JpdGVSdHBEZXNjcmlwdGlvbi5cbiAgc2RwICs9ICdhPXNzcmM6JyArIHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0uc3NyYyArXG4gICAgICAnIGNuYW1lOicgKyBTRFBVdGlscy5sb2NhbENOYW1lICsgJ1xcclxcbic7XG4gIGlmICh0cmFuc2NlaXZlci5ydHBTZW5kZXIgJiYgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHgpIHtcbiAgICBzZHAgKz0gJ2E9c3NyYzonICsgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHguc3NyYyArXG4gICAgICAgICcgY25hbWU6JyArIFNEUFV0aWxzLmxvY2FsQ05hbWUgKyAnXFxyXFxuJztcbiAgfVxuICByZXR1cm4gc2RwO1xufTtcblxuLy8gR2V0cyB0aGUgZGlyZWN0aW9uIGZyb20gdGhlIG1lZGlhU2VjdGlvbiBvciB0aGUgc2Vzc2lvbnBhcnQuXG5TRFBVdGlscy5nZXREaXJlY3Rpb24gPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KSB7XG4gIC8vIExvb2sgZm9yIHNlbmRyZWN2LCBzZW5kb25seSwgcmVjdm9ubHksIGluYWN0aXZlLCBkZWZhdWx0IHRvIHNlbmRyZWN2LlxuICB2YXIgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICBzd2l0Y2ggKGxpbmVzW2ldKSB7XG4gICAgICBjYXNlICdhPXNlbmRyZWN2JzpcbiAgICAgIGNhc2UgJ2E9c2VuZG9ubHknOlxuICAgICAgY2FzZSAnYT1yZWN2b25seSc6XG4gICAgICBjYXNlICdhPWluYWN0aXZlJzpcbiAgICAgICAgcmV0dXJuIGxpbmVzW2ldLnN1YnN0cigyKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIC8vIEZJWE1FOiBXaGF0IHNob3VsZCBoYXBwZW4gaGVyZT9cbiAgICB9XG4gIH1cbiAgaWYgKHNlc3Npb25wYXJ0KSB7XG4gICAgcmV0dXJuIFNEUFV0aWxzLmdldERpcmVjdGlvbihzZXNzaW9ucGFydCk7XG4gIH1cbiAgcmV0dXJuICdzZW5kcmVjdic7XG59O1xuXG5TRFBVdGlscy5nZXRLaW5kID0gZnVuY3Rpb24obWVkaWFTZWN0aW9uKSB7XG4gIHZhciBsaW5lcyA9IFNEUFV0aWxzLnNwbGl0TGluZXMobWVkaWFTZWN0aW9uKTtcbiAgdmFyIG1saW5lID0gbGluZXNbMF0uc3BsaXQoJyAnKTtcbiAgcmV0dXJuIG1saW5lWzBdLnN1YnN0cigyKTtcbn07XG5cblNEUFV0aWxzLmlzUmVqZWN0ZWQgPSBmdW5jdGlvbihtZWRpYVNlY3Rpb24pIHtcbiAgcmV0dXJuIG1lZGlhU2VjdGlvbi5zcGxpdCgnICcsIDIpWzFdID09PSAnMCc7XG59O1xuXG4vLyBFeHBvc2UgcHVibGljIG1ldGhvZHMuXG5tb2R1bGUuZXhwb3J0cyA9IFNEUFV0aWxzO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdHJhbnNwb3J0TGlzdCA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0LWxpc3QnKTtcblxubW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL21haW4nKSh0cmFuc3BvcnRMaXN0KTtcblxuLy8gVE9ETyBjYW4ndCBnZXQgcmlkIG9mIHRoaXMgdW50aWwgYWxsIHNlcnZlcnMgZG9cbmlmICgnX3NvY2tqc19vbmxvYWQnIGluIGdsb2JhbCkge1xuICBzZXRUaW1lb3V0KGdsb2JhbC5fc29ja2pzX29ubG9hZCwgMSk7XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBFdmVudCA9IHJlcXVpcmUoJy4vZXZlbnQnKVxuICA7XG5cbmZ1bmN0aW9uIENsb3NlRXZlbnQoKSB7XG4gIEV2ZW50LmNhbGwodGhpcyk7XG4gIHRoaXMuaW5pdEV2ZW50KCdjbG9zZScsIGZhbHNlLCBmYWxzZSk7XG4gIHRoaXMud2FzQ2xlYW4gPSBmYWxzZTtcbiAgdGhpcy5jb2RlID0gMDtcbiAgdGhpcy5yZWFzb24gPSAnJztcbn1cblxuaW5oZXJpdHMoQ2xvc2VFdmVudCwgRXZlbnQpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IENsb3NlRXZlbnQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBFdmVudFRhcmdldCA9IHJlcXVpcmUoJy4vZXZlbnR0YXJnZXQnKVxuICA7XG5cbmZ1bmN0aW9uIEV2ZW50RW1pdHRlcigpIHtcbiAgRXZlbnRUYXJnZXQuY2FsbCh0aGlzKTtcbn1cblxuaW5oZXJpdHMoRXZlbnRFbWl0dGVyLCBFdmVudFRhcmdldCk7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlQWxsTGlzdGVuZXJzID0gZnVuY3Rpb24odHlwZSkge1xuICBpZiAodHlwZSkge1xuICAgIGRlbGV0ZSB0aGlzLl9saXN0ZW5lcnNbdHlwZV07XG4gIH0gZWxzZSB7XG4gICAgdGhpcy5fbGlzdGVuZXJzID0ge307XG4gIH1cbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub25jZSA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHZhciBzZWxmID0gdGhpc1xuICAgICwgZmlyZWQgPSBmYWxzZTtcblxuICBmdW5jdGlvbiBnKCkge1xuICAgIHNlbGYucmVtb3ZlTGlzdGVuZXIodHlwZSwgZyk7XG5cbiAgICBpZiAoIWZpcmVkKSB7XG4gICAgICBmaXJlZCA9IHRydWU7XG4gICAgICBsaXN0ZW5lci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH1cbiAgfVxuXG4gIHRoaXMub24odHlwZSwgZyk7XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmVtaXQgPSBmdW5jdGlvbigpIHtcbiAgdmFyIHR5cGUgPSBhcmd1bWVudHNbMF07XG4gIHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnNbdHlwZV07XG4gIGlmICghbGlzdGVuZXJzKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIC8vIGVxdWl2YWxlbnQgb2YgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgdmFyIGwgPSBhcmd1bWVudHMubGVuZ3RoO1xuICB2YXIgYXJncyA9IG5ldyBBcnJheShsIC0gMSk7XG4gIGZvciAodmFyIGFpID0gMTsgYWkgPCBsOyBhaSsrKSB7XG4gICAgYXJnc1thaSAtIDFdID0gYXJndW1lbnRzW2FpXTtcbiAgfVxuICBmb3IgKHZhciBpID0gMDsgaSA8IGxpc3RlbmVycy5sZW5ndGg7IGkrKykge1xuICAgIGxpc3RlbmVyc1tpXS5hcHBseSh0aGlzLCBhcmdzKTtcbiAgfVxufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbiA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXIgPSBFdmVudFRhcmdldC5wcm90b3R5cGUuYWRkRXZlbnRMaXN0ZW5lcjtcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlTGlzdGVuZXIgPSBFdmVudFRhcmdldC5wcm90b3R5cGUucmVtb3ZlRXZlbnRMaXN0ZW5lcjtcblxubW9kdWxlLmV4cG9ydHMuRXZlbnRFbWl0dGVyID0gRXZlbnRFbWl0dGVyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBFdmVudChldmVudFR5cGUpIHtcbiAgdGhpcy50eXBlID0gZXZlbnRUeXBlO1xufVxuXG5FdmVudC5wcm90b3R5cGUuaW5pdEV2ZW50ID0gZnVuY3Rpb24oZXZlbnRUeXBlLCBjYW5CdWJibGUsIGNhbmNlbGFibGUpIHtcbiAgdGhpcy50eXBlID0gZXZlbnRUeXBlO1xuICB0aGlzLmJ1YmJsZXMgPSBjYW5CdWJibGU7XG4gIHRoaXMuY2FuY2VsYWJsZSA9IGNhbmNlbGFibGU7XG4gIHRoaXMudGltZVN0YW1wID0gK25ldyBEYXRlKCk7XG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnQucHJvdG90eXBlLnN0b3BQcm9wYWdhdGlvbiA9IGZ1bmN0aW9uKCkge307XG5FdmVudC5wcm90b3R5cGUucHJldmVudERlZmF1bHQgPSBmdW5jdGlvbigpIHt9O1xuXG5FdmVudC5DQVBUVVJJTkdfUEhBU0UgPSAxO1xuRXZlbnQuQVRfVEFSR0VUID0gMjtcbkV2ZW50LkJVQkJMSU5HX1BIQVNFID0gMztcblxubW9kdWxlLmV4cG9ydHMgPSBFdmVudDtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyogU2ltcGxpZmllZCBpbXBsZW1lbnRhdGlvbiBvZiBET00yIEV2ZW50VGFyZ2V0LlxuICogICBodHRwOi8vd3d3LnczLm9yZy9UUi9ET00tTGV2ZWwtMi1FdmVudHMvZXZlbnRzLmh0bWwjRXZlbnRzLUV2ZW50VGFyZ2V0XG4gKi9cblxuZnVuY3Rpb24gRXZlbnRUYXJnZXQoKSB7XG4gIHRoaXMuX2xpc3RlbmVycyA9IHt9O1xufVxuXG5FdmVudFRhcmdldC5wcm90b3R5cGUuYWRkRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uKGV2ZW50VHlwZSwgbGlzdGVuZXIpIHtcbiAgaWYgKCEoZXZlbnRUeXBlIGluIHRoaXMuX2xpc3RlbmVycykpIHtcbiAgICB0aGlzLl9saXN0ZW5lcnNbZXZlbnRUeXBlXSA9IFtdO1xuICB9XG4gIHZhciBhcnIgPSB0aGlzLl9saXN0ZW5lcnNbZXZlbnRUeXBlXTtcbiAgLy8gIzRcbiAgaWYgKGFyci5pbmRleE9mKGxpc3RlbmVyKSA9PT0gLTEpIHtcbiAgICAvLyBNYWtlIGEgY29weSBzbyBhcyBub3QgdG8gaW50ZXJmZXJlIHdpdGggYSBjdXJyZW50IGRpc3BhdGNoRXZlbnQuXG4gICAgYXJyID0gYXJyLmNvbmNhdChbbGlzdGVuZXJdKTtcbiAgfVxuICB0aGlzLl9saXN0ZW5lcnNbZXZlbnRUeXBlXSA9IGFycjtcbn07XG5cbkV2ZW50VGFyZ2V0LnByb3RvdHlwZS5yZW1vdmVFdmVudExpc3RlbmVyID0gZnVuY3Rpb24oZXZlbnRUeXBlLCBsaXN0ZW5lcikge1xuICB2YXIgYXJyID0gdGhpcy5fbGlzdGVuZXJzW2V2ZW50VHlwZV07XG4gIGlmICghYXJyKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHZhciBpZHggPSBhcnIuaW5kZXhPZihsaXN0ZW5lcik7XG4gIGlmIChpZHggIT09IC0xKSB7XG4gICAgaWYgKGFyci5sZW5ndGggPiAxKSB7XG4gICAgICAvLyBNYWtlIGEgY29weSBzbyBhcyBub3QgdG8gaW50ZXJmZXJlIHdpdGggYSBjdXJyZW50IGRpc3BhdGNoRXZlbnQuXG4gICAgICB0aGlzLl9saXN0ZW5lcnNbZXZlbnRUeXBlXSA9IGFyci5zbGljZSgwLCBpZHgpLmNvbmNhdChhcnIuc2xpY2UoaWR4ICsgMSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWxldGUgdGhpcy5fbGlzdGVuZXJzW2V2ZW50VHlwZV07XG4gICAgfVxuICAgIHJldHVybjtcbiAgfVxufTtcblxuRXZlbnRUYXJnZXQucHJvdG90eXBlLmRpc3BhdGNoRXZlbnQgPSBmdW5jdGlvbigpIHtcbiAgdmFyIGV2ZW50ID0gYXJndW1lbnRzWzBdO1xuICB2YXIgdCA9IGV2ZW50LnR5cGU7XG4gIC8vIGVxdWl2YWxlbnQgb2YgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAwKTtcbiAgdmFyIGFyZ3MgPSBhcmd1bWVudHMubGVuZ3RoID09PSAxID8gW2V2ZW50XSA6IEFycmF5LmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gIC8vIFRPRE86IFRoaXMgZG9lc24ndCBtYXRjaCB0aGUgcmVhbCBiZWhhdmlvcjsgcGVyIHNwZWMsIG9uZm9vIGdldFxuICAvLyB0aGVpciBwbGFjZSBpbiBsaW5lIGZyb20gdGhlIC9maXJzdC8gdGltZSB0aGV5J3JlIHNldCBmcm9tXG4gIC8vIG5vbi1udWxsLiBBbHRob3VnaCBXZWJLaXQgYnVtcHMgaXQgdG8gdGhlIGVuZCBldmVyeSB0aW1lIGl0J3NcbiAgLy8gc2V0LlxuICBpZiAodGhpc1snb24nICsgdF0pIHtcbiAgICB0aGlzWydvbicgKyB0XS5hcHBseSh0aGlzLCBhcmdzKTtcbiAgfVxuICBpZiAodCBpbiB0aGlzLl9saXN0ZW5lcnMpIHtcbiAgICAvLyBHcmFiIGEgcmVmZXJlbmNlIHRvIHRoZSBsaXN0ZW5lcnMgbGlzdC4gcmVtb3ZlRXZlbnRMaXN0ZW5lciBtYXkgYWx0ZXIgdGhlIGxpc3QuXG4gICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuX2xpc3RlbmVyc1t0XTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxpc3RlbmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgbGlzdGVuZXJzW2ldLmFwcGx5KHRoaXMsIGFyZ3MpO1xuICAgIH1cbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBFdmVudFRhcmdldDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEV2ZW50ID0gcmVxdWlyZSgnLi9ldmVudCcpXG4gIDtcblxuZnVuY3Rpb24gVHJhbnNwb3J0TWVzc2FnZUV2ZW50KGRhdGEpIHtcbiAgRXZlbnQuY2FsbCh0aGlzKTtcbiAgdGhpcy5pbml0RXZlbnQoJ21lc3NhZ2UnLCBmYWxzZSwgZmFsc2UpO1xuICB0aGlzLmRhdGEgPSBkYXRhO1xufVxuXG5pbmhlcml0cyhUcmFuc3BvcnRNZXNzYWdlRXZlbnQsIEV2ZW50KTtcblxubW9kdWxlLmV4cG9ydHMgPSBUcmFuc3BvcnRNZXNzYWdlRXZlbnQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBKU09OMyA9IHJlcXVpcmUoJ2pzb24zJylcbiAgLCBpZnJhbWVVdGlscyA9IHJlcXVpcmUoJy4vdXRpbHMvaWZyYW1lJylcbiAgO1xuXG5mdW5jdGlvbiBGYWNhZGVKUyh0cmFuc3BvcnQpIHtcbiAgdGhpcy5fdHJhbnNwb3J0ID0gdHJhbnNwb3J0O1xuICB0cmFuc3BvcnQub24oJ21lc3NhZ2UnLCB0aGlzLl90cmFuc3BvcnRNZXNzYWdlLmJpbmQodGhpcykpO1xuICB0cmFuc3BvcnQub24oJ2Nsb3NlJywgdGhpcy5fdHJhbnNwb3J0Q2xvc2UuYmluZCh0aGlzKSk7XG59XG5cbkZhY2FkZUpTLnByb3RvdHlwZS5fdHJhbnNwb3J0Q2xvc2UgPSBmdW5jdGlvbihjb2RlLCByZWFzb24pIHtcbiAgaWZyYW1lVXRpbHMucG9zdE1lc3NhZ2UoJ2MnLCBKU09OMy5zdHJpbmdpZnkoW2NvZGUsIHJlYXNvbl0pKTtcbn07XG5GYWNhZGVKUy5wcm90b3R5cGUuX3RyYW5zcG9ydE1lc3NhZ2UgPSBmdW5jdGlvbihmcmFtZSkge1xuICBpZnJhbWVVdGlscy5wb3N0TWVzc2FnZSgndCcsIGZyYW1lKTtcbn07XG5GYWNhZGVKUy5wcm90b3R5cGUuX3NlbmQgPSBmdW5jdGlvbihkYXRhKSB7XG4gIHRoaXMuX3RyYW5zcG9ydC5zZW5kKGRhdGEpO1xufTtcbkZhY2FkZUpTLnByb3RvdHlwZS5fY2xvc2UgPSBmdW5jdGlvbigpIHtcbiAgdGhpcy5fdHJhbnNwb3J0LmNsb3NlKCk7XG4gIHRoaXMuX3RyYW5zcG9ydC5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRmFjYWRlSlM7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciB1cmxVdGlscyA9IHJlcXVpcmUoJy4vdXRpbHMvdXJsJylcbiAgLCBldmVudFV0aWxzID0gcmVxdWlyZSgnLi91dGlscy9ldmVudCcpXG4gICwgSlNPTjMgPSByZXF1aXJlKCdqc29uMycpXG4gICwgRmFjYWRlSlMgPSByZXF1aXJlKCcuL2ZhY2FkZScpXG4gICwgSW5mb0lmcmFtZVJlY2VpdmVyID0gcmVxdWlyZSgnLi9pbmZvLWlmcmFtZS1yZWNlaXZlcicpXG4gICwgaWZyYW1lVXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzL2lmcmFtZScpXG4gICwgbG9jID0gcmVxdWlyZSgnLi9sb2NhdGlvbicpXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDppZnJhbWUtYm9vdHN0cmFwJyk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oU29ja0pTLCBhdmFpbGFibGVUcmFuc3BvcnRzKSB7XG4gIHZhciB0cmFuc3BvcnRNYXAgPSB7fTtcbiAgYXZhaWxhYmxlVHJhbnNwb3J0cy5mb3JFYWNoKGZ1bmN0aW9uKGF0KSB7XG4gICAgaWYgKGF0LmZhY2FkZVRyYW5zcG9ydCkge1xuICAgICAgdHJhbnNwb3J0TWFwW2F0LmZhY2FkZVRyYW5zcG9ydC50cmFuc3BvcnROYW1lXSA9IGF0LmZhY2FkZVRyYW5zcG9ydDtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIGhhcmQtY29kZWQgZm9yIHRoZSBpbmZvIGlmcmFtZVxuICAvLyBUT0RPIHNlZSBpZiB3ZSBjYW4gbWFrZSB0aGlzIG1vcmUgZHluYW1pY1xuICB0cmFuc3BvcnRNYXBbSW5mb0lmcmFtZVJlY2VpdmVyLnRyYW5zcG9ydE5hbWVdID0gSW5mb0lmcmFtZVJlY2VpdmVyO1xuICB2YXIgcGFyZW50T3JpZ2luO1xuXG4gIC8qIGVzbGludC1kaXNhYmxlIGNhbWVsY2FzZSAqL1xuICBTb2NrSlMuYm9vdHN0cmFwX2lmcmFtZSA9IGZ1bmN0aW9uKCkge1xuICAgIC8qIGVzbGludC1lbmFibGUgY2FtZWxjYXNlICovXG4gICAgdmFyIGZhY2FkZTtcbiAgICBpZnJhbWVVdGlscy5jdXJyZW50V2luZG93SWQgPSBsb2MuaGFzaC5zbGljZSgxKTtcbiAgICB2YXIgb25NZXNzYWdlID0gZnVuY3Rpb24oZSkge1xuICAgICAgaWYgKGUuc291cmNlICE9PSBwYXJlbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGVvZiBwYXJlbnRPcmlnaW4gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHBhcmVudE9yaWdpbiA9IGUub3JpZ2luO1xuICAgICAgfVxuICAgICAgaWYgKGUub3JpZ2luICE9PSBwYXJlbnRPcmlnaW4pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICB2YXIgaWZyYW1lTWVzc2FnZTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGlmcmFtZU1lc3NhZ2UgPSBKU09OMy5wYXJzZShlLmRhdGEpO1xuICAgICAgfSBjYXRjaCAoaWdub3JlZCkge1xuICAgICAgICBkZWJ1ZygnYmFkIGpzb24nLCBlLmRhdGEpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChpZnJhbWVNZXNzYWdlLndpbmRvd0lkICE9PSBpZnJhbWVVdGlscy5jdXJyZW50V2luZG93SWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgc3dpdGNoIChpZnJhbWVNZXNzYWdlLnR5cGUpIHtcbiAgICAgIGNhc2UgJ3MnOlxuICAgICAgICB2YXIgcDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBwID0gSlNPTjMucGFyc2UoaWZyYW1lTWVzc2FnZS5kYXRhKTtcbiAgICAgICAgfSBjYXRjaCAoaWdub3JlZCkge1xuICAgICAgICAgIGRlYnVnKCdiYWQganNvbicsIGlmcmFtZU1lc3NhZ2UuZGF0YSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHZlcnNpb24gPSBwWzBdO1xuICAgICAgICB2YXIgdHJhbnNwb3J0ID0gcFsxXTtcbiAgICAgICAgdmFyIHRyYW5zVXJsID0gcFsyXTtcbiAgICAgICAgdmFyIGJhc2VVcmwgPSBwWzNdO1xuICAgICAgICBkZWJ1Zyh2ZXJzaW9uLCB0cmFuc3BvcnQsIHRyYW5zVXJsLCBiYXNlVXJsKTtcbiAgICAgICAgLy8gY2hhbmdlIHRoaXMgdG8gc2VtdmVyIGxvZ2ljXG4gICAgICAgIGlmICh2ZXJzaW9uICE9PSBTb2NrSlMudmVyc2lvbikge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW5jb21wYXRpYmxlIFNvY2tKUyEgTWFpbiBzaXRlIHVzZXM6JyArXG4gICAgICAgICAgICAgICAgICAgICcgXCInICsgdmVyc2lvbiArICdcIiwgdGhlIGlmcmFtZTonICtcbiAgICAgICAgICAgICAgICAgICAgJyBcIicgKyBTb2NrSlMudmVyc2lvbiArICdcIi4nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdXJsVXRpbHMuaXNPcmlnaW5FcXVhbCh0cmFuc1VybCwgbG9jLmhyZWYpIHx8XG4gICAgICAgICAgICAhdXJsVXRpbHMuaXNPcmlnaW5FcXVhbChiYXNlVXJsLCBsb2MuaHJlZikpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NhblxcJ3QgY29ubmVjdCB0byBkaWZmZXJlbnQgZG9tYWluIGZyb20gd2l0aGluIGFuICcgK1xuICAgICAgICAgICAgICAgICAgICAnaWZyYW1lLiAoJyArIGxvYy5ocmVmICsgJywgJyArIHRyYW5zVXJsICsgJywgJyArIGJhc2VVcmwgKyAnKScpO1xuICAgICAgICB9XG4gICAgICAgIGZhY2FkZSA9IG5ldyBGYWNhZGVKUyhuZXcgdHJhbnNwb3J0TWFwW3RyYW5zcG9ydF0odHJhbnNVcmwsIGJhc2VVcmwpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdtJzpcbiAgICAgICAgZmFjYWRlLl9zZW5kKGlmcmFtZU1lc3NhZ2UuZGF0YSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnYyc6XG4gICAgICAgIGlmIChmYWNhZGUpIHtcbiAgICAgICAgICBmYWNhZGUuX2Nsb3NlKCk7XG4gICAgICAgIH1cbiAgICAgICAgZmFjYWRlID0gbnVsbDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfTtcblxuICAgIGV2ZW50VXRpbHMuYXR0YWNoRXZlbnQoJ21lc3NhZ2UnLCBvbk1lc3NhZ2UpO1xuXG4gICAgLy8gU3RhcnRcbiAgICBpZnJhbWVVdGlscy5wb3N0TWVzc2FnZSgncycpO1xuICB9O1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxuICAsIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEpTT04zID0gcmVxdWlyZSgnanNvbjMnKVxuICAsIG9iamVjdFV0aWxzID0gcmVxdWlyZSgnLi91dGlscy9vYmplY3QnKVxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6aW5mby1hamF4Jyk7XG59XG5cbmZ1bmN0aW9uIEluZm9BamF4KHVybCwgQWpheE9iamVjdCkge1xuICBFdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcblxuICB2YXIgc2VsZiA9IHRoaXM7XG4gIHZhciB0MCA9ICtuZXcgRGF0ZSgpO1xuICB0aGlzLnhvID0gbmV3IEFqYXhPYmplY3QoJ0dFVCcsIHVybCk7XG5cbiAgdGhpcy54by5vbmNlKCdmaW5pc2gnLCBmdW5jdGlvbihzdGF0dXMsIHRleHQpIHtcbiAgICB2YXIgaW5mbywgcnR0O1xuICAgIGlmIChzdGF0dXMgPT09IDIwMCkge1xuICAgICAgcnR0ID0gKCtuZXcgRGF0ZSgpKSAtIHQwO1xuICAgICAgaWYgKHRleHQpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpbmZvID0gSlNPTjMucGFyc2UodGV4dCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICBkZWJ1ZygnYmFkIGpzb24nLCB0ZXh0KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoIW9iamVjdFV0aWxzLmlzT2JqZWN0KGluZm8pKSB7XG4gICAgICAgIGluZm8gPSB7fTtcbiAgICAgIH1cbiAgICB9XG4gICAgc2VsZi5lbWl0KCdmaW5pc2gnLCBpbmZvLCBydHQpO1xuICAgIHNlbGYucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gIH0pO1xufVxuXG5pbmhlcml0cyhJbmZvQWpheCwgRXZlbnRFbWl0dGVyKTtcblxuSW5mb0FqYXgucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24oKSB7XG4gIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gIHRoaXMueG8uY2xvc2UoKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSW5mb0FqYXg7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXJcbiAgLCBKU09OMyA9IHJlcXVpcmUoJ2pzb24zJylcbiAgLCBYSFJMb2NhbE9iamVjdCA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L3NlbmRlci94aHItbG9jYWwnKVxuICAsIEluZm9BamF4ID0gcmVxdWlyZSgnLi9pbmZvLWFqYXgnKVxuICA7XG5cbmZ1bmN0aW9uIEluZm9SZWNlaXZlcklmcmFtZSh0cmFuc1VybCkge1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuXG4gIHRoaXMuaXIgPSBuZXcgSW5mb0FqYXgodHJhbnNVcmwsIFhIUkxvY2FsT2JqZWN0KTtcbiAgdGhpcy5pci5vbmNlKCdmaW5pc2gnLCBmdW5jdGlvbihpbmZvLCBydHQpIHtcbiAgICBzZWxmLmlyID0gbnVsbDtcbiAgICBzZWxmLmVtaXQoJ21lc3NhZ2UnLCBKU09OMy5zdHJpbmdpZnkoW2luZm8sIHJ0dF0pKTtcbiAgfSk7XG59XG5cbmluaGVyaXRzKEluZm9SZWNlaXZlcklmcmFtZSwgRXZlbnRFbWl0dGVyKTtcblxuSW5mb1JlY2VpdmVySWZyYW1lLnRyYW5zcG9ydE5hbWUgPSAnaWZyYW1lLWluZm8tcmVjZWl2ZXInO1xuXG5JbmZvUmVjZWl2ZXJJZnJhbWUucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24oKSB7XG4gIGlmICh0aGlzLmlyKSB7XG4gICAgdGhpcy5pci5jbG9zZSgpO1xuICAgIHRoaXMuaXIgPSBudWxsO1xuICB9XG4gIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEluZm9SZWNlaXZlcklmcmFtZTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxuICAsIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEpTT04zID0gcmVxdWlyZSgnanNvbjMnKVxuICAsIHV0aWxzID0gcmVxdWlyZSgnLi91dGlscy9ldmVudCcpXG4gICwgSWZyYW1lVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvaWZyYW1lJylcbiAgLCBJbmZvUmVjZWl2ZXJJZnJhbWUgPSByZXF1aXJlKCcuL2luZm8taWZyYW1lLXJlY2VpdmVyJylcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OmluZm8taWZyYW1lJyk7XG59XG5cbmZ1bmN0aW9uIEluZm9JZnJhbWUoYmFzZVVybCwgdXJsKSB7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG5cbiAgdmFyIGdvID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGlmciA9IHNlbGYuaWZyID0gbmV3IElmcmFtZVRyYW5zcG9ydChJbmZvUmVjZWl2ZXJJZnJhbWUudHJhbnNwb3J0TmFtZSwgdXJsLCBiYXNlVXJsKTtcblxuICAgIGlmci5vbmNlKCdtZXNzYWdlJywgZnVuY3Rpb24obXNnKSB7XG4gICAgICBpZiAobXNnKSB7XG4gICAgICAgIHZhciBkO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGQgPSBKU09OMy5wYXJzZShtc2cpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgZGVidWcoJ2JhZCBqc29uJywgbXNnKTtcbiAgICAgICAgICBzZWxmLmVtaXQoJ2ZpbmlzaCcpO1xuICAgICAgICAgIHNlbGYuY2xvc2UoKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgaW5mbyA9IGRbMF0sIHJ0dCA9IGRbMV07XG4gICAgICAgIHNlbGYuZW1pdCgnZmluaXNoJywgaW5mbywgcnR0KTtcbiAgICAgIH1cbiAgICAgIHNlbGYuY2xvc2UoKTtcbiAgICB9KTtcblxuICAgIGlmci5vbmNlKCdjbG9zZScsIGZ1bmN0aW9uKCkge1xuICAgICAgc2VsZi5lbWl0KCdmaW5pc2gnKTtcbiAgICAgIHNlbGYuY2xvc2UoKTtcbiAgICB9KTtcbiAgfTtcblxuICAvLyBUT0RPIHRoaXMgc2VlbXMgdGhlIHNhbWUgYXMgdGhlICduZWVkQm9keScgZnJvbSB0cmFuc3BvcnRzXG4gIGlmICghZ2xvYmFsLmRvY3VtZW50LmJvZHkpIHtcbiAgICB1dGlscy5hdHRhY2hFdmVudCgnbG9hZCcsIGdvKTtcbiAgfSBlbHNlIHtcbiAgICBnbygpO1xuICB9XG59XG5cbmluaGVyaXRzKEluZm9JZnJhbWUsIEV2ZW50RW1pdHRlcik7XG5cbkluZm9JZnJhbWUuZW5hYmxlZCA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gSWZyYW1lVHJhbnNwb3J0LmVuYWJsZWQoKTtcbn07XG5cbkluZm9JZnJhbWUucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24oKSB7XG4gIGlmICh0aGlzLmlmcikge1xuICAgIHRoaXMuaWZyLmNsb3NlKCk7XG4gIH1cbiAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgdGhpcy5pZnIgPSBudWxsO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBJbmZvSWZyYW1lO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gICwgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgdXJsVXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzL3VybCcpXG4gICwgWERSID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvc2VuZGVyL3hkcicpXG4gICwgWEhSQ29ycyA9IHJlcXVpcmUoJy4vdHJhbnNwb3J0L3NlbmRlci94aHItY29ycycpXG4gICwgWEhSTG9jYWwgPSByZXF1aXJlKCcuL3RyYW5zcG9ydC9zZW5kZXIveGhyLWxvY2FsJylcbiAgLCBYSFJGYWtlID0gcmVxdWlyZSgnLi90cmFuc3BvcnQvc2VuZGVyL3hoci1mYWtlJylcbiAgLCBJbmZvSWZyYW1lID0gcmVxdWlyZSgnLi9pbmZvLWlmcmFtZScpXG4gICwgSW5mb0FqYXggPSByZXF1aXJlKCcuL2luZm8tYWpheCcpXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDppbmZvLXJlY2VpdmVyJyk7XG59XG5cbmZ1bmN0aW9uIEluZm9SZWNlaXZlcihiYXNlVXJsLCB1cmxJbmZvKSB7XG4gIGRlYnVnKGJhc2VVcmwpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuXG4gIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgc2VsZi5kb1hocihiYXNlVXJsLCB1cmxJbmZvKTtcbiAgfSwgMCk7XG59XG5cbmluaGVyaXRzKEluZm9SZWNlaXZlciwgRXZlbnRFbWl0dGVyKTtcblxuLy8gVE9ETyB0aGlzIGlzIGN1cnJlbnRseSBpZ25vcmluZyB0aGUgbGlzdCBvZiBhdmFpbGFibGUgdHJhbnNwb3J0cyBhbmQgdGhlIHdoaXRlbGlzdFxuXG5JbmZvUmVjZWl2ZXIuX2dldFJlY2VpdmVyID0gZnVuY3Rpb24oYmFzZVVybCwgdXJsLCB1cmxJbmZvKSB7XG4gIC8vIGRldGVybWluZSBtZXRob2Qgb2YgQ09SUyBzdXBwb3J0IChpZiBuZWVkZWQpXG4gIGlmICh1cmxJbmZvLnNhbWVPcmlnaW4pIHtcbiAgICByZXR1cm4gbmV3IEluZm9BamF4KHVybCwgWEhSTG9jYWwpO1xuICB9XG4gIGlmIChYSFJDb3JzLmVuYWJsZWQpIHtcbiAgICByZXR1cm4gbmV3IEluZm9BamF4KHVybCwgWEhSQ29ycyk7XG4gIH1cbiAgaWYgKFhEUi5lbmFibGVkICYmIHVybEluZm8uc2FtZVNjaGVtZSkge1xuICAgIHJldHVybiBuZXcgSW5mb0FqYXgodXJsLCBYRFIpO1xuICB9XG4gIGlmIChJbmZvSWZyYW1lLmVuYWJsZWQoKSkge1xuICAgIHJldHVybiBuZXcgSW5mb0lmcmFtZShiYXNlVXJsLCB1cmwpO1xuICB9XG4gIHJldHVybiBuZXcgSW5mb0FqYXgodXJsLCBYSFJGYWtlKTtcbn07XG5cbkluZm9SZWNlaXZlci5wcm90b3R5cGUuZG9YaHIgPSBmdW5jdGlvbihiYXNlVXJsLCB1cmxJbmZvKSB7XG4gIHZhciBzZWxmID0gdGhpc1xuICAgICwgdXJsID0gdXJsVXRpbHMuYWRkUGF0aChiYXNlVXJsLCAnL2luZm8nKVxuICAgIDtcbiAgZGVidWcoJ2RvWGhyJywgdXJsKTtcblxuICB0aGlzLnhvID0gSW5mb1JlY2VpdmVyLl9nZXRSZWNlaXZlcihiYXNlVXJsLCB1cmwsIHVybEluZm8pO1xuXG4gIHRoaXMudGltZW91dFJlZiA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ3RpbWVvdXQnKTtcbiAgICBzZWxmLl9jbGVhbnVwKGZhbHNlKTtcbiAgICBzZWxmLmVtaXQoJ2ZpbmlzaCcpO1xuICB9LCBJbmZvUmVjZWl2ZXIudGltZW91dCk7XG5cbiAgdGhpcy54by5vbmNlKCdmaW5pc2gnLCBmdW5jdGlvbihpbmZvLCBydHQpIHtcbiAgICBkZWJ1ZygnZmluaXNoJywgaW5mbywgcnR0KTtcbiAgICBzZWxmLl9jbGVhbnVwKHRydWUpO1xuICAgIHNlbGYuZW1pdCgnZmluaXNoJywgaW5mbywgcnR0KTtcbiAgfSk7XG59O1xuXG5JbmZvUmVjZWl2ZXIucHJvdG90eXBlLl9jbGVhbnVwID0gZnVuY3Rpb24od2FzQ2xlYW4pIHtcbiAgZGVidWcoJ19jbGVhbnVwJyk7XG4gIGNsZWFyVGltZW91dCh0aGlzLnRpbWVvdXRSZWYpO1xuICB0aGlzLnRpbWVvdXRSZWYgPSBudWxsO1xuICBpZiAoIXdhc0NsZWFuICYmIHRoaXMueG8pIHtcbiAgICB0aGlzLnhvLmNsb3NlKCk7XG4gIH1cbiAgdGhpcy54byA9IG51bGw7XG59O1xuXG5JbmZvUmVjZWl2ZXIucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdjbG9zZScpO1xuICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xuICB0aGlzLl9jbGVhbnVwKGZhbHNlKTtcbn07XG5cbkluZm9SZWNlaXZlci50aW1lb3V0ID0gODAwMDtcblxubW9kdWxlLmV4cG9ydHMgPSBJbmZvUmVjZWl2ZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gZ2xvYmFsLmxvY2F0aW9uIHx8IHtcbiAgb3JpZ2luOiAnaHR0cDovL2xvY2FsaG9zdDo4MCdcbiwgcHJvdG9jb2w6ICdodHRwJ1xuLCBob3N0OiAnbG9jYWxob3N0J1xuLCBwb3J0OiA4MFxuLCBocmVmOiAnaHR0cDovL2xvY2FsaG9zdC8nXG4sIGhhc2g6ICcnXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5yZXF1aXJlKCcuL3NoaW1zJyk7XG5cbnZhciBVUkwgPSByZXF1aXJlKCd1cmwtcGFyc2UnKVxuICAsIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEpTT04zID0gcmVxdWlyZSgnanNvbjMnKVxuICAsIHJhbmRvbSA9IHJlcXVpcmUoJy4vdXRpbHMvcmFuZG9tJylcbiAgLCBlc2NhcGUgPSByZXF1aXJlKCcuL3V0aWxzL2VzY2FwZScpXG4gICwgdXJsVXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzL3VybCcpXG4gICwgZXZlbnRVdGlscyA9IHJlcXVpcmUoJy4vdXRpbHMvZXZlbnQnKVxuICAsIHRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vdXRpbHMvdHJhbnNwb3J0JylcbiAgLCBvYmplY3RVdGlscyA9IHJlcXVpcmUoJy4vdXRpbHMvb2JqZWN0JylcbiAgLCBicm93c2VyID0gcmVxdWlyZSgnLi91dGlscy9icm93c2VyJylcbiAgLCBsb2cgPSByZXF1aXJlKCcuL3V0aWxzL2xvZycpXG4gICwgRXZlbnQgPSByZXF1aXJlKCcuL2V2ZW50L2V2ZW50JylcbiAgLCBFdmVudFRhcmdldCA9IHJlcXVpcmUoJy4vZXZlbnQvZXZlbnR0YXJnZXQnKVxuICAsIGxvYyA9IHJlcXVpcmUoJy4vbG9jYXRpb24nKVxuICAsIENsb3NlRXZlbnQgPSByZXF1aXJlKCcuL2V2ZW50L2Nsb3NlJylcbiAgLCBUcmFuc3BvcnRNZXNzYWdlRXZlbnQgPSByZXF1aXJlKCcuL2V2ZW50L3RyYW5zLW1lc3NhZ2UnKVxuICAsIEluZm9SZWNlaXZlciA9IHJlcXVpcmUoJy4vaW5mby1yZWNlaXZlcicpXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDptYWluJyk7XG59XG5cbnZhciB0cmFuc3BvcnRzO1xuXG4vLyBmb2xsb3cgY29uc3RydWN0b3Igc3RlcHMgZGVmaW5lZCBhdCBodHRwOi8vZGV2LnczLm9yZy9odG1sNS93ZWJzb2NrZXRzLyN0aGUtd2Vic29ja2V0LWludGVyZmFjZVxuZnVuY3Rpb24gU29ja0pTKHVybCwgcHJvdG9jb2xzLCBvcHRpb25zKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBTb2NrSlMpKSB7XG4gICAgcmV0dXJuIG5ldyBTb2NrSlModXJsLCBwcm90b2NvbHMsIG9wdGlvbnMpO1xuICB9XG4gIGlmIChhcmd1bWVudHMubGVuZ3RoIDwgMSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJGYWlsZWQgdG8gY29uc3RydWN0ICdTb2NrSlM6IDEgYXJndW1lbnQgcmVxdWlyZWQsIGJ1dCBvbmx5IDAgcHJlc2VudFwiKTtcbiAgfVxuICBFdmVudFRhcmdldC5jYWxsKHRoaXMpO1xuXG4gIHRoaXMucmVhZHlTdGF0ZSA9IFNvY2tKUy5DT05ORUNUSU5HO1xuICB0aGlzLmV4dGVuc2lvbnMgPSAnJztcbiAgdGhpcy5wcm90b2NvbCA9ICcnO1xuXG4gIC8vIG5vbi1zdGFuZGFyZCBleHRlbnNpb25cbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gIGlmIChvcHRpb25zLnByb3RvY29sc193aGl0ZWxpc3QpIHtcbiAgICBsb2cud2FybihcIidwcm90b2NvbHNfd2hpdGVsaXN0JyBpcyBERVBSRUNBVEVELiBVc2UgJ3RyYW5zcG9ydHMnIGluc3RlYWQuXCIpO1xuICB9XG4gIHRoaXMuX3RyYW5zcG9ydHNXaGl0ZWxpc3QgPSBvcHRpb25zLnRyYW5zcG9ydHM7XG4gIHRoaXMuX3RyYW5zcG9ydE9wdGlvbnMgPSBvcHRpb25zLnRyYW5zcG9ydE9wdGlvbnMgfHwge307XG5cbiAgdmFyIHNlc3Npb25JZCA9IG9wdGlvbnMuc2Vzc2lvbklkIHx8IDg7XG4gIGlmICh0eXBlb2Ygc2Vzc2lvbklkID09PSAnZnVuY3Rpb24nKSB7XG4gICAgdGhpcy5fZ2VuZXJhdGVTZXNzaW9uSWQgPSBzZXNzaW9uSWQ7XG4gIH0gZWxzZSBpZiAodHlwZW9mIHNlc3Npb25JZCA9PT0gJ251bWJlcicpIHtcbiAgICB0aGlzLl9nZW5lcmF0ZVNlc3Npb25JZCA9IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIHJhbmRvbS5zdHJpbmcoc2Vzc2lvbklkKTtcbiAgICB9O1xuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0lmIHNlc3Npb25JZCBpcyB1c2VkIGluIHRoZSBvcHRpb25zLCBpdCBuZWVkcyB0byBiZSBhIG51bWJlciBvciBhIGZ1bmN0aW9uLicpO1xuICB9XG5cbiAgdGhpcy5fc2VydmVyID0gb3B0aW9ucy5zZXJ2ZXIgfHwgcmFuZG9tLm51bWJlclN0cmluZygxMDAwKTtcblxuICAvLyBTdGVwIDEgb2YgV1Mgc3BlYyAtIHBhcnNlIGFuZCB2YWxpZGF0ZSB0aGUgdXJsLiBJc3N1ZSAjOFxuICB2YXIgcGFyc2VkVXJsID0gbmV3IFVSTCh1cmwpO1xuICBpZiAoIXBhcnNlZFVybC5ob3N0IHx8ICFwYXJzZWRVcmwucHJvdG9jb2wpIHtcbiAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJUaGUgVVJMICdcIiArIHVybCArIFwiJyBpcyBpbnZhbGlkXCIpO1xuICB9IGVsc2UgaWYgKHBhcnNlZFVybC5oYXNoKSB7XG4gICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKCdUaGUgVVJMIG11c3Qgbm90IGNvbnRhaW4gYSBmcmFnbWVudCcpO1xuICB9IGVsc2UgaWYgKHBhcnNlZFVybC5wcm90b2NvbCAhPT0gJ2h0dHA6JyAmJiBwYXJzZWRVcmwucHJvdG9jb2wgIT09ICdodHRwczonKSB7XG4gICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlIFVSTCdzIHNjaGVtZSBtdXN0IGJlIGVpdGhlciAnaHR0cDonIG9yICdodHRwczonLiAnXCIgKyBwYXJzZWRVcmwucHJvdG9jb2wgKyBcIicgaXMgbm90IGFsbG93ZWQuXCIpO1xuICB9XG5cbiAgdmFyIHNlY3VyZSA9IHBhcnNlZFVybC5wcm90b2NvbCA9PT0gJ2h0dHBzOic7XG4gIC8vIFN0ZXAgMiAtIGRvbid0IGFsbG93IHNlY3VyZSBvcmlnaW4gd2l0aCBhbiBpbnNlY3VyZSBwcm90b2NvbFxuICBpZiAobG9jLnByb3RvY29sID09PSAnaHR0cHMnICYmICFzZWN1cmUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1NlY3VyaXR5RXJyb3I6IEFuIGluc2VjdXJlIFNvY2tKUyBjb25uZWN0aW9uIG1heSBub3QgYmUgaW5pdGlhdGVkIGZyb20gYSBwYWdlIGxvYWRlZCBvdmVyIEhUVFBTJyk7XG4gIH1cblxuICAvLyBTdGVwIDMgLSBjaGVjayBwb3J0IGFjY2VzcyAtIG5vIG5lZWQgaGVyZVxuICAvLyBTdGVwIDQgLSBwYXJzZSBwcm90b2NvbHMgYXJndW1lbnRcbiAgaWYgKCFwcm90b2NvbHMpIHtcbiAgICBwcm90b2NvbHMgPSBbXTtcbiAgfSBlbHNlIGlmICghQXJyYXkuaXNBcnJheShwcm90b2NvbHMpKSB7XG4gICAgcHJvdG9jb2xzID0gW3Byb3RvY29sc107XG4gIH1cblxuICAvLyBTdGVwIDUgLSBjaGVjayBwcm90b2NvbHMgYXJndW1lbnRcbiAgdmFyIHNvcnRlZFByb3RvY29scyA9IHByb3RvY29scy5zb3J0KCk7XG4gIHNvcnRlZFByb3RvY29scy5mb3JFYWNoKGZ1bmN0aW9uKHByb3RvLCBpKSB7XG4gICAgaWYgKCFwcm90bykge1xuICAgICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKFwiVGhlIHByb3RvY29scyBlbnRyeSAnXCIgKyBwcm90byArIFwiJyBpcyBpbnZhbGlkLlwiKTtcbiAgICB9XG4gICAgaWYgKGkgPCAoc29ydGVkUHJvdG9jb2xzLmxlbmd0aCAtIDEpICYmIHByb3RvID09PSBzb3J0ZWRQcm90b2NvbHNbaSArIDFdKSB7XG4gICAgICB0aHJvdyBuZXcgU3ludGF4RXJyb3IoXCJUaGUgcHJvdG9jb2xzIGVudHJ5ICdcIiArIHByb3RvICsgXCInIGlzIGR1cGxpY2F0ZWQuXCIpO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gU3RlcCA2IC0gY29udmVydCBvcmlnaW5cbiAgdmFyIG8gPSB1cmxVdGlscy5nZXRPcmlnaW4obG9jLmhyZWYpO1xuICB0aGlzLl9vcmlnaW4gPSBvID8gby50b0xvd2VyQ2FzZSgpIDogbnVsbDtcblxuICAvLyByZW1vdmUgdGhlIHRyYWlsaW5nIHNsYXNoXG4gIHBhcnNlZFVybC5zZXQoJ3BhdGhuYW1lJywgcGFyc2VkVXJsLnBhdGhuYW1lLnJlcGxhY2UoL1xcLyskLywgJycpKTtcblxuICAvLyBzdG9yZSB0aGUgc2FuaXRpemVkIHVybFxuICB0aGlzLnVybCA9IHBhcnNlZFVybC5ocmVmO1xuICBkZWJ1ZygndXNpbmcgdXJsJywgdGhpcy51cmwpO1xuXG4gIC8vIFN0ZXAgNyAtIHN0YXJ0IGNvbm5lY3Rpb24gaW4gYmFja2dyb3VuZFxuICAvLyBvYnRhaW4gc2VydmVyIGluZm9cbiAgLy8gaHR0cDovL3NvY2tqcy5naXRodWIuaW8vc29ja2pzLXByb3RvY29sL3NvY2tqcy1wcm90b2NvbC0wLjMuMy5odG1sI3NlY3Rpb24tMjZcbiAgdGhpcy5fdXJsSW5mbyA9IHtcbiAgICBudWxsT3JpZ2luOiAhYnJvd3Nlci5oYXNEb21haW4oKVxuICAsIHNhbWVPcmlnaW46IHVybFV0aWxzLmlzT3JpZ2luRXF1YWwodGhpcy51cmwsIGxvYy5ocmVmKVxuICAsIHNhbWVTY2hlbWU6IHVybFV0aWxzLmlzU2NoZW1lRXF1YWwodGhpcy51cmwsIGxvYy5ocmVmKVxuICB9O1xuXG4gIHRoaXMuX2lyID0gbmV3IEluZm9SZWNlaXZlcih0aGlzLnVybCwgdGhpcy5fdXJsSW5mbyk7XG4gIHRoaXMuX2lyLm9uY2UoJ2ZpbmlzaCcsIHRoaXMuX3JlY2VpdmVJbmZvLmJpbmQodGhpcykpO1xufVxuXG5pbmhlcml0cyhTb2NrSlMsIEV2ZW50VGFyZ2V0KTtcblxuZnVuY3Rpb24gdXNlclNldENvZGUoY29kZSkge1xuICByZXR1cm4gY29kZSA9PT0gMTAwMCB8fCAoY29kZSA+PSAzMDAwICYmIGNvZGUgPD0gNDk5OSk7XG59XG5cblNvY2tKUy5wcm90b3R5cGUuY2xvc2UgPSBmdW5jdGlvbihjb2RlLCByZWFzb24pIHtcbiAgLy8gU3RlcCAxXG4gIGlmIChjb2RlICYmICF1c2VyU2V0Q29kZShjb2RlKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZEFjY2Vzc0Vycm9yOiBJbnZhbGlkIGNvZGUnKTtcbiAgfVxuICAvLyBTdGVwIDIuNCBzdGF0ZXMgdGhlIG1heCBpcyAxMjMgYnl0ZXMsIGJ1dCB3ZSBhcmUganVzdCBjaGVja2luZyBsZW5ndGhcbiAgaWYgKHJlYXNvbiAmJiByZWFzb24ubGVuZ3RoID4gMTIzKSB7XG4gICAgdGhyb3cgbmV3IFN5bnRheEVycm9yKCdyZWFzb24gYXJndW1lbnQgaGFzIGFuIGludmFsaWQgbGVuZ3RoJyk7XG4gIH1cblxuICAvLyBTdGVwIDMuMVxuICBpZiAodGhpcy5yZWFkeVN0YXRlID09PSBTb2NrSlMuQ0xPU0lORyB8fCB0aGlzLnJlYWR5U3RhdGUgPT09IFNvY2tKUy5DTE9TRUQpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBUT0RPIGxvb2sgYXQgZG9jcyB0byBkZXRlcm1pbmUgaG93IHRvIHNldCB0aGlzXG4gIHZhciB3YXNDbGVhbiA9IHRydWU7XG4gIHRoaXMuX2Nsb3NlKGNvZGUgfHwgMTAwMCwgcmVhc29uIHx8ICdOb3JtYWwgY2xvc3VyZScsIHdhc0NsZWFuKTtcbn07XG5cblNvY2tKUy5wcm90b3R5cGUuc2VuZCA9IGZ1bmN0aW9uKGRhdGEpIHtcbiAgLy8gIzEzIC0gY29udmVydCBhbnl0aGluZyBub24tc3RyaW5nIHRvIHN0cmluZ1xuICAvLyBUT0RPIHRoaXMgY3VycmVudGx5IHR1cm5zIG9iamVjdHMgaW50byBbb2JqZWN0IE9iamVjdF1cbiAgaWYgKHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJykge1xuICAgIGRhdGEgPSAnJyArIGRhdGE7XG4gIH1cbiAgaWYgKHRoaXMucmVhZHlTdGF0ZSA9PT0gU29ja0pTLkNPTk5FQ1RJTkcpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWRTdGF0ZUVycm9yOiBUaGUgY29ubmVjdGlvbiBoYXMgbm90IGJlZW4gZXN0YWJsaXNoZWQgeWV0Jyk7XG4gIH1cbiAgaWYgKHRoaXMucmVhZHlTdGF0ZSAhPT0gU29ja0pTLk9QRU4pIHtcbiAgICByZXR1cm47XG4gIH1cbiAgdGhpcy5fdHJhbnNwb3J0LnNlbmQoZXNjYXBlLnF1b3RlKGRhdGEpKTtcbn07XG5cblNvY2tKUy52ZXJzaW9uID0gcmVxdWlyZSgnLi92ZXJzaW9uJyk7XG5cblNvY2tKUy5DT05ORUNUSU5HID0gMDtcblNvY2tKUy5PUEVOID0gMTtcblNvY2tKUy5DTE9TSU5HID0gMjtcblNvY2tKUy5DTE9TRUQgPSAzO1xuXG5Tb2NrSlMucHJvdG90eXBlLl9yZWNlaXZlSW5mbyA9IGZ1bmN0aW9uKGluZm8sIHJ0dCkge1xuICBkZWJ1ZygnX3JlY2VpdmVJbmZvJywgcnR0KTtcbiAgdGhpcy5faXIgPSBudWxsO1xuICBpZiAoIWluZm8pIHtcbiAgICB0aGlzLl9jbG9zZSgxMDAyLCAnQ2Fubm90IGNvbm5lY3QgdG8gc2VydmVyJyk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gZXN0YWJsaXNoIGEgcm91bmQtdHJpcCB0aW1lb3V0IChSVE8pIGJhc2VkIG9uIHRoZVxuICAvLyByb3VuZC10cmlwIHRpbWUgKFJUVClcbiAgdGhpcy5fcnRvID0gdGhpcy5jb3VudFJUTyhydHQpO1xuICAvLyBhbGxvdyBzZXJ2ZXIgdG8gb3ZlcnJpZGUgdXJsIHVzZWQgZm9yIHRoZSBhY3R1YWwgdHJhbnNwb3J0XG4gIHRoaXMuX3RyYW5zVXJsID0gaW5mby5iYXNlX3VybCA/IGluZm8uYmFzZV91cmwgOiB0aGlzLnVybDtcbiAgaW5mbyA9IG9iamVjdFV0aWxzLmV4dGVuZChpbmZvLCB0aGlzLl91cmxJbmZvKTtcbiAgZGVidWcoJ2luZm8nLCBpbmZvKTtcbiAgLy8gZGV0ZXJtaW5lIGxpc3Qgb2YgZGVzaXJlZCBhbmQgc3VwcG9ydGVkIHRyYW5zcG9ydHNcbiAgdmFyIGVuYWJsZWRUcmFuc3BvcnRzID0gdHJhbnNwb3J0cy5maWx0ZXJUb0VuYWJsZWQodGhpcy5fdHJhbnNwb3J0c1doaXRlbGlzdCwgaW5mbyk7XG4gIHRoaXMuX3RyYW5zcG9ydHMgPSBlbmFibGVkVHJhbnNwb3J0cy5tYWluO1xuICBkZWJ1Zyh0aGlzLl90cmFuc3BvcnRzLmxlbmd0aCArICcgZW5hYmxlZCB0cmFuc3BvcnRzJyk7XG5cbiAgdGhpcy5fY29ubmVjdCgpO1xufTtcblxuU29ja0pTLnByb3RvdHlwZS5fY29ubmVjdCA9IGZ1bmN0aW9uKCkge1xuICBmb3IgKHZhciBUcmFuc3BvcnQgPSB0aGlzLl90cmFuc3BvcnRzLnNoaWZ0KCk7IFRyYW5zcG9ydDsgVHJhbnNwb3J0ID0gdGhpcy5fdHJhbnNwb3J0cy5zaGlmdCgpKSB7XG4gICAgZGVidWcoJ2F0dGVtcHQnLCBUcmFuc3BvcnQudHJhbnNwb3J0TmFtZSk7XG4gICAgaWYgKFRyYW5zcG9ydC5uZWVkQm9keSkge1xuICAgICAgaWYgKCFnbG9iYWwuZG9jdW1lbnQuYm9keSB8fFxuICAgICAgICAgICh0eXBlb2YgZ2xvYmFsLmRvY3VtZW50LnJlYWR5U3RhdGUgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICAgICBnbG9iYWwuZG9jdW1lbnQucmVhZHlTdGF0ZSAhPT0gJ2NvbXBsZXRlJyAmJlxuICAgICAgICAgICAgZ2xvYmFsLmRvY3VtZW50LnJlYWR5U3RhdGUgIT09ICdpbnRlcmFjdGl2ZScpKSB7XG4gICAgICAgIGRlYnVnKCd3YWl0aW5nIGZvciBib2R5Jyk7XG4gICAgICAgIHRoaXMuX3RyYW5zcG9ydHMudW5zaGlmdChUcmFuc3BvcnQpO1xuICAgICAgICBldmVudFV0aWxzLmF0dGFjaEV2ZW50KCdsb2FkJywgdGhpcy5fY29ubmVjdC5iaW5kKHRoaXMpKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGNhbGN1bGF0ZSB0aW1lb3V0IGJhc2VkIG9uIFJUTyBhbmQgcm91bmQgdHJpcHMuIERlZmF1bHQgdG8gNXNcbiAgICB2YXIgdGltZW91dE1zID0gKHRoaXMuX3J0byAqIFRyYW5zcG9ydC5yb3VuZFRyaXBzKSB8fCA1MDAwO1xuICAgIHRoaXMuX3RyYW5zcG9ydFRpbWVvdXRJZCA9IHNldFRpbWVvdXQodGhpcy5fdHJhbnNwb3J0VGltZW91dC5iaW5kKHRoaXMpLCB0aW1lb3V0TXMpO1xuICAgIGRlYnVnKCd1c2luZyB0aW1lb3V0JywgdGltZW91dE1zKTtcblxuICAgIHZhciB0cmFuc3BvcnRVcmwgPSB1cmxVdGlscy5hZGRQYXRoKHRoaXMuX3RyYW5zVXJsLCAnLycgKyB0aGlzLl9zZXJ2ZXIgKyAnLycgKyB0aGlzLl9nZW5lcmF0ZVNlc3Npb25JZCgpKTtcbiAgICB2YXIgb3B0aW9ucyA9IHRoaXMuX3RyYW5zcG9ydE9wdGlvbnNbVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWVdO1xuICAgIGRlYnVnKCd0cmFuc3BvcnQgdXJsJywgdHJhbnNwb3J0VXJsKTtcbiAgICB2YXIgdHJhbnNwb3J0T2JqID0gbmV3IFRyYW5zcG9ydCh0cmFuc3BvcnRVcmwsIHRoaXMuX3RyYW5zVXJsLCBvcHRpb25zKTtcbiAgICB0cmFuc3BvcnRPYmoub24oJ21lc3NhZ2UnLCB0aGlzLl90cmFuc3BvcnRNZXNzYWdlLmJpbmQodGhpcykpO1xuICAgIHRyYW5zcG9ydE9iai5vbmNlKCdjbG9zZScsIHRoaXMuX3RyYW5zcG9ydENsb3NlLmJpbmQodGhpcykpO1xuICAgIHRyYW5zcG9ydE9iai50cmFuc3BvcnROYW1lID0gVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWU7XG4gICAgdGhpcy5fdHJhbnNwb3J0ID0gdHJhbnNwb3J0T2JqO1xuXG4gICAgcmV0dXJuO1xuICB9XG4gIHRoaXMuX2Nsb3NlKDIwMDAsICdBbGwgdHJhbnNwb3J0cyBmYWlsZWQnLCBmYWxzZSk7XG59O1xuXG5Tb2NrSlMucHJvdG90eXBlLl90cmFuc3BvcnRUaW1lb3V0ID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdfdHJhbnNwb3J0VGltZW91dCcpO1xuICBpZiAodGhpcy5yZWFkeVN0YXRlID09PSBTb2NrSlMuQ09OTkVDVElORykge1xuICAgIHRoaXMuX3RyYW5zcG9ydENsb3NlKDIwMDcsICdUcmFuc3BvcnQgdGltZWQgb3V0Jyk7XG4gIH1cbn07XG5cblNvY2tKUy5wcm90b3R5cGUuX3RyYW5zcG9ydE1lc3NhZ2UgPSBmdW5jdGlvbihtc2cpIHtcbiAgZGVidWcoJ190cmFuc3BvcnRNZXNzYWdlJywgbXNnKTtcbiAgdmFyIHNlbGYgPSB0aGlzXG4gICAgLCB0eXBlID0gbXNnLnNsaWNlKDAsIDEpXG4gICAgLCBjb250ZW50ID0gbXNnLnNsaWNlKDEpXG4gICAgLCBwYXlsb2FkXG4gICAgO1xuXG4gIC8vIGZpcnN0IGNoZWNrIGZvciBtZXNzYWdlcyB0aGF0IGRvbid0IG5lZWQgYSBwYXlsb2FkXG4gIHN3aXRjaCAodHlwZSkge1xuICAgIGNhc2UgJ28nOlxuICAgICAgdGhpcy5fb3BlbigpO1xuICAgICAgcmV0dXJuO1xuICAgIGNhc2UgJ2gnOlxuICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgnaGVhcnRiZWF0JykpO1xuICAgICAgZGVidWcoJ2hlYXJ0YmVhdCcsIHRoaXMudHJhbnNwb3J0KTtcbiAgICAgIHJldHVybjtcbiAgfVxuXG4gIGlmIChjb250ZW50KSB7XG4gICAgdHJ5IHtcbiAgICAgIHBheWxvYWQgPSBKU09OMy5wYXJzZShjb250ZW50KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBkZWJ1ZygnYmFkIGpzb24nLCBjb250ZW50KTtcbiAgICB9XG4gIH1cblxuICBpZiAodHlwZW9mIHBheWxvYWQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgZGVidWcoJ2VtcHR5IHBheWxvYWQnLCBjb250ZW50KTtcbiAgICByZXR1cm47XG4gIH1cblxuICBzd2l0Y2ggKHR5cGUpIHtcbiAgICBjYXNlICdhJzpcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHBheWxvYWQpKSB7XG4gICAgICAgIHBheWxvYWQuZm9yRWFjaChmdW5jdGlvbihwKSB7XG4gICAgICAgICAgZGVidWcoJ21lc3NhZ2UnLCBzZWxmLnRyYW5zcG9ydCwgcCk7XG4gICAgICAgICAgc2VsZi5kaXNwYXRjaEV2ZW50KG5ldyBUcmFuc3BvcnRNZXNzYWdlRXZlbnQocCkpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgJ20nOlxuICAgICAgZGVidWcoJ21lc3NhZ2UnLCB0aGlzLnRyYW5zcG9ydCwgcGF5bG9hZCk7XG4gICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IFRyYW5zcG9ydE1lc3NhZ2VFdmVudChwYXlsb2FkKSk7XG4gICAgICBicmVhaztcbiAgICBjYXNlICdjJzpcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHBheWxvYWQpICYmIHBheWxvYWQubGVuZ3RoID09PSAyKSB7XG4gICAgICAgIHRoaXMuX2Nsb3NlKHBheWxvYWRbMF0sIHBheWxvYWRbMV0sIHRydWUpO1xuICAgICAgfVxuICAgICAgYnJlYWs7XG4gIH1cbn07XG5cblNvY2tKUy5wcm90b3R5cGUuX3RyYW5zcG9ydENsb3NlID0gZnVuY3Rpb24oY29kZSwgcmVhc29uKSB7XG4gIGRlYnVnKCdfdHJhbnNwb3J0Q2xvc2UnLCB0aGlzLnRyYW5zcG9ydCwgY29kZSwgcmVhc29uKTtcbiAgaWYgKHRoaXMuX3RyYW5zcG9ydCkge1xuICAgIHRoaXMuX3RyYW5zcG9ydC5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgICB0aGlzLl90cmFuc3BvcnQgPSBudWxsO1xuICAgIHRoaXMudHJhbnNwb3J0ID0gbnVsbDtcbiAgfVxuXG4gIGlmICghdXNlclNldENvZGUoY29kZSkgJiYgY29kZSAhPT0gMjAwMCAmJiB0aGlzLnJlYWR5U3RhdGUgPT09IFNvY2tKUy5DT05ORUNUSU5HKSB7XG4gICAgdGhpcy5fY29ubmVjdCgpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHRoaXMuX2Nsb3NlKGNvZGUsIHJlYXNvbik7XG59O1xuXG5Tb2NrSlMucHJvdG90eXBlLl9vcGVuID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdfb3BlbicsIHRoaXMuX3RyYW5zcG9ydC50cmFuc3BvcnROYW1lLCB0aGlzLnJlYWR5U3RhdGUpO1xuICBpZiAodGhpcy5yZWFkeVN0YXRlID09PSBTb2NrSlMuQ09OTkVDVElORykge1xuICAgIGlmICh0aGlzLl90cmFuc3BvcnRUaW1lb3V0SWQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLl90cmFuc3BvcnRUaW1lb3V0SWQpO1xuICAgICAgdGhpcy5fdHJhbnNwb3J0VGltZW91dElkID0gbnVsbDtcbiAgICB9XG4gICAgdGhpcy5yZWFkeVN0YXRlID0gU29ja0pTLk9QRU47XG4gICAgdGhpcy50cmFuc3BvcnQgPSB0aGlzLl90cmFuc3BvcnQudHJhbnNwb3J0TmFtZTtcbiAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KCdvcGVuJykpO1xuICAgIGRlYnVnKCdjb25uZWN0ZWQnLCB0aGlzLnRyYW5zcG9ydCk7XG4gIH0gZWxzZSB7XG4gICAgLy8gVGhlIHNlcnZlciBtaWdodCBoYXZlIGJlZW4gcmVzdGFydGVkLCBhbmQgbG9zdCB0cmFjayBvZiBvdXJcbiAgICAvLyBjb25uZWN0aW9uLlxuICAgIHRoaXMuX2Nsb3NlKDEwMDYsICdTZXJ2ZXIgbG9zdCBzZXNzaW9uJyk7XG4gIH1cbn07XG5cblNvY2tKUy5wcm90b3R5cGUuX2Nsb3NlID0gZnVuY3Rpb24oY29kZSwgcmVhc29uLCB3YXNDbGVhbikge1xuICBkZWJ1ZygnX2Nsb3NlJywgdGhpcy50cmFuc3BvcnQsIGNvZGUsIHJlYXNvbiwgd2FzQ2xlYW4sIHRoaXMucmVhZHlTdGF0ZSk7XG4gIHZhciBmb3JjZUZhaWwgPSBmYWxzZTtcblxuICBpZiAodGhpcy5faXIpIHtcbiAgICBmb3JjZUZhaWwgPSB0cnVlO1xuICAgIHRoaXMuX2lyLmNsb3NlKCk7XG4gICAgdGhpcy5faXIgPSBudWxsO1xuICB9XG4gIGlmICh0aGlzLl90cmFuc3BvcnQpIHtcbiAgICB0aGlzLl90cmFuc3BvcnQuY2xvc2UoKTtcbiAgICB0aGlzLl90cmFuc3BvcnQgPSBudWxsO1xuICAgIHRoaXMudHJhbnNwb3J0ID0gbnVsbDtcbiAgfVxuXG4gIGlmICh0aGlzLnJlYWR5U3RhdGUgPT09IFNvY2tKUy5DTE9TRUQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWRTdGF0ZUVycm9yOiBTb2NrSlMgaGFzIGFscmVhZHkgYmVlbiBjbG9zZWQnKTtcbiAgfVxuXG4gIHRoaXMucmVhZHlTdGF0ZSA9IFNvY2tKUy5DTE9TSU5HO1xuICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgIHRoaXMucmVhZHlTdGF0ZSA9IFNvY2tKUy5DTE9TRUQ7XG5cbiAgICBpZiAoZm9yY2VGYWlsKSB7XG4gICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KCdlcnJvcicpKTtcbiAgICB9XG5cbiAgICB2YXIgZSA9IG5ldyBDbG9zZUV2ZW50KCdjbG9zZScpO1xuICAgIGUud2FzQ2xlYW4gPSB3YXNDbGVhbiB8fCBmYWxzZTtcbiAgICBlLmNvZGUgPSBjb2RlIHx8IDEwMDA7XG4gICAgZS5yZWFzb24gPSByZWFzb247XG5cbiAgICB0aGlzLmRpc3BhdGNoRXZlbnQoZSk7XG4gICAgdGhpcy5vbm1lc3NhZ2UgPSB0aGlzLm9uY2xvc2UgPSB0aGlzLm9uZXJyb3IgPSBudWxsO1xuICAgIGRlYnVnKCdkaXNjb25uZWN0ZWQnKTtcbiAgfS5iaW5kKHRoaXMpLCAwKTtcbn07XG5cbi8vIFNlZTogaHR0cDovL3d3dy5lcmcuYWJkbi5hYy51ay9+Z2Vycml0L2RjY3Avbm90ZXMvY2NpZDIvcnRvX2VzdGltYXRvci9cbi8vIGFuZCBSRkMgMjk4OC5cblNvY2tKUy5wcm90b3R5cGUuY291bnRSVE8gPSBmdW5jdGlvbihydHQpIHtcbiAgLy8gSW4gYSBsb2NhbCBlbnZpcm9ubWVudCwgd2hlbiB1c2luZyBJRTgvOSBhbmQgdGhlIGBqc29ucC1wb2xsaW5nYFxuICAvLyB0cmFuc3BvcnQgdGhlIHRpbWUgbmVlZGVkIHRvIGVzdGFibGlzaCBhIGNvbm5lY3Rpb24gKHRoZSB0aW1lIHRoYXQgcGFzc1xuICAvLyBmcm9tIHRoZSBvcGVuaW5nIG9mIHRoZSB0cmFuc3BvcnQgdG8gdGhlIGNhbGwgb2YgYF9kaXNwYXRjaE9wZW5gKSBpc1xuICAvLyBhcm91bmQgMjAwbXNlYyAodGhlIGxvd2VyIGJvdW5kIHVzZWQgaW4gdGhlIGFydGljbGUgYWJvdmUpIGFuZCB0aGlzXG4gIC8vIGNhdXNlcyBzcHVyaW91cyB0aW1lb3V0cy4gRm9yIHRoaXMgcmVhc29uIHdlIGNhbGN1bGF0ZSBhIHZhbHVlIHNsaWdodGx5XG4gIC8vIGxhcmdlciB0aGFuIHRoYXQgdXNlZCBpbiB0aGUgYXJ0aWNsZS5cbiAgaWYgKHJ0dCA+IDEwMCkge1xuICAgIHJldHVybiA0ICogcnR0OyAvLyBydG8gPiA0MDBtc2VjXG4gIH1cbiAgcmV0dXJuIDMwMCArIHJ0dDsgLy8gMzAwbXNlYyA8IHJ0byA8PSA0MDBtc2VjXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKGF2YWlsYWJsZVRyYW5zcG9ydHMpIHtcbiAgdHJhbnNwb3J0cyA9IHRyYW5zcG9ydChhdmFpbGFibGVUcmFuc3BvcnRzKTtcbiAgcmVxdWlyZSgnLi9pZnJhbWUtYm9vdHN0cmFwJykoU29ja0pTLCBhdmFpbGFibGVUcmFuc3BvcnRzKTtcbiAgcmV0dXJuIFNvY2tKUztcbn07XG4iLCIvKiBlc2xpbnQtZGlzYWJsZSAqL1xuLyoganNjczogZGlzYWJsZSAqL1xuJ3VzZSBzdHJpY3QnO1xuXG4vLyBwdWxsZWQgc3BlY2lmaWMgc2hpbXMgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vZXMtc2hpbXMvZXM1LXNoaW1cblxudmFyIEFycmF5UHJvdG90eXBlID0gQXJyYXkucHJvdG90eXBlO1xudmFyIE9iamVjdFByb3RvdHlwZSA9IE9iamVjdC5wcm90b3R5cGU7XG52YXIgRnVuY3Rpb25Qcm90b3R5cGUgPSBGdW5jdGlvbi5wcm90b3R5cGU7XG52YXIgU3RyaW5nUHJvdG90eXBlID0gU3RyaW5nLnByb3RvdHlwZTtcbnZhciBhcnJheV9zbGljZSA9IEFycmF5UHJvdG90eXBlLnNsaWNlO1xuXG52YXIgX3RvU3RyaW5nID0gT2JqZWN0UHJvdG90eXBlLnRvU3RyaW5nO1xudmFyIGlzRnVuY3Rpb24gPSBmdW5jdGlvbiAodmFsKSB7XG4gICAgcmV0dXJuIE9iamVjdFByb3RvdHlwZS50b1N0cmluZy5jYWxsKHZhbCkgPT09ICdbb2JqZWN0IEZ1bmN0aW9uXSc7XG59O1xudmFyIGlzQXJyYXkgPSBmdW5jdGlvbiBpc0FycmF5KG9iaikge1xuICAgIHJldHVybiBfdG9TdHJpbmcuY2FsbChvYmopID09PSAnW29iamVjdCBBcnJheV0nO1xufTtcbnZhciBpc1N0cmluZyA9IGZ1bmN0aW9uIGlzU3RyaW5nKG9iaikge1xuICAgIHJldHVybiBfdG9TdHJpbmcuY2FsbChvYmopID09PSAnW29iamVjdCBTdHJpbmddJztcbn07XG5cbnZhciBzdXBwb3J0c0Rlc2NyaXB0b3JzID0gT2JqZWN0LmRlZmluZVByb3BlcnR5ICYmIChmdW5jdGlvbiAoKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHt9LCAneCcsIHt9KTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZSkgeyAvKiB0aGlzIGlzIEVTMyAqL1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufSgpKTtcblxuLy8gRGVmaW5lIGNvbmZpZ3VyYWJsZSwgd3JpdGFibGUgYW5kIG5vbi1lbnVtZXJhYmxlIHByb3BzXG4vLyBpZiB0aGV5IGRvbid0IGV4aXN0LlxudmFyIGRlZmluZVByb3BlcnR5O1xuaWYgKHN1cHBvcnRzRGVzY3JpcHRvcnMpIHtcbiAgICBkZWZpbmVQcm9wZXJ0eSA9IGZ1bmN0aW9uIChvYmplY3QsIG5hbWUsIG1ldGhvZCwgZm9yY2VBc3NpZ24pIHtcbiAgICAgICAgaWYgKCFmb3JjZUFzc2lnbiAmJiAobmFtZSBpbiBvYmplY3QpKSB7IHJldHVybjsgfVxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkob2JqZWN0LCBuYW1lLCB7XG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgICAgICAgdmFsdWU6IG1ldGhvZFxuICAgICAgICB9KTtcbiAgICB9O1xufSBlbHNlIHtcbiAgICBkZWZpbmVQcm9wZXJ0eSA9IGZ1bmN0aW9uIChvYmplY3QsIG5hbWUsIG1ldGhvZCwgZm9yY2VBc3NpZ24pIHtcbiAgICAgICAgaWYgKCFmb3JjZUFzc2lnbiAmJiAobmFtZSBpbiBvYmplY3QpKSB7IHJldHVybjsgfVxuICAgICAgICBvYmplY3RbbmFtZV0gPSBtZXRob2Q7XG4gICAgfTtcbn1cbnZhciBkZWZpbmVQcm9wZXJ0aWVzID0gZnVuY3Rpb24gKG9iamVjdCwgbWFwLCBmb3JjZUFzc2lnbikge1xuICAgIGZvciAodmFyIG5hbWUgaW4gbWFwKSB7XG4gICAgICAgIGlmIChPYmplY3RQcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChtYXAsIG5hbWUpKSB7XG4gICAgICAgICAgZGVmaW5lUHJvcGVydHkob2JqZWN0LCBuYW1lLCBtYXBbbmFtZV0sIGZvcmNlQXNzaWduKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbnZhciB0b09iamVjdCA9IGZ1bmN0aW9uIChvKSB7XG4gICAgaWYgKG8gPT0gbnVsbCkgeyAvLyB0aGlzIG1hdGNoZXMgYm90aCBudWxsIGFuZCB1bmRlZmluZWRcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcImNhbid0IGNvbnZlcnQgXCIgKyBvICsgJyB0byBvYmplY3QnKTtcbiAgICB9XG4gICAgcmV0dXJuIE9iamVjdChvKTtcbn07XG5cbi8vXG4vLyBVdGlsXG4vLyA9PT09PT1cbi8vXG5cbi8vIEVTNSA5LjRcbi8vIGh0dHA6Ly9lczUuZ2l0aHViLmNvbS8jeDkuNFxuLy8gaHR0cDovL2pzcGVyZi5jb20vdG8taW50ZWdlclxuXG5mdW5jdGlvbiB0b0ludGVnZXIobnVtKSB7XG4gICAgdmFyIG4gPSArbnVtO1xuICAgIGlmIChuICE9PSBuKSB7IC8vIGlzTmFOXG4gICAgICAgIG4gPSAwO1xuICAgIH0gZWxzZSBpZiAobiAhPT0gMCAmJiBuICE9PSAoMSAvIDApICYmIG4gIT09IC0oMSAvIDApKSB7XG4gICAgICAgIG4gPSAobiA+IDAgfHwgLTEpICogTWF0aC5mbG9vcihNYXRoLmFicyhuKSk7XG4gICAgfVxuICAgIHJldHVybiBuO1xufVxuXG5mdW5jdGlvbiBUb1VpbnQzMih4KSB7XG4gICAgcmV0dXJuIHggPj4+IDA7XG59XG5cbi8vXG4vLyBGdW5jdGlvblxuLy8gPT09PT09PT1cbi8vXG5cbi8vIEVTLTUgMTUuMy40LjVcbi8vIGh0dHA6Ly9lczUuZ2l0aHViLmNvbS8jeDE1LjMuNC41XG5cbmZ1bmN0aW9uIEVtcHR5KCkge31cblxuZGVmaW5lUHJvcGVydGllcyhGdW5jdGlvblByb3RvdHlwZSwge1xuICAgIGJpbmQ6IGZ1bmN0aW9uIGJpbmQodGhhdCkgeyAvLyAubGVuZ3RoIGlzIDFcbiAgICAgICAgLy8gMS4gTGV0IFRhcmdldCBiZSB0aGUgdGhpcyB2YWx1ZS5cbiAgICAgICAgdmFyIHRhcmdldCA9IHRoaXM7XG4gICAgICAgIC8vIDIuIElmIElzQ2FsbGFibGUoVGFyZ2V0KSBpcyBmYWxzZSwgdGhyb3cgYSBUeXBlRXJyb3IgZXhjZXB0aW9uLlxuICAgICAgICBpZiAoIWlzRnVuY3Rpb24odGFyZ2V0KSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQgY2FsbGVkIG9uIGluY29tcGF0aWJsZSAnICsgdGFyZ2V0KTtcbiAgICAgICAgfVxuICAgICAgICAvLyAzLiBMZXQgQSBiZSBhIG5ldyAocG9zc2libHkgZW1wdHkpIGludGVybmFsIGxpc3Qgb2YgYWxsIG9mIHRoZVxuICAgICAgICAvLyAgIGFyZ3VtZW50IHZhbHVlcyBwcm92aWRlZCBhZnRlciB0aGlzQXJnIChhcmcxLCBhcmcyIGV0YyksIGluIG9yZGVyLlxuICAgICAgICAvLyBYWFggc2xpY2VkQXJncyB3aWxsIHN0YW5kIGluIGZvciBcIkFcIiBpZiB1c2VkXG4gICAgICAgIHZhciBhcmdzID0gYXJyYXlfc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpOyAvLyBmb3Igbm9ybWFsIGNhbGxcbiAgICAgICAgLy8gNC4gTGV0IEYgYmUgYSBuZXcgbmF0aXZlIEVDTUFTY3JpcHQgb2JqZWN0LlxuICAgICAgICAvLyAxMS4gU2V0IHRoZSBbW1Byb3RvdHlwZV1dIGludGVybmFsIHByb3BlcnR5IG9mIEYgdG8gdGhlIHN0YW5kYXJkXG4gICAgICAgIC8vICAgYnVpbHQtaW4gRnVuY3Rpb24gcHJvdG90eXBlIG9iamVjdCBhcyBzcGVjaWZpZWQgaW4gMTUuMy4zLjEuXG4gICAgICAgIC8vIDEyLiBTZXQgdGhlIFtbQ2FsbF1dIGludGVybmFsIHByb3BlcnR5IG9mIEYgYXMgZGVzY3JpYmVkIGluXG4gICAgICAgIC8vICAgMTUuMy40LjUuMS5cbiAgICAgICAgLy8gMTMuIFNldCB0aGUgW1tDb25zdHJ1Y3RdXSBpbnRlcm5hbCBwcm9wZXJ0eSBvZiBGIGFzIGRlc2NyaWJlZCBpblxuICAgICAgICAvLyAgIDE1LjMuNC41LjIuXG4gICAgICAgIC8vIDE0LiBTZXQgdGhlIFtbSGFzSW5zdGFuY2VdXSBpbnRlcm5hbCBwcm9wZXJ0eSBvZiBGIGFzIGRlc2NyaWJlZCBpblxuICAgICAgICAvLyAgIDE1LjMuNC41LjMuXG4gICAgICAgIHZhciBiaW5kZXIgPSBmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgICAgIGlmICh0aGlzIGluc3RhbmNlb2YgYm91bmQpIHtcbiAgICAgICAgICAgICAgICAvLyAxNS4zLjQuNS4yIFtbQ29uc3RydWN0XV1cbiAgICAgICAgICAgICAgICAvLyBXaGVuIHRoZSBbW0NvbnN0cnVjdF1dIGludGVybmFsIG1ldGhvZCBvZiBhIGZ1bmN0aW9uIG9iamVjdCxcbiAgICAgICAgICAgICAgICAvLyBGIHRoYXQgd2FzIGNyZWF0ZWQgdXNpbmcgdGhlIGJpbmQgZnVuY3Rpb24gaXMgY2FsbGVkIHdpdGggYVxuICAgICAgICAgICAgICAgIC8vIGxpc3Qgb2YgYXJndW1lbnRzIEV4dHJhQXJncywgdGhlIGZvbGxvd2luZyBzdGVwcyBhcmUgdGFrZW46XG4gICAgICAgICAgICAgICAgLy8gMS4gTGV0IHRhcmdldCBiZSB0aGUgdmFsdWUgb2YgRidzIFtbVGFyZ2V0RnVuY3Rpb25dXVxuICAgICAgICAgICAgICAgIC8vICAgaW50ZXJuYWwgcHJvcGVydHkuXG4gICAgICAgICAgICAgICAgLy8gMi4gSWYgdGFyZ2V0IGhhcyBubyBbW0NvbnN0cnVjdF1dIGludGVybmFsIG1ldGhvZCwgYVxuICAgICAgICAgICAgICAgIC8vICAgVHlwZUVycm9yIGV4Y2VwdGlvbiBpcyB0aHJvd24uXG4gICAgICAgICAgICAgICAgLy8gMy4gTGV0IGJvdW5kQXJncyBiZSB0aGUgdmFsdWUgb2YgRidzIFtbQm91bmRBcmdzXV0gaW50ZXJuYWxcbiAgICAgICAgICAgICAgICAvLyAgIHByb3BlcnR5LlxuICAgICAgICAgICAgICAgIC8vIDQuIExldCBhcmdzIGJlIGEgbmV3IGxpc3QgY29udGFpbmluZyB0aGUgc2FtZSB2YWx1ZXMgYXMgdGhlXG4gICAgICAgICAgICAgICAgLy8gICBsaXN0IGJvdW5kQXJncyBpbiB0aGUgc2FtZSBvcmRlciBmb2xsb3dlZCBieSB0aGUgc2FtZVxuICAgICAgICAgICAgICAgIC8vICAgdmFsdWVzIGFzIHRoZSBsaXN0IEV4dHJhQXJncyBpbiB0aGUgc2FtZSBvcmRlci5cbiAgICAgICAgICAgICAgICAvLyA1LiBSZXR1cm4gdGhlIHJlc3VsdCBvZiBjYWxsaW5nIHRoZSBbW0NvbnN0cnVjdF1dIGludGVybmFsXG4gICAgICAgICAgICAgICAgLy8gICBtZXRob2Qgb2YgdGFyZ2V0IHByb3ZpZGluZyBhcmdzIGFzIHRoZSBhcmd1bWVudHMuXG5cbiAgICAgICAgICAgICAgICB2YXIgcmVzdWx0ID0gdGFyZ2V0LmFwcGx5KFxuICAgICAgICAgICAgICAgICAgICB0aGlzLFxuICAgICAgICAgICAgICAgICAgICBhcmdzLmNvbmNhdChhcnJheV9zbGljZS5jYWxsKGFyZ3VtZW50cykpXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBpZiAoT2JqZWN0KHJlc3VsdCkgPT09IHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcblxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyAxNS4zLjQuNS4xIFtbQ2FsbF1dXG4gICAgICAgICAgICAgICAgLy8gV2hlbiB0aGUgW1tDYWxsXV0gaW50ZXJuYWwgbWV0aG9kIG9mIGEgZnVuY3Rpb24gb2JqZWN0LCBGLFxuICAgICAgICAgICAgICAgIC8vIHdoaWNoIHdhcyBjcmVhdGVkIHVzaW5nIHRoZSBiaW5kIGZ1bmN0aW9uIGlzIGNhbGxlZCB3aXRoIGFcbiAgICAgICAgICAgICAgICAvLyB0aGlzIHZhbHVlIGFuZCBhIGxpc3Qgb2YgYXJndW1lbnRzIEV4dHJhQXJncywgdGhlIGZvbGxvd2luZ1xuICAgICAgICAgICAgICAgIC8vIHN0ZXBzIGFyZSB0YWtlbjpcbiAgICAgICAgICAgICAgICAvLyAxLiBMZXQgYm91bmRBcmdzIGJlIHRoZSB2YWx1ZSBvZiBGJ3MgW1tCb3VuZEFyZ3NdXSBpbnRlcm5hbFxuICAgICAgICAgICAgICAgIC8vICAgcHJvcGVydHkuXG4gICAgICAgICAgICAgICAgLy8gMi4gTGV0IGJvdW5kVGhpcyBiZSB0aGUgdmFsdWUgb2YgRidzIFtbQm91bmRUaGlzXV0gaW50ZXJuYWxcbiAgICAgICAgICAgICAgICAvLyAgIHByb3BlcnR5LlxuICAgICAgICAgICAgICAgIC8vIDMuIExldCB0YXJnZXQgYmUgdGhlIHZhbHVlIG9mIEYncyBbW1RhcmdldEZ1bmN0aW9uXV0gaW50ZXJuYWxcbiAgICAgICAgICAgICAgICAvLyAgIHByb3BlcnR5LlxuICAgICAgICAgICAgICAgIC8vIDQuIExldCBhcmdzIGJlIGEgbmV3IGxpc3QgY29udGFpbmluZyB0aGUgc2FtZSB2YWx1ZXMgYXMgdGhlXG4gICAgICAgICAgICAgICAgLy8gICBsaXN0IGJvdW5kQXJncyBpbiB0aGUgc2FtZSBvcmRlciBmb2xsb3dlZCBieSB0aGUgc2FtZVxuICAgICAgICAgICAgICAgIC8vICAgdmFsdWVzIGFzIHRoZSBsaXN0IEV4dHJhQXJncyBpbiB0aGUgc2FtZSBvcmRlci5cbiAgICAgICAgICAgICAgICAvLyA1LiBSZXR1cm4gdGhlIHJlc3VsdCBvZiBjYWxsaW5nIHRoZSBbW0NhbGxdXSBpbnRlcm5hbCBtZXRob2RcbiAgICAgICAgICAgICAgICAvLyAgIG9mIHRhcmdldCBwcm92aWRpbmcgYm91bmRUaGlzIGFzIHRoZSB0aGlzIHZhbHVlIGFuZFxuICAgICAgICAgICAgICAgIC8vICAgcHJvdmlkaW5nIGFyZ3MgYXMgdGhlIGFyZ3VtZW50cy5cblxuICAgICAgICAgICAgICAgIC8vIGVxdWl2OiB0YXJnZXQuY2FsbCh0aGlzLCAuLi5ib3VuZEFyZ3MsIC4uLmFyZ3MpXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRhcmdldC5hcHBseShcbiAgICAgICAgICAgICAgICAgICAgdGhhdCxcbiAgICAgICAgICAgICAgICAgICAgYXJncy5jb25jYXQoYXJyYXlfc2xpY2UuY2FsbChhcmd1bWVudHMpKVxuICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIH1cblxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIDE1LiBJZiB0aGUgW1tDbGFzc11dIGludGVybmFsIHByb3BlcnR5IG9mIFRhcmdldCBpcyBcIkZ1bmN0aW9uXCIsIHRoZW5cbiAgICAgICAgLy8gICAgIGEuIExldCBMIGJlIHRoZSBsZW5ndGggcHJvcGVydHkgb2YgVGFyZ2V0IG1pbnVzIHRoZSBsZW5ndGggb2YgQS5cbiAgICAgICAgLy8gICAgIGIuIFNldCB0aGUgbGVuZ3RoIG93biBwcm9wZXJ0eSBvZiBGIHRvIGVpdGhlciAwIG9yIEwsIHdoaWNoZXZlciBpc1xuICAgICAgICAvLyAgICAgICBsYXJnZXIuXG4gICAgICAgIC8vIDE2LiBFbHNlIHNldCB0aGUgbGVuZ3RoIG93biBwcm9wZXJ0eSBvZiBGIHRvIDAuXG5cbiAgICAgICAgdmFyIGJvdW5kTGVuZ3RoID0gTWF0aC5tYXgoMCwgdGFyZ2V0Lmxlbmd0aCAtIGFyZ3MubGVuZ3RoKTtcblxuICAgICAgICAvLyAxNy4gU2V0IHRoZSBhdHRyaWJ1dGVzIG9mIHRoZSBsZW5ndGggb3duIHByb3BlcnR5IG9mIEYgdG8gdGhlIHZhbHVlc1xuICAgICAgICAvLyAgIHNwZWNpZmllZCBpbiAxNS4zLjUuMS5cbiAgICAgICAgdmFyIGJvdW5kQXJncyA9IFtdO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJvdW5kTGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGJvdW5kQXJncy5wdXNoKCckJyArIGkpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gWFhYIEJ1aWxkIGEgZHluYW1pYyBmdW5jdGlvbiB3aXRoIGRlc2lyZWQgYW1vdW50IG9mIGFyZ3VtZW50cyBpcyB0aGUgb25seVxuICAgICAgICAvLyB3YXkgdG8gc2V0IHRoZSBsZW5ndGggcHJvcGVydHkgb2YgYSBmdW5jdGlvbi5cbiAgICAgICAgLy8gSW4gZW52aXJvbm1lbnRzIHdoZXJlIENvbnRlbnQgU2VjdXJpdHkgUG9saWNpZXMgZW5hYmxlZCAoQ2hyb21lIGV4dGVuc2lvbnMsXG4gICAgICAgIC8vIGZvciBleC4pIGFsbCB1c2Ugb2YgZXZhbCBvciBGdW5jdGlvbiBjb3N0cnVjdG9yIHRocm93cyBhbiBleGNlcHRpb24uXG4gICAgICAgIC8vIEhvd2V2ZXIgaW4gYWxsIG9mIHRoZXNlIGVudmlyb25tZW50cyBGdW5jdGlvbi5wcm90b3R5cGUuYmluZCBleGlzdHNcbiAgICAgICAgLy8gYW5kIHNvIHRoaXMgY29kZSB3aWxsIG5ldmVyIGJlIGV4ZWN1dGVkLlxuICAgICAgICB2YXIgYm91bmQgPSBGdW5jdGlvbignYmluZGVyJywgJ3JldHVybiBmdW5jdGlvbiAoJyArIGJvdW5kQXJncy5qb2luKCcsJykgKyAnKXsgcmV0dXJuIGJpbmRlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpOyB9JykoYmluZGVyKTtcblxuICAgICAgICBpZiAodGFyZ2V0LnByb3RvdHlwZSkge1xuICAgICAgICAgICAgRW1wdHkucHJvdG90eXBlID0gdGFyZ2V0LnByb3RvdHlwZTtcbiAgICAgICAgICAgIGJvdW5kLnByb3RvdHlwZSA9IG5ldyBFbXB0eSgpO1xuICAgICAgICAgICAgLy8gQ2xlYW4gdXAgZGFuZ2xpbmcgcmVmZXJlbmNlcy5cbiAgICAgICAgICAgIEVtcHR5LnByb3RvdHlwZSA9IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUT0RPXG4gICAgICAgIC8vIDE4LiBTZXQgdGhlIFtbRXh0ZW5zaWJsZV1dIGludGVybmFsIHByb3BlcnR5IG9mIEYgdG8gdHJ1ZS5cblxuICAgICAgICAvLyBUT0RPXG4gICAgICAgIC8vIDE5LiBMZXQgdGhyb3dlciBiZSB0aGUgW1tUaHJvd1R5cGVFcnJvcl1dIGZ1bmN0aW9uIE9iamVjdCAoMTMuMi4zKS5cbiAgICAgICAgLy8gMjAuIENhbGwgdGhlIFtbRGVmaW5lT3duUHJvcGVydHldXSBpbnRlcm5hbCBtZXRob2Qgb2YgRiB3aXRoXG4gICAgICAgIC8vICAgYXJndW1lbnRzIFwiY2FsbGVyXCIsIFByb3BlcnR5RGVzY3JpcHRvciB7W1tHZXRdXTogdGhyb3dlciwgW1tTZXRdXTpcbiAgICAgICAgLy8gICB0aHJvd2VyLCBbW0VudW1lcmFibGVdXTogZmFsc2UsIFtbQ29uZmlndXJhYmxlXV06IGZhbHNlfSwgYW5kXG4gICAgICAgIC8vICAgZmFsc2UuXG4gICAgICAgIC8vIDIxLiBDYWxsIHRoZSBbW0RlZmluZU93blByb3BlcnR5XV0gaW50ZXJuYWwgbWV0aG9kIG9mIEYgd2l0aFxuICAgICAgICAvLyAgIGFyZ3VtZW50cyBcImFyZ3VtZW50c1wiLCBQcm9wZXJ0eURlc2NyaXB0b3Ige1tbR2V0XV06IHRocm93ZXIsXG4gICAgICAgIC8vICAgW1tTZXRdXTogdGhyb3dlciwgW1tFbnVtZXJhYmxlXV06IGZhbHNlLCBbW0NvbmZpZ3VyYWJsZV1dOiBmYWxzZX0sXG4gICAgICAgIC8vICAgYW5kIGZhbHNlLlxuXG4gICAgICAgIC8vIFRPRE9cbiAgICAgICAgLy8gTk9URSBGdW5jdGlvbiBvYmplY3RzIGNyZWF0ZWQgdXNpbmcgRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQgZG8gbm90XG4gICAgICAgIC8vIGhhdmUgYSBwcm90b3R5cGUgcHJvcGVydHkgb3IgdGhlIFtbQ29kZV1dLCBbW0Zvcm1hbFBhcmFtZXRlcnNdXSwgYW5kXG4gICAgICAgIC8vIFtbU2NvcGVdXSBpbnRlcm5hbCBwcm9wZXJ0aWVzLlxuICAgICAgICAvLyBYWFggY2FuJ3QgZGVsZXRlIHByb3RvdHlwZSBpbiBwdXJlLWpzLlxuXG4gICAgICAgIC8vIDIyLiBSZXR1cm4gRi5cbiAgICAgICAgcmV0dXJuIGJvdW5kO1xuICAgIH1cbn0pO1xuXG4vL1xuLy8gQXJyYXlcbi8vID09PT09XG4vL1xuXG4vLyBFUzUgMTUuNC4zLjJcbi8vIGh0dHA6Ly9lczUuZ2l0aHViLmNvbS8jeDE1LjQuMy4yXG4vLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9pc0FycmF5XG5kZWZpbmVQcm9wZXJ0aWVzKEFycmF5LCB7IGlzQXJyYXk6IGlzQXJyYXkgfSk7XG5cblxudmFyIGJveGVkU3RyaW5nID0gT2JqZWN0KCdhJyk7XG52YXIgc3BsaXRTdHJpbmcgPSBib3hlZFN0cmluZ1swXSAhPT0gJ2EnIHx8ICEoMCBpbiBib3hlZFN0cmluZyk7XG5cbnZhciBwcm9wZXJseUJveGVzQ29udGV4dCA9IGZ1bmN0aW9uIHByb3Blcmx5Qm94ZWQobWV0aG9kKSB7XG4gICAgLy8gQ2hlY2sgbm9kZSAwLjYuMjEgYnVnIHdoZXJlIHRoaXJkIHBhcmFtZXRlciBpcyBub3QgYm94ZWRcbiAgICB2YXIgcHJvcGVybHlCb3hlc05vblN0cmljdCA9IHRydWU7XG4gICAgdmFyIHByb3Blcmx5Qm94ZXNTdHJpY3QgPSB0cnVlO1xuICAgIGlmIChtZXRob2QpIHtcbiAgICAgICAgbWV0aG9kLmNhbGwoJ2ZvbycsIGZ1bmN0aW9uIChfLCBfXywgY29udGV4dCkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBjb250ZXh0ICE9PSAnb2JqZWN0JykgeyBwcm9wZXJseUJveGVzTm9uU3RyaWN0ID0gZmFsc2U7IH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgbWV0aG9kLmNhbGwoWzFdLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAndXNlIHN0cmljdCc7XG4gICAgICAgICAgICBwcm9wZXJseUJveGVzU3RyaWN0ID0gdHlwZW9mIHRoaXMgPT09ICdzdHJpbmcnO1xuICAgICAgICB9LCAneCcpO1xuICAgIH1cbiAgICByZXR1cm4gISFtZXRob2QgJiYgcHJvcGVybHlCb3hlc05vblN0cmljdCAmJiBwcm9wZXJseUJveGVzU3RyaWN0O1xufTtcblxuZGVmaW5lUHJvcGVydGllcyhBcnJheVByb3RvdHlwZSwge1xuICAgIGZvckVhY2g6IGZ1bmN0aW9uIGZvckVhY2goZnVuIC8qLCB0aGlzcCovKSB7XG4gICAgICAgIHZhciBvYmplY3QgPSB0b09iamVjdCh0aGlzKSxcbiAgICAgICAgICAgIHNlbGYgPSBzcGxpdFN0cmluZyAmJiBpc1N0cmluZyh0aGlzKSA/IHRoaXMuc3BsaXQoJycpIDogb2JqZWN0LFxuICAgICAgICAgICAgdGhpc3AgPSBhcmd1bWVudHNbMV0sXG4gICAgICAgICAgICBpID0gLTEsXG4gICAgICAgICAgICBsZW5ndGggPSBzZWxmLmxlbmd0aCA+Pj4gMDtcblxuICAgICAgICAvLyBJZiBubyBjYWxsYmFjayBmdW5jdGlvbiBvciBpZiBjYWxsYmFjayBpcyBub3QgYSBjYWxsYWJsZSBmdW5jdGlvblxuICAgICAgICBpZiAoIWlzRnVuY3Rpb24oZnVuKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigpOyAvLyBUT0RPIG1lc3NhZ2VcbiAgICAgICAgfVxuXG4gICAgICAgIHdoaWxlICgrK2kgPCBsZW5ndGgpIHtcbiAgICAgICAgICAgIGlmIChpIGluIHNlbGYpIHtcbiAgICAgICAgICAgICAgICAvLyBJbnZva2UgdGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHdpdGggY2FsbCwgcGFzc2luZyBhcmd1bWVudHM6XG4gICAgICAgICAgICAgICAgLy8gY29udGV4dCwgcHJvcGVydHkgdmFsdWUsIHByb3BlcnR5IGtleSwgdGhpc0FyZyBvYmplY3RcbiAgICAgICAgICAgICAgICAvLyBjb250ZXh0XG4gICAgICAgICAgICAgICAgZnVuLmNhbGwodGhpc3AsIHNlbGZbaV0sIGksIG9iamVjdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59LCAhcHJvcGVybHlCb3hlc0NvbnRleHQoQXJyYXlQcm90b3R5cGUuZm9yRWFjaCkpO1xuXG4vLyBFUzUgMTUuNC40LjE0XG4vLyBodHRwOi8vZXM1LmdpdGh1Yi5jb20vI3gxNS40LjQuMTRcbi8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0FycmF5L2luZGV4T2ZcbnZhciBoYXNGaXJlZm94MkluZGV4T2ZCdWcgPSBBcnJheS5wcm90b3R5cGUuaW5kZXhPZiAmJiBbMCwgMV0uaW5kZXhPZigxLCAyKSAhPT0gLTE7XG5kZWZpbmVQcm9wZXJ0aWVzKEFycmF5UHJvdG90eXBlLCB7XG4gICAgaW5kZXhPZjogZnVuY3Rpb24gaW5kZXhPZihzb3VnaHQgLyosIGZyb21JbmRleCAqLyApIHtcbiAgICAgICAgdmFyIHNlbGYgPSBzcGxpdFN0cmluZyAmJiBpc1N0cmluZyh0aGlzKSA/IHRoaXMuc3BsaXQoJycpIDogdG9PYmplY3QodGhpcyksXG4gICAgICAgICAgICBsZW5ndGggPSBzZWxmLmxlbmd0aCA+Pj4gMDtcblxuICAgICAgICBpZiAoIWxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGkgPSAwO1xuICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgIGkgPSB0b0ludGVnZXIoYXJndW1lbnRzWzFdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGhhbmRsZSBuZWdhdGl2ZSBpbmRpY2VzXG4gICAgICAgIGkgPSBpID49IDAgPyBpIDogTWF0aC5tYXgoMCwgbGVuZ3RoICsgaSk7XG4gICAgICAgIGZvciAoOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChpIGluIHNlbGYgJiYgc2VsZltpXSA9PT0gc291Z2h0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cbn0sIGhhc0ZpcmVmb3gySW5kZXhPZkJ1Zyk7XG5cbi8vXG4vLyBTdHJpbmdcbi8vID09PT09PVxuLy9cblxuLy8gRVM1IDE1LjUuNC4xNFxuLy8gaHR0cDovL2VzNS5naXRodWIuY29tLyN4MTUuNS40LjE0XG5cbi8vIFtidWdmaXgsIElFIGx0IDksIGZpcmVmb3ggNCwgS29ucXVlcm9yLCBPcGVyYSwgb2JzY3VyZSBicm93c2Vyc11cbi8vIE1hbnkgYnJvd3NlcnMgZG8gbm90IHNwbGl0IHByb3Blcmx5IHdpdGggcmVndWxhciBleHByZXNzaW9ucyBvciB0aGV5XG4vLyBkbyBub3QgcGVyZm9ybSB0aGUgc3BsaXQgY29ycmVjdGx5IHVuZGVyIG9ic2N1cmUgY29uZGl0aW9ucy5cbi8vIFNlZSBodHRwOi8vYmxvZy5zdGV2ZW5sZXZpdGhhbi5jb20vYXJjaGl2ZXMvY3Jvc3MtYnJvd3Nlci1zcGxpdFxuLy8gSSd2ZSB0ZXN0ZWQgaW4gbWFueSBicm93c2VycyBhbmQgdGhpcyBzZWVtcyB0byBjb3ZlciB0aGUgZGV2aWFudCBvbmVzOlxuLy8gICAgJ2FiJy5zcGxpdCgvKD86YWIpKi8pIHNob3VsZCBiZSBbXCJcIiwgXCJcIl0sIG5vdCBbXCJcIl1cbi8vICAgICcuJy5zcGxpdCgvKC4/KSguPykvKSBzaG91bGQgYmUgW1wiXCIsIFwiLlwiLCBcIlwiLCBcIlwiXSwgbm90IFtcIlwiLCBcIlwiXVxuLy8gICAgJ3Rlc3N0Jy5zcGxpdCgvKHMpKi8pIHNob3VsZCBiZSBbXCJ0XCIsIHVuZGVmaW5lZCwgXCJlXCIsIFwic1wiLCBcInRcIl0sIG5vdFxuLy8gICAgICAgW3VuZGVmaW5lZCwgXCJ0XCIsIHVuZGVmaW5lZCwgXCJlXCIsIC4uLl1cbi8vICAgICcnLnNwbGl0KC8uPy8pIHNob3VsZCBiZSBbXSwgbm90IFtcIlwiXVxuLy8gICAgJy4nLnNwbGl0KC8oKSgpLykgc2hvdWxkIGJlIFtcIi5cIl0sIG5vdCBbXCJcIiwgXCJcIiwgXCIuXCJdXG5cbnZhciBzdHJpbmdfc3BsaXQgPSBTdHJpbmdQcm90b3R5cGUuc3BsaXQ7XG5pZiAoXG4gICAgJ2FiJy5zcGxpdCgvKD86YWIpKi8pLmxlbmd0aCAhPT0gMiB8fFxuICAgICcuJy5zcGxpdCgvKC4/KSguPykvKS5sZW5ndGggIT09IDQgfHxcbiAgICAndGVzc3QnLnNwbGl0KC8ocykqLylbMV0gPT09ICd0JyB8fFxuICAgICd0ZXN0Jy5zcGxpdCgvKD86KS8sIC0xKS5sZW5ndGggIT09IDQgfHxcbiAgICAnJy5zcGxpdCgvLj8vKS5sZW5ndGggfHxcbiAgICAnLicuc3BsaXQoLygpKCkvKS5sZW5ndGggPiAxXG4pIHtcbiAgICAoZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgY29tcGxpYW50RXhlY05wY2cgPSAvKCk/Py8uZXhlYygnJylbMV0gPT09IHZvaWQgMDsgLy8gTlBDRzogbm9ucGFydGljaXBhdGluZyBjYXB0dXJpbmcgZ3JvdXBcblxuICAgICAgICBTdHJpbmdQcm90b3R5cGUuc3BsaXQgPSBmdW5jdGlvbiAoc2VwYXJhdG9yLCBsaW1pdCkge1xuICAgICAgICAgICAgdmFyIHN0cmluZyA9IHRoaXM7XG4gICAgICAgICAgICBpZiAoc2VwYXJhdG9yID09PSB2b2lkIDAgJiYgbGltaXQgPT09IDApIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIElmIGBzZXBhcmF0b3JgIGlzIG5vdCBhIHJlZ2V4LCB1c2UgbmF0aXZlIHNwbGl0XG4gICAgICAgICAgICBpZiAoX3RvU3RyaW5nLmNhbGwoc2VwYXJhdG9yKSAhPT0gJ1tvYmplY3QgUmVnRXhwXScpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3RyaW5nX3NwbGl0LmNhbGwodGhpcywgc2VwYXJhdG9yLCBsaW1pdCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBvdXRwdXQgPSBbXSxcbiAgICAgICAgICAgICAgICBmbGFncyA9IChzZXBhcmF0b3IuaWdub3JlQ2FzZSA/ICdpJyA6ICcnKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAoc2VwYXJhdG9yLm11bHRpbGluZSAgPyAnbScgOiAnJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgKHNlcGFyYXRvci5leHRlbmRlZCAgID8gJ3gnIDogJycpICsgLy8gUHJvcG9zZWQgZm9yIEVTNlxuICAgICAgICAgICAgICAgICAgICAgICAgKHNlcGFyYXRvci5zdGlja3kgICAgID8gJ3knIDogJycpLCAvLyBGaXJlZm94IDMrXG4gICAgICAgICAgICAgICAgbGFzdExhc3RJbmRleCA9IDAsXG4gICAgICAgICAgICAgICAgLy8gTWFrZSBgZ2xvYmFsYCBhbmQgYXZvaWQgYGxhc3RJbmRleGAgaXNzdWVzIGJ5IHdvcmtpbmcgd2l0aCBhIGNvcHlcbiAgICAgICAgICAgICAgICBzZXBhcmF0b3IyLCBtYXRjaCwgbGFzdEluZGV4LCBsYXN0TGVuZ3RoO1xuICAgICAgICAgICAgc2VwYXJhdG9yID0gbmV3IFJlZ0V4cChzZXBhcmF0b3Iuc291cmNlLCBmbGFncyArICdnJyk7XG4gICAgICAgICAgICBzdHJpbmcgKz0gJyc7IC8vIFR5cGUtY29udmVydFxuICAgICAgICAgICAgaWYgKCFjb21wbGlhbnRFeGVjTnBjZykge1xuICAgICAgICAgICAgICAgIC8vIERvZXNuJ3QgbmVlZCBmbGFncyBneSwgYnV0IHRoZXkgZG9uJ3QgaHVydFxuICAgICAgICAgICAgICAgIHNlcGFyYXRvcjIgPSBuZXcgUmVnRXhwKCdeJyArIHNlcGFyYXRvci5zb3VyY2UgKyAnJCg/IVxcXFxzKScsIGZsYWdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8qIFZhbHVlcyBmb3IgYGxpbWl0YCwgcGVyIHRoZSBzcGVjOlxuICAgICAgICAgICAgICogSWYgdW5kZWZpbmVkOiA0Mjk0OTY3Mjk1IC8vIE1hdGgucG93KDIsIDMyKSAtIDFcbiAgICAgICAgICAgICAqIElmIDAsIEluZmluaXR5LCBvciBOYU46IDBcbiAgICAgICAgICAgICAqIElmIHBvc2l0aXZlIG51bWJlcjogbGltaXQgPSBNYXRoLmZsb29yKGxpbWl0KTsgaWYgKGxpbWl0ID4gNDI5NDk2NzI5NSkgbGltaXQgLT0gNDI5NDk2NzI5NjtcbiAgICAgICAgICAgICAqIElmIG5lZ2F0aXZlIG51bWJlcjogNDI5NDk2NzI5NiAtIE1hdGguZmxvb3IoTWF0aC5hYnMobGltaXQpKVxuICAgICAgICAgICAgICogSWYgb3RoZXI6IFR5cGUtY29udmVydCwgdGhlbiB1c2UgdGhlIGFib3ZlIHJ1bGVzXG4gICAgICAgICAgICAgKi9cbiAgICAgICAgICAgIGxpbWl0ID0gbGltaXQgPT09IHZvaWQgMCA/XG4gICAgICAgICAgICAgICAgLTEgPj4+IDAgOiAvLyBNYXRoLnBvdygyLCAzMikgLSAxXG4gICAgICAgICAgICAgICAgVG9VaW50MzIobGltaXQpO1xuICAgICAgICAgICAgd2hpbGUgKG1hdGNoID0gc2VwYXJhdG9yLmV4ZWMoc3RyaW5nKSkge1xuICAgICAgICAgICAgICAgIC8vIGBzZXBhcmF0b3IubGFzdEluZGV4YCBpcyBub3QgcmVsaWFibGUgY3Jvc3MtYnJvd3NlclxuICAgICAgICAgICAgICAgIGxhc3RJbmRleCA9IG1hdGNoLmluZGV4ICsgbWF0Y2hbMF0ubGVuZ3RoO1xuICAgICAgICAgICAgICAgIGlmIChsYXN0SW5kZXggPiBsYXN0TGFzdEluZGV4KSB7XG4gICAgICAgICAgICAgICAgICAgIG91dHB1dC5wdXNoKHN0cmluZy5zbGljZShsYXN0TGFzdEluZGV4LCBtYXRjaC5pbmRleCkpO1xuICAgICAgICAgICAgICAgICAgICAvLyBGaXggYnJvd3NlcnMgd2hvc2UgYGV4ZWNgIG1ldGhvZHMgZG9uJ3QgY29uc2lzdGVudGx5IHJldHVybiBgdW5kZWZpbmVkYCBmb3JcbiAgICAgICAgICAgICAgICAgICAgLy8gbm9ucGFydGljaXBhdGluZyBjYXB0dXJpbmcgZ3JvdXBzXG4gICAgICAgICAgICAgICAgICAgIGlmICghY29tcGxpYW50RXhlY05wY2cgJiYgbWF0Y2gubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2hbMF0ucmVwbGFjZShzZXBhcmF0b3IyLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDE7IGkgPCBhcmd1bWVudHMubGVuZ3RoIC0gMjsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhcmd1bWVudHNbaV0gPT09IHZvaWQgMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2hbaV0gPSB2b2lkIDA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAobWF0Y2gubGVuZ3RoID4gMSAmJiBtYXRjaC5pbmRleCA8IHN0cmluZy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIEFycmF5UHJvdG90eXBlLnB1c2guYXBwbHkob3V0cHV0LCBtYXRjaC5zbGljZSgxKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgbGFzdExlbmd0aCA9IG1hdGNoWzBdLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgbGFzdExhc3RJbmRleCA9IGxhc3RJbmRleDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG91dHB1dC5sZW5ndGggPj0gbGltaXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChzZXBhcmF0b3IubGFzdEluZGV4ID09PSBtYXRjaC5pbmRleCkge1xuICAgICAgICAgICAgICAgICAgICBzZXBhcmF0b3IubGFzdEluZGV4Kys7IC8vIEF2b2lkIGFuIGluZmluaXRlIGxvb3BcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobGFzdExhc3RJbmRleCA9PT0gc3RyaW5nLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGlmIChsYXN0TGVuZ3RoIHx8ICFzZXBhcmF0b3IudGVzdCgnJykpIHtcbiAgICAgICAgICAgICAgICAgICAgb3V0cHV0LnB1c2goJycpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgb3V0cHV0LnB1c2goc3RyaW5nLnNsaWNlKGxhc3RMYXN0SW5kZXgpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBvdXRwdXQubGVuZ3RoID4gbGltaXQgPyBvdXRwdXQuc2xpY2UoMCwgbGltaXQpIDogb3V0cHV0O1xuICAgICAgICB9O1xuICAgIH0oKSk7XG5cbi8vIFtidWdmaXgsIGNocm9tZV1cbi8vIElmIHNlcGFyYXRvciBpcyB1bmRlZmluZWQsIHRoZW4gdGhlIHJlc3VsdCBhcnJheSBjb250YWlucyBqdXN0IG9uZSBTdHJpbmcsXG4vLyB3aGljaCBpcyB0aGUgdGhpcyB2YWx1ZSAoY29udmVydGVkIHRvIGEgU3RyaW5nKS4gSWYgbGltaXQgaXMgbm90IHVuZGVmaW5lZCxcbi8vIHRoZW4gdGhlIG91dHB1dCBhcnJheSBpcyB0cnVuY2F0ZWQgc28gdGhhdCBpdCBjb250YWlucyBubyBtb3JlIHRoYW4gbGltaXRcbi8vIGVsZW1lbnRzLlxuLy8gXCIwXCIuc3BsaXQodW5kZWZpbmVkLCAwKSAtPiBbXVxufSBlbHNlIGlmICgnMCcuc3BsaXQodm9pZCAwLCAwKS5sZW5ndGgpIHtcbiAgICBTdHJpbmdQcm90b3R5cGUuc3BsaXQgPSBmdW5jdGlvbiBzcGxpdChzZXBhcmF0b3IsIGxpbWl0KSB7XG4gICAgICAgIGlmIChzZXBhcmF0b3IgPT09IHZvaWQgMCAmJiBsaW1pdCA9PT0gMCkgeyByZXR1cm4gW107IH1cbiAgICAgICAgcmV0dXJuIHN0cmluZ19zcGxpdC5jYWxsKHRoaXMsIHNlcGFyYXRvciwgbGltaXQpO1xuICAgIH07XG59XG5cbi8vIEVTNSAxNS41LjQuMjBcbi8vIHdoaXRlc3BhY2UgZnJvbTogaHR0cDovL2VzNS5naXRodWIuaW8vI3gxNS41LjQuMjBcbnZhciB3cyA9ICdcXHgwOVxceDBBXFx4MEJcXHgwQ1xceDBEXFx4MjBcXHhBMFxcdTE2ODBcXHUxODBFXFx1MjAwMFxcdTIwMDFcXHUyMDAyXFx1MjAwMycgK1xuICAgICdcXHUyMDA0XFx1MjAwNVxcdTIwMDZcXHUyMDA3XFx1MjAwOFxcdTIwMDlcXHUyMDBBXFx1MjAyRlxcdTIwNUZcXHUzMDAwXFx1MjAyOCcgK1xuICAgICdcXHUyMDI5XFx1RkVGRic7XG52YXIgemVyb1dpZHRoID0gJ1xcdTIwMGInO1xudmFyIHdzUmVnZXhDaGFycyA9ICdbJyArIHdzICsgJ10nO1xudmFyIHRyaW1CZWdpblJlZ2V4cCA9IG5ldyBSZWdFeHAoJ14nICsgd3NSZWdleENoYXJzICsgd3NSZWdleENoYXJzICsgJyonKTtcbnZhciB0cmltRW5kUmVnZXhwID0gbmV3IFJlZ0V4cCh3c1JlZ2V4Q2hhcnMgKyB3c1JlZ2V4Q2hhcnMgKyAnKiQnKTtcbnZhciBoYXNUcmltV2hpdGVzcGFjZUJ1ZyA9IFN0cmluZ1Byb3RvdHlwZS50cmltICYmICh3cy50cmltKCkgfHwgIXplcm9XaWR0aC50cmltKCkpO1xuZGVmaW5lUHJvcGVydGllcyhTdHJpbmdQcm90b3R5cGUsIHtcbiAgICAvLyBodHRwOi8vYmxvZy5zdGV2ZW5sZXZpdGhhbi5jb20vYXJjaGl2ZXMvZmFzdGVyLXRyaW0tamF2YXNjcmlwdFxuICAgIC8vIGh0dHA6Ly9wZXJmZWN0aW9ua2lsbHMuY29tL3doaXRlc3BhY2UtZGV2aWF0aW9ucy9cbiAgICB0cmltOiBmdW5jdGlvbiB0cmltKCkge1xuICAgICAgICBpZiAodGhpcyA9PT0gdm9pZCAwIHx8IHRoaXMgPT09IG51bGwpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJjYW4ndCBjb252ZXJ0IFwiICsgdGhpcyArICcgdG8gb2JqZWN0Jyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFN0cmluZyh0aGlzKS5yZXBsYWNlKHRyaW1CZWdpblJlZ2V4cCwgJycpLnJlcGxhY2UodHJpbUVuZFJlZ2V4cCwgJycpO1xuICAgIH1cbn0sIGhhc1RyaW1XaGl0ZXNwYWNlQnVnKTtcblxuLy8gRUNNQS0yNjIsIDNyZCBCLjIuM1xuLy8gTm90IGFuIEVDTUFTY3JpcHQgc3RhbmRhcmQsIGFsdGhvdWdoIEVDTUFTY3JpcHQgM3JkIEVkaXRpb24gaGFzIGFcbi8vIG5vbi1ub3JtYXRpdmUgc2VjdGlvbiBzdWdnZXN0aW5nIHVuaWZvcm0gc2VtYW50aWNzIGFuZCBpdCBzaG91bGQgYmVcbi8vIG5vcm1hbGl6ZWQgYWNyb3NzIGFsbCBicm93c2Vyc1xuLy8gW2J1Z2ZpeCwgSUUgbHQgOV0gSUUgPCA5IHN1YnN0cigpIHdpdGggbmVnYXRpdmUgdmFsdWUgbm90IHdvcmtpbmcgaW4gSUVcbnZhciBzdHJpbmdfc3Vic3RyID0gU3RyaW5nUHJvdG90eXBlLnN1YnN0cjtcbnZhciBoYXNOZWdhdGl2ZVN1YnN0ckJ1ZyA9ICcnLnN1YnN0ciAmJiAnMGInLnN1YnN0cigtMSkgIT09ICdiJztcbmRlZmluZVByb3BlcnRpZXMoU3RyaW5nUHJvdG90eXBlLCB7XG4gICAgc3Vic3RyOiBmdW5jdGlvbiBzdWJzdHIoc3RhcnQsIGxlbmd0aCkge1xuICAgICAgICByZXR1cm4gc3RyaW5nX3N1YnN0ci5jYWxsKFxuICAgICAgICAgICAgdGhpcyxcbiAgICAgICAgICAgIHN0YXJ0IDwgMCA/ICgoc3RhcnQgPSB0aGlzLmxlbmd0aCArIHN0YXJ0KSA8IDAgPyAwIDogc3RhcnQpIDogc3RhcnQsXG4gICAgICAgICAgICBsZW5ndGhcbiAgICAgICAgKTtcbiAgICB9XG59LCBoYXNOZWdhdGl2ZVN1YnN0ckJ1Zyk7XG4iLCIndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gW1xuICAvLyBzdHJlYW1pbmcgdHJhbnNwb3J0c1xuICByZXF1aXJlKCcuL3RyYW5zcG9ydC93ZWJzb2NrZXQnKVxuLCByZXF1aXJlKCcuL3RyYW5zcG9ydC94aHItc3RyZWFtaW5nJylcbiwgcmVxdWlyZSgnLi90cmFuc3BvcnQveGRyLXN0cmVhbWluZycpXG4sIHJlcXVpcmUoJy4vdHJhbnNwb3J0L2V2ZW50c291cmNlJylcbiwgcmVxdWlyZSgnLi90cmFuc3BvcnQvbGliL2lmcmFtZS13cmFwJykocmVxdWlyZSgnLi90cmFuc3BvcnQvZXZlbnRzb3VyY2UnKSlcblxuICAvLyBwb2xsaW5nIHRyYW5zcG9ydHNcbiwgcmVxdWlyZSgnLi90cmFuc3BvcnQvaHRtbGZpbGUnKVxuLCByZXF1aXJlKCcuL3RyYW5zcG9ydC9saWIvaWZyYW1lLXdyYXAnKShyZXF1aXJlKCcuL3RyYW5zcG9ydC9odG1sZmlsZScpKVxuLCByZXF1aXJlKCcuL3RyYW5zcG9ydC94aHItcG9sbGluZycpXG4sIHJlcXVpcmUoJy4vdHJhbnNwb3J0L3hkci1wb2xsaW5nJylcbiwgcmVxdWlyZSgnLi90cmFuc3BvcnQvbGliL2lmcmFtZS13cmFwJykocmVxdWlyZSgnLi90cmFuc3BvcnQveGhyLXBvbGxpbmcnKSlcbiwgcmVxdWlyZSgnLi90cmFuc3BvcnQvanNvbnAtcG9sbGluZycpXG5dO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gICwgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgdXRpbHMgPSByZXF1aXJlKCcuLi8uLi91dGlscy9ldmVudCcpXG4gICwgdXJsVXRpbHMgPSByZXF1aXJlKCcuLi8uLi91dGlscy91cmwnKVxuICAsIFhIUiA9IGdsb2JhbC5YTUxIdHRwUmVxdWVzdFxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6YnJvd3Nlcjp4aHInKTtcbn1cblxuZnVuY3Rpb24gQWJzdHJhY3RYSFJPYmplY3QobWV0aG9kLCB1cmwsIHBheWxvYWQsIG9wdHMpIHtcbiAgZGVidWcobWV0aG9kLCB1cmwpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuXG4gIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgIHNlbGYuX3N0YXJ0KG1ldGhvZCwgdXJsLCBwYXlsb2FkLCBvcHRzKTtcbiAgfSwgMCk7XG59XG5cbmluaGVyaXRzKEFic3RyYWN0WEhST2JqZWN0LCBFdmVudEVtaXR0ZXIpO1xuXG5BYnN0cmFjdFhIUk9iamVjdC5wcm90b3R5cGUuX3N0YXJ0ID0gZnVuY3Rpb24obWV0aG9kLCB1cmwsIHBheWxvYWQsIG9wdHMpIHtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gIHRyeSB7XG4gICAgdGhpcy54aHIgPSBuZXcgWEhSKCk7XG4gIH0gY2F0Y2ggKHgpIHtcbiAgICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG4gIH1cblxuICBpZiAoIXRoaXMueGhyKSB7XG4gICAgZGVidWcoJ25vIHhocicpO1xuICAgIHRoaXMuZW1pdCgnZmluaXNoJywgMCwgJ25vIHhociBzdXBwb3J0Jyk7XG4gICAgdGhpcy5fY2xlYW51cCgpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIHNldmVyYWwgYnJvd3NlcnMgY2FjaGUgUE9TVHNcbiAgdXJsID0gdXJsVXRpbHMuYWRkUXVlcnkodXJsLCAndD0nICsgKCtuZXcgRGF0ZSgpKSk7XG5cbiAgLy8gRXhwbG9yZXIgdGVuZHMgdG8ga2VlcCBjb25uZWN0aW9uIG9wZW4sIGV2ZW4gYWZ0ZXIgdGhlXG4gIC8vIHRhYiBnZXRzIGNsb3NlZDogaHR0cDovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvNTI4MFxuICB0aGlzLnVubG9hZFJlZiA9IHV0aWxzLnVubG9hZEFkZChmdW5jdGlvbigpIHtcbiAgICBkZWJ1ZygndW5sb2FkIGNsZWFudXAnKTtcbiAgICBzZWxmLl9jbGVhbnVwKHRydWUpO1xuICB9KTtcbiAgdHJ5IHtcbiAgICB0aGlzLnhoci5vcGVuKG1ldGhvZCwgdXJsLCB0cnVlKTtcbiAgICBpZiAodGhpcy50aW1lb3V0ICYmICd0aW1lb3V0JyBpbiB0aGlzLnhocikge1xuICAgICAgdGhpcy54aHIudGltZW91dCA9IHRoaXMudGltZW91dDtcbiAgICAgIHRoaXMueGhyLm9udGltZW91dCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBkZWJ1ZygneGhyIHRpbWVvdXQnKTtcbiAgICAgICAgc2VsZi5lbWl0KCdmaW5pc2gnLCAwLCAnJyk7XG4gICAgICAgIHNlbGYuX2NsZWFudXAoZmFsc2UpO1xuICAgICAgfTtcbiAgICB9XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBkZWJ1ZygnZXhjZXB0aW9uJywgZSk7XG4gICAgLy8gSUUgcmFpc2VzIGFuIGV4Y2VwdGlvbiBvbiB3cm9uZyBwb3J0LlxuICAgIHRoaXMuZW1pdCgnZmluaXNoJywgMCwgJycpO1xuICAgIHRoaXMuX2NsZWFudXAoZmFsc2UpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmICgoIW9wdHMgfHwgIW9wdHMubm9DcmVkZW50aWFscykgJiYgQWJzdHJhY3RYSFJPYmplY3Quc3VwcG9ydHNDT1JTKSB7XG4gICAgZGVidWcoJ3dpdGhDcmVkZW50aWFscycpO1xuICAgIC8vIE1vemlsbGEgZG9jcyBzYXlzIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuL1hNTEh0dHBSZXF1ZXN0IDpcbiAgICAvLyBcIlRoaXMgbmV2ZXIgYWZmZWN0cyBzYW1lLXNpdGUgcmVxdWVzdHMuXCJcblxuICAgIHRoaXMueGhyLndpdGhDcmVkZW50aWFscyA9ICd0cnVlJztcbiAgfVxuICBpZiAob3B0cyAmJiBvcHRzLmhlYWRlcnMpIHtcbiAgICBmb3IgKHZhciBrZXkgaW4gb3B0cy5oZWFkZXJzKSB7XG4gICAgICB0aGlzLnhoci5zZXRSZXF1ZXN0SGVhZGVyKGtleSwgb3B0cy5oZWFkZXJzW2tleV0pO1xuICAgIH1cbiAgfVxuXG4gIHRoaXMueGhyLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uKCkge1xuICAgIGlmIChzZWxmLnhocikge1xuICAgICAgdmFyIHggPSBzZWxmLnhocjtcbiAgICAgIHZhciB0ZXh0LCBzdGF0dXM7XG4gICAgICBkZWJ1ZygncmVhZHlTdGF0ZScsIHgucmVhZHlTdGF0ZSk7XG4gICAgICBzd2l0Y2ggKHgucmVhZHlTdGF0ZSkge1xuICAgICAgY2FzZSAzOlxuICAgICAgICAvLyBJRSBkb2Vzbid0IGxpa2UgcGVla2luZyBpbnRvIHJlc3BvbnNlVGV4dCBvciBzdGF0dXNcbiAgICAgICAgLy8gb24gTWljcm9zb2Z0LlhNTEhUVFAgYW5kIHJlYWR5c3RhdGU9M1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHN0YXR1cyA9IHguc3RhdHVzO1xuICAgICAgICAgIHRleHQgPSB4LnJlc3BvbnNlVGV4dDtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIC8vIGludGVudGlvbmFsbHkgZW1wdHlcbiAgICAgICAgfVxuICAgICAgICBkZWJ1Zygnc3RhdHVzJywgc3RhdHVzKTtcbiAgICAgICAgLy8gSUUgcmV0dXJucyAxMjIzIGZvciAyMDQ6IGh0dHA6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzE0NTBcbiAgICAgICAgaWYgKHN0YXR1cyA9PT0gMTIyMykge1xuICAgICAgICAgIHN0YXR1cyA9IDIwNDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElFIGRvZXMgcmV0dXJuIHJlYWR5c3RhdGUgPT0gMyBmb3IgNDA0IGFuc3dlcnMuXG4gICAgICAgIGlmIChzdGF0dXMgPT09IDIwMCAmJiB0ZXh0ICYmIHRleHQubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGRlYnVnKCdjaHVuaycpO1xuICAgICAgICAgIHNlbGYuZW1pdCgnY2h1bmsnLCBzdGF0dXMsIHRleHQpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA0OlxuICAgICAgICBzdGF0dXMgPSB4LnN0YXR1cztcbiAgICAgICAgZGVidWcoJ3N0YXR1cycsIHN0YXR1cyk7XG4gICAgICAgIC8vIElFIHJldHVybnMgMTIyMyBmb3IgMjA0OiBodHRwOi8vYnVncy5qcXVlcnkuY29tL3RpY2tldC8xNDUwXG4gICAgICAgIGlmIChzdGF0dXMgPT09IDEyMjMpIHtcbiAgICAgICAgICBzdGF0dXMgPSAyMDQ7XG4gICAgICAgIH1cbiAgICAgICAgLy8gSUUgcmV0dXJucyB0aGlzIGZvciBhIGJhZCBwb3J0XG4gICAgICAgIC8vIGh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20vZW4tdXMvbGlicmFyeS93aW5kb3dzL2Rlc2t0b3AvYWEzODM3NzAodj12cy44NSkuYXNweFxuICAgICAgICBpZiAoc3RhdHVzID09PSAxMjAwNSB8fCBzdGF0dXMgPT09IDEyMDI5KSB7XG4gICAgICAgICAgc3RhdHVzID0gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIGRlYnVnKCdmaW5pc2gnLCBzdGF0dXMsIHgucmVzcG9uc2VUZXh0KTtcbiAgICAgICAgc2VsZi5lbWl0KCdmaW5pc2gnLCBzdGF0dXMsIHgucmVzcG9uc2VUZXh0KTtcbiAgICAgICAgc2VsZi5fY2xlYW51cChmYWxzZSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICB0cnkge1xuICAgIHNlbGYueGhyLnNlbmQocGF5bG9hZCk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBzZWxmLmVtaXQoJ2ZpbmlzaCcsIDAsICcnKTtcbiAgICBzZWxmLl9jbGVhbnVwKGZhbHNlKTtcbiAgfVxufTtcblxuQWJzdHJhY3RYSFJPYmplY3QucHJvdG90eXBlLl9jbGVhbnVwID0gZnVuY3Rpb24oYWJvcnQpIHtcbiAgZGVidWcoJ2NsZWFudXAnKTtcbiAgaWYgKCF0aGlzLnhocikge1xuICAgIHJldHVybjtcbiAgfVxuICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xuICB1dGlscy51bmxvYWREZWwodGhpcy51bmxvYWRSZWYpO1xuXG4gIC8vIElFIG5lZWRzIHRoaXMgZmllbGQgdG8gYmUgYSBmdW5jdGlvblxuICB0aGlzLnhoci5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHt9O1xuICBpZiAodGhpcy54aHIub250aW1lb3V0KSB7XG4gICAgdGhpcy54aHIub250aW1lb3V0ID0gbnVsbDtcbiAgfVxuXG4gIGlmIChhYm9ydCkge1xuICAgIHRyeSB7XG4gICAgICB0aGlzLnhoci5hYm9ydCgpO1xuICAgIH0gY2F0Y2ggKHgpIHtcbiAgICAgIC8vIGludGVudGlvbmFsbHkgZW1wdHlcbiAgICB9XG4gIH1cbiAgdGhpcy51bmxvYWRSZWYgPSB0aGlzLnhociA9IG51bGw7XG59O1xuXG5BYnN0cmFjdFhIUk9iamVjdC5wcm90b3R5cGUuY2xvc2UgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ2Nsb3NlJyk7XG4gIHRoaXMuX2NsZWFudXAodHJ1ZSk7XG59O1xuXG5BYnN0cmFjdFhIUk9iamVjdC5lbmFibGVkID0gISFYSFI7XG4vLyBvdmVycmlkZSBYTUxIdHRwUmVxdWVzdCBmb3IgSUU2Lzdcbi8vIG9iZnVzY2F0ZSB0byBhdm9pZCBmaXJld2FsbHNcbnZhciBheG8gPSBbJ0FjdGl2ZSddLmNvbmNhdCgnT2JqZWN0Jykuam9pbignWCcpO1xuaWYgKCFBYnN0cmFjdFhIUk9iamVjdC5lbmFibGVkICYmIChheG8gaW4gZ2xvYmFsKSkge1xuICBkZWJ1Zygnb3ZlcnJpZGluZyB4bWxodHRwcmVxdWVzdCcpO1xuICBYSFIgPSBmdW5jdGlvbigpIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIG5ldyBnbG9iYWxbYXhvXSgnTWljcm9zb2Z0LlhNTEhUVFAnKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH07XG4gIEFic3RyYWN0WEhST2JqZWN0LmVuYWJsZWQgPSAhIW5ldyBYSFIoKTtcbn1cblxudmFyIGNvcnMgPSBmYWxzZTtcbnRyeSB7XG4gIGNvcnMgPSAnd2l0aENyZWRlbnRpYWxzJyBpbiBuZXcgWEhSKCk7XG59IGNhdGNoIChpZ25vcmVkKSB7XG4gIC8vIGludGVudGlvbmFsbHkgZW1wdHlcbn1cblxuQWJzdHJhY3RYSFJPYmplY3Quc3VwcG9ydHNDT1JTID0gY29ycztcblxubW9kdWxlLmV4cG9ydHMgPSBBYnN0cmFjdFhIUk9iamVjdDtcbiIsIm1vZHVsZS5leHBvcnRzID0gZ2xvYmFsLkV2ZW50U291cmNlO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgRHJpdmVyID0gZ2xvYmFsLldlYlNvY2tldCB8fCBnbG9iYWwuTW96V2ViU29ja2V0O1xuaWYgKERyaXZlcikge1xuXHRtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIFdlYlNvY2tldEJyb3dzZXJEcml2ZXIodXJsKSB7XG5cdFx0cmV0dXJuIG5ldyBEcml2ZXIodXJsKTtcblx0fTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEFqYXhCYXNlZFRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vbGliL2FqYXgtYmFzZWQnKVxuICAsIEV2ZW50U291cmNlUmVjZWl2ZXIgPSByZXF1aXJlKCcuL3JlY2VpdmVyL2V2ZW50c291cmNlJylcbiAgLCBYSFJDb3JzT2JqZWN0ID0gcmVxdWlyZSgnLi9zZW5kZXIveGhyLWNvcnMnKVxuICAsIEV2ZW50U291cmNlRHJpdmVyID0gcmVxdWlyZSgnZXZlbnRzb3VyY2UnKVxuICA7XG5cbmZ1bmN0aW9uIEV2ZW50U291cmNlVHJhbnNwb3J0KHRyYW5zVXJsKSB7XG4gIGlmICghRXZlbnRTb3VyY2VUcmFuc3BvcnQuZW5hYmxlZCgpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdUcmFuc3BvcnQgY3JlYXRlZCB3aGVuIGRpc2FibGVkJyk7XG4gIH1cblxuICBBamF4QmFzZWRUcmFuc3BvcnQuY2FsbCh0aGlzLCB0cmFuc1VybCwgJy9ldmVudHNvdXJjZScsIEV2ZW50U291cmNlUmVjZWl2ZXIsIFhIUkNvcnNPYmplY3QpO1xufVxuXG5pbmhlcml0cyhFdmVudFNvdXJjZVRyYW5zcG9ydCwgQWpheEJhc2VkVHJhbnNwb3J0KTtcblxuRXZlbnRTb3VyY2VUcmFuc3BvcnQuZW5hYmxlZCA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gISFFdmVudFNvdXJjZURyaXZlcjtcbn07XG5cbkV2ZW50U291cmNlVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUgPSAnZXZlbnRzb3VyY2UnO1xuRXZlbnRTb3VyY2VUcmFuc3BvcnQucm91bmRUcmlwcyA9IDI7XG5cbm1vZHVsZS5leHBvcnRzID0gRXZlbnRTb3VyY2VUcmFuc3BvcnQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBIdG1sZmlsZVJlY2VpdmVyID0gcmVxdWlyZSgnLi9yZWNlaXZlci9odG1sZmlsZScpXG4gICwgWEhSTG9jYWxPYmplY3QgPSByZXF1aXJlKCcuL3NlbmRlci94aHItbG9jYWwnKVxuICAsIEFqYXhCYXNlZFRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vbGliL2FqYXgtYmFzZWQnKVxuICA7XG5cbmZ1bmN0aW9uIEh0bWxGaWxlVHJhbnNwb3J0KHRyYW5zVXJsKSB7XG4gIGlmICghSHRtbGZpbGVSZWNlaXZlci5lbmFibGVkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdUcmFuc3BvcnQgY3JlYXRlZCB3aGVuIGRpc2FibGVkJyk7XG4gIH1cbiAgQWpheEJhc2VkVHJhbnNwb3J0LmNhbGwodGhpcywgdHJhbnNVcmwsICcvaHRtbGZpbGUnLCBIdG1sZmlsZVJlY2VpdmVyLCBYSFJMb2NhbE9iamVjdCk7XG59XG5cbmluaGVyaXRzKEh0bWxGaWxlVHJhbnNwb3J0LCBBamF4QmFzZWRUcmFuc3BvcnQpO1xuXG5IdG1sRmlsZVRyYW5zcG9ydC5lbmFibGVkID0gZnVuY3Rpb24oaW5mbykge1xuICByZXR1cm4gSHRtbGZpbGVSZWNlaXZlci5lbmFibGVkICYmIGluZm8uc2FtZU9yaWdpbjtcbn07XG5cbkh0bWxGaWxlVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUgPSAnaHRtbGZpbGUnO1xuSHRtbEZpbGVUcmFuc3BvcnQucm91bmRUcmlwcyA9IDI7XG5cbm1vZHVsZS5leHBvcnRzID0gSHRtbEZpbGVUcmFuc3BvcnQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vIEZldyBjb29sIHRyYW5zcG9ydHMgZG8gd29yayBvbmx5IGZvciBzYW1lLW9yaWdpbi4gSW4gb3JkZXIgdG8gbWFrZVxuLy8gdGhlbSB3b3JrIGNyb3NzLWRvbWFpbiB3ZSBzaGFsbCB1c2UgaWZyYW1lLCBzZXJ2ZWQgZnJvbSB0aGVcbi8vIHJlbW90ZSBkb21haW4uIE5ldyBicm93c2VycyBoYXZlIGNhcGFiaWxpdGllcyB0byBjb21tdW5pY2F0ZSB3aXRoXG4vLyBjcm9zcyBkb21haW4gaWZyYW1lIHVzaW5nIHBvc3RNZXNzYWdlKCkuIEluIElFIGl0IHdhcyBpbXBsZW1lbnRlZFxuLy8gZnJvbSBJRSA4KywgYnV0IG9mIGNvdXJzZSwgSUUgZ290IHNvbWUgZGV0YWlscyB3cm9uZzpcbi8vICAgIGh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20vZW4tdXMvbGlicmFyeS9jYzE5NzAxNSh2PVZTLjg1KS5hc3B4XG4vLyAgICBodHRwOi8vc3RldmVzb3VkZXJzLmNvbS9taXNjL3Rlc3QtcG9zdG1lc3NhZ2UucGhwXG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBKU09OMyA9IHJlcXVpcmUoJ2pzb24zJylcbiAgLCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXJcbiAgLCB2ZXJzaW9uID0gcmVxdWlyZSgnLi4vdmVyc2lvbicpXG4gICwgdXJsVXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91cmwnKVxuICAsIGlmcmFtZVV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvaWZyYW1lJylcbiAgLCBldmVudFV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvZXZlbnQnKVxuICAsIHJhbmRvbSA9IHJlcXVpcmUoJy4uL3V0aWxzL3JhbmRvbScpXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDp0cmFuc3BvcnQ6aWZyYW1lJyk7XG59XG5cbmZ1bmN0aW9uIElmcmFtZVRyYW5zcG9ydCh0cmFuc3BvcnQsIHRyYW5zVXJsLCBiYXNlVXJsKSB7XG4gIGlmICghSWZyYW1lVHJhbnNwb3J0LmVuYWJsZWQoKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignVHJhbnNwb3J0IGNyZWF0ZWQgd2hlbiBkaXNhYmxlZCcpO1xuICB9XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuXG4gIHZhciBzZWxmID0gdGhpcztcbiAgdGhpcy5vcmlnaW4gPSB1cmxVdGlscy5nZXRPcmlnaW4oYmFzZVVybCk7XG4gIHRoaXMuYmFzZVVybCA9IGJhc2VVcmw7XG4gIHRoaXMudHJhbnNVcmwgPSB0cmFuc1VybDtcbiAgdGhpcy50cmFuc3BvcnQgPSB0cmFuc3BvcnQ7XG4gIHRoaXMud2luZG93SWQgPSByYW5kb20uc3RyaW5nKDgpO1xuXG4gIHZhciBpZnJhbWVVcmwgPSB1cmxVdGlscy5hZGRQYXRoKGJhc2VVcmwsICcvaWZyYW1lLmh0bWwnKSArICcjJyArIHRoaXMud2luZG93SWQ7XG4gIGRlYnVnKHRyYW5zcG9ydCwgdHJhbnNVcmwsIGlmcmFtZVVybCk7XG5cbiAgdGhpcy5pZnJhbWVPYmogPSBpZnJhbWVVdGlscy5jcmVhdGVJZnJhbWUoaWZyYW1lVXJsLCBmdW5jdGlvbihyKSB7XG4gICAgZGVidWcoJ2VyciBjYWxsYmFjaycpO1xuICAgIHNlbGYuZW1pdCgnY2xvc2UnLCAxMDA2LCAnVW5hYmxlIHRvIGxvYWQgYW4gaWZyYW1lICgnICsgciArICcpJyk7XG4gICAgc2VsZi5jbG9zZSgpO1xuICB9KTtcblxuICB0aGlzLm9ubWVzc2FnZUNhbGxiYWNrID0gdGhpcy5fbWVzc2FnZS5iaW5kKHRoaXMpO1xuICBldmVudFV0aWxzLmF0dGFjaEV2ZW50KCdtZXNzYWdlJywgdGhpcy5vbm1lc3NhZ2VDYWxsYmFjayk7XG59XG5cbmluaGVyaXRzKElmcmFtZVRyYW5zcG9ydCwgRXZlbnRFbWl0dGVyKTtcblxuSWZyYW1lVHJhbnNwb3J0LnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnY2xvc2UnKTtcbiAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgaWYgKHRoaXMuaWZyYW1lT2JqKSB7XG4gICAgZXZlbnRVdGlscy5kZXRhY2hFdmVudCgnbWVzc2FnZScsIHRoaXMub25tZXNzYWdlQ2FsbGJhY2spO1xuICAgIHRyeSB7XG4gICAgICAvLyBXaGVuIHRoZSBpZnJhbWUgaXMgbm90IGxvYWRlZCwgSUUgcmFpc2VzIGFuIGV4Y2VwdGlvblxuICAgICAgLy8gb24gJ2NvbnRlbnRXaW5kb3cnLlxuICAgICAgdGhpcy5wb3N0TWVzc2FnZSgnYycpO1xuICAgIH0gY2F0Y2ggKHgpIHtcbiAgICAgIC8vIGludGVudGlvbmFsbHkgZW1wdHlcbiAgICB9XG4gICAgdGhpcy5pZnJhbWVPYmouY2xlYW51cCgpO1xuICAgIHRoaXMuaWZyYW1lT2JqID0gbnVsbDtcbiAgICB0aGlzLm9ubWVzc2FnZUNhbGxiYWNrID0gdGhpcy5pZnJhbWVPYmogPSBudWxsO1xuICB9XG59O1xuXG5JZnJhbWVUcmFuc3BvcnQucHJvdG90eXBlLl9tZXNzYWdlID0gZnVuY3Rpb24oZSkge1xuICBkZWJ1ZygnbWVzc2FnZScsIGUuZGF0YSk7XG4gIGlmICghdXJsVXRpbHMuaXNPcmlnaW5FcXVhbChlLm9yaWdpbiwgdGhpcy5vcmlnaW4pKSB7XG4gICAgZGVidWcoJ25vdCBzYW1lIG9yaWdpbicsIGUub3JpZ2luLCB0aGlzLm9yaWdpbik7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgdmFyIGlmcmFtZU1lc3NhZ2U7XG4gIHRyeSB7XG4gICAgaWZyYW1lTWVzc2FnZSA9IEpTT04zLnBhcnNlKGUuZGF0YSk7XG4gIH0gY2F0Y2ggKGlnbm9yZWQpIHtcbiAgICBkZWJ1ZygnYmFkIGpzb24nLCBlLmRhdGEpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmIChpZnJhbWVNZXNzYWdlLndpbmRvd0lkICE9PSB0aGlzLndpbmRvd0lkKSB7XG4gICAgZGVidWcoJ21pc21hdGNoZWQgd2luZG93IGlkJywgaWZyYW1lTWVzc2FnZS53aW5kb3dJZCwgdGhpcy53aW5kb3dJZCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgc3dpdGNoIChpZnJhbWVNZXNzYWdlLnR5cGUpIHtcbiAgY2FzZSAncyc6XG4gICAgdGhpcy5pZnJhbWVPYmoubG9hZGVkKCk7XG4gICAgLy8gd2luZG93IGdsb2JhbCBkZXBlbmRlbmN5XG4gICAgdGhpcy5wb3N0TWVzc2FnZSgncycsIEpTT04zLnN0cmluZ2lmeShbXG4gICAgICB2ZXJzaW9uXG4gICAgLCB0aGlzLnRyYW5zcG9ydFxuICAgICwgdGhpcy50cmFuc1VybFxuICAgICwgdGhpcy5iYXNlVXJsXG4gICAgXSkpO1xuICAgIGJyZWFrO1xuICBjYXNlICd0JzpcbiAgICB0aGlzLmVtaXQoJ21lc3NhZ2UnLCBpZnJhbWVNZXNzYWdlLmRhdGEpO1xuICAgIGJyZWFrO1xuICBjYXNlICdjJzpcbiAgICB2YXIgY2RhdGE7XG4gICAgdHJ5IHtcbiAgICAgIGNkYXRhID0gSlNPTjMucGFyc2UoaWZyYW1lTWVzc2FnZS5kYXRhKTtcbiAgICB9IGNhdGNoIChpZ25vcmVkKSB7XG4gICAgICBkZWJ1ZygnYmFkIGpzb24nLCBpZnJhbWVNZXNzYWdlLmRhdGEpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmVtaXQoJ2Nsb3NlJywgY2RhdGFbMF0sIGNkYXRhWzFdKTtcbiAgICB0aGlzLmNsb3NlKCk7XG4gICAgYnJlYWs7XG4gIH1cbn07XG5cbklmcmFtZVRyYW5zcG9ydC5wcm90b3R5cGUucG9zdE1lc3NhZ2UgPSBmdW5jdGlvbih0eXBlLCBkYXRhKSB7XG4gIGRlYnVnKCdwb3N0TWVzc2FnZScsIHR5cGUsIGRhdGEpO1xuICB0aGlzLmlmcmFtZU9iai5wb3N0KEpTT04zLnN0cmluZ2lmeSh7XG4gICAgd2luZG93SWQ6IHRoaXMud2luZG93SWRcbiAgLCB0eXBlOiB0eXBlXG4gICwgZGF0YTogZGF0YSB8fCAnJ1xuICB9KSwgdGhpcy5vcmlnaW4pO1xufTtcblxuSWZyYW1lVHJhbnNwb3J0LnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24obWVzc2FnZSkge1xuICBkZWJ1Zygnc2VuZCcsIG1lc3NhZ2UpO1xuICB0aGlzLnBvc3RNZXNzYWdlKCdtJywgbWVzc2FnZSk7XG59O1xuXG5JZnJhbWVUcmFuc3BvcnQuZW5hYmxlZCA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gaWZyYW1lVXRpbHMuaWZyYW1lRW5hYmxlZDtcbn07XG5cbklmcmFtZVRyYW5zcG9ydC50cmFuc3BvcnROYW1lID0gJ2lmcmFtZSc7XG5JZnJhbWVUcmFuc3BvcnQucm91bmRUcmlwcyA9IDI7XG5cbm1vZHVsZS5leHBvcnRzID0gSWZyYW1lVHJhbnNwb3J0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyBUaGUgc2ltcGxlc3QgYW5kIG1vc3Qgcm9idXN0IHRyYW5zcG9ydCwgdXNpbmcgdGhlIHdlbGwta25vdyBjcm9zc1xuLy8gZG9tYWluIGhhY2sgLSBKU09OUC4gVGhpcyB0cmFuc3BvcnQgaXMgcXVpdGUgaW5lZmZpY2llbnQgLSBvbmVcbi8vIG1lc3NhZ2UgY291bGQgdXNlIHVwIHRvIG9uZSBodHRwIHJlcXVlc3QuIEJ1dCBhdCBsZWFzdCBpdCB3b3JrcyBhbG1vc3Rcbi8vIGV2ZXJ5d2hlcmUuXG4vLyBLbm93biBsaW1pdGF0aW9uczpcbi8vICAgbyB5b3Ugd2lsbCBnZXQgYSBzcGlubmluZyBjdXJzb3Jcbi8vICAgbyBmb3IgS29ucXVlcm9yIGEgZHVtYiB0aW1lciBpcyBuZWVkZWQgdG8gZGV0ZWN0IGVycm9yc1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgU2VuZGVyUmVjZWl2ZXIgPSByZXF1aXJlKCcuL2xpYi9zZW5kZXItcmVjZWl2ZXInKVxuICAsIEpzb25wUmVjZWl2ZXIgPSByZXF1aXJlKCcuL3JlY2VpdmVyL2pzb25wJylcbiAgLCBqc29ucFNlbmRlciA9IHJlcXVpcmUoJy4vc2VuZGVyL2pzb25wJylcbiAgO1xuXG5mdW5jdGlvbiBKc29uUFRyYW5zcG9ydCh0cmFuc1VybCkge1xuICBpZiAoIUpzb25QVHJhbnNwb3J0LmVuYWJsZWQoKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignVHJhbnNwb3J0IGNyZWF0ZWQgd2hlbiBkaXNhYmxlZCcpO1xuICB9XG4gIFNlbmRlclJlY2VpdmVyLmNhbGwodGhpcywgdHJhbnNVcmwsICcvanNvbnAnLCBqc29ucFNlbmRlciwgSnNvbnBSZWNlaXZlcik7XG59XG5cbmluaGVyaXRzKEpzb25QVHJhbnNwb3J0LCBTZW5kZXJSZWNlaXZlcik7XG5cbkpzb25QVHJhbnNwb3J0LmVuYWJsZWQgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuICEhZ2xvYmFsLmRvY3VtZW50O1xufTtcblxuSnNvblBUcmFuc3BvcnQudHJhbnNwb3J0TmFtZSA9ICdqc29ucC1wb2xsaW5nJztcbkpzb25QVHJhbnNwb3J0LnJvdW5kVHJpcHMgPSAxO1xuSnNvblBUcmFuc3BvcnQubmVlZEJvZHkgPSB0cnVlO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEpzb25QVHJhbnNwb3J0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgdXJsVXRpbHMgPSByZXF1aXJlKCcuLi8uLi91dGlscy91cmwnKVxuICAsIFNlbmRlclJlY2VpdmVyID0gcmVxdWlyZSgnLi9zZW5kZXItcmVjZWl2ZXInKVxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6YWpheC1iYXNlZCcpO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVBamF4U2VuZGVyKEFqYXhPYmplY3QpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uKHVybCwgcGF5bG9hZCwgY2FsbGJhY2spIHtcbiAgICBkZWJ1ZygnY3JlYXRlIGFqYXggc2VuZGVyJywgdXJsLCBwYXlsb2FkKTtcbiAgICB2YXIgb3B0ID0ge307XG4gICAgaWYgKHR5cGVvZiBwYXlsb2FkID09PSAnc3RyaW5nJykge1xuICAgICAgb3B0LmhlYWRlcnMgPSB7J0NvbnRlbnQtdHlwZSc6ICd0ZXh0L3BsYWluJ307XG4gICAgfVxuICAgIHZhciBhamF4VXJsID0gdXJsVXRpbHMuYWRkUGF0aCh1cmwsICcveGhyX3NlbmQnKTtcbiAgICB2YXIgeG8gPSBuZXcgQWpheE9iamVjdCgnUE9TVCcsIGFqYXhVcmwsIHBheWxvYWQsIG9wdCk7XG4gICAgeG8ub25jZSgnZmluaXNoJywgZnVuY3Rpb24oc3RhdHVzKSB7XG4gICAgICBkZWJ1ZygnZmluaXNoJywgc3RhdHVzKTtcbiAgICAgIHhvID0gbnVsbDtcblxuICAgICAgaWYgKHN0YXR1cyAhPT0gMjAwICYmIHN0YXR1cyAhPT0gMjA0KSB7XG4gICAgICAgIHJldHVybiBjYWxsYmFjayhuZXcgRXJyb3IoJ2h0dHAgc3RhdHVzICcgKyBzdGF0dXMpKTtcbiAgICAgIH1cbiAgICAgIGNhbGxiYWNrKCk7XG4gICAgfSk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgZGVidWcoJ2Fib3J0Jyk7XG4gICAgICB4by5jbG9zZSgpO1xuICAgICAgeG8gPSBudWxsO1xuXG4gICAgICB2YXIgZXJyID0gbmV3IEVycm9yKCdBYm9ydGVkJyk7XG4gICAgICBlcnIuY29kZSA9IDEwMDA7XG4gICAgICBjYWxsYmFjayhlcnIpO1xuICAgIH07XG4gIH07XG59XG5cbmZ1bmN0aW9uIEFqYXhCYXNlZFRyYW5zcG9ydCh0cmFuc1VybCwgdXJsU3VmZml4LCBSZWNlaXZlciwgQWpheE9iamVjdCkge1xuICBTZW5kZXJSZWNlaXZlci5jYWxsKHRoaXMsIHRyYW5zVXJsLCB1cmxTdWZmaXgsIGNyZWF0ZUFqYXhTZW5kZXIoQWpheE9iamVjdCksIFJlY2VpdmVyLCBBamF4T2JqZWN0KTtcbn1cblxuaW5oZXJpdHMoQWpheEJhc2VkVHJhbnNwb3J0LCBTZW5kZXJSZWNlaXZlcik7XG5cbm1vZHVsZS5leHBvcnRzID0gQWpheEJhc2VkVHJhbnNwb3J0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDpidWZmZXJlZC1zZW5kZXInKTtcbn1cblxuZnVuY3Rpb24gQnVmZmVyZWRTZW5kZXIodXJsLCBzZW5kZXIpIHtcbiAgZGVidWcodXJsKTtcbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG4gIHRoaXMuc2VuZEJ1ZmZlciA9IFtdO1xuICB0aGlzLnNlbmRlciA9IHNlbmRlcjtcbiAgdGhpcy51cmwgPSB1cmw7XG59XG5cbmluaGVyaXRzKEJ1ZmZlcmVkU2VuZGVyLCBFdmVudEVtaXR0ZXIpO1xuXG5CdWZmZXJlZFNlbmRlci5wcm90b3R5cGUuc2VuZCA9IGZ1bmN0aW9uKG1lc3NhZ2UpIHtcbiAgZGVidWcoJ3NlbmQnLCBtZXNzYWdlKTtcbiAgdGhpcy5zZW5kQnVmZmVyLnB1c2gobWVzc2FnZSk7XG4gIGlmICghdGhpcy5zZW5kU3RvcCkge1xuICAgIHRoaXMuc2VuZFNjaGVkdWxlKCk7XG4gIH1cbn07XG5cbi8vIEZvciBwb2xsaW5nIHRyYW5zcG9ydHMgaW4gYSBzaXR1YXRpb24gd2hlbiBpbiB0aGUgbWVzc2FnZSBjYWxsYmFjayxcbi8vIG5ldyBtZXNzYWdlIGlzIGJlaW5nIHNlbmQuIElmIHRoZSBzZW5kaW5nIGNvbm5lY3Rpb24gd2FzIHN0YXJ0ZWRcbi8vIGJlZm9yZSByZWNlaXZpbmcgb25lLCBpdCBpcyBwb3NzaWJsZSB0byBzYXR1cmF0ZSB0aGUgbmV0d29yayBhbmRcbi8vIHRpbWVvdXQgZHVlIHRvIHRoZSBsYWNrIG9mIHJlY2VpdmluZyBzb2NrZXQuIFRvIGF2b2lkIHRoYXQgd2UgZGVsYXlcbi8vIHNlbmRpbmcgbWVzc2FnZXMgYnkgc29tZSBzbWFsbCB0aW1lLCBpbiBvcmRlciB0byBsZXQgcmVjZWl2aW5nXG4vLyBjb25uZWN0aW9uIGJlIHN0YXJ0ZWQgYmVmb3JlaGFuZC4gVGhpcyBpcyBvbmx5IGEgaGFsZm1lYXN1cmUgYW5kXG4vLyBkb2VzIG5vdCBmaXggdGhlIGJpZyBwcm9ibGVtLCBidXQgaXQgZG9lcyBtYWtlIHRoZSB0ZXN0cyBnbyBtb3JlXG4vLyBzdGFibGUgb24gc2xvdyBuZXR3b3Jrcy5cbkJ1ZmZlcmVkU2VuZGVyLnByb3RvdHlwZS5zZW5kU2NoZWR1bGVXYWl0ID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdzZW5kU2NoZWR1bGVXYWl0Jyk7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgdmFyIHRyZWY7XG4gIHRoaXMuc2VuZFN0b3AgPSBmdW5jdGlvbigpIHtcbiAgICBkZWJ1Zygnc2VuZFN0b3AnKTtcbiAgICBzZWxmLnNlbmRTdG9wID0gbnVsbDtcbiAgICBjbGVhclRpbWVvdXQodHJlZik7XG4gIH07XG4gIHRyZWYgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCd0aW1lb3V0Jyk7XG4gICAgc2VsZi5zZW5kU3RvcCA9IG51bGw7XG4gICAgc2VsZi5zZW5kU2NoZWR1bGUoKTtcbiAgfSwgMjUpO1xufTtcblxuQnVmZmVyZWRTZW5kZXIucHJvdG90eXBlLnNlbmRTY2hlZHVsZSA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1Zygnc2VuZFNjaGVkdWxlJywgdGhpcy5zZW5kQnVmZmVyLmxlbmd0aCk7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgaWYgKHRoaXMuc2VuZEJ1ZmZlci5sZW5ndGggPiAwKSB7XG4gICAgdmFyIHBheWxvYWQgPSAnWycgKyB0aGlzLnNlbmRCdWZmZXIuam9pbignLCcpICsgJ10nO1xuICAgIHRoaXMuc2VuZFN0b3AgPSB0aGlzLnNlbmRlcih0aGlzLnVybCwgcGF5bG9hZCwgZnVuY3Rpb24oZXJyKSB7XG4gICAgICBzZWxmLnNlbmRTdG9wID0gbnVsbDtcbiAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgZGVidWcoJ2Vycm9yJywgZXJyKTtcbiAgICAgICAgc2VsZi5lbWl0KCdjbG9zZScsIGVyci5jb2RlIHx8IDEwMDYsICdTZW5kaW5nIGVycm9yOiAnICsgZXJyKTtcbiAgICAgICAgc2VsZi5fY2xlYW51cCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2VsZi5zZW5kU2NoZWR1bGVXYWl0KCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgdGhpcy5zZW5kQnVmZmVyID0gW107XG4gIH1cbn07XG5cbkJ1ZmZlcmVkU2VuZGVyLnByb3RvdHlwZS5fY2xlYW51cCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnX2NsZWFudXAnKTtcbiAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbn07XG5cbkJ1ZmZlcmVkU2VuZGVyLnByb3RvdHlwZS5zdG9wID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdzdG9wJyk7XG4gIHRoaXMuX2NsZWFudXAoKTtcbiAgaWYgKHRoaXMuc2VuZFN0b3ApIHtcbiAgICB0aGlzLnNlbmRTdG9wKCk7XG4gICAgdGhpcy5zZW5kU3RvcCA9IG51bGw7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQnVmZmVyZWRTZW5kZXI7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBJZnJhbWVUcmFuc3BvcnQgPSByZXF1aXJlKCcuLi9pZnJhbWUnKVxuICAsIG9iamVjdFV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvb2JqZWN0JylcbiAgO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKHRyYW5zcG9ydCkge1xuXG4gIGZ1bmN0aW9uIElmcmFtZVdyYXBUcmFuc3BvcnQodHJhbnNVcmwsIGJhc2VVcmwpIHtcbiAgICBJZnJhbWVUcmFuc3BvcnQuY2FsbCh0aGlzLCB0cmFuc3BvcnQudHJhbnNwb3J0TmFtZSwgdHJhbnNVcmwsIGJhc2VVcmwpO1xuICB9XG5cbiAgaW5oZXJpdHMoSWZyYW1lV3JhcFRyYW5zcG9ydCwgSWZyYW1lVHJhbnNwb3J0KTtcblxuICBJZnJhbWVXcmFwVHJhbnNwb3J0LmVuYWJsZWQgPSBmdW5jdGlvbih1cmwsIGluZm8pIHtcbiAgICBpZiAoIWdsb2JhbC5kb2N1bWVudCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHZhciBpZnJhbWVJbmZvID0gb2JqZWN0VXRpbHMuZXh0ZW5kKHt9LCBpbmZvKTtcbiAgICBpZnJhbWVJbmZvLnNhbWVPcmlnaW4gPSB0cnVlO1xuICAgIHJldHVybiB0cmFuc3BvcnQuZW5hYmxlZChpZnJhbWVJbmZvKSAmJiBJZnJhbWVUcmFuc3BvcnQuZW5hYmxlZCgpO1xuICB9O1xuXG4gIElmcmFtZVdyYXBUcmFuc3BvcnQudHJhbnNwb3J0TmFtZSA9ICdpZnJhbWUtJyArIHRyYW5zcG9ydC50cmFuc3BvcnROYW1lO1xuICBJZnJhbWVXcmFwVHJhbnNwb3J0Lm5lZWRCb2R5ID0gdHJ1ZTtcbiAgSWZyYW1lV3JhcFRyYW5zcG9ydC5yb3VuZFRyaXBzID0gSWZyYW1lVHJhbnNwb3J0LnJvdW5kVHJpcHMgKyB0cmFuc3BvcnQucm91bmRUcmlwcyAtIDE7IC8vIGh0bWwsIGphdmFzY3JpcHQgKDIpICsgdHJhbnNwb3J0IC0gbm8gQ09SUyAoMSlcblxuICBJZnJhbWVXcmFwVHJhbnNwb3J0LmZhY2FkZVRyYW5zcG9ydCA9IHRyYW5zcG9ydDtcblxuICByZXR1cm4gSWZyYW1lV3JhcFRyYW5zcG9ydDtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXJcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OnBvbGxpbmcnKTtcbn1cblxuZnVuY3Rpb24gUG9sbGluZyhSZWNlaXZlciwgcmVjZWl2ZVVybCwgQWpheE9iamVjdCkge1xuICBkZWJ1ZyhyZWNlaXZlVXJsKTtcbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG4gIHRoaXMuUmVjZWl2ZXIgPSBSZWNlaXZlcjtcbiAgdGhpcy5yZWNlaXZlVXJsID0gcmVjZWl2ZVVybDtcbiAgdGhpcy5BamF4T2JqZWN0ID0gQWpheE9iamVjdDtcbiAgdGhpcy5fc2NoZWR1bGVSZWNlaXZlcigpO1xufVxuXG5pbmhlcml0cyhQb2xsaW5nLCBFdmVudEVtaXR0ZXIpO1xuXG5Qb2xsaW5nLnByb3RvdHlwZS5fc2NoZWR1bGVSZWNlaXZlciA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnX3NjaGVkdWxlUmVjZWl2ZXInKTtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICB2YXIgcG9sbCA9IHRoaXMucG9sbCA9IG5ldyB0aGlzLlJlY2VpdmVyKHRoaXMucmVjZWl2ZVVybCwgdGhpcy5BamF4T2JqZWN0KTtcblxuICBwb2xsLm9uKCdtZXNzYWdlJywgZnVuY3Rpb24obXNnKSB7XG4gICAgZGVidWcoJ21lc3NhZ2UnLCBtc2cpO1xuICAgIHNlbGYuZW1pdCgnbWVzc2FnZScsIG1zZyk7XG4gIH0pO1xuXG4gIHBvbGwub25jZSgnY2xvc2UnLCBmdW5jdGlvbihjb2RlLCByZWFzb24pIHtcbiAgICBkZWJ1ZygnY2xvc2UnLCBjb2RlLCByZWFzb24sIHNlbGYucG9sbElzQ2xvc2luZyk7XG4gICAgc2VsZi5wb2xsID0gcG9sbCA9IG51bGw7XG5cbiAgICBpZiAoIXNlbGYucG9sbElzQ2xvc2luZykge1xuICAgICAgaWYgKHJlYXNvbiA9PT0gJ25ldHdvcmsnKSB7XG4gICAgICAgIHNlbGYuX3NjaGVkdWxlUmVjZWl2ZXIoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNlbGYuZW1pdCgnY2xvc2UnLCBjb2RlIHx8IDEwMDYsIHJlYXNvbik7XG4gICAgICAgIHNlbGYucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcbn07XG5cblBvbGxpbmcucHJvdG90eXBlLmFib3J0ID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdhYm9ydCcpO1xuICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xuICB0aGlzLnBvbGxJc0Nsb3NpbmcgPSB0cnVlO1xuICBpZiAodGhpcy5wb2xsKSB7XG4gICAgdGhpcy5wb2xsLmFib3J0KCk7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUG9sbGluZztcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIHVybFV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvdXJsJylcbiAgLCBCdWZmZXJlZFNlbmRlciA9IHJlcXVpcmUoJy4vYnVmZmVyZWQtc2VuZGVyJylcbiAgLCBQb2xsaW5nID0gcmVxdWlyZSgnLi9wb2xsaW5nJylcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OnNlbmRlci1yZWNlaXZlcicpO1xufVxuXG5mdW5jdGlvbiBTZW5kZXJSZWNlaXZlcih0cmFuc1VybCwgdXJsU3VmZml4LCBzZW5kZXJGdW5jLCBSZWNlaXZlciwgQWpheE9iamVjdCkge1xuICB2YXIgcG9sbFVybCA9IHVybFV0aWxzLmFkZFBhdGgodHJhbnNVcmwsIHVybFN1ZmZpeCk7XG4gIGRlYnVnKHBvbGxVcmwpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIEJ1ZmZlcmVkU2VuZGVyLmNhbGwodGhpcywgdHJhbnNVcmwsIHNlbmRlckZ1bmMpO1xuXG4gIHRoaXMucG9sbCA9IG5ldyBQb2xsaW5nKFJlY2VpdmVyLCBwb2xsVXJsLCBBamF4T2JqZWN0KTtcbiAgdGhpcy5wb2xsLm9uKCdtZXNzYWdlJywgZnVuY3Rpb24obXNnKSB7XG4gICAgZGVidWcoJ3BvbGwgbWVzc2FnZScsIG1zZyk7XG4gICAgc2VsZi5lbWl0KCdtZXNzYWdlJywgbXNnKTtcbiAgfSk7XG4gIHRoaXMucG9sbC5vbmNlKCdjbG9zZScsIGZ1bmN0aW9uKGNvZGUsIHJlYXNvbikge1xuICAgIGRlYnVnKCdwb2xsIGNsb3NlJywgY29kZSwgcmVhc29uKTtcbiAgICBzZWxmLnBvbGwgPSBudWxsO1xuICAgIHNlbGYuZW1pdCgnY2xvc2UnLCBjb2RlLCByZWFzb24pO1xuICAgIHNlbGYuY2xvc2UoKTtcbiAgfSk7XG59XG5cbmluaGVyaXRzKFNlbmRlclJlY2VpdmVyLCBCdWZmZXJlZFNlbmRlcik7XG5cblNlbmRlclJlY2VpdmVyLnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnY2xvc2UnKTtcbiAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgaWYgKHRoaXMucG9sbCkge1xuICAgIHRoaXMucG9sbC5hYm9ydCgpO1xuICAgIHRoaXMucG9sbCA9IG51bGw7XG4gIH1cbiAgdGhpcy5zdG9wKCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNlbmRlclJlY2VpdmVyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gICwgRXZlbnRTb3VyY2VEcml2ZXIgPSByZXF1aXJlKCdldmVudHNvdXJjZScpXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDpyZWNlaXZlcjpldmVudHNvdXJjZScpO1xufVxuXG5mdW5jdGlvbiBFdmVudFNvdXJjZVJlY2VpdmVyKHVybCkge1xuICBkZWJ1Zyh1cmwpO1xuICBFdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcblxuICB2YXIgc2VsZiA9IHRoaXM7XG4gIHZhciBlcyA9IHRoaXMuZXMgPSBuZXcgRXZlbnRTb3VyY2VEcml2ZXIodXJsKTtcbiAgZXMub25tZXNzYWdlID0gZnVuY3Rpb24oZSkge1xuICAgIGRlYnVnKCdtZXNzYWdlJywgZS5kYXRhKTtcbiAgICBzZWxmLmVtaXQoJ21lc3NhZ2UnLCBkZWNvZGVVUkkoZS5kYXRhKSk7XG4gIH07XG4gIGVzLm9uZXJyb3IgPSBmdW5jdGlvbihlKSB7XG4gICAgZGVidWcoJ2Vycm9yJywgZXMucmVhZHlTdGF0ZSwgZSk7XG4gICAgLy8gRVMgb24gcmVjb25uZWN0aW9uIGhhcyByZWFkeVN0YXRlID0gMCBvciAxLlxuICAgIC8vIG9uIG5ldHdvcmsgZXJyb3IgaXQncyBDTE9TRUQgPSAyXG4gICAgdmFyIHJlYXNvbiA9IChlcy5yZWFkeVN0YXRlICE9PSAyID8gJ25ldHdvcmsnIDogJ3Blcm1hbmVudCcpO1xuICAgIHNlbGYuX2NsZWFudXAoKTtcbiAgICBzZWxmLl9jbG9zZShyZWFzb24pO1xuICB9O1xufVxuXG5pbmhlcml0cyhFdmVudFNvdXJjZVJlY2VpdmVyLCBFdmVudEVtaXR0ZXIpO1xuXG5FdmVudFNvdXJjZVJlY2VpdmVyLnByb3RvdHlwZS5hYm9ydCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnYWJvcnQnKTtcbiAgdGhpcy5fY2xlYW51cCgpO1xuICB0aGlzLl9jbG9zZSgndXNlcicpO1xufTtcblxuRXZlbnRTb3VyY2VSZWNlaXZlci5wcm90b3R5cGUuX2NsZWFudXAgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ2NsZWFudXAnKTtcbiAgdmFyIGVzID0gdGhpcy5lcztcbiAgaWYgKGVzKSB7XG4gICAgZXMub25tZXNzYWdlID0gZXMub25lcnJvciA9IG51bGw7XG4gICAgZXMuY2xvc2UoKTtcbiAgICB0aGlzLmVzID0gbnVsbDtcbiAgfVxufTtcblxuRXZlbnRTb3VyY2VSZWNlaXZlci5wcm90b3R5cGUuX2Nsb3NlID0gZnVuY3Rpb24ocmVhc29uKSB7XG4gIGRlYnVnKCdjbG9zZScsIHJlYXNvbik7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgLy8gU2FmYXJpIGFuZCBjaHJvbWUgPCAxNSBjcmFzaCBpZiB3ZSBjbG9zZSB3aW5kb3cgYmVmb3JlXG4gIC8vIHdhaXRpbmcgZm9yIEVTIGNsZWFudXAuIFNlZTpcbiAgLy8gaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTg5MTU1XG4gIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgc2VsZi5lbWl0KCdjbG9zZScsIG51bGwsIHJlYXNvbik7XG4gICAgc2VsZi5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbiAgfSwgMjAwKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRXZlbnRTb3VyY2VSZWNlaXZlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIGlmcmFtZVV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvaWZyYW1lJylcbiAgLCB1cmxVdGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL3VybCcpXG4gICwgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gICwgcmFuZG9tID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvcmFuZG9tJylcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OnJlY2VpdmVyOmh0bWxmaWxlJyk7XG59XG5cbmZ1bmN0aW9uIEh0bWxmaWxlUmVjZWl2ZXIodXJsKSB7XG4gIGRlYnVnKHVybCk7XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIGlmcmFtZVV0aWxzLnBvbGx1dGVHbG9iYWxOYW1lc3BhY2UoKTtcblxuICB0aGlzLmlkID0gJ2EnICsgcmFuZG9tLnN0cmluZyg2KTtcbiAgdXJsID0gdXJsVXRpbHMuYWRkUXVlcnkodXJsLCAnYz0nICsgZGVjb2RlVVJJQ29tcG9uZW50KGlmcmFtZVV0aWxzLldQcmVmaXggKyAnLicgKyB0aGlzLmlkKSk7XG5cbiAgZGVidWcoJ3VzaW5nIGh0bWxmaWxlJywgSHRtbGZpbGVSZWNlaXZlci5odG1sZmlsZUVuYWJsZWQpO1xuICB2YXIgY29uc3RydWN0RnVuYyA9IEh0bWxmaWxlUmVjZWl2ZXIuaHRtbGZpbGVFbmFibGVkID9cbiAgICAgIGlmcmFtZVV0aWxzLmNyZWF0ZUh0bWxmaWxlIDogaWZyYW1lVXRpbHMuY3JlYXRlSWZyYW1lO1xuXG4gIGdsb2JhbFtpZnJhbWVVdGlscy5XUHJlZml4XVt0aGlzLmlkXSA9IHtcbiAgICBzdGFydDogZnVuY3Rpb24oKSB7XG4gICAgICBkZWJ1Zygnc3RhcnQnKTtcbiAgICAgIHNlbGYuaWZyYW1lT2JqLmxvYWRlZCgpO1xuICAgIH1cbiAgLCBtZXNzYWdlOiBmdW5jdGlvbihkYXRhKSB7XG4gICAgICBkZWJ1ZygnbWVzc2FnZScsIGRhdGEpO1xuICAgICAgc2VsZi5lbWl0KCdtZXNzYWdlJywgZGF0YSk7XG4gICAgfVxuICAsIHN0b3A6IGZ1bmN0aW9uKCkge1xuICAgICAgZGVidWcoJ3N0b3AnKTtcbiAgICAgIHNlbGYuX2NsZWFudXAoKTtcbiAgICAgIHNlbGYuX2Nsb3NlKCduZXR3b3JrJyk7XG4gICAgfVxuICB9O1xuICB0aGlzLmlmcmFtZU9iaiA9IGNvbnN0cnVjdEZ1bmModXJsLCBmdW5jdGlvbigpIHtcbiAgICBkZWJ1ZygnY2FsbGJhY2snKTtcbiAgICBzZWxmLl9jbGVhbnVwKCk7XG4gICAgc2VsZi5fY2xvc2UoJ3Blcm1hbmVudCcpO1xuICB9KTtcbn1cblxuaW5oZXJpdHMoSHRtbGZpbGVSZWNlaXZlciwgRXZlbnRFbWl0dGVyKTtcblxuSHRtbGZpbGVSZWNlaXZlci5wcm90b3R5cGUuYWJvcnQgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ2Fib3J0Jyk7XG4gIHRoaXMuX2NsZWFudXAoKTtcbiAgdGhpcy5fY2xvc2UoJ3VzZXInKTtcbn07XG5cbkh0bWxmaWxlUmVjZWl2ZXIucHJvdG90eXBlLl9jbGVhbnVwID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdfY2xlYW51cCcpO1xuICBpZiAodGhpcy5pZnJhbWVPYmopIHtcbiAgICB0aGlzLmlmcmFtZU9iai5jbGVhbnVwKCk7XG4gICAgdGhpcy5pZnJhbWVPYmogPSBudWxsO1xuICB9XG4gIGRlbGV0ZSBnbG9iYWxbaWZyYW1lVXRpbHMuV1ByZWZpeF1bdGhpcy5pZF07XG59O1xuXG5IdG1sZmlsZVJlY2VpdmVyLnByb3RvdHlwZS5fY2xvc2UgPSBmdW5jdGlvbihyZWFzb24pIHtcbiAgZGVidWcoJ19jbG9zZScsIHJlYXNvbik7XG4gIHRoaXMuZW1pdCgnY2xvc2UnLCBudWxsLCByZWFzb24pO1xuICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xufTtcblxuSHRtbGZpbGVSZWNlaXZlci5odG1sZmlsZUVuYWJsZWQgPSBmYWxzZTtcblxuLy8gb2JmdXNjYXRlIHRvIGF2b2lkIGZpcmV3YWxsc1xudmFyIGF4byA9IFsnQWN0aXZlJ10uY29uY2F0KCdPYmplY3QnKS5qb2luKCdYJyk7XG5pZiAoYXhvIGluIGdsb2JhbCkge1xuICB0cnkge1xuICAgIEh0bWxmaWxlUmVjZWl2ZXIuaHRtbGZpbGVFbmFibGVkID0gISFuZXcgZ2xvYmFsW2F4b10oJ2h0bWxmaWxlJyk7XG4gIH0gY2F0Y2ggKHgpIHtcbiAgICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG4gIH1cbn1cblxuSHRtbGZpbGVSZWNlaXZlci5lbmFibGVkID0gSHRtbGZpbGVSZWNlaXZlci5odG1sZmlsZUVuYWJsZWQgfHwgaWZyYW1lVXRpbHMuaWZyYW1lRW5hYmxlZDtcblxubW9kdWxlLmV4cG9ydHMgPSBIdG1sZmlsZVJlY2VpdmVyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi8uLi91dGlscy9pZnJhbWUnKVxuICAsIHJhbmRvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL3JhbmRvbScpXG4gICwgYnJvd3NlciA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL2Jyb3dzZXInKVxuICAsIHVybFV0aWxzID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvdXJsJylcbiAgLCBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXJcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OnJlY2VpdmVyOmpzb25wJyk7XG59XG5cbmZ1bmN0aW9uIEpzb25wUmVjZWl2ZXIodXJsKSB7XG4gIGRlYnVnKHVybCk7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG5cbiAgdXRpbHMucG9sbHV0ZUdsb2JhbE5hbWVzcGFjZSgpO1xuXG4gIHRoaXMuaWQgPSAnYScgKyByYW5kb20uc3RyaW5nKDYpO1xuICB2YXIgdXJsV2l0aElkID0gdXJsVXRpbHMuYWRkUXVlcnkodXJsLCAnYz0nICsgZW5jb2RlVVJJQ29tcG9uZW50KHV0aWxzLldQcmVmaXggKyAnLicgKyB0aGlzLmlkKSk7XG5cbiAgZ2xvYmFsW3V0aWxzLldQcmVmaXhdW3RoaXMuaWRdID0gdGhpcy5fY2FsbGJhY2suYmluZCh0aGlzKTtcbiAgdGhpcy5fY3JlYXRlU2NyaXB0KHVybFdpdGhJZCk7XG5cbiAgLy8gRmFsbGJhY2sgbW9zdGx5IGZvciBLb25xdWVyb3IgLSBzdHVwaWQgdGltZXIsIDM1IHNlY29uZHMgc2hhbGwgYmUgcGxlbnR5LlxuICB0aGlzLnRpbWVvdXRJZCA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ3RpbWVvdXQnKTtcbiAgICBzZWxmLl9hYm9ydChuZXcgRXJyb3IoJ0pTT05QIHNjcmlwdCBsb2FkZWQgYWJub3JtYWxseSAodGltZW91dCknKSk7XG4gIH0sIEpzb25wUmVjZWl2ZXIudGltZW91dCk7XG59XG5cbmluaGVyaXRzKEpzb25wUmVjZWl2ZXIsIEV2ZW50RW1pdHRlcik7XG5cbkpzb25wUmVjZWl2ZXIucHJvdG90eXBlLmFib3J0ID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdhYm9ydCcpO1xuICBpZiAoZ2xvYmFsW3V0aWxzLldQcmVmaXhdW3RoaXMuaWRdKSB7XG4gICAgdmFyIGVyciA9IG5ldyBFcnJvcignSlNPTlAgdXNlciBhYm9ydGVkIHJlYWQnKTtcbiAgICBlcnIuY29kZSA9IDEwMDA7XG4gICAgdGhpcy5fYWJvcnQoZXJyKTtcbiAgfVxufTtcblxuSnNvbnBSZWNlaXZlci50aW1lb3V0ID0gMzUwMDA7XG5Kc29ucFJlY2VpdmVyLnNjcmlwdEVycm9yVGltZW91dCA9IDEwMDA7XG5cbkpzb25wUmVjZWl2ZXIucHJvdG90eXBlLl9jYWxsYmFjayA9IGZ1bmN0aW9uKGRhdGEpIHtcbiAgZGVidWcoJ19jYWxsYmFjaycsIGRhdGEpO1xuICB0aGlzLl9jbGVhbnVwKCk7XG5cbiAgaWYgKHRoaXMuYWJvcnRpbmcpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoZGF0YSkge1xuICAgIGRlYnVnKCdtZXNzYWdlJywgZGF0YSk7XG4gICAgdGhpcy5lbWl0KCdtZXNzYWdlJywgZGF0YSk7XG4gIH1cbiAgdGhpcy5lbWl0KCdjbG9zZScsIG51bGwsICduZXR3b3JrJyk7XG4gIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG59O1xuXG5Kc29ucFJlY2VpdmVyLnByb3RvdHlwZS5fYWJvcnQgPSBmdW5jdGlvbihlcnIpIHtcbiAgZGVidWcoJ19hYm9ydCcsIGVycik7XG4gIHRoaXMuX2NsZWFudXAoKTtcbiAgdGhpcy5hYm9ydGluZyA9IHRydWU7XG4gIHRoaXMuZW1pdCgnY2xvc2UnLCBlcnIuY29kZSwgZXJyLm1lc3NhZ2UpO1xuICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xufTtcblxuSnNvbnBSZWNlaXZlci5wcm90b3R5cGUuX2NsZWFudXAgPSBmdW5jdGlvbigpIHtcbiAgZGVidWcoJ19jbGVhbnVwJyk7XG4gIGNsZWFyVGltZW91dCh0aGlzLnRpbWVvdXRJZCk7XG4gIGlmICh0aGlzLnNjcmlwdDIpIHtcbiAgICB0aGlzLnNjcmlwdDIucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0aGlzLnNjcmlwdDIpO1xuICAgIHRoaXMuc2NyaXB0MiA9IG51bGw7XG4gIH1cbiAgaWYgKHRoaXMuc2NyaXB0KSB7XG4gICAgdmFyIHNjcmlwdCA9IHRoaXMuc2NyaXB0O1xuICAgIC8vIFVuZm9ydHVuYXRlbHksIHlvdSBjYW4ndCByZWFsbHkgYWJvcnQgc2NyaXB0IGxvYWRpbmcgb2ZcbiAgICAvLyB0aGUgc2NyaXB0LlxuICAgIHNjcmlwdC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHNjcmlwdCk7XG4gICAgc2NyaXB0Lm9ucmVhZHlzdGF0ZWNoYW5nZSA9IHNjcmlwdC5vbmVycm9yID1cbiAgICAgICAgc2NyaXB0Lm9ubG9hZCA9IHNjcmlwdC5vbmNsaWNrID0gbnVsbDtcbiAgICB0aGlzLnNjcmlwdCA9IG51bGw7XG4gIH1cbiAgZGVsZXRlIGdsb2JhbFt1dGlscy5XUHJlZml4XVt0aGlzLmlkXTtcbn07XG5cbkpzb25wUmVjZWl2ZXIucHJvdG90eXBlLl9zY3JpcHRFcnJvciA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnX3NjcmlwdEVycm9yJyk7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgaWYgKHRoaXMuZXJyb3JUaW1lcikge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHRoaXMuZXJyb3JUaW1lciA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgaWYgKCFzZWxmLmxvYWRlZE9rYXkpIHtcbiAgICAgIHNlbGYuX2Fib3J0KG5ldyBFcnJvcignSlNPTlAgc2NyaXB0IGxvYWRlZCBhYm5vcm1hbGx5IChvbmVycm9yKScpKTtcbiAgICB9XG4gIH0sIEpzb25wUmVjZWl2ZXIuc2NyaXB0RXJyb3JUaW1lb3V0KTtcbn07XG5cbkpzb25wUmVjZWl2ZXIucHJvdG90eXBlLl9jcmVhdGVTY3JpcHQgPSBmdW5jdGlvbih1cmwpIHtcbiAgZGVidWcoJ19jcmVhdGVTY3JpcHQnLCB1cmwpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIHZhciBzY3JpcHQgPSB0aGlzLnNjcmlwdCA9IGdsb2JhbC5kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtcbiAgdmFyIHNjcmlwdDI7ICAvLyBPcGVyYSBzeW5jaHJvbm91cyBsb2FkIHRyaWNrLlxuXG4gIHNjcmlwdC5pZCA9ICdhJyArIHJhbmRvbS5zdHJpbmcoOCk7XG4gIHNjcmlwdC5zcmMgPSB1cmw7XG4gIHNjcmlwdC50eXBlID0gJ3RleHQvamF2YXNjcmlwdCc7XG4gIHNjcmlwdC5jaGFyc2V0ID0gJ1VURi04JztcbiAgc2NyaXB0Lm9uZXJyb3IgPSB0aGlzLl9zY3JpcHRFcnJvci5iaW5kKHRoaXMpO1xuICBzY3JpcHQub25sb2FkID0gZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ29ubG9hZCcpO1xuICAgIHNlbGYuX2Fib3J0KG5ldyBFcnJvcignSlNPTlAgc2NyaXB0IGxvYWRlZCBhYm5vcm1hbGx5IChvbmxvYWQpJykpO1xuICB9O1xuXG4gIC8vIElFOSBmaXJlcyAnZXJyb3InIGV2ZW50IGFmdGVyIG9ucmVhZHlzdGF0ZWNoYW5nZSBvciBiZWZvcmUsIGluIHJhbmRvbSBvcmRlci5cbiAgLy8gVXNlIGxvYWRlZE9rYXkgdG8gZGV0ZXJtaW5lIGlmIGFjdHVhbGx5IGVycm9yZWRcbiAgc2NyaXB0Lm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCdvbnJlYWR5c3RhdGVjaGFuZ2UnLCBzY3JpcHQucmVhZHlTdGF0ZSk7XG4gICAgaWYgKC9sb2FkZWR8Y2xvc2VkLy50ZXN0KHNjcmlwdC5yZWFkeVN0YXRlKSkge1xuICAgICAgaWYgKHNjcmlwdCAmJiBzY3JpcHQuaHRtbEZvciAmJiBzY3JpcHQub25jbGljaykge1xuICAgICAgICBzZWxmLmxvYWRlZE9rYXkgPSB0cnVlO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIC8vIEluIElFLCBhY3R1YWxseSBleGVjdXRlIHRoZSBzY3JpcHQuXG4gICAgICAgICAgc2NyaXB0Lm9uY2xpY2soKTtcbiAgICAgICAgfSBjYXRjaCAoeCkge1xuICAgICAgICAgIC8vIGludGVudGlvbmFsbHkgZW1wdHlcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKHNjcmlwdCkge1xuICAgICAgICBzZWxmLl9hYm9ydChuZXcgRXJyb3IoJ0pTT05QIHNjcmlwdCBsb2FkZWQgYWJub3JtYWxseSAob25yZWFkeXN0YXRlY2hhbmdlKScpKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG4gIC8vIElFOiBldmVudC9odG1sRm9yL29uY2xpY2sgdHJpY2suXG4gIC8vIE9uZSBjYW4ndCByZWx5IG9uIHByb3BlciBvcmRlciBmb3Igb25yZWFkeXN0YXRlY2hhbmdlLiBJbiBvcmRlciB0b1xuICAvLyBtYWtlIHN1cmUsIHNldCBhICdodG1sRm9yJyBhbmQgJ2V2ZW50JyBwcm9wZXJ0aWVzLCBzbyB0aGF0XG4gIC8vIHNjcmlwdCBjb2RlIHdpbGwgYmUgaW5zdGFsbGVkIGFzICdvbmNsaWNrJyBoYW5kbGVyIGZvciB0aGVcbiAgLy8gc2NyaXB0IG9iamVjdC4gTGF0ZXIsIG9ucmVhZHlzdGF0ZWNoYW5nZSwgbWFudWFsbHkgZXhlY3V0ZSB0aGlzXG4gIC8vIGNvZGUuIEZGIGFuZCBDaHJvbWUgZG9lc24ndCB3b3JrIHdpdGggJ2V2ZW50JyBhbmQgJ2h0bWxGb3InXG4gIC8vIHNldC4gRm9yIHJlZmVyZW5jZSBzZWU6XG4gIC8vICAgaHR0cDovL2phdWJvdXJnLm5ldC8yMDEwLzA3L2xvYWRpbmctc2NyaXB0LWFzLW9uY2xpY2staGFuZGxlci1vZi5odG1sXG4gIC8vIEFsc28sIHJlYWQgb24gdGhhdCBhYm91dCBzY3JpcHQgb3JkZXJpbmc6XG4gIC8vICAgaHR0cDovL3dpa2kud2hhdHdnLm9yZy93aWtpL0R5bmFtaWNfU2NyaXB0X0V4ZWN1dGlvbl9PcmRlclxuICBpZiAodHlwZW9mIHNjcmlwdC5hc3luYyA9PT0gJ3VuZGVmaW5lZCcgJiYgZ2xvYmFsLmRvY3VtZW50LmF0dGFjaEV2ZW50KSB7XG4gICAgLy8gQWNjb3JkaW5nIHRvIG1vemlsbGEgZG9jcywgaW4gcmVjZW50IGJyb3dzZXJzIHNjcmlwdC5hc3luYyBkZWZhdWx0c1xuICAgIC8vIHRvICd0cnVlJywgc28gd2UgbWF5IHVzZSBpdCB0byBkZXRlY3QgYSBnb29kIGJyb3dzZXI6XG4gICAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4vSFRNTC9FbGVtZW50L3NjcmlwdFxuICAgIGlmICghYnJvd3Nlci5pc09wZXJhKCkpIHtcbiAgICAgIC8vIE5haXZlbHkgYXNzdW1lIHdlJ3JlIGluIElFXG4gICAgICB0cnkge1xuICAgICAgICBzY3JpcHQuaHRtbEZvciA9IHNjcmlwdC5pZDtcbiAgICAgICAgc2NyaXB0LmV2ZW50ID0gJ29uY2xpY2snO1xuICAgICAgfSBjYXRjaCAoeCkge1xuICAgICAgICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG4gICAgICB9XG4gICAgICBzY3JpcHQuYXN5bmMgPSB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBPcGVyYSwgc2Vjb25kIHN5bmMgc2NyaXB0IGhhY2tcbiAgICAgIHNjcmlwdDIgPSB0aGlzLnNjcmlwdDIgPSBnbG9iYWwuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7XG4gICAgICBzY3JpcHQyLnRleHQgPSBcInRyeXt2YXIgYSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdcIiArIHNjcmlwdC5pZCArIFwiJyk7IGlmKGEpYS5vbmVycm9yKCk7fWNhdGNoKHgpe307XCI7XG4gICAgICBzY3JpcHQuYXN5bmMgPSBzY3JpcHQyLmFzeW5jID0gZmFsc2U7XG4gICAgfVxuICB9XG4gIGlmICh0eXBlb2Ygc2NyaXB0LmFzeW5jICE9PSAndW5kZWZpbmVkJykge1xuICAgIHNjcmlwdC5hc3luYyA9IHRydWU7XG4gIH1cblxuICB2YXIgaGVhZCA9IGdsb2JhbC5kb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnaGVhZCcpWzBdO1xuICBoZWFkLmluc2VydEJlZm9yZShzY3JpcHQsIGhlYWQuZmlyc3RDaGlsZCk7XG4gIGlmIChzY3JpcHQyKSB7XG4gICAgaGVhZC5pbnNlcnRCZWZvcmUoc2NyaXB0MiwgaGVhZC5maXJzdENoaWxkKTtcbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBKc29ucFJlY2VpdmVyO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gIDtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDpyZWNlaXZlcjp4aHInKTtcbn1cblxuZnVuY3Rpb24gWGhyUmVjZWl2ZXIodXJsLCBBamF4T2JqZWN0KSB7XG4gIGRlYnVnKHVybCk7XG4gIEV2ZW50RW1pdHRlci5jYWxsKHRoaXMpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgdGhpcy5idWZmZXJQb3NpdGlvbiA9IDA7XG5cbiAgdGhpcy54byA9IG5ldyBBamF4T2JqZWN0KCdQT1NUJywgdXJsLCBudWxsKTtcbiAgdGhpcy54by5vbignY2h1bmsnLCB0aGlzLl9jaHVua0hhbmRsZXIuYmluZCh0aGlzKSk7XG4gIHRoaXMueG8ub25jZSgnZmluaXNoJywgZnVuY3Rpb24oc3RhdHVzLCB0ZXh0KSB7XG4gICAgZGVidWcoJ2ZpbmlzaCcsIHN0YXR1cywgdGV4dCk7XG4gICAgc2VsZi5fY2h1bmtIYW5kbGVyKHN0YXR1cywgdGV4dCk7XG4gICAgc2VsZi54byA9IG51bGw7XG4gICAgdmFyIHJlYXNvbiA9IHN0YXR1cyA9PT0gMjAwID8gJ25ldHdvcmsnIDogJ3Blcm1hbmVudCc7XG4gICAgZGVidWcoJ2Nsb3NlJywgcmVhc29uKTtcbiAgICBzZWxmLmVtaXQoJ2Nsb3NlJywgbnVsbCwgcmVhc29uKTtcbiAgICBzZWxmLl9jbGVhbnVwKCk7XG4gIH0pO1xufVxuXG5pbmhlcml0cyhYaHJSZWNlaXZlciwgRXZlbnRFbWl0dGVyKTtcblxuWGhyUmVjZWl2ZXIucHJvdG90eXBlLl9jaHVua0hhbmRsZXIgPSBmdW5jdGlvbihzdGF0dXMsIHRleHQpIHtcbiAgZGVidWcoJ19jaHVua0hhbmRsZXInLCBzdGF0dXMpO1xuICBpZiAoc3RhdHVzICE9PSAyMDAgfHwgIXRleHQpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBmb3IgKHZhciBpZHggPSAtMTsgOyB0aGlzLmJ1ZmZlclBvc2l0aW9uICs9IGlkeCArIDEpIHtcbiAgICB2YXIgYnVmID0gdGV4dC5zbGljZSh0aGlzLmJ1ZmZlclBvc2l0aW9uKTtcbiAgICBpZHggPSBidWYuaW5kZXhPZignXFxuJyk7XG4gICAgaWYgKGlkeCA9PT0gLTEpIHtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgICB2YXIgbXNnID0gYnVmLnNsaWNlKDAsIGlkeCk7XG4gICAgaWYgKG1zZykge1xuICAgICAgZGVidWcoJ21lc3NhZ2UnLCBtc2cpO1xuICAgICAgdGhpcy5lbWl0KCdtZXNzYWdlJywgbXNnKTtcbiAgICB9XG4gIH1cbn07XG5cblhoclJlY2VpdmVyLnByb3RvdHlwZS5fY2xlYW51cCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnX2NsZWFudXAnKTtcbiAgdGhpcy5yZW1vdmVBbGxMaXN0ZW5lcnMoKTtcbn07XG5cblhoclJlY2VpdmVyLnByb3RvdHlwZS5hYm9ydCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnYWJvcnQnKTtcbiAgaWYgKHRoaXMueG8pIHtcbiAgICB0aGlzLnhvLmNsb3NlKCk7XG4gICAgZGVidWcoJ2Nsb3NlJyk7XG4gICAgdGhpcy5lbWl0KCdjbG9zZScsIG51bGwsICd1c2VyJyk7XG4gICAgdGhpcy54byA9IG51bGw7XG4gIH1cbiAgdGhpcy5fY2xlYW51cCgpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBYaHJSZWNlaXZlcjtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHJhbmRvbSA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL3JhbmRvbScpXG4gICwgdXJsVXRpbHMgPSByZXF1aXJlKCcuLi8uLi91dGlscy91cmwnKVxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6c2VuZGVyOmpzb25wJyk7XG59XG5cbnZhciBmb3JtLCBhcmVhO1xuXG5mdW5jdGlvbiBjcmVhdGVJZnJhbWUoaWQpIHtcbiAgZGVidWcoJ2NyZWF0ZUlmcmFtZScsIGlkKTtcbiAgdHJ5IHtcbiAgICAvLyBpZTYgZHluYW1pYyBpZnJhbWVzIHdpdGggdGFyZ2V0PVwiXCIgc3VwcG9ydCAodGhhbmtzIENocmlzIExhbWJhY2hlcilcbiAgICByZXR1cm4gZ2xvYmFsLmRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJzxpZnJhbWUgbmFtZT1cIicgKyBpZCArICdcIj4nKTtcbiAgfSBjYXRjaCAoeCkge1xuICAgIHZhciBpZnJhbWUgPSBnbG9iYWwuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaWZyYW1lJyk7XG4gICAgaWZyYW1lLm5hbWUgPSBpZDtcbiAgICByZXR1cm4gaWZyYW1lO1xuICB9XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUZvcm0oKSB7XG4gIGRlYnVnKCdjcmVhdGVGb3JtJyk7XG4gIGZvcm0gPSBnbG9iYWwuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZm9ybScpO1xuICBmb3JtLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gIGZvcm0uc3R5bGUucG9zaXRpb24gPSAnYWJzb2x1dGUnO1xuICBmb3JtLm1ldGhvZCA9ICdQT1NUJztcbiAgZm9ybS5lbmN0eXBlID0gJ2FwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCc7XG4gIGZvcm0uYWNjZXB0Q2hhcnNldCA9ICdVVEYtOCc7XG5cbiAgYXJlYSA9IGdsb2JhbC5kb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0ZXh0YXJlYScpO1xuICBhcmVhLm5hbWUgPSAnZCc7XG4gIGZvcm0uYXBwZW5kQ2hpbGQoYXJlYSk7XG5cbiAgZ2xvYmFsLmRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoZm9ybSk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24odXJsLCBwYXlsb2FkLCBjYWxsYmFjaykge1xuICBkZWJ1Zyh1cmwsIHBheWxvYWQpO1xuICBpZiAoIWZvcm0pIHtcbiAgICBjcmVhdGVGb3JtKCk7XG4gIH1cbiAgdmFyIGlkID0gJ2EnICsgcmFuZG9tLnN0cmluZyg4KTtcbiAgZm9ybS50YXJnZXQgPSBpZDtcbiAgZm9ybS5hY3Rpb24gPSB1cmxVdGlscy5hZGRRdWVyeSh1cmxVdGlscy5hZGRQYXRoKHVybCwgJy9qc29ucF9zZW5kJyksICdpPScgKyBpZCk7XG5cbiAgdmFyIGlmcmFtZSA9IGNyZWF0ZUlmcmFtZShpZCk7XG4gIGlmcmFtZS5pZCA9IGlkO1xuICBpZnJhbWUuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgZm9ybS5hcHBlbmRDaGlsZChpZnJhbWUpO1xuXG4gIHRyeSB7XG4gICAgYXJlYS52YWx1ZSA9IHBheWxvYWQ7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICAvLyBzZXJpb3VzbHkgYnJva2VuIGJyb3dzZXJzIGdldCBoZXJlXG4gIH1cbiAgZm9ybS5zdWJtaXQoKTtcblxuICB2YXIgY29tcGxldGVkID0gZnVuY3Rpb24oZXJyKSB7XG4gICAgZGVidWcoJ2NvbXBsZXRlZCcsIGlkLCBlcnIpO1xuICAgIGlmICghaWZyYW1lLm9uZXJyb3IpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWZyYW1lLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGlmcmFtZS5vbmVycm9yID0gaWZyYW1lLm9ubG9hZCA9IG51bGw7XG4gICAgLy8gT3BlcmEgbWluaSBkb2Vzbid0IGxpa2UgaWYgd2UgR0MgaWZyYW1lXG4gICAgLy8gaW1tZWRpYXRlbHksIHRodXMgdGhpcyB0aW1lb3V0LlxuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICBkZWJ1ZygnY2xlYW5pbmcgdXAnLCBpZCk7XG4gICAgICBpZnJhbWUucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChpZnJhbWUpO1xuICAgICAgaWZyYW1lID0gbnVsbDtcbiAgICB9LCA1MDApO1xuICAgIGFyZWEudmFsdWUgPSAnJztcbiAgICAvLyBJdCBpcyBub3QgcG9zc2libGUgdG8gZGV0ZWN0IGlmIHRoZSBpZnJhbWUgc3VjY2VlZGVkIG9yXG4gICAgLy8gZmFpbGVkIHRvIHN1Ym1pdCBvdXIgZm9ybS5cbiAgICBjYWxsYmFjayhlcnIpO1xuICB9O1xuICBpZnJhbWUub25lcnJvciA9IGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCdvbmVycm9yJywgaWQpO1xuICAgIGNvbXBsZXRlZCgpO1xuICB9O1xuICBpZnJhbWUub25sb2FkID0gZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ29ubG9hZCcsIGlkKTtcbiAgICBjb21wbGV0ZWQoKTtcbiAgfTtcbiAgaWZyYW1lLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uKGUpIHtcbiAgICBkZWJ1Zygnb25yZWFkeXN0YXRlY2hhbmdlJywgaWQsIGlmcmFtZS5yZWFkeVN0YXRlLCBlKTtcbiAgICBpZiAoaWZyYW1lLnJlYWR5U3RhdGUgPT09ICdjb21wbGV0ZScpIHtcbiAgICAgIGNvbXBsZXRlZCgpO1xuICAgIH1cbiAgfTtcbiAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgIGRlYnVnKCdhYm9ydGVkJywgaWQpO1xuICAgIGNvbXBsZXRlZChuZXcgRXJyb3IoJ0Fib3J0ZWQnKSk7XG4gIH07XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnZXZlbnRzJykuRXZlbnRFbWl0dGVyXG4gICwgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgZXZlbnRVdGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzL2V2ZW50JylcbiAgLCBicm93c2VyID0gcmVxdWlyZSgnLi4vLi4vdXRpbHMvYnJvd3NlcicpXG4gICwgdXJsVXRpbHMgPSByZXF1aXJlKCcuLi8uLi91dGlscy91cmwnKVxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6c2VuZGVyOnhkcicpO1xufVxuXG4vLyBSZWZlcmVuY2VzOlxuLy8gICBodHRwOi8vYWpheGlhbi5jb20vYXJjaGl2ZXMvMTAwLWxpbmUtYWpheC13cmFwcGVyXG4vLyAgIGh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20vZW4tdXMvbGlicmFyeS9jYzI4ODA2MCh2PVZTLjg1KS5hc3B4XG5cbmZ1bmN0aW9uIFhEUk9iamVjdChtZXRob2QsIHVybCwgcGF5bG9hZCkge1xuICBkZWJ1ZyhtZXRob2QsIHVybCk7XG4gIHZhciBzZWxmID0gdGhpcztcbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG5cbiAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICBzZWxmLl9zdGFydChtZXRob2QsIHVybCwgcGF5bG9hZCk7XG4gIH0sIDApO1xufVxuXG5pbmhlcml0cyhYRFJPYmplY3QsIEV2ZW50RW1pdHRlcik7XG5cblhEUk9iamVjdC5wcm90b3R5cGUuX3N0YXJ0ID0gZnVuY3Rpb24obWV0aG9kLCB1cmwsIHBheWxvYWQpIHtcbiAgZGVidWcoJ19zdGFydCcpO1xuICB2YXIgc2VsZiA9IHRoaXM7XG4gIHZhciB4ZHIgPSBuZXcgZ2xvYmFsLlhEb21haW5SZXF1ZXN0KCk7XG4gIC8vIElFIGNhY2hlcyBldmVuIFBPU1RzXG4gIHVybCA9IHVybFV0aWxzLmFkZFF1ZXJ5KHVybCwgJ3Q9JyArICgrbmV3IERhdGUoKSkpO1xuXG4gIHhkci5vbmVycm9yID0gZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ29uZXJyb3InKTtcbiAgICBzZWxmLl9lcnJvcigpO1xuICB9O1xuICB4ZHIub250aW1lb3V0ID0gZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ29udGltZW91dCcpO1xuICAgIHNlbGYuX2Vycm9yKCk7XG4gIH07XG4gIHhkci5vbnByb2dyZXNzID0gZnVuY3Rpb24oKSB7XG4gICAgZGVidWcoJ3Byb2dyZXNzJywgeGRyLnJlc3BvbnNlVGV4dCk7XG4gICAgc2VsZi5lbWl0KCdjaHVuaycsIDIwMCwgeGRyLnJlc3BvbnNlVGV4dCk7XG4gIH07XG4gIHhkci5vbmxvYWQgPSBmdW5jdGlvbigpIHtcbiAgICBkZWJ1ZygnbG9hZCcpO1xuICAgIHNlbGYuZW1pdCgnZmluaXNoJywgMjAwLCB4ZHIucmVzcG9uc2VUZXh0KTtcbiAgICBzZWxmLl9jbGVhbnVwKGZhbHNlKTtcbiAgfTtcbiAgdGhpcy54ZHIgPSB4ZHI7XG4gIHRoaXMudW5sb2FkUmVmID0gZXZlbnRVdGlscy51bmxvYWRBZGQoZnVuY3Rpb24oKSB7XG4gICAgc2VsZi5fY2xlYW51cCh0cnVlKTtcbiAgfSk7XG4gIHRyeSB7XG4gICAgLy8gRmFpbHMgd2l0aCBBY2Nlc3NEZW5pZWQgaWYgcG9ydCBudW1iZXIgaXMgYm9ndXNcbiAgICB0aGlzLnhkci5vcGVuKG1ldGhvZCwgdXJsKTtcbiAgICBpZiAodGhpcy50aW1lb3V0KSB7XG4gICAgICB0aGlzLnhkci50aW1lb3V0ID0gdGhpcy50aW1lb3V0O1xuICAgIH1cbiAgICB0aGlzLnhkci5zZW5kKHBheWxvYWQpO1xuICB9IGNhdGNoICh4KSB7XG4gICAgdGhpcy5fZXJyb3IoKTtcbiAgfVxufTtcblxuWERST2JqZWN0LnByb3RvdHlwZS5fZXJyb3IgPSBmdW5jdGlvbigpIHtcbiAgdGhpcy5lbWl0KCdmaW5pc2gnLCAwLCAnJyk7XG4gIHRoaXMuX2NsZWFudXAoZmFsc2UpO1xufTtcblxuWERST2JqZWN0LnByb3RvdHlwZS5fY2xlYW51cCA9IGZ1bmN0aW9uKGFib3J0KSB7XG4gIGRlYnVnKCdjbGVhbnVwJywgYWJvcnQpO1xuICBpZiAoIXRoaXMueGRyKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gIGV2ZW50VXRpbHMudW5sb2FkRGVsKHRoaXMudW5sb2FkUmVmKTtcblxuICB0aGlzLnhkci5vbnRpbWVvdXQgPSB0aGlzLnhkci5vbmVycm9yID0gdGhpcy54ZHIub25wcm9ncmVzcyA9IHRoaXMueGRyLm9ubG9hZCA9IG51bGw7XG4gIGlmIChhYm9ydCkge1xuICAgIHRyeSB7XG4gICAgICB0aGlzLnhkci5hYm9ydCgpO1xuICAgIH0gY2F0Y2ggKHgpIHtcbiAgICAgIC8vIGludGVudGlvbmFsbHkgZW1wdHlcbiAgICB9XG4gIH1cbiAgdGhpcy51bmxvYWRSZWYgPSB0aGlzLnhkciA9IG51bGw7XG59O1xuXG5YRFJPYmplY3QucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24oKSB7XG4gIGRlYnVnKCdjbG9zZScpO1xuICB0aGlzLl9jbGVhbnVwKHRydWUpO1xufTtcblxuLy8gSUUgOC85IGlmIHRoZSByZXF1ZXN0IHRhcmdldCB1c2VzIHRoZSBzYW1lIHNjaGVtZSAtICM3OVxuWERST2JqZWN0LmVuYWJsZWQgPSAhIShnbG9iYWwuWERvbWFpblJlcXVlc3QgJiYgYnJvd3Nlci5oYXNEb21haW4oKSk7XG5cbm1vZHVsZS5leHBvcnRzID0gWERST2JqZWN0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgWGhyRHJpdmVyID0gcmVxdWlyZSgnLi4vZHJpdmVyL3hocicpXG4gIDtcblxuZnVuY3Rpb24gWEhSQ29yc09iamVjdChtZXRob2QsIHVybCwgcGF5bG9hZCwgb3B0cykge1xuICBYaHJEcml2ZXIuY2FsbCh0aGlzLCBtZXRob2QsIHVybCwgcGF5bG9hZCwgb3B0cyk7XG59XG5cbmluaGVyaXRzKFhIUkNvcnNPYmplY3QsIFhockRyaXZlcik7XG5cblhIUkNvcnNPYmplY3QuZW5hYmxlZCA9IFhockRyaXZlci5lbmFibGVkICYmIFhockRyaXZlci5zdXBwb3J0c0NPUlM7XG5cbm1vZHVsZS5leHBvcnRzID0gWEhSQ29yc09iamVjdDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ2V2ZW50cycpLkV2ZW50RW1pdHRlclxuICAsIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICA7XG5cbmZ1bmN0aW9uIFhIUkZha2UoLyogbWV0aG9kLCB1cmwsIHBheWxvYWQsIG9wdHMgKi8pIHtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuICBFdmVudEVtaXR0ZXIuY2FsbCh0aGlzKTtcblxuICB0aGlzLnRvID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICBzZWxmLmVtaXQoJ2ZpbmlzaCcsIDIwMCwgJ3t9Jyk7XG4gIH0sIFhIUkZha2UudGltZW91dCk7XG59XG5cbmluaGVyaXRzKFhIUkZha2UsIEV2ZW50RW1pdHRlcik7XG5cblhIUkZha2UucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24oKSB7XG4gIGNsZWFyVGltZW91dCh0aGlzLnRvKTtcbn07XG5cblhIUkZha2UudGltZW91dCA9IDIwMDA7XG5cbm1vZHVsZS5leHBvcnRzID0gWEhSRmFrZTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIFhockRyaXZlciA9IHJlcXVpcmUoJy4uL2RyaXZlci94aHInKVxuICA7XG5cbmZ1bmN0aW9uIFhIUkxvY2FsT2JqZWN0KG1ldGhvZCwgdXJsLCBwYXlsb2FkIC8qLCBvcHRzICovKSB7XG4gIFhockRyaXZlci5jYWxsKHRoaXMsIG1ldGhvZCwgdXJsLCBwYXlsb2FkLCB7XG4gICAgbm9DcmVkZW50aWFsczogdHJ1ZVxuICB9KTtcbn1cblxuaW5oZXJpdHMoWEhSTG9jYWxPYmplY3QsIFhockRyaXZlcik7XG5cblhIUkxvY2FsT2JqZWN0LmVuYWJsZWQgPSBYaHJEcml2ZXIuZW5hYmxlZDtcblxubW9kdWxlLmV4cG9ydHMgPSBYSFJMb2NhbE9iamVjdDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvZXZlbnQnKVxuICAsIHVybFV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXJsJylcbiAgLCBpbmhlcml0cyA9IHJlcXVpcmUoJ2luaGVyaXRzJylcbiAgLCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXJcbiAgLCBXZWJzb2NrZXREcml2ZXIgPSByZXF1aXJlKCcuL2RyaXZlci93ZWJzb2NrZXQnKVxuICA7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6d2Vic29ja2V0Jyk7XG59XG5cbmZ1bmN0aW9uIFdlYlNvY2tldFRyYW5zcG9ydCh0cmFuc1VybCwgaWdub3JlLCBvcHRpb25zKSB7XG4gIGlmICghV2ViU29ja2V0VHJhbnNwb3J0LmVuYWJsZWQoKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignVHJhbnNwb3J0IGNyZWF0ZWQgd2hlbiBkaXNhYmxlZCcpO1xuICB9XG5cbiAgRXZlbnRFbWl0dGVyLmNhbGwodGhpcyk7XG4gIGRlYnVnKCdjb25zdHJ1Y3RvcicsIHRyYW5zVXJsKTtcblxuICB2YXIgc2VsZiA9IHRoaXM7XG4gIHZhciB1cmwgPSB1cmxVdGlscy5hZGRQYXRoKHRyYW5zVXJsLCAnL3dlYnNvY2tldCcpO1xuICBpZiAodXJsLnNsaWNlKDAsIDUpID09PSAnaHR0cHMnKSB7XG4gICAgdXJsID0gJ3dzcycgKyB1cmwuc2xpY2UoNSk7XG4gIH0gZWxzZSB7XG4gICAgdXJsID0gJ3dzJyArIHVybC5zbGljZSg0KTtcbiAgfVxuICB0aGlzLnVybCA9IHVybDtcblxuICB0aGlzLndzID0gbmV3IFdlYnNvY2tldERyaXZlcih0aGlzLnVybCwgW10sIG9wdGlvbnMpO1xuICB0aGlzLndzLm9ubWVzc2FnZSA9IGZ1bmN0aW9uKGUpIHtcbiAgICBkZWJ1ZygnbWVzc2FnZSBldmVudCcsIGUuZGF0YSk7XG4gICAgc2VsZi5lbWl0KCdtZXNzYWdlJywgZS5kYXRhKTtcbiAgfTtcbiAgLy8gRmlyZWZveCBoYXMgYW4gaW50ZXJlc3RpbmcgYnVnLiBJZiBhIHdlYnNvY2tldCBjb25uZWN0aW9uIGlzXG4gIC8vIGNyZWF0ZWQgYWZ0ZXIgb251bmxvYWQsIGl0IHN0YXlzIGFsaXZlIGV2ZW4gd2hlbiB1c2VyXG4gIC8vIG5hdmlnYXRlcyBhd2F5IGZyb20gdGhlIHBhZ2UuIEluIHN1Y2ggc2l0dWF0aW9uIGxldCdzIGxpZSAtXG4gIC8vIGxldCdzIG5vdCBvcGVuIHRoZSB3cyBjb25uZWN0aW9uIGF0IGFsbC4gU2VlOlxuICAvLyBodHRwczovL2dpdGh1Yi5jb20vc29ja2pzL3NvY2tqcy1jbGllbnQvaXNzdWVzLzI4XG4gIC8vIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY5NjA4NVxuICB0aGlzLnVubG9hZFJlZiA9IHV0aWxzLnVubG9hZEFkZChmdW5jdGlvbigpIHtcbiAgICBkZWJ1ZygndW5sb2FkJyk7XG4gICAgc2VsZi53cy5jbG9zZSgpO1xuICB9KTtcbiAgdGhpcy53cy5vbmNsb3NlID0gZnVuY3Rpb24oZSkge1xuICAgIGRlYnVnKCdjbG9zZSBldmVudCcsIGUuY29kZSwgZS5yZWFzb24pO1xuICAgIHNlbGYuZW1pdCgnY2xvc2UnLCBlLmNvZGUsIGUucmVhc29uKTtcbiAgICBzZWxmLl9jbGVhbnVwKCk7XG4gIH07XG4gIHRoaXMud3Mub25lcnJvciA9IGZ1bmN0aW9uKGUpIHtcbiAgICBkZWJ1ZygnZXJyb3IgZXZlbnQnLCBlKTtcbiAgICBzZWxmLmVtaXQoJ2Nsb3NlJywgMTAwNiwgJ1dlYlNvY2tldCBjb25uZWN0aW9uIGJyb2tlbicpO1xuICAgIHNlbGYuX2NsZWFudXAoKTtcbiAgfTtcbn1cblxuaW5oZXJpdHMoV2ViU29ja2V0VHJhbnNwb3J0LCBFdmVudEVtaXR0ZXIpO1xuXG5XZWJTb2NrZXRUcmFuc3BvcnQucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbihkYXRhKSB7XG4gIHZhciBtc2cgPSAnWycgKyBkYXRhICsgJ10nO1xuICBkZWJ1Zygnc2VuZCcsIG1zZyk7XG4gIHRoaXMud3Muc2VuZChtc2cpO1xufTtcblxuV2ViU29ja2V0VHJhbnNwb3J0LnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnY2xvc2UnKTtcbiAgaWYgKHRoaXMud3MpIHtcbiAgICB0aGlzLndzLmNsb3NlKCk7XG4gIH1cbiAgdGhpcy5fY2xlYW51cCgpO1xufTtcblxuV2ViU29ja2V0VHJhbnNwb3J0LnByb3RvdHlwZS5fY2xlYW51cCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnX2NsZWFudXAnKTtcbiAgdmFyIHdzID0gdGhpcy53cztcbiAgaWYgKHdzKSB7XG4gICAgd3Mub25tZXNzYWdlID0gd3Mub25jbG9zZSA9IHdzLm9uZXJyb3IgPSBudWxsO1xuICB9XG4gIHV0aWxzLnVubG9hZERlbCh0aGlzLnVubG9hZFJlZik7XG4gIHRoaXMudW5sb2FkUmVmID0gdGhpcy53cyA9IG51bGw7XG4gIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG59O1xuXG5XZWJTb2NrZXRUcmFuc3BvcnQuZW5hYmxlZCA9IGZ1bmN0aW9uKCkge1xuICBkZWJ1ZygnZW5hYmxlZCcpO1xuICByZXR1cm4gISFXZWJzb2NrZXREcml2ZXI7XG59O1xuV2ViU29ja2V0VHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUgPSAnd2Vic29ja2V0JztcblxuLy8gSW4gdGhlb3J5LCB3cyBzaG91bGQgcmVxdWlyZSAxIHJvdW5kIHRyaXAuIEJ1dCBpbiBjaHJvbWUsIHRoaXMgaXNcbi8vIG5vdCB2ZXJ5IHN0YWJsZSBvdmVyIFNTTC4gTW9zdCBsaWtlbHkgYSB3cyBjb25uZWN0aW9uIHJlcXVpcmVzIGFcbi8vIHNlcGFyYXRlIFNTTCBjb25uZWN0aW9uLCBpbiB3aGljaCBjYXNlIDIgcm91bmQgdHJpcHMgYXJlIGFuXG4vLyBhYnNvbHV0ZSBtaW51bXVtLlxuV2ViU29ja2V0VHJhbnNwb3J0LnJvdW5kVHJpcHMgPSAyO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFdlYlNvY2tldFRyYW5zcG9ydDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEFqYXhCYXNlZFRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vbGliL2FqYXgtYmFzZWQnKVxuICAsIFhkclN0cmVhbWluZ1RyYW5zcG9ydCA9IHJlcXVpcmUoJy4veGRyLXN0cmVhbWluZycpXG4gICwgWGhyUmVjZWl2ZXIgPSByZXF1aXJlKCcuL3JlY2VpdmVyL3hocicpXG4gICwgWERST2JqZWN0ID0gcmVxdWlyZSgnLi9zZW5kZXIveGRyJylcbiAgO1xuXG5mdW5jdGlvbiBYZHJQb2xsaW5nVHJhbnNwb3J0KHRyYW5zVXJsKSB7XG4gIGlmICghWERST2JqZWN0LmVuYWJsZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1RyYW5zcG9ydCBjcmVhdGVkIHdoZW4gZGlzYWJsZWQnKTtcbiAgfVxuICBBamF4QmFzZWRUcmFuc3BvcnQuY2FsbCh0aGlzLCB0cmFuc1VybCwgJy94aHInLCBYaHJSZWNlaXZlciwgWERST2JqZWN0KTtcbn1cblxuaW5oZXJpdHMoWGRyUG9sbGluZ1RyYW5zcG9ydCwgQWpheEJhc2VkVHJhbnNwb3J0KTtcblxuWGRyUG9sbGluZ1RyYW5zcG9ydC5lbmFibGVkID0gWGRyU3RyZWFtaW5nVHJhbnNwb3J0LmVuYWJsZWQ7XG5YZHJQb2xsaW5nVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUgPSAneGRyLXBvbGxpbmcnO1xuWGRyUG9sbGluZ1RyYW5zcG9ydC5yb3VuZFRyaXBzID0gMjsgLy8gcHJlZmxpZ2h0LCBhamF4XG5cbm1vZHVsZS5leHBvcnRzID0gWGRyUG9sbGluZ1RyYW5zcG9ydDtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKVxuICAsIEFqYXhCYXNlZFRyYW5zcG9ydCA9IHJlcXVpcmUoJy4vbGliL2FqYXgtYmFzZWQnKVxuICAsIFhoclJlY2VpdmVyID0gcmVxdWlyZSgnLi9yZWNlaXZlci94aHInKVxuICAsIFhEUk9iamVjdCA9IHJlcXVpcmUoJy4vc2VuZGVyL3hkcicpXG4gIDtcblxuLy8gQWNjb3JkaW5nIHRvOlxuLy8gICBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzE2NDE1MDcvZGV0ZWN0LWJyb3dzZXItc3VwcG9ydC1mb3ItY3Jvc3MtZG9tYWluLXhtbGh0dHByZXF1ZXN0c1xuLy8gICBodHRwOi8vaGFja3MubW96aWxsYS5vcmcvMjAwOS8wNy9jcm9zcy1zaXRlLXhtbGh0dHByZXF1ZXN0LXdpdGgtY29ycy9cblxuZnVuY3Rpb24gWGRyU3RyZWFtaW5nVHJhbnNwb3J0KHRyYW5zVXJsKSB7XG4gIGlmICghWERST2JqZWN0LmVuYWJsZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1RyYW5zcG9ydCBjcmVhdGVkIHdoZW4gZGlzYWJsZWQnKTtcbiAgfVxuICBBamF4QmFzZWRUcmFuc3BvcnQuY2FsbCh0aGlzLCB0cmFuc1VybCwgJy94aHJfc3RyZWFtaW5nJywgWGhyUmVjZWl2ZXIsIFhEUk9iamVjdCk7XG59XG5cbmluaGVyaXRzKFhkclN0cmVhbWluZ1RyYW5zcG9ydCwgQWpheEJhc2VkVHJhbnNwb3J0KTtcblxuWGRyU3RyZWFtaW5nVHJhbnNwb3J0LmVuYWJsZWQgPSBmdW5jdGlvbihpbmZvKSB7XG4gIGlmIChpbmZvLmNvb2tpZV9uZWVkZWQgfHwgaW5mby5udWxsT3JpZ2luKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHJldHVybiBYRFJPYmplY3QuZW5hYmxlZCAmJiBpbmZvLnNhbWVTY2hlbWU7XG59O1xuXG5YZHJTdHJlYW1pbmdUcmFuc3BvcnQudHJhbnNwb3J0TmFtZSA9ICd4ZHItc3RyZWFtaW5nJztcblhkclN0cmVhbWluZ1RyYW5zcG9ydC5yb3VuZFRyaXBzID0gMjsgLy8gcHJlZmxpZ2h0LCBhamF4XG5cbm1vZHVsZS5leHBvcnRzID0gWGRyU3RyZWFtaW5nVHJhbnNwb3J0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgQWpheEJhc2VkVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi9saWIvYWpheC1iYXNlZCcpXG4gICwgWGhyUmVjZWl2ZXIgPSByZXF1aXJlKCcuL3JlY2VpdmVyL3hocicpXG4gICwgWEhSQ29yc09iamVjdCA9IHJlcXVpcmUoJy4vc2VuZGVyL3hoci1jb3JzJylcbiAgLCBYSFJMb2NhbE9iamVjdCA9IHJlcXVpcmUoJy4vc2VuZGVyL3hoci1sb2NhbCcpXG4gIDtcblxuZnVuY3Rpb24gWGhyUG9sbGluZ1RyYW5zcG9ydCh0cmFuc1VybCkge1xuICBpZiAoIVhIUkxvY2FsT2JqZWN0LmVuYWJsZWQgJiYgIVhIUkNvcnNPYmplY3QuZW5hYmxlZCkge1xuICAgIHRocm93IG5ldyBFcnJvcignVHJhbnNwb3J0IGNyZWF0ZWQgd2hlbiBkaXNhYmxlZCcpO1xuICB9XG4gIEFqYXhCYXNlZFRyYW5zcG9ydC5jYWxsKHRoaXMsIHRyYW5zVXJsLCAnL3hocicsIFhoclJlY2VpdmVyLCBYSFJDb3JzT2JqZWN0KTtcbn1cblxuaW5oZXJpdHMoWGhyUG9sbGluZ1RyYW5zcG9ydCwgQWpheEJhc2VkVHJhbnNwb3J0KTtcblxuWGhyUG9sbGluZ1RyYW5zcG9ydC5lbmFibGVkID0gZnVuY3Rpb24oaW5mbykge1xuICBpZiAoaW5mby5udWxsT3JpZ2luKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgaWYgKFhIUkxvY2FsT2JqZWN0LmVuYWJsZWQgJiYgaW5mby5zYW1lT3JpZ2luKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgcmV0dXJuIFhIUkNvcnNPYmplY3QuZW5hYmxlZDtcbn07XG5cblhoclBvbGxpbmdUcmFuc3BvcnQudHJhbnNwb3J0TmFtZSA9ICd4aHItcG9sbGluZyc7XG5YaHJQb2xsaW5nVHJhbnNwb3J0LnJvdW5kVHJpcHMgPSAyOyAvLyBwcmVmbGlnaHQsIGFqYXhcblxubW9kdWxlLmV4cG9ydHMgPSBYaHJQb2xsaW5nVHJhbnNwb3J0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5oZXJpdHMgPSByZXF1aXJlKCdpbmhlcml0cycpXG4gICwgQWpheEJhc2VkVHJhbnNwb3J0ID0gcmVxdWlyZSgnLi9saWIvYWpheC1iYXNlZCcpXG4gICwgWGhyUmVjZWl2ZXIgPSByZXF1aXJlKCcuL3JlY2VpdmVyL3hocicpXG4gICwgWEhSQ29yc09iamVjdCA9IHJlcXVpcmUoJy4vc2VuZGVyL3hoci1jb3JzJylcbiAgLCBYSFJMb2NhbE9iamVjdCA9IHJlcXVpcmUoJy4vc2VuZGVyL3hoci1sb2NhbCcpXG4gICwgYnJvd3NlciA9IHJlcXVpcmUoJy4uL3V0aWxzL2Jyb3dzZXInKVxuICA7XG5cbmZ1bmN0aW9uIFhoclN0cmVhbWluZ1RyYW5zcG9ydCh0cmFuc1VybCkge1xuICBpZiAoIVhIUkxvY2FsT2JqZWN0LmVuYWJsZWQgJiYgIVhIUkNvcnNPYmplY3QuZW5hYmxlZCkge1xuICAgIHRocm93IG5ldyBFcnJvcignVHJhbnNwb3J0IGNyZWF0ZWQgd2hlbiBkaXNhYmxlZCcpO1xuICB9XG4gIEFqYXhCYXNlZFRyYW5zcG9ydC5jYWxsKHRoaXMsIHRyYW5zVXJsLCAnL3hocl9zdHJlYW1pbmcnLCBYaHJSZWNlaXZlciwgWEhSQ29yc09iamVjdCk7XG59XG5cbmluaGVyaXRzKFhoclN0cmVhbWluZ1RyYW5zcG9ydCwgQWpheEJhc2VkVHJhbnNwb3J0KTtcblxuWGhyU3RyZWFtaW5nVHJhbnNwb3J0LmVuYWJsZWQgPSBmdW5jdGlvbihpbmZvKSB7XG4gIGlmIChpbmZvLm51bGxPcmlnaW4pIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgLy8gT3BlcmEgZG9lc24ndCBzdXBwb3J0IHhoci1zdHJlYW1pbmcgIzYwXG4gIC8vIEJ1dCBpdCBtaWdodCBiZSBhYmxlIHRvICM5MlxuICBpZiAoYnJvd3Nlci5pc09wZXJhKCkpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICByZXR1cm4gWEhSQ29yc09iamVjdC5lbmFibGVkO1xufTtcblxuWGhyU3RyZWFtaW5nVHJhbnNwb3J0LnRyYW5zcG9ydE5hbWUgPSAneGhyLXN0cmVhbWluZyc7XG5YaHJTdHJlYW1pbmdUcmFuc3BvcnQucm91bmRUcmlwcyA9IDI7IC8vIHByZWZsaWdodCwgYWpheFxuXG4vLyBTYWZhcmkgZ2V0cyBjb25mdXNlZCB3aGVuIGEgc3RyZWFtaW5nIGFqYXggcmVxdWVzdCBpcyBzdGFydGVkXG4vLyBiZWZvcmUgb25sb2FkLiBUaGlzIGNhdXNlcyB0aGUgbG9hZCBpbmRpY2F0b3IgdG8gc3BpbiBpbmRlZmluZXRlbHkuXG4vLyBPbmx5IHJlcXVpcmUgYm9keSB3aGVuIHVzZWQgaW4gYSBicm93c2VyXG5YaHJTdHJlYW1pbmdUcmFuc3BvcnQubmVlZEJvZHkgPSAhIWdsb2JhbC5kb2N1bWVudDtcblxubW9kdWxlLmV4cG9ydHMgPSBYaHJTdHJlYW1pbmdUcmFuc3BvcnQ7XG4iLCIndXNlIHN0cmljdCc7XG5cbmlmIChnbG9iYWwuY3J5cHRvICYmIGdsb2JhbC5jcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKSB7XG4gIG1vZHVsZS5leHBvcnRzLnJhbmRvbUJ5dGVzID0gZnVuY3Rpb24obGVuZ3RoKSB7XG4gICAgdmFyIGJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkobGVuZ3RoKTtcbiAgICBnbG9iYWwuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhieXRlcyk7XG4gICAgcmV0dXJuIGJ5dGVzO1xuICB9O1xufSBlbHNlIHtcbiAgbW9kdWxlLmV4cG9ydHMucmFuZG9tQnl0ZXMgPSBmdW5jdGlvbihsZW5ndGgpIHtcbiAgICB2YXIgYnl0ZXMgPSBuZXcgQXJyYXkobGVuZ3RoKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICBieXRlc1tpXSA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDI1Nik7XG4gICAgfVxuICAgIHJldHVybiBieXRlcztcbiAgfTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGlzT3BlcmE6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBnbG9iYWwubmF2aWdhdG9yICYmXG4gICAgICAvb3BlcmEvaS50ZXN0KGdsb2JhbC5uYXZpZ2F0b3IudXNlckFnZW50KTtcbiAgfVxuXG4sIGlzS29ucXVlcm9yOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gZ2xvYmFsLm5hdmlnYXRvciAmJlxuICAgICAgL2tvbnF1ZXJvci9pLnRlc3QoZ2xvYmFsLm5hdmlnYXRvci51c2VyQWdlbnQpO1xuICB9XG5cbiAgLy8gIzE4NyB3cmFwIGRvY3VtZW50LmRvbWFpbiBpbiB0cnkvY2F0Y2ggYmVjYXVzZSBvZiBXUDggZnJvbSBmaWxlOi8vL1xuLCBoYXNEb21haW46IGZ1bmN0aW9uICgpIHtcbiAgICAvLyBub24tYnJvd3NlciBjbGllbnQgYWx3YXlzIGhhcyBhIGRvbWFpblxuICAgIGlmICghZ2xvYmFsLmRvY3VtZW50KSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgcmV0dXJuICEhZ2xvYmFsLmRvY3VtZW50LmRvbWFpbjtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgSlNPTjMgPSByZXF1aXJlKCdqc29uMycpO1xuXG4vLyBTb21lIGV4dHJhIGNoYXJhY3RlcnMgdGhhdCBDaHJvbWUgZ2V0cyB3cm9uZywgYW5kIHN1YnN0aXR1dGVzIHdpdGhcbi8vIHNvbWV0aGluZyBlbHNlIG9uIHRoZSB3aXJlLlxudmFyIGV4dHJhRXNjYXBhYmxlID0gL1tcXHgwMC1cXHgxZlxcdWQ4MDAtXFx1ZGZmZlxcdWZmZmVcXHVmZmZmXFx1MDMwMC1cXHUwMzMzXFx1MDMzZC1cXHUwMzQ2XFx1MDM0YS1cXHUwMzRjXFx1MDM1MC1cXHUwMzUyXFx1MDM1Ny1cXHUwMzU4XFx1MDM1Yy1cXHUwMzYyXFx1MDM3NFxcdTAzN2VcXHUwMzg3XFx1MDU5MS1cXHUwNWFmXFx1MDVjNFxcdTA2MTAtXFx1MDYxN1xcdTA2NTMtXFx1MDY1NFxcdTA2NTctXFx1MDY1YlxcdTA2NWQtXFx1MDY1ZVxcdTA2ZGYtXFx1MDZlMlxcdTA2ZWItXFx1MDZlY1xcdTA3MzBcXHUwNzMyLVxcdTA3MzNcXHUwNzM1LVxcdTA3MzZcXHUwNzNhXFx1MDczZFxcdTA3M2YtXFx1MDc0MVxcdTA3NDNcXHUwNzQ1XFx1MDc0N1xcdTA3ZWItXFx1MDdmMVxcdTA5NTFcXHUwOTU4LVxcdTA5NWZcXHUwOWRjLVxcdTA5ZGRcXHUwOWRmXFx1MGEzM1xcdTBhMzZcXHUwYTU5LVxcdTBhNWJcXHUwYTVlXFx1MGI1Yy1cXHUwYjVkXFx1MGUzOC1cXHUwZTM5XFx1MGY0M1xcdTBmNGRcXHUwZjUyXFx1MGY1N1xcdTBmNWNcXHUwZjY5XFx1MGY3Mi1cXHUwZjc2XFx1MGY3OFxcdTBmODAtXFx1MGY4M1xcdTBmOTNcXHUwZjlkXFx1MGZhMlxcdTBmYTdcXHUwZmFjXFx1MGZiOVxcdTE5MzktXFx1MTkzYVxcdTFhMTdcXHUxYjZiXFx1MWNkYS1cXHUxY2RiXFx1MWRjMC1cXHUxZGNmXFx1MWRmY1xcdTFkZmVcXHUxZjcxXFx1MWY3M1xcdTFmNzVcXHUxZjc3XFx1MWY3OVxcdTFmN2JcXHUxZjdkXFx1MWZiYlxcdTFmYmVcXHUxZmM5XFx1MWZjYlxcdTFmZDNcXHUxZmRiXFx1MWZlM1xcdTFmZWJcXHUxZmVlLVxcdTFmZWZcXHUxZmY5XFx1MWZmYlxcdTFmZmRcXHUyMDAwLVxcdTIwMDFcXHUyMGQwLVxcdTIwZDFcXHUyMGQ0LVxcdTIwZDdcXHUyMGU3LVxcdTIwZTlcXHUyMTI2XFx1MjEyYS1cXHUyMTJiXFx1MjMyOS1cXHUyMzJhXFx1MmFkY1xcdTMwMmItXFx1MzAyY1xcdWFhYjItXFx1YWFiM1xcdWY5MDAtXFx1ZmEwZFxcdWZhMTBcXHVmYTEyXFx1ZmExNS1cXHVmYTFlXFx1ZmEyMFxcdWZhMjJcXHVmYTI1LVxcdWZhMjZcXHVmYTJhLVxcdWZhMmRcXHVmYTMwLVxcdWZhNmRcXHVmYTcwLVxcdWZhZDlcXHVmYjFkXFx1ZmIxZlxcdWZiMmEtXFx1ZmIzNlxcdWZiMzgtXFx1ZmIzY1xcdWZiM2VcXHVmYjQwLVxcdWZiNDFcXHVmYjQzLVxcdWZiNDRcXHVmYjQ2LVxcdWZiNGVcXHVmZmYwLVxcdWZmZmZdL2dcbiAgLCBleHRyYUxvb2t1cDtcblxuLy8gVGhpcyBtYXkgYmUgcXVpdGUgc2xvdywgc28gbGV0J3MgZGVsYXkgdW50aWwgdXNlciBhY3R1YWxseSB1c2VzIGJhZFxuLy8gY2hhcmFjdGVycy5cbnZhciB1bnJvbGxMb29rdXAgPSBmdW5jdGlvbihlc2NhcGFibGUpIHtcbiAgdmFyIGk7XG4gIHZhciB1bnJvbGxlZCA9IHt9O1xuICB2YXIgYyA9IFtdO1xuICBmb3IgKGkgPSAwOyBpIDwgNjU1MzY7IGkrKykge1xuICAgIGMucHVzaCggU3RyaW5nLmZyb21DaGFyQ29kZShpKSApO1xuICB9XG4gIGVzY2FwYWJsZS5sYXN0SW5kZXggPSAwO1xuICBjLmpvaW4oJycpLnJlcGxhY2UoZXNjYXBhYmxlLCBmdW5jdGlvbihhKSB7XG4gICAgdW5yb2xsZWRbIGEgXSA9ICdcXFxcdScgKyAoJzAwMDAnICsgYS5jaGFyQ29kZUF0KDApLnRvU3RyaW5nKDE2KSkuc2xpY2UoLTQpO1xuICAgIHJldHVybiAnJztcbiAgfSk7XG4gIGVzY2FwYWJsZS5sYXN0SW5kZXggPSAwO1xuICByZXR1cm4gdW5yb2xsZWQ7XG59O1xuXG4vLyBRdW90ZSBzdHJpbmcsIGFsc28gdGFraW5nIGNhcmUgb2YgdW5pY29kZSBjaGFyYWN0ZXJzIHRoYXQgYnJvd3NlcnNcbi8vIG9mdGVuIGJyZWFrLiBFc3BlY2lhbGx5LCB0YWtlIGNhcmUgb2YgdW5pY29kZSBzdXJyb2dhdGVzOlxuLy8gaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9NYXBwaW5nX29mX1VuaWNvZGVfY2hhcmFjdGVycyNTdXJyb2dhdGVzXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgcXVvdGU6IGZ1bmN0aW9uKHN0cmluZykge1xuICAgIHZhciBxdW90ZWQgPSBKU09OMy5zdHJpbmdpZnkoc3RyaW5nKTtcblxuICAgIC8vIEluIG1vc3QgY2FzZXMgdGhpcyBzaG91bGQgYmUgdmVyeSBmYXN0IGFuZCBnb29kIGVub3VnaC5cbiAgICBleHRyYUVzY2FwYWJsZS5sYXN0SW5kZXggPSAwO1xuICAgIGlmICghZXh0cmFFc2NhcGFibGUudGVzdChxdW90ZWQpKSB7XG4gICAgICByZXR1cm4gcXVvdGVkO1xuICAgIH1cblxuICAgIGlmICghZXh0cmFMb29rdXApIHtcbiAgICAgIGV4dHJhTG9va3VwID0gdW5yb2xsTG9va3VwKGV4dHJhRXNjYXBhYmxlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcXVvdGVkLnJlcGxhY2UoZXh0cmFFc2NhcGFibGUsIGZ1bmN0aW9uKGEpIHtcbiAgICAgIHJldHVybiBleHRyYUxvb2t1cFthXTtcbiAgICB9KTtcbiAgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHJhbmRvbSA9IHJlcXVpcmUoJy4vcmFuZG9tJyk7XG5cbnZhciBvblVubG9hZCA9IHt9XG4gICwgYWZ0ZXJVbmxvYWQgPSBmYWxzZVxuICAgIC8vIGRldGVjdCBnb29nbGUgY2hyb21lIHBhY2thZ2VkIGFwcHMgYmVjYXVzZSB0aGV5IGRvbid0IGFsbG93IHRoZSAndW5sb2FkJyBldmVudFxuICAsIGlzQ2hyb21lUGFja2FnZWRBcHAgPSBnbG9iYWwuY2hyb21lICYmIGdsb2JhbC5jaHJvbWUuYXBwICYmIGdsb2JhbC5jaHJvbWUuYXBwLnJ1bnRpbWVcbiAgO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgYXR0YWNoRXZlbnQ6IGZ1bmN0aW9uKGV2ZW50LCBsaXN0ZW5lcikge1xuICAgIGlmICh0eXBlb2YgZ2xvYmFsLmFkZEV2ZW50TGlzdGVuZXIgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICBnbG9iYWwuYWRkRXZlbnRMaXN0ZW5lcihldmVudCwgbGlzdGVuZXIsIGZhbHNlKTtcbiAgICB9IGVsc2UgaWYgKGdsb2JhbC5kb2N1bWVudCAmJiBnbG9iYWwuYXR0YWNoRXZlbnQpIHtcbiAgICAgIC8vIElFIHF1aXJrcy5cbiAgICAgIC8vIEFjY29yZGluZyB0bzogaHR0cDovL3N0ZXZlc291ZGVycy5jb20vbWlzYy90ZXN0LXBvc3RtZXNzYWdlLnBocFxuICAgICAgLy8gdGhlIG1lc3NhZ2UgZ2V0cyBkZWxpdmVyZWQgb25seSB0byAnZG9jdW1lbnQnLCBub3QgJ3dpbmRvdycuXG4gICAgICBnbG9iYWwuZG9jdW1lbnQuYXR0YWNoRXZlbnQoJ29uJyArIGV2ZW50LCBsaXN0ZW5lcik7XG4gICAgICAvLyBJIGdldCAnd2luZG93JyBmb3IgaWU4LlxuICAgICAgZ2xvYmFsLmF0dGFjaEV2ZW50KCdvbicgKyBldmVudCwgbGlzdGVuZXIpO1xuICAgIH1cbiAgfVxuXG4sIGRldGFjaEV2ZW50OiBmdW5jdGlvbihldmVudCwgbGlzdGVuZXIpIHtcbiAgICBpZiAodHlwZW9mIGdsb2JhbC5hZGRFdmVudExpc3RlbmVyICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgZ2xvYmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVyLCBmYWxzZSk7XG4gICAgfSBlbHNlIGlmIChnbG9iYWwuZG9jdW1lbnQgJiYgZ2xvYmFsLmRldGFjaEV2ZW50KSB7XG4gICAgICBnbG9iYWwuZG9jdW1lbnQuZGV0YWNoRXZlbnQoJ29uJyArIGV2ZW50LCBsaXN0ZW5lcik7XG4gICAgICBnbG9iYWwuZGV0YWNoRXZlbnQoJ29uJyArIGV2ZW50LCBsaXN0ZW5lcik7XG4gICAgfVxuICB9XG5cbiwgdW5sb2FkQWRkOiBmdW5jdGlvbihsaXN0ZW5lcikge1xuICAgIGlmIChpc0Nocm9tZVBhY2thZ2VkQXBwKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgcmVmID0gcmFuZG9tLnN0cmluZyg4KTtcbiAgICBvblVubG9hZFtyZWZdID0gbGlzdGVuZXI7XG4gICAgaWYgKGFmdGVyVW5sb2FkKSB7XG4gICAgICBzZXRUaW1lb3V0KHRoaXMudHJpZ2dlclVubG9hZENhbGxiYWNrcywgMCk7XG4gICAgfVxuICAgIHJldHVybiByZWY7XG4gIH1cblxuLCB1bmxvYWREZWw6IGZ1bmN0aW9uKHJlZikge1xuICAgIGlmIChyZWYgaW4gb25VbmxvYWQpIHtcbiAgICAgIGRlbGV0ZSBvblVubG9hZFtyZWZdO1xuICAgIH1cbiAgfVxuXG4sIHRyaWdnZXJVbmxvYWRDYWxsYmFja3M6IGZ1bmN0aW9uKCkge1xuICAgIGZvciAodmFyIHJlZiBpbiBvblVubG9hZCkge1xuICAgICAgb25VbmxvYWRbcmVmXSgpO1xuICAgICAgZGVsZXRlIG9uVW5sb2FkW3JlZl07XG4gICAgfVxuICB9XG59O1xuXG52YXIgdW5sb2FkVHJpZ2dlcmVkID0gZnVuY3Rpb24oKSB7XG4gIGlmIChhZnRlclVubG9hZCkge1xuICAgIHJldHVybjtcbiAgfVxuICBhZnRlclVubG9hZCA9IHRydWU7XG4gIG1vZHVsZS5leHBvcnRzLnRyaWdnZXJVbmxvYWRDYWxsYmFja3MoKTtcbn07XG5cbi8vICd1bmxvYWQnIGFsb25lIGlzIG5vdCByZWxpYWJsZSBpbiBvcGVyYSB3aXRoaW4gYW4gaWZyYW1lLCBidXQgd2Vcbi8vIGNhbid0IHVzZSBgYmVmb3JldW5sb2FkYCBhcyBJRSBmaXJlcyBpdCBvbiBqYXZhc2NyaXB0OiBsaW5rcy5cbmlmICghaXNDaHJvbWVQYWNrYWdlZEFwcCkge1xuICBtb2R1bGUuZXhwb3J0cy5hdHRhY2hFdmVudCgndW5sb2FkJywgdW5sb2FkVHJpZ2dlcmVkKTtcbn1cbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGV2ZW50VXRpbHMgPSByZXF1aXJlKCcuL2V2ZW50JylcbiAgLCBKU09OMyA9IHJlcXVpcmUoJ2pzb24zJylcbiAgLCBicm93c2VyID0gcmVxdWlyZSgnLi9icm93c2VyJylcbiAgO1xuXG52YXIgZGVidWcgPSBmdW5jdGlvbigpIHt9O1xuaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgZGVidWcgPSByZXF1aXJlKCdkZWJ1ZycpKCdzb2NranMtY2xpZW50OnV0aWxzOmlmcmFtZScpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgV1ByZWZpeDogJ19qcCdcbiwgY3VycmVudFdpbmRvd0lkOiBudWxsXG5cbiwgcG9sbHV0ZUdsb2JhbE5hbWVzcGFjZTogZnVuY3Rpb24oKSB7XG4gICAgaWYgKCEobW9kdWxlLmV4cG9ydHMuV1ByZWZpeCBpbiBnbG9iYWwpKSB7XG4gICAgICBnbG9iYWxbbW9kdWxlLmV4cG9ydHMuV1ByZWZpeF0gPSB7fTtcbiAgICB9XG4gIH1cblxuLCBwb3N0TWVzc2FnZTogZnVuY3Rpb24odHlwZSwgZGF0YSkge1xuICAgIGlmIChnbG9iYWwucGFyZW50ICE9PSBnbG9iYWwpIHtcbiAgICAgIGdsb2JhbC5wYXJlbnQucG9zdE1lc3NhZ2UoSlNPTjMuc3RyaW5naWZ5KHtcbiAgICAgICAgd2luZG93SWQ6IG1vZHVsZS5leHBvcnRzLmN1cnJlbnRXaW5kb3dJZFxuICAgICAgLCB0eXBlOiB0eXBlXG4gICAgICAsIGRhdGE6IGRhdGEgfHwgJydcbiAgICAgIH0pLCAnKicpO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWJ1ZygnQ2Fubm90IHBvc3RNZXNzYWdlLCBubyBwYXJlbnQgd2luZG93LicsIHR5cGUsIGRhdGEpO1xuICAgIH1cbiAgfVxuXG4sIGNyZWF0ZUlmcmFtZTogZnVuY3Rpb24oaWZyYW1lVXJsLCBlcnJvckNhbGxiYWNrKSB7XG4gICAgdmFyIGlmcmFtZSA9IGdsb2JhbC5kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpZnJhbWUnKTtcbiAgICB2YXIgdHJlZiwgdW5sb2FkUmVmO1xuICAgIHZhciB1bmF0dGFjaCA9IGZ1bmN0aW9uKCkge1xuICAgICAgZGVidWcoJ3VuYXR0YWNoJyk7XG4gICAgICBjbGVhclRpbWVvdXQodHJlZik7XG4gICAgICAvLyBFeHBsb3JlciBoYWQgcHJvYmxlbXMgd2l0aCB0aGF0LlxuICAgICAgdHJ5IHtcbiAgICAgICAgaWZyYW1lLm9ubG9hZCA9IG51bGw7XG4gICAgICB9IGNhdGNoICh4KSB7XG4gICAgICAgIC8vIGludGVudGlvbmFsbHkgZW1wdHlcbiAgICAgIH1cbiAgICAgIGlmcmFtZS5vbmVycm9yID0gbnVsbDtcbiAgICB9O1xuICAgIHZhciBjbGVhbnVwID0gZnVuY3Rpb24oKSB7XG4gICAgICBkZWJ1ZygnY2xlYW51cCcpO1xuICAgICAgaWYgKGlmcmFtZSkge1xuICAgICAgICB1bmF0dGFjaCgpO1xuICAgICAgICAvLyBUaGlzIHRpbWVvdXQgbWFrZXMgY2hyb21lIGZpcmUgb25iZWZvcmV1bmxvYWQgZXZlbnRcbiAgICAgICAgLy8gd2l0aGluIGlmcmFtZS4gV2l0aG91dCB0aGUgdGltZW91dCBpdCBnb2VzIHN0cmFpZ2h0IHRvXG4gICAgICAgIC8vIG9udW5sb2FkLlxuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgIGlmIChpZnJhbWUpIHtcbiAgICAgICAgICAgIGlmcmFtZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGlmcmFtZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmcmFtZSA9IG51bGw7XG4gICAgICAgIH0sIDApO1xuICAgICAgICBldmVudFV0aWxzLnVubG9hZERlbCh1bmxvYWRSZWYpO1xuICAgICAgfVxuICAgIH07XG4gICAgdmFyIG9uZXJyb3IgPSBmdW5jdGlvbihlcnIpIHtcbiAgICAgIGRlYnVnKCdvbmVycm9yJywgZXJyKTtcbiAgICAgIGlmIChpZnJhbWUpIHtcbiAgICAgICAgY2xlYW51cCgpO1xuICAgICAgICBlcnJvckNhbGxiYWNrKGVycik7XG4gICAgICB9XG4gICAgfTtcbiAgICB2YXIgcG9zdCA9IGZ1bmN0aW9uKG1zZywgb3JpZ2luKSB7XG4gICAgICBkZWJ1ZygncG9zdCcsIG1zZywgb3JpZ2luKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIFdoZW4gdGhlIGlmcmFtZSBpcyBub3QgbG9hZGVkLCBJRSByYWlzZXMgYW4gZXhjZXB0aW9uXG4gICAgICAgIC8vIG9uICdjb250ZW50V2luZG93Jy5cbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICBpZiAoaWZyYW1lICYmIGlmcmFtZS5jb250ZW50V2luZG93KSB7XG4gICAgICAgICAgICBpZnJhbWUuY29udGVudFdpbmRvdy5wb3N0TWVzc2FnZShtc2csIG9yaWdpbik7XG4gICAgICAgICAgfVxuICAgICAgICB9LCAwKTtcbiAgICAgIH0gY2F0Y2ggKHgpIHtcbiAgICAgICAgLy8gaW50ZW50aW9uYWxseSBlbXB0eVxuICAgICAgfVxuICAgIH07XG5cbiAgICBpZnJhbWUuc3JjID0gaWZyYW1lVXJsO1xuICAgIGlmcmFtZS5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgIGlmcmFtZS5zdHlsZS5wb3NpdGlvbiA9ICdhYnNvbHV0ZSc7XG4gICAgaWZyYW1lLm9uZXJyb3IgPSBmdW5jdGlvbigpIHtcbiAgICAgIG9uZXJyb3IoJ29uZXJyb3InKTtcbiAgICB9O1xuICAgIGlmcmFtZS5vbmxvYWQgPSBmdW5jdGlvbigpIHtcbiAgICAgIGRlYnVnKCdvbmxvYWQnKTtcbiAgICAgIC8vIGBvbmxvYWRgIGlzIHRyaWdnZXJlZCBiZWZvcmUgc2NyaXB0cyBvbiB0aGUgaWZyYW1lIGFyZVxuICAgICAgLy8gZXhlY3V0ZWQuIEdpdmUgaXQgZmV3IHNlY29uZHMgdG8gYWN0dWFsbHkgbG9hZCBzdHVmZi5cbiAgICAgIGNsZWFyVGltZW91dCh0cmVmKTtcbiAgICAgIHRyZWYgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICBvbmVycm9yKCdvbmxvYWQgdGltZW91dCcpO1xuICAgICAgfSwgMjAwMCk7XG4gICAgfTtcbiAgICBnbG9iYWwuZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChpZnJhbWUpO1xuICAgIHRyZWYgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgb25lcnJvcigndGltZW91dCcpO1xuICAgIH0sIDE1MDAwKTtcbiAgICB1bmxvYWRSZWYgPSBldmVudFV0aWxzLnVubG9hZEFkZChjbGVhbnVwKTtcbiAgICByZXR1cm4ge1xuICAgICAgcG9zdDogcG9zdFxuICAgICwgY2xlYW51cDogY2xlYW51cFxuICAgICwgbG9hZGVkOiB1bmF0dGFjaFxuICAgIH07XG4gIH1cblxuLyoganNoaW50IHVuZGVmOiBmYWxzZSwgbmV3Y2FwOiBmYWxzZSAqL1xuLyogZXNsaW50IG5vLXVuZGVmOiAwLCBuZXctY2FwOiAwICovXG4sIGNyZWF0ZUh0bWxmaWxlOiBmdW5jdGlvbihpZnJhbWVVcmwsIGVycm9yQ2FsbGJhY2spIHtcbiAgICB2YXIgYXhvID0gWydBY3RpdmUnXS5jb25jYXQoJ09iamVjdCcpLmpvaW4oJ1gnKTtcbiAgICB2YXIgZG9jID0gbmV3IGdsb2JhbFtheG9dKCdodG1sZmlsZScpO1xuICAgIHZhciB0cmVmLCB1bmxvYWRSZWY7XG4gICAgdmFyIGlmcmFtZTtcbiAgICB2YXIgdW5hdHRhY2ggPSBmdW5jdGlvbigpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0cmVmKTtcbiAgICAgIGlmcmFtZS5vbmVycm9yID0gbnVsbDtcbiAgICB9O1xuICAgIHZhciBjbGVhbnVwID0gZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoZG9jKSB7XG4gICAgICAgIHVuYXR0YWNoKCk7XG4gICAgICAgIGV2ZW50VXRpbHMudW5sb2FkRGVsKHVubG9hZFJlZik7XG4gICAgICAgIGlmcmFtZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGlmcmFtZSk7XG4gICAgICAgIGlmcmFtZSA9IGRvYyA9IG51bGw7XG4gICAgICAgIENvbGxlY3RHYXJiYWdlKCk7XG4gICAgICB9XG4gICAgfTtcbiAgICB2YXIgb25lcnJvciA9IGZ1bmN0aW9uKHIpIHtcbiAgICAgIGRlYnVnKCdvbmVycm9yJywgcik7XG4gICAgICBpZiAoZG9jKSB7XG4gICAgICAgIGNsZWFudXAoKTtcbiAgICAgICAgZXJyb3JDYWxsYmFjayhyKTtcbiAgICAgIH1cbiAgICB9O1xuICAgIHZhciBwb3N0ID0gZnVuY3Rpb24obXNnLCBvcmlnaW4pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIFdoZW4gdGhlIGlmcmFtZSBpcyBub3QgbG9hZGVkLCBJRSByYWlzZXMgYW4gZXhjZXB0aW9uXG4gICAgICAgIC8vIG9uICdjb250ZW50V2luZG93Jy5cbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICBpZiAoaWZyYW1lICYmIGlmcmFtZS5jb250ZW50V2luZG93KSB7XG4gICAgICAgICAgICAgIGlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKG1zZywgb3JpZ2luKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sIDApO1xuICAgICAgfSBjYXRjaCAoeCkge1xuICAgICAgICAvLyBpbnRlbnRpb25hbGx5IGVtcHR5XG4gICAgICB9XG4gICAgfTtcblxuICAgIGRvYy5vcGVuKCk7XG4gICAgZG9jLndyaXRlKCc8aHRtbD48cycgKyAnY3JpcHQ+JyArXG4gICAgICAgICAgICAgICdkb2N1bWVudC5kb21haW49XCInICsgZ2xvYmFsLmRvY3VtZW50LmRvbWFpbiArICdcIjsnICtcbiAgICAgICAgICAgICAgJzwvcycgKyAnY3JpcHQ+PC9odG1sPicpO1xuICAgIGRvYy5jbG9zZSgpO1xuICAgIGRvYy5wYXJlbnRXaW5kb3dbbW9kdWxlLmV4cG9ydHMuV1ByZWZpeF0gPSBnbG9iYWxbbW9kdWxlLmV4cG9ydHMuV1ByZWZpeF07XG4gICAgdmFyIGMgPSBkb2MuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgZG9jLmJvZHkuYXBwZW5kQ2hpbGQoYyk7XG4gICAgaWZyYW1lID0gZG9jLmNyZWF0ZUVsZW1lbnQoJ2lmcmFtZScpO1xuICAgIGMuYXBwZW5kQ2hpbGQoaWZyYW1lKTtcbiAgICBpZnJhbWUuc3JjID0gaWZyYW1lVXJsO1xuICAgIGlmcmFtZS5vbmVycm9yID0gZnVuY3Rpb24oKSB7XG4gICAgICBvbmVycm9yKCdvbmVycm9yJyk7XG4gICAgfTtcbiAgICB0cmVmID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgIG9uZXJyb3IoJ3RpbWVvdXQnKTtcbiAgICB9LCAxNTAwMCk7XG4gICAgdW5sb2FkUmVmID0gZXZlbnRVdGlscy51bmxvYWRBZGQoY2xlYW51cCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHBvc3Q6IHBvc3RcbiAgICAsIGNsZWFudXA6IGNsZWFudXBcbiAgICAsIGxvYWRlZDogdW5hdHRhY2hcbiAgICB9O1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cy5pZnJhbWVFbmFibGVkID0gZmFsc2U7XG5pZiAoZ2xvYmFsLmRvY3VtZW50KSB7XG4gIC8vIHBvc3RNZXNzYWdlIG1pc2JlaGF2ZXMgaW4ga29ucXVlcm9yIDQuNi41IC0gdGhlIG1lc3NhZ2VzIGFyZSBkZWxpdmVyZWQgd2l0aFxuICAvLyBodWdlIGRlbGF5LCBvciBub3QgYXQgYWxsLlxuICBtb2R1bGUuZXhwb3J0cy5pZnJhbWVFbmFibGVkID0gKHR5cGVvZiBnbG9iYWwucG9zdE1lc3NhZ2UgPT09ICdmdW5jdGlvbicgfHxcbiAgICB0eXBlb2YgZ2xvYmFsLnBvc3RNZXNzYWdlID09PSAnb2JqZWN0JykgJiYgKCFicm93c2VyLmlzS29ucXVlcm9yKCkpO1xufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgbG9nT2JqZWN0ID0ge307XG5bJ2xvZycsICdkZWJ1ZycsICd3YXJuJ10uZm9yRWFjaChmdW5jdGlvbiAobGV2ZWwpIHtcbiAgdmFyIGxldmVsRXhpc3RzO1xuXG4gIHRyeSB7XG4gICAgbGV2ZWxFeGlzdHMgPSBnbG9iYWwuY29uc29sZSAmJiBnbG9iYWwuY29uc29sZVtsZXZlbF0gJiYgZ2xvYmFsLmNvbnNvbGVbbGV2ZWxdLmFwcGx5O1xuICB9IGNhdGNoKGUpIHtcbiAgICAvLyBkbyBub3RoaW5nXG4gIH1cblxuICBsb2dPYmplY3RbbGV2ZWxdID0gbGV2ZWxFeGlzdHMgPyBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIGdsb2JhbC5jb25zb2xlW2xldmVsXS5hcHBseShnbG9iYWwuY29uc29sZSwgYXJndW1lbnRzKTtcbiAgfSA6IChsZXZlbCA9PT0gJ2xvZycgPyBmdW5jdGlvbiAoKSB7fSA6IGxvZ09iamVjdC5sb2cpO1xufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gbG9nT2JqZWN0O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgaXNPYmplY3Q6IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciB0eXBlID0gdHlwZW9mIG9iajtcbiAgICByZXR1cm4gdHlwZSA9PT0gJ2Z1bmN0aW9uJyB8fCB0eXBlID09PSAnb2JqZWN0JyAmJiAhIW9iajtcbiAgfVxuXG4sIGV4dGVuZDogZnVuY3Rpb24ob2JqKSB7XG4gICAgaWYgKCF0aGlzLmlzT2JqZWN0KG9iaikpIHtcbiAgICAgIHJldHVybiBvYmo7XG4gICAgfVxuICAgIHZhciBzb3VyY2UsIHByb3A7XG4gICAgZm9yICh2YXIgaSA9IDEsIGxlbmd0aCA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgc291cmNlID0gYXJndW1lbnRzW2ldO1xuICAgICAgZm9yIChwcm9wIGluIHNvdXJjZSkge1xuICAgICAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHNvdXJjZSwgcHJvcCkpIHtcbiAgICAgICAgICBvYmpbcHJvcF0gPSBzb3VyY2VbcHJvcF07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG9iajtcbiAgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLyogZ2xvYmFsIGNyeXB0bzp0cnVlICovXG52YXIgY3J5cHRvID0gcmVxdWlyZSgnY3J5cHRvJyk7XG5cbi8vIFRoaXMgc3RyaW5nIGhhcyBsZW5ndGggMzIsIGEgcG93ZXIgb2YgMiwgc28gdGhlIG1vZHVsdXMgZG9lc24ndCBpbnRyb2R1Y2UgYVxuLy8gYmlhcy5cbnZhciBfcmFuZG9tU3RyaW5nQ2hhcnMgPSAnYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDUnO1xubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHN0cmluZzogZnVuY3Rpb24obGVuZ3RoKSB7XG4gICAgdmFyIG1heCA9IF9yYW5kb21TdHJpbmdDaGFycy5sZW5ndGg7XG4gICAgdmFyIGJ5dGVzID0gY3J5cHRvLnJhbmRvbUJ5dGVzKGxlbmd0aCk7XG4gICAgdmFyIHJldCA9IFtdO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHJldC5wdXNoKF9yYW5kb21TdHJpbmdDaGFycy5zdWJzdHIoYnl0ZXNbaV0gJSBtYXgsIDEpKTtcbiAgICB9XG4gICAgcmV0dXJuIHJldC5qb2luKCcnKTtcbiAgfVxuXG4sIG51bWJlcjogZnVuY3Rpb24obWF4KSB7XG4gICAgcmV0dXJuIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIG1heCk7XG4gIH1cblxuLCBudW1iZXJTdHJpbmc6IGZ1bmN0aW9uKG1heCkge1xuICAgIHZhciB0ID0gKCcnICsgKG1heCAtIDEpKS5sZW5ndGg7XG4gICAgdmFyIHAgPSBuZXcgQXJyYXkodCArIDEpLmpvaW4oJzAnKTtcbiAgICByZXR1cm4gKHAgKyB0aGlzLm51bWJlcihtYXgpKS5zbGljZSgtdCk7XG4gIH1cbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBkZWJ1ZyA9IGZ1bmN0aW9uKCkge307XG5pZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICBkZWJ1ZyA9IHJlcXVpcmUoJ2RlYnVnJykoJ3NvY2tqcy1jbGllbnQ6dXRpbHM6dHJhbnNwb3J0Jyk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oYXZhaWxhYmxlVHJhbnNwb3J0cykge1xuICByZXR1cm4ge1xuICAgIGZpbHRlclRvRW5hYmxlZDogZnVuY3Rpb24odHJhbnNwb3J0c1doaXRlbGlzdCwgaW5mbykge1xuICAgICAgdmFyIHRyYW5zcG9ydHMgPSB7XG4gICAgICAgIG1haW46IFtdXG4gICAgICAsIGZhY2FkZTogW11cbiAgICAgIH07XG4gICAgICBpZiAoIXRyYW5zcG9ydHNXaGl0ZWxpc3QpIHtcbiAgICAgICAgdHJhbnNwb3J0c1doaXRlbGlzdCA9IFtdO1xuICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdHJhbnNwb3J0c1doaXRlbGlzdCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgdHJhbnNwb3J0c1doaXRlbGlzdCA9IFt0cmFuc3BvcnRzV2hpdGVsaXN0XTtcbiAgICAgIH1cblxuICAgICAgYXZhaWxhYmxlVHJhbnNwb3J0cy5mb3JFYWNoKGZ1bmN0aW9uKHRyYW5zKSB7XG4gICAgICAgIGlmICghdHJhbnMpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHJhbnMudHJhbnNwb3J0TmFtZSA9PT0gJ3dlYnNvY2tldCcgJiYgaW5mby53ZWJzb2NrZXQgPT09IGZhbHNlKSB7XG4gICAgICAgICAgZGVidWcoJ2Rpc2FibGVkIGZyb20gc2VydmVyJywgJ3dlYnNvY2tldCcpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0cmFuc3BvcnRzV2hpdGVsaXN0Lmxlbmd0aCAmJlxuICAgICAgICAgICAgdHJhbnNwb3J0c1doaXRlbGlzdC5pbmRleE9mKHRyYW5zLnRyYW5zcG9ydE5hbWUpID09PSAtMSkge1xuICAgICAgICAgIGRlYnVnKCdub3QgaW4gd2hpdGVsaXN0JywgdHJhbnMudHJhbnNwb3J0TmFtZSk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRyYW5zLmVuYWJsZWQoaW5mbykpIHtcbiAgICAgICAgICBkZWJ1ZygnZW5hYmxlZCcsIHRyYW5zLnRyYW5zcG9ydE5hbWUpO1xuICAgICAgICAgIHRyYW5zcG9ydHMubWFpbi5wdXNoKHRyYW5zKTtcbiAgICAgICAgICBpZiAodHJhbnMuZmFjYWRlVHJhbnNwb3J0KSB7XG4gICAgICAgICAgICB0cmFuc3BvcnRzLmZhY2FkZS5wdXNoKHRyYW5zLmZhY2FkZVRyYW5zcG9ydCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGRlYnVnKCdkaXNhYmxlZCcsIHRyYW5zLnRyYW5zcG9ydE5hbWUpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHJldHVybiB0cmFuc3BvcnRzO1xuICAgIH1cbiAgfTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBVUkwgPSByZXF1aXJlKCd1cmwtcGFyc2UnKTtcblxudmFyIGRlYnVnID0gZnVuY3Rpb24oKSB7fTtcbmlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gIGRlYnVnID0gcmVxdWlyZSgnZGVidWcnKSgnc29ja2pzLWNsaWVudDp1dGlsczp1cmwnKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGdldE9yaWdpbjogZnVuY3Rpb24odXJsKSB7XG4gICAgaWYgKCF1cmwpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHZhciBwID0gbmV3IFVSTCh1cmwpO1xuICAgIGlmIChwLnByb3RvY29sID09PSAnZmlsZTonKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgcG9ydCA9IHAucG9ydDtcbiAgICBpZiAoIXBvcnQpIHtcbiAgICAgIHBvcnQgPSAocC5wcm90b2NvbCA9PT0gJ2h0dHBzOicpID8gJzQ0MycgOiAnODAnO1xuICAgIH1cblxuICAgIHJldHVybiBwLnByb3RvY29sICsgJy8vJyArIHAuaG9zdG5hbWUgKyAnOicgKyBwb3J0O1xuICB9XG5cbiwgaXNPcmlnaW5FcXVhbDogZnVuY3Rpb24oYSwgYikge1xuICAgIHZhciByZXMgPSB0aGlzLmdldE9yaWdpbihhKSA9PT0gdGhpcy5nZXRPcmlnaW4oYik7XG4gICAgZGVidWcoJ3NhbWUnLCBhLCBiLCByZXMpO1xuICAgIHJldHVybiByZXM7XG4gIH1cblxuLCBpc1NjaGVtZUVxdWFsOiBmdW5jdGlvbihhLCBiKSB7XG4gICAgcmV0dXJuIChhLnNwbGl0KCc6JylbMF0gPT09IGIuc3BsaXQoJzonKVswXSk7XG4gIH1cblxuLCBhZGRQYXRoOiBmdW5jdGlvbiAodXJsLCBwYXRoKSB7XG4gICAgdmFyIHFzID0gdXJsLnNwbGl0KCc/Jyk7XG4gICAgcmV0dXJuIHFzWzBdICsgcGF0aCArIChxc1sxXSA/ICc/JyArIHFzWzFdIDogJycpO1xuICB9XG5cbiwgYWRkUXVlcnk6IGZ1bmN0aW9uICh1cmwsIHEpIHtcbiAgICByZXR1cm4gdXJsICsgKHVybC5pbmRleE9mKCc/JykgPT09IC0xID8gKCc/JyArIHEpIDogKCcmJyArIHEpKTtcbiAgfVxufTtcbiIsIm1vZHVsZS5leHBvcnRzID0gJzEuMS4xJztcbiIsIi8qKlxuICogVUFQYXJzZXIuanMgdjAuNy4xMlxuICogTGlnaHR3ZWlnaHQgSmF2YVNjcmlwdC1iYXNlZCBVc2VyLUFnZW50IHN0cmluZyBwYXJzZXJcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9mYWlzYWxtYW4vdWEtcGFyc2VyLWpzXG4gKlxuICogQ29weXJpZ2h0IMKpIDIwMTItMjAxNiBGYWlzYWwgU2FsbWFuIDxmeXpsbWFuQGdtYWlsLmNvbT5cbiAqIER1YWwgbGljZW5zZWQgdW5kZXIgR1BMdjIgJiBNSVRcbiAqL1xuXG4oZnVuY3Rpb24gKHdpbmRvdywgdW5kZWZpbmVkKSB7XG5cbiAgICAndXNlIHN0cmljdCc7XG5cbiAgICAvLy8vLy8vLy8vLy8vL1xuICAgIC8vIENvbnN0YW50c1xuICAgIC8vLy8vLy8vLy8vLy9cblxuXG4gICAgdmFyIExJQlZFUlNJT04gID0gJzAuNy4xMicsXG4gICAgICAgIEVNUFRZICAgICAgID0gJycsXG4gICAgICAgIFVOS05PV04gICAgID0gJz8nLFxuICAgICAgICBGVU5DX1RZUEUgICA9ICdmdW5jdGlvbicsXG4gICAgICAgIFVOREVGX1RZUEUgID0gJ3VuZGVmaW5lZCcsXG4gICAgICAgIE9CSl9UWVBFICAgID0gJ29iamVjdCcsXG4gICAgICAgIFNUUl9UWVBFICAgID0gJ3N0cmluZycsXG4gICAgICAgIE1BSk9SICAgICAgID0gJ21ham9yJywgLy8gZGVwcmVjYXRlZFxuICAgICAgICBNT0RFTCAgICAgICA9ICdtb2RlbCcsXG4gICAgICAgIE5BTUUgICAgICAgID0gJ25hbWUnLFxuICAgICAgICBUWVBFICAgICAgICA9ICd0eXBlJyxcbiAgICAgICAgVkVORE9SICAgICAgPSAndmVuZG9yJyxcbiAgICAgICAgVkVSU0lPTiAgICAgPSAndmVyc2lvbicsXG4gICAgICAgIEFSQ0hJVEVDVFVSRT0gJ2FyY2hpdGVjdHVyZScsXG4gICAgICAgIENPTlNPTEUgICAgID0gJ2NvbnNvbGUnLFxuICAgICAgICBNT0JJTEUgICAgICA9ICdtb2JpbGUnLFxuICAgICAgICBUQUJMRVQgICAgICA9ICd0YWJsZXQnLFxuICAgICAgICBTTUFSVFRWICAgICA9ICdzbWFydHR2JyxcbiAgICAgICAgV0VBUkFCTEUgICAgPSAnd2VhcmFibGUnLFxuICAgICAgICBFTUJFRERFRCAgICA9ICdlbWJlZGRlZCc7XG5cblxuICAgIC8vLy8vLy8vLy8vXG4gICAgLy8gSGVscGVyXG4gICAgLy8vLy8vLy8vL1xuXG5cbiAgICB2YXIgdXRpbCA9IHtcbiAgICAgICAgZXh0ZW5kIDogZnVuY3Rpb24gKHJlZ2V4ZXMsIGV4dGVuc2lvbnMpIHtcbiAgICAgICAgICAgIHZhciBtYXJnZWRSZWdleGVzID0ge307XG4gICAgICAgICAgICBmb3IgKHZhciBpIGluIHJlZ2V4ZXMpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXh0ZW5zaW9uc1tpXSAmJiBleHRlbnNpb25zW2ldLmxlbmd0aCAlIDIgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgbWFyZ2VkUmVnZXhlc1tpXSA9IGV4dGVuc2lvbnNbaV0uY29uY2F0KHJlZ2V4ZXNbaV0pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG1hcmdlZFJlZ2V4ZXNbaV0gPSByZWdleGVzW2ldO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBtYXJnZWRSZWdleGVzO1xuICAgICAgICB9LFxuICAgICAgICBoYXMgOiBmdW5jdGlvbiAoc3RyMSwgc3RyMikge1xuICAgICAgICAgIGlmICh0eXBlb2Ygc3RyMSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgcmV0dXJuIHN0cjIudG9Mb3dlckNhc2UoKS5pbmRleE9mKHN0cjEudG9Mb3dlckNhc2UoKSkgIT09IC0xO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBsb3dlcml6ZSA6IGZ1bmN0aW9uIChzdHIpIHtcbiAgICAgICAgICAgIHJldHVybiBzdHIudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgfSxcbiAgICAgICAgbWFqb3IgOiBmdW5jdGlvbiAodmVyc2lvbikge1xuICAgICAgICAgICAgcmV0dXJuIHR5cGVvZih2ZXJzaW9uKSA9PT0gU1RSX1RZUEUgPyB2ZXJzaW9uLnJlcGxhY2UoL1teXFxkXFwuXS9nLCcnKS5zcGxpdChcIi5cIilbMF0gOiB1bmRlZmluZWQ7XG4gICAgICAgIH0sXG4gICAgICAgIHRyaW0gOiBmdW5jdGlvbiAoc3RyKSB7XG4gICAgICAgICAgcmV0dXJuIHN0ci5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywgJycpO1xuICAgICAgICB9XG4gICAgfTtcblxuXG4gICAgLy8vLy8vLy8vLy8vLy8vXG4gICAgLy8gTWFwIGhlbHBlclxuICAgIC8vLy8vLy8vLy8vLy8vXG5cblxuICAgIHZhciBtYXBwZXIgPSB7XG5cbiAgICAgICAgcmd4IDogZnVuY3Rpb24gKCkge1xuXG4gICAgICAgICAgICB2YXIgcmVzdWx0LCBpID0gMCwgaiwgaywgcCwgcSwgbWF0Y2hlcywgbWF0Y2gsIGFyZ3MgPSBhcmd1bWVudHM7XG5cbiAgICAgICAgICAgIC8vIGxvb3AgdGhyb3VnaCBhbGwgcmVnZXhlcyBtYXBzXG4gICAgICAgICAgICB3aGlsZSAoaSA8IGFyZ3MubGVuZ3RoICYmICFtYXRjaGVzKSB7XG5cbiAgICAgICAgICAgICAgICB2YXIgcmVnZXggPSBhcmdzW2ldLCAgICAgICAvLyBldmVuIHNlcXVlbmNlICgwLDIsNCwuLilcbiAgICAgICAgICAgICAgICAgICAgcHJvcHMgPSBhcmdzW2kgKyAxXTsgICAvLyBvZGQgc2VxdWVuY2UgKDEsMyw1LC4uKVxuXG4gICAgICAgICAgICAgICAgLy8gY29uc3RydWN0IG9iamVjdCBiYXJlYm9uZXNcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHJlc3VsdCA9PT0gVU5ERUZfVFlQRSkge1xuICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgZm9yIChwIGluIHByb3BzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocHJvcHMuaGFzT3duUHJvcGVydHkocCkpe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHEgPSBwcm9wc1twXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHEgPT09IE9CSl9UWVBFKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdFtxWzBdXSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRbcV0gPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gdHJ5IG1hdGNoaW5nIHVhc3RyaW5nIHdpdGggcmVnZXhlc1xuICAgICAgICAgICAgICAgIGogPSBrID0gMDtcbiAgICAgICAgICAgICAgICB3aGlsZSAoaiA8IHJlZ2V4Lmxlbmd0aCAmJiAhbWF0Y2hlcykge1xuICAgICAgICAgICAgICAgICAgICBtYXRjaGVzID0gcmVnZXhbaisrXS5leGVjKHRoaXMuZ2V0VUEoKSk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghIW1hdGNoZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAocCA9IDA7IHAgPCBwcm9wcy5sZW5ndGg7IHArKykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoID0gbWF0Y2hlc1srK2tdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHEgPSBwcm9wc1twXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjaGVjayBpZiBnaXZlbiBwcm9wZXJ0eSBpcyBhY3R1YWxseSBhcnJheVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgcSA9PT0gT0JKX1RZUEUgJiYgcS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChxLmxlbmd0aCA9PSAyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHFbMV0gPT0gRlVOQ19UWVBFKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXNzaWduIG1vZGlmaWVkIG1hdGNoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0W3FbMF1dID0gcVsxXS5jYWxsKHRoaXMsIG1hdGNoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXNzaWduIGdpdmVuIHZhbHVlLCBpZ25vcmUgcmVnZXggbWF0Y2hcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRbcVswXV0gPSBxWzFdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHEubGVuZ3RoID09IDMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNoZWNrIHdoZXRoZXIgZnVuY3Rpb24gb3IgcmVnZXhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgcVsxXSA9PT0gRlVOQ19UWVBFICYmICEocVsxXS5leGVjICYmIHFbMV0udGVzdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjYWxsIGZ1bmN0aW9uICh1c3VhbGx5IHN0cmluZyBtYXBwZXIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0W3FbMF1dID0gbWF0Y2ggPyBxWzFdLmNhbGwodGhpcywgbWF0Y2gsIHFbMl0pIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBzYW5pdGl6ZSBtYXRjaCB1c2luZyBnaXZlbiByZWdleFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdFtxWzBdXSA9IG1hdGNoID8gbWF0Y2gucmVwbGFjZShxWzFdLCBxWzJdKSA6IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChxLmxlbmd0aCA9PSA0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0W3FbMF1dID0gbWF0Y2ggPyBxWzNdLmNhbGwodGhpcywgbWF0Y2gucmVwbGFjZShxWzFdLCBxWzJdKSkgOiB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRbcV0gPSBtYXRjaCA/IG1hdGNoIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpICs9IDI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9LFxuXG4gICAgICAgIHN0ciA6IGZ1bmN0aW9uIChzdHIsIG1hcCkge1xuXG4gICAgICAgICAgICBmb3IgKHZhciBpIGluIG1hcCkge1xuICAgICAgICAgICAgICAgIC8vIGNoZWNrIGlmIGFycmF5XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBtYXBbaV0gPT09IE9CSl9UWVBFICYmIG1hcFtpXS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbWFwW2ldLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodXRpbC5oYXMobWFwW2ldW2pdLCBzdHIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChpID09PSBVTktOT1dOKSA/IHVuZGVmaW5lZCA6IGk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHV0aWwuaGFzKG1hcFtpXSwgc3RyKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gKGkgPT09IFVOS05PV04pID8gdW5kZWZpbmVkIDogaTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gc3RyO1xuICAgICAgICB9XG4gICAgfTtcblxuXG4gICAgLy8vLy8vLy8vLy8vLy8vXG4gICAgLy8gU3RyaW5nIG1hcFxuICAgIC8vLy8vLy8vLy8vLy8vXG5cblxuICAgIHZhciBtYXBzID0ge1xuXG4gICAgICAgIGJyb3dzZXIgOiB7XG4gICAgICAgICAgICBvbGRzYWZhcmkgOiB7XG4gICAgICAgICAgICAgICAgdmVyc2lvbiA6IHtcbiAgICAgICAgICAgICAgICAgICAgJzEuMCcgICA6ICcvOCcsXG4gICAgICAgICAgICAgICAgICAgICcxLjInICAgOiAnLzEnLFxuICAgICAgICAgICAgICAgICAgICAnMS4zJyAgIDogJy8zJyxcbiAgICAgICAgICAgICAgICAgICAgJzIuMCcgICA6ICcvNDEyJyxcbiAgICAgICAgICAgICAgICAgICAgJzIuMC4yJyA6ICcvNDE2JyxcbiAgICAgICAgICAgICAgICAgICAgJzIuMC4zJyA6ICcvNDE3JyxcbiAgICAgICAgICAgICAgICAgICAgJzIuMC40JyA6ICcvNDE5JyxcbiAgICAgICAgICAgICAgICAgICAgJz8nICAgICA6ICcvJ1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBkZXZpY2UgOiB7XG4gICAgICAgICAgICBhbWF6b24gOiB7XG4gICAgICAgICAgICAgICAgbW9kZWwgOiB7XG4gICAgICAgICAgICAgICAgICAgICdGaXJlIFBob25lJyA6IFsnU0QnLCAnS0YnXVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBzcHJpbnQgOiB7XG4gICAgICAgICAgICAgICAgbW9kZWwgOiB7XG4gICAgICAgICAgICAgICAgICAgICdFdm8gU2hpZnQgNEcnIDogJzczNzNLVCdcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHZlbmRvciA6IHtcbiAgICAgICAgICAgICAgICAgICAgJ0hUQycgICAgICAgOiAnQVBBJyxcbiAgICAgICAgICAgICAgICAgICAgJ1NwcmludCcgICAgOiAnU3ByaW50J1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBvcyA6IHtcbiAgICAgICAgICAgIHdpbmRvd3MgOiB7XG4gICAgICAgICAgICAgICAgdmVyc2lvbiA6IHtcbiAgICAgICAgICAgICAgICAgICAgJ01FJyAgICAgICAgOiAnNC45MCcsXG4gICAgICAgICAgICAgICAgICAgICdOVCAzLjExJyAgIDogJ05UMy41MScsXG4gICAgICAgICAgICAgICAgICAgICdOVCA0LjAnICAgIDogJ05UNC4wJyxcbiAgICAgICAgICAgICAgICAgICAgJzIwMDAnICAgICAgOiAnTlQgNS4wJyxcbiAgICAgICAgICAgICAgICAgICAgJ1hQJyAgICAgICAgOiBbJ05UIDUuMScsICdOVCA1LjInXSxcbiAgICAgICAgICAgICAgICAgICAgJ1Zpc3RhJyAgICAgOiAnTlQgNi4wJyxcbiAgICAgICAgICAgICAgICAgICAgJzcnICAgICAgICAgOiAnTlQgNi4xJyxcbiAgICAgICAgICAgICAgICAgICAgJzgnICAgICAgICAgOiAnTlQgNi4yJyxcbiAgICAgICAgICAgICAgICAgICAgJzguMScgICAgICAgOiAnTlQgNi4zJyxcbiAgICAgICAgICAgICAgICAgICAgJzEwJyAgICAgICAgOiBbJ05UIDYuNCcsICdOVCAxMC4wJ10sXG4gICAgICAgICAgICAgICAgICAgICdSVCcgICAgICAgIDogJ0FSTSdcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG5cbiAgICAvLy8vLy8vLy8vLy8vL1xuICAgIC8vIFJlZ2V4IG1hcFxuICAgIC8vLy8vLy8vLy8vLy9cblxuXG4gICAgdmFyIHJlZ2V4ZXMgPSB7XG5cbiAgICAgICAgYnJvd3NlciA6IFtbXG5cbiAgICAgICAgICAgIC8vIFByZXN0byBiYXNlZFxuICAgICAgICAgICAgLyhvcGVyYVxcc21pbmkpXFwvKFtcXHdcXC4tXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlcmEgTWluaVxuICAgICAgICAgICAgLyhvcGVyYVxcc1ttb2JpbGV0YWJdKykuK3ZlcnNpb25cXC8oW1xcd1xcLi1dKykvaSwgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlcmEgTW9iaS9UYWJsZXRcbiAgICAgICAgICAgIC8ob3BlcmEpLit2ZXJzaW9uXFwvKFtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlcmEgPiA5LjgwXG4gICAgICAgICAgICAvKG9wZXJhKVtcXC9cXHNdKyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPcGVyYSA8IDkuODBcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKG9waW9zKVtcXC9cXHNdKyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPcGVyYSBtaW5pIG9uIGlwaG9uZSA+PSA4LjBcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ09wZXJhIE1pbmknXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgL1xccyhvcHIpXFwvKFtcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BlcmEgV2Via2l0XG4gICAgICAgICAgICBdLCBbW05BTUUsICdPcGVyYSddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvLyBNaXhlZFxuICAgICAgICAgICAgLyhraW5kbGUpXFwvKFtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBLaW5kbGVcbiAgICAgICAgICAgIC8obHVuYXNjYXBlfG1heHRob258bmV0ZnJvbnR8amFzbWluZXxibGF6ZXIpW1xcL1xcc10/KFtcXHdcXC5dKykqL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEx1bmFzY2FwZS9NYXh0aG9uL05ldGZyb250L0phc21pbmUvQmxhemVyXG5cbiAgICAgICAgICAgIC8vIFRyaWRlbnQgYmFzZWRcbiAgICAgICAgICAgIC8oYXZhbnRcXHN8aWVtb2JpbGV8c2xpbXxiYWlkdSkoPzpicm93c2VyKT9bXFwvXFxzXT8oW1xcd1xcLl0qKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBdmFudC9JRU1vYmlsZS9TbGltQnJvd3Nlci9CYWlkdVxuICAgICAgICAgICAgLyg/Om1zfFxcKCkoaWUpXFxzKFtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSW50ZXJuZXQgRXhwbG9yZXJcblxuICAgICAgICAgICAgLy8gV2Via2l0L0tIVE1MIGJhc2VkXG4gICAgICAgICAgICAvKHJla29ucSlcXC8oW1xcd1xcLl0rKSovaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJla29ucVxuICAgICAgICAgICAgLyhjaHJvbWl1bXxmbG9ja3xyb2NrbWVsdHxtaWRvcml8ZXBpcGhhbnl8c2lsa3xza3lmaXJlfG92aWJyb3dzZXJ8Ym9sdHxpcm9ufHZpdmFsZGl8aXJpZGl1bXxwaGFudG9tanMpXFwvKFtcXHdcXC4tXSspL2lcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2hyb21pdW0vRmxvY2svUm9ja01lbHQvTWlkb3JpL0VwaXBoYW55L1NpbGsvU2t5ZmlyZS9Cb2x0L0lyb24vSXJpZGl1bS9QaGFudG9tSlNcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKHRyaWRlbnQpLitydls6XFxzXShbXFx3XFwuXSspLitsaWtlXFxzZ2Vja28vaSAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJRTExXG4gICAgICAgICAgICBdLCBbW05BTUUsICdJRSddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKGVkZ2UpXFwvKChcXGQrKT9bXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNaWNyb3NvZnQgRWRnZVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oeWFicm93c2VyKVxcLyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gWWFuZGV4XG4gICAgICAgICAgICBdLCBbW05BTUUsICdZYW5kZXgnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhjb21vZG9fZHJhZ29uKVxcLyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDb21vZG8gRHJhZ29uXG4gICAgICAgICAgICBdLCBbW05BTUUsIC9fL2csICcgJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8obWljcm9tZXNzZW5nZXIpXFwvKFtcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2VDaGF0XG4gICAgICAgICAgICBdLCBbW05BTUUsICdXZUNoYXQnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgL3hpYW9taVxcL21pdWlicm93c2VyXFwvKFtcXHdcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTUlVSSBCcm93c2VyXG4gICAgICAgICAgICBdLCBbVkVSU0lPTiwgW05BTUUsICdNSVVJIEJyb3dzZXInXV0sIFtcblxuICAgICAgICAgICAgL1xcc3d2XFwpLisoY2hyb21lKVxcLyhbXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENocm9tZSBXZWJWaWV3XG4gICAgICAgICAgICBdLCBbW05BTUUsIC8oLispLywgJyQxIFdlYlZpZXcnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuK3NhbXN1bmdicm93c2VyXFwvKFtcXHdcXC5dKykvaSxcbiAgICAgICAgICAgIC9hbmRyb2lkLit2ZXJzaW9uXFwvKFtcXHdcXC5dKylcXHMrKD86bW9iaWxlXFxzP3NhZmFyaXxzYWZhcmkpKi9pICAgICAgICAvLyBBbmRyb2lkIEJyb3dzZXJcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBbTkFNRSwgJ0FuZHJvaWQgQnJvd3NlciddXSwgW1xuXG4gICAgICAgICAgICAvKGNocm9tZXxvbW5pd2VifGFyb3JhfFt0aXplbm9rYV17NX1cXHM/YnJvd3NlcilcXC92PyhbXFx3XFwuXSspL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENocm9tZS9PbW5pV2ViL0Fyb3JhL1RpemVuL05va2lhXG4gICAgICAgICAgICAvKHFxYnJvd3NlcilbXFwvXFxzXT8oW1xcd1xcLl0rKS9pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFFRQnJvd3NlclxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8odWNcXHM/YnJvd3NlcilbXFwvXFxzXT8oW1xcd1xcLl0rKS9pLFxuICAgICAgICAgICAgL3Vjd2ViLisodWNicm93c2VyKVtcXC9cXHNdPyhbXFx3XFwuXSspL2ksXG4gICAgICAgICAgICAvanVjLisodWN3ZWIpW1xcL1xcc10/KFtcXHdcXC5dKykvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBVQ0Jyb3dzZXJcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ1VDQnJvd3NlciddLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKGRvbGZpbilcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIERvbHBoaW5cbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ0RvbHBoaW4nXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLygoPzphbmRyb2lkLispY3Jtb3xjcmlvcylcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDaHJvbWUgZm9yIEFuZHJvaWQvaU9TXG4gICAgICAgICAgICBdLCBbW05BTUUsICdDaHJvbWUnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLztmYmF2XFwvKFtcXHdcXC5dKyk7L2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGYWNlYm9vayBBcHAgZm9yIGlPU1xuICAgICAgICAgICAgXSwgW1ZFUlNJT04sIFtOQU1FLCAnRmFjZWJvb2snXV0sIFtcblxuICAgICAgICAgICAgL2Z4aW9zXFwvKFtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGaXJlZm94IGZvciBpT1NcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBbTkFNRSwgJ0ZpcmVmb3gnXV0sIFtcblxuICAgICAgICAgICAgL3ZlcnNpb25cXC8oW1xcd1xcLl0rKS4rP21vYmlsZVxcL1xcdytcXHMoc2FmYXJpKS9pICAgICAgICAgICAgICAgICAgICAgICAvLyBNb2JpbGUgU2FmYXJpXG4gICAgICAgICAgICBdLCBbVkVSU0lPTiwgW05BTUUsICdNb2JpbGUgU2FmYXJpJ11dLCBbXG5cbiAgICAgICAgICAgIC92ZXJzaW9uXFwvKFtcXHdcXC5dKykuKz8obW9iaWxlXFxzP3NhZmFyaXxzYWZhcmkpL2kgICAgICAgICAgICAgICAgICAgIC8vIFNhZmFyaSAmIFNhZmFyaSBNb2JpbGVcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBOQU1FXSwgW1xuXG4gICAgICAgICAgICAvd2Via2l0Lis/KG1vYmlsZVxccz9zYWZhcml8c2FmYXJpKShcXC9bXFx3XFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAvLyBTYWZhcmkgPCAzLjBcbiAgICAgICAgICAgIF0sIFtOQU1FLCBbVkVSU0lPTiwgbWFwcGVyLnN0ciwgbWFwcy5icm93c2VyLm9sZHNhZmFyaS52ZXJzaW9uXV0sIFtcblxuICAgICAgICAgICAgLyhrb25xdWVyb3IpXFwvKFtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBLb25xdWVyb3JcbiAgICAgICAgICAgIC8od2Via2l0fGtodG1sKVxcLyhbXFx3XFwuXSspL2lcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvLyBHZWNrbyBiYXNlZFxuICAgICAgICAgICAgLyhuYXZpZ2F0b3J8bmV0c2NhcGUpXFwvKFtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOZXRzY2FwZVxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnTmV0c2NhcGUnXSwgVkVSU0lPTl0sIFtcbiAgICAgICAgICAgIC8oc3dpZnRmb3gpL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3dpZnRmb3hcbiAgICAgICAgICAgIC8oaWNlZHJhZ29ufGljZXdlYXNlbHxjYW1pbm98Y2hpbWVyYXxmZW5uZWN8bWFlbW9cXHNicm93c2VyfG1pbmltb3xjb25rZXJvcilbXFwvXFxzXT8oW1xcd1xcLlxcK10rKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJY2VEcmFnb24vSWNld2Vhc2VsL0NhbWluby9DaGltZXJhL0Zlbm5lYy9NYWVtby9NaW5pbW8vQ29ua2Vyb3JcbiAgICAgICAgICAgIC8oZmlyZWZveHxzZWFtb25rZXl8ay1tZWxlb258aWNlY2F0fGljZWFwZXxmaXJlYmlyZHxwaG9lbml4KVxcLyhbXFx3XFwuLV0rKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGaXJlZm94L1NlYU1vbmtleS9LLU1lbGVvbi9JY2VDYXQvSWNlQXBlL0ZpcmViaXJkL1Bob2VuaXhcbiAgICAgICAgICAgIC8obW96aWxsYSlcXC8oW1xcd1xcLl0rKS4rcnZcXDouK2dlY2tvXFwvXFxkKy9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTW96aWxsYVxuXG4gICAgICAgICAgICAvLyBPdGhlclxuICAgICAgICAgICAgLyhwb2xhcmlzfGx5bnh8ZGlsbG98aWNhYnxkb3Jpc3xhbWF5YXx3M218bmV0c3VyZnxzbGVpcG5pcilbXFwvXFxzXT8oW1xcd1xcLl0rKS9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQb2xhcmlzL0x5bngvRGlsbG8vaUNhYi9Eb3Jpcy9BbWF5YS93M20vTmV0U3VyZi9TbGVpcG5pclxuICAgICAgICAgICAgLyhsaW5rcylcXHNcXCgoW1xcd1xcLl0rKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTGlua3NcbiAgICAgICAgICAgIC8oZ29icm93c2VyKVxcLz8oW1xcd1xcLl0rKSovaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR29Ccm93c2VyXG4gICAgICAgICAgICAvKGljZVxccz9icm93c2VyKVxcL3Y/KFtcXHdcXC5fXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJQ0UgQnJvd3NlclxuICAgICAgICAgICAgLyhtb3NhaWMpW1xcL1xcc10oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTW9zYWljXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl1cblxuICAgICAgICAgICAgLyogLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG4gICAgICAgICAgICAvLyBNZWRpYSBwbGF5ZXJzIEJFR0lOXG4gICAgICAgICAgICAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cblxuICAgICAgICAgICAgLCBbXG5cbiAgICAgICAgICAgIC8oYXBwbGUoPzpjb3JlbWVkaWF8KSlcXC8oKFxcZCspW1xcd1xcLl9dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdlbmVyaWMgQXBwbGUgQ29yZU1lZGlhXG4gICAgICAgICAgICAvKGNvcmVtZWRpYSkgdigoXFxkKylbXFx3XFwuX10rKS9pXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhhcXVhbHVuZ3xseXNzbmF8YnNwbGF5ZXIpXFwvKChcXGQrKT9bXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgLy8gQXF1YWx1bmcvTHlzc25hL0JTUGxheWVyXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhhcmVzfG9zc3Byb3h5KVxccygoXFxkKylbXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQXJlcy9PU1NQcm94eVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oYXVkYWNpb3VzfGF1ZGltdXNpY3N0cmVhbXxhbWFyb2t8YmFzc3xjb3JlfGRhbHZpa3xnbm9tZW1wbGF5ZXJ8bXVzaWMgb24gY29uc29sZXxuc3BsYXllcnxwc3AtaW50ZXJuZXRyYWRpb3BsYXllcnx2aWRlb3MpXFwvKChcXGQrKVtcXHdcXC4tXSspL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEF1ZGFjaW91cy9BdWRpTXVzaWNTdHJlYW0vQW1hcm9rL0JBU1MvT3BlbkNPUkUvRGFsdmlrL0dub21lTXBsYXllci9Nb0NcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTlNQbGF5ZXIvUFNQLUludGVybmV0UmFkaW9QbGF5ZXIvVmlkZW9zXG4gICAgICAgICAgICAvKGNsZW1lbnRpbmV8bXVzaWMgcGxheWVyIGRhZW1vbilcXHMoKFxcZCspW1xcd1xcLi1dKykvaSwgICAgICAgICAgICAgICAvLyBDbGVtZW50aW5lL01QRFxuICAgICAgICAgICAgLyhsZyBwbGF5ZXJ8bmV4cGxheWVyKVxccygoXFxkKylbXFxkXFwuXSspL2ksXG4gICAgICAgICAgICAvcGxheWVyXFwvKG5leHBsYXllcnxsZyBwbGF5ZXIpXFxzKChcXGQrKVtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgLy8gTmV4UGxheWVyL0xHIFBsYXllclxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG4gICAgICAgICAgICAvKG5leHBsYXllcilcXHMoKFxcZCspW1xcd1xcLi1dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOZXhwbGF5ZXJcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKGZscnApXFwvKChcXGQrKVtcXHdcXC4tXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGbGlwIFBsYXllclxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnRmxpcCBQbGF5ZXInXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhmc3RyZWFtfG5hdGl2ZWhvc3R8cXVlcnlzZWVrc3BpZGVyfGlhLWFyY2hpdmVyfGZhY2Vib29rZXh0ZXJuYWxoaXQpL2lcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRlN0cmVhbS9OYXRpdmVIb3N0L1F1ZXJ5U2Vla1NwaWRlci9JQSBBcmNoaXZlci9mYWNlYm9va2V4dGVybmFsaGl0XG4gICAgICAgICAgICBdLCBbTkFNRV0sIFtcblxuICAgICAgICAgICAgLyhnc3RyZWFtZXIpIHNvdXBodHRwc3JjICg/OlxcKFteXFwpXStcXCkpezAsMX0gbGlic291cFxcLygoXFxkKylbXFx3XFwuLV0rKS9pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdzdHJlYW1lclxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oaHRjIHN0cmVhbWluZyBwbGF5ZXIpXFxzW1xcd19dK1xcc1xcL1xccygoXFxkKylbXFxkXFwuXSspL2ksICAgICAgICAgICAgICAvLyBIVEMgU3RyZWFtaW5nIFBsYXllclxuICAgICAgICAgICAgLyhqYXZhfHB5dGhvbi11cmxsaWJ8cHl0aG9uLXJlcXVlc3RzfHdnZXR8bGliY3VybClcXC8oKFxcZCspW1xcd1xcLi1fXSspL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEphdmEvdXJsbGliL3JlcXVlc3RzL3dnZXQvY1VSTFxuICAgICAgICAgICAgLyhsYXZmKSgoXFxkKylbXFxkXFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBMYXZmIChGRk1QRUcpXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhodGNfb25lX3MpXFwvKChcXGQrKVtcXGRcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSFRDIE9uZSBTXG4gICAgICAgICAgICBdLCBbW05BTUUsIC9fL2csICcgJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8obXBsYXllcikoPzpcXHN8XFwvKSg/Oig/OnNoZXJweWEtKXswLDF9c3ZuKSg/Oi18XFxzKShyXFxkKyg/Oi1cXGQrW1xcd1xcLi1dKyl7MCwxfSkvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNUGxheWVyIFNWTlxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8obXBsYXllcikoPzpcXHN8XFwvfFt1bmtvdy1dKykoKFxcZCspW1xcd1xcLi1dKykvaSAgICAgICAgICAgICAgICAgICAgICAvLyBNUGxheWVyXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhtcGxheWVyKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNUGxheWVyIChubyBvdGhlciBpbmZvKVxuICAgICAgICAgICAgLyh5b3VybXV6ZSkvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBZb3VyTXV6ZVxuICAgICAgICAgICAgLyhtZWRpYSBwbGF5ZXIgY2xhc3NpY3xuZXJvIHNob3d0aW1lKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNZWRpYSBQbGF5ZXIgQ2xhc3NpYy9OZXJvIFNob3dUaW1lXG4gICAgICAgICAgICBdLCBbTkFNRV0sIFtcblxuICAgICAgICAgICAgLyhuZXJvICg/OmhvbWV8c2NvdXQpKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTmVybyBIb21lL05lcm8gU2NvdXRcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvKG5va2lhXFxkKylcXC8oKFxcZCspW1xcd1xcLi1dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTm9raWFcbiAgICAgICAgICAgIF0sIFtOQU1FLCBWRVJTSU9OXSwgW1xuXG4gICAgICAgICAgICAvXFxzKHNvbmdiaXJkKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU29uZ2JpcmQvUGhpbGlwcy1Tb25nYmlyZFxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8od2luYW1wKTMgdmVyc2lvbiAoKFxcZCspW1xcd1xcLi1dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2luYW1wXG4gICAgICAgICAgICAvKHdpbmFtcClcXHMoKFxcZCspW1xcd1xcLi1dKykvaSxcbiAgICAgICAgICAgIC8od2luYW1wKW1wZWdcXC8oKFxcZCspW1xcd1xcLi1dKykvaVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8ob2Ntcy1ib3R8dGFwaW5yYWRpb3x0dW5laW4gcmFkaW98dW5rbm93bnx3aW5hbXB8aW5saWdodCByYWRpbykvaSAgLy8gT0NNUy1ib3QvdGFwIGluIHJhZGlvL3R1bmVpbi91bmtub3duL3dpbmFtcCAobm8gb3RoZXIgaW5mbylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaW5saWdodCByYWRpb1xuICAgICAgICAgICAgXSwgW05BTUVdLCBbXG5cbiAgICAgICAgICAgIC8ocXVpY2t0aW1lfHJtYXxyYWRpb2FwcHxyYWRpb2NsaWVudGFwcGxpY2F0aW9ufHNvdW5kdGFwfHRvdGVtfHN0YWdlZnJpZ2h0fHN0cmVhbWl1bSlcXC8oKFxcZCspW1xcd1xcLi1dKykvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBRdWlja1RpbWUvUmVhbE1lZGlhL1JhZGlvQXBwL1JhZGlvQ2xpZW50QXBwbGljYXRpb24vXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvdW5kVGFwL1RvdGVtL1N0YWdlZnJpZ2h0L1N0cmVhbWl1bVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8oc21wKSgoXFxkKylbXFxkXFwuXSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU01QXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyh2bGMpIG1lZGlhIHBsYXllciAtIHZlcnNpb24gKChcXGQrKVtcXHdcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAvLyBWTEMgVmlkZW9sYW5cbiAgICAgICAgICAgIC8odmxjKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pLFxuICAgICAgICAgICAgLyh4Ym1jfGd2ZnN8eGluZXx4bW1zfGlyYXBwKVxcLygoXFxkKylbXFx3XFwuLV0rKS9pLCAgICAgICAgICAgICAgICAgICAgLy8gWEJNQy9ndmZzL1hpbmUvWE1NUy9pcmFwcFxuICAgICAgICAgICAgLyhmb29iYXIyMDAwKVxcLygoXFxkKylbXFxkXFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRm9vYmFyMjAwMFxuICAgICAgICAgICAgLyhpdHVuZXMpXFwvKChcXGQrKVtcXGRcXC5dKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaVR1bmVzXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyh3bXBsYXllcilcXC8oKFxcZCspW1xcd1xcLi1dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2luZG93cyBNZWRpYSBQbGF5ZXJcbiAgICAgICAgICAgIC8od2luZG93cy1tZWRpYS1wbGF5ZXIpXFwvKChcXGQrKVtcXHdcXC4tXSspL2lcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgLy0vZywgJyAnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgL3dpbmRvd3NcXC8oKFxcZCspW1xcd1xcLi1dKykgdXBucFxcL1tcXGRcXC5dKyBkbG5hZG9jXFwvW1xcZFxcLl0rIChob21lIG1lZGlhIHNlcnZlcikvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBXaW5kb3dzIE1lZGlhIFNlcnZlclxuICAgICAgICAgICAgXSwgW1ZFUlNJT04sIFtOQU1FLCAnV2luZG93cyddXSwgW1xuXG4gICAgICAgICAgICAvKGNvbVxcLnJpc2V1cHJhZGlvYWxhcm0pXFwvKChcXGQrKVtcXGRcXC5dKikvaSAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmlzZVVQIFJhZGlvIEFsYXJtXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhyYWQuaW8pXFxzKChcXGQrKVtcXGRcXC5dKykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmFkLmlvXG4gICAgICAgICAgICAvKHJhZGlvLig/OmRlfGF0fGZyKSlcXHMoKFxcZCspW1xcZFxcLl0rKS9pXG4gICAgICAgICAgICBdLCBbW05BTUUsICdyYWQuaW8nXSwgVkVSU0lPTl1cblxuICAgICAgICAgICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuICAgICAgICAgICAgLy8gTWVkaWEgcGxheWVycyBFTkRcbiAgICAgICAgICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vKi9cblxuICAgICAgICBdLFxuXG4gICAgICAgIGNwdSA6IFtbXG5cbiAgICAgICAgICAgIC8oPzooYW1kfHgoPzooPzo4Nnw2NClbXy1dKT98d293fHdpbik2NClbO1xcKV0vaSAgICAgICAgICAgICAgICAgICAgIC8vIEFNRDY0XG4gICAgICAgICAgICBdLCBbW0FSQ0hJVEVDVFVSRSwgJ2FtZDY0J11dLCBbXG5cbiAgICAgICAgICAgIC8oaWEzMig/PTspKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSUEzMiAocXVpY2t0aW1lKVxuICAgICAgICAgICAgXSwgW1tBUkNISVRFQ1RVUkUsIHV0aWwubG93ZXJpemVdXSwgW1xuXG4gICAgICAgICAgICAvKCg/OmlbMzQ2XXx4KTg2KVs7XFwpXS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJQTMyXG4gICAgICAgICAgICBdLCBbW0FSQ0hJVEVDVFVSRSwgJ2lhMzInXV0sIFtcblxuICAgICAgICAgICAgLy8gUG9ja2V0UEMgbWlzdGFrZW5seSBpZGVudGlmaWVkIGFzIFBvd2VyUENcbiAgICAgICAgICAgIC93aW5kb3dzXFxzKGNlfG1vYmlsZSk7XFxzcHBjOy9pXG4gICAgICAgICAgICBdLCBbW0FSQ0hJVEVDVFVSRSwgJ2FybSddXSwgW1xuXG4gICAgICAgICAgICAvKCg/OnBwY3xwb3dlcnBjKSg/OjY0KT8pKD86XFxzbWFjfDt8XFwpKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUG93ZXJQQ1xuICAgICAgICAgICAgXSwgW1tBUkNISVRFQ1RVUkUsIC9vd2VyLywgJycsIHV0aWwubG93ZXJpemVdXSwgW1xuXG4gICAgICAgICAgICAvKHN1bjRcXHcpWztcXCldL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU1BBUkNcbiAgICAgICAgICAgIF0sIFtbQVJDSElURUNUVVJFLCAnc3BhcmMnXV0sIFtcblxuICAgICAgICAgICAgLygoPzphdnIzMnxpYTY0KD89OykpfDY4ayg/PVxcKSl8YXJtKD86NjR8KD89dlxcZCs7KSl8KD89YXRtZWxcXHMpYXZyfCg/OmlyaXh8bWlwc3xzcGFyYykoPzo2NCk/KD89Oyl8cGEtcmlzYykvaVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJQTY0LCA2OEssIEFSTS82NCwgQVZSLzMyLCBJUklYLzY0LCBNSVBTLzY0LCBTUEFSQy82NCwgUEEtUklTQ1xuICAgICAgICAgICAgXSwgW1tBUkNISVRFQ1RVUkUsIHV0aWwubG93ZXJpemVdXVxuICAgICAgICBdLFxuXG4gICAgICAgIGRldmljZSA6IFtbXG5cbiAgICAgICAgICAgIC9cXCgoaXBhZHxwbGF5Ym9vayk7W1xcd1xcc1xcKTstXSsocmltfGFwcGxlKS9pICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlQYWQvUGxheUJvb2tcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgVkVORE9SLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgL2FwcGxlY29yZW1lZGlhXFwvW1xcd1xcLl0rIFxcKChpcGFkKS8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaVBhZFxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQXBwbGUnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC8oYXBwbGVcXHN7MCwxfXR2KS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFwcGxlIFRWXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnQXBwbGUgVFYnXSwgW1ZFTkRPUiwgJ0FwcGxlJ11dLCBbXG5cbiAgICAgICAgICAgIC8oYXJjaG9zKVxccyhnYW1lcGFkMj8pL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFyY2hvc1xuICAgICAgICAgICAgLyhocCkuKyh0b3VjaHBhZCkvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIUCBUb3VjaFBhZFxuICAgICAgICAgICAgLyhocCkuKyh0YWJsZXQpL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIUCBUYWJsZXRcbiAgICAgICAgICAgIC8oa2luZGxlKVxcLyhbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gS2luZGxlXG4gICAgICAgICAgICAvXFxzKG5vb2spW1xcd1xcc10rYnVpbGRcXC8oXFx3KykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTm9va1xuICAgICAgICAgICAgLyhkZWxsKVxccyhzdHJlYVtrcHJcXHNcXGRdKltcXGRrb10pL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRGVsbCBTdHJlYWtcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgLyhrZltBLXpdKylcXHNidWlsZFxcL1tcXHdcXC5dKy4qc2lsa1xcLy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEtpbmRsZSBGaXJlIEhEXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdBbWF6b24nXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG4gICAgICAgICAgICAvKHNkfGtmKVswMzQ5aGlqb3JzdHV3XStcXHNidWlsZFxcL1tcXHdcXC5dKy4qc2lsa1xcLy9pICAgICAgICAgICAgICAgICAgLy8gRmlyZSBQaG9uZVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgbWFwcGVyLnN0ciwgbWFwcy5kZXZpY2UuYW1hem9uLm1vZGVsXSwgW1ZFTkRPUiwgJ0FtYXpvbiddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgL1xcKChpcFtob25lZHxcXHNcXHcqXSspOy4rKGFwcGxlKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpUG9kL2lQaG9uZVxuICAgICAgICAgICAgXSwgW01PREVMLCBWRU5ET1IsIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgL1xcKChpcFtob25lZHxcXHNcXHcqXSspOy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpUG9kL2lQaG9uZVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQXBwbGUnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8oYmxhY2tiZXJyeSlbXFxzLV0/KFxcdyspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBCbGFja0JlcnJ5XG4gICAgICAgICAgICAvKGJsYWNrYmVycnl8YmVucXxwYWxtKD89XFwtKXxzb255ZXJpY3Nzb258YWNlcnxhc3VzfGRlbGx8aHVhd2VpfG1laXp1fG1vdG9yb2xhfHBvbHl0cm9uKVtcXHNfLV0/KFtcXHctXSspKi9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBCZW5RL1BhbG0vU29ueS1Fcmljc3Nvbi9BY2VyL0FzdXMvRGVsbC9IdWF3ZWkvTWVpenUvTW90b3JvbGEvUG9seXRyb25cbiAgICAgICAgICAgIC8oaHApXFxzKFtcXHdcXHNdK1xcdykvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEhQIGlQQVFcbiAgICAgICAgICAgIC8oYXN1cyktPyhcXHcrKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFzdXNcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgIC9cXChiYjEwO1xccyhcXHcrKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQmxhY2tCZXJyeSAxMFxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQmxhY2tCZXJyeSddLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQXN1cyBUYWJsZXRzXG4gICAgICAgICAgICAvYW5kcm9pZC4rKHRyYW5zZm9bcHJpbWVcXHNdezQsMTB9XFxzXFx3K3xlZWVwY3xzbGlkZXJcXHNcXHcrfG5leHVzIDd8cGFkZm9uZSkvaVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQXN1cyddLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgLyhzb255KVxccyh0YWJsZXRcXHNbcHNdKVxcc2J1aWxkXFwvL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvbnlcbiAgICAgICAgICAgIC8oc29ueSk/KD86c2dwLispXFxzYnVpbGRcXC8vaVxuICAgICAgICAgICAgXSwgW1tWRU5ET1IsICdTb255J10sIFtNT0RFTCwgJ1hwZXJpYSBUYWJsZXQnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG4gICAgICAgICAgICAvKD86c29ueSk/KD86KD86KD86Y3xkKVxcZHs0fSl8KD86c29bLWxdLispKVxcc2J1aWxkXFwvL2lcbiAgICAgICAgICAgIF0sIFtbVkVORE9SLCAnU29ueSddLCBbTU9ERUwsICdYcGVyaWEgUGhvbmUnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC9cXHMob3V5YSlcXHMvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPdXlhXG4gICAgICAgICAgICAvKG5pbnRlbmRvKVxccyhbd2lkczN1XSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOaW50ZW5kb1xuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBDT05TT0xFXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuKztcXHMoc2hpZWxkKVxcc2J1aWxkL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE52aWRpYVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnTnZpZGlhJ10sIFtUWVBFLCBDT05TT0xFXV0sIFtcblxuICAgICAgICAgICAgLyhwbGF5c3RhdGlvblxcc1szNHBvcnRhYmxldmldKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUGxheXN0YXRpb25cbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ1NvbnknXSwgW1RZUEUsIENPTlNPTEVdXSwgW1xuXG4gICAgICAgICAgICAvKHNwcmludFxccyhcXHcrKSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3ByaW50IFBob25lc1xuICAgICAgICAgICAgXSwgW1tWRU5ET1IsIG1hcHBlci5zdHIsIG1hcHMuZGV2aWNlLnNwcmludC52ZW5kb3JdLCBbTU9ERUwsIG1hcHBlci5zdHIsIG1hcHMuZGV2aWNlLnNwcmludC5tb2RlbF0sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKGxlbm92bylcXHM/KFMoPzo1MDAwfDYwMDApKyg/OlstXVtcXHcrXSkpL2kgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTGVub3ZvIHRhYmxldHNcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgLyhodGMpWztfXFxzLV0rKFtcXHdcXHNdKyg/PVxcKSl8XFx3KykqL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEhUQ1xuICAgICAgICAgICAgLyh6dGUpLShcXHcrKSovaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gWlRFXG4gICAgICAgICAgICAvKGFsY2F0ZWx8Z2Vla3NwaG9uZXxodWF3ZWl8bGVub3ZvfG5leGlhbnxwYW5hc29uaWN8KD89O1xccylzb255KVtfXFxzLV0/KFtcXHctXSspKi9pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFsY2F0ZWwvR2Vla3NQaG9uZS9IdWF3ZWkvTGVub3ZvL05leGlhbi9QYW5hc29uaWMvU29ueVxuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgW01PREVMLCAvXy9nLCAnICddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgLyhuZXh1c1xcczkpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSFRDIE5leHVzIDlcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ0hUQyddLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgLyhuZXh1c1xcczZwKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSHVhd2VpIE5leHVzIDZQXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdIdWF3ZWknXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8obWljcm9zb2Z0KTtcXHMobHVtaWFbXFxzXFx3XSspL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTWljcm9zb2Z0IEx1bWlhXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC9bXFxzXFwoO10oeGJveCg/Olxcc29uZSk/KVtcXHNcXCk7XS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNaWNyb3NvZnQgWGJveFxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnTWljcm9zb2Z0J10sIFtUWVBFLCBDT05TT0xFXV0sIFtcbiAgICAgICAgICAgIC8oa2luXFwuW29uZXR3XXszfSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1pY3Jvc29mdCBLaW5cbiAgICAgICAgICAgIF0sIFtbTU9ERUwsIC9cXC4vZywgJyAnXSwgW1ZFTkRPUiwgJ01pY3Jvc29mdCddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNb3Rvcm9sYVxuICAgICAgICAgICAgL1xccyhtaWxlc3RvbmV8ZHJvaWQoPzpbMi00eF18XFxzKD86YmlvbmljfHgyfHByb3xyYXpyKSk/KDo/XFxzNGcpPylbXFx3XFxzXStidWlsZFxcLy9pLFxuICAgICAgICAgICAgL21vdFtcXHMtXT8oXFx3KykqL2ksXG4gICAgICAgICAgICAvKFhUXFxkezMsNH0pIGJ1aWxkXFwvL2ksXG4gICAgICAgICAgICAvKG5leHVzXFxzNikvaVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnTW90b3JvbGEnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvYW5kcm9pZC4rXFxzKG16NjBcXGR8eG9vbVtcXHMyXXswLDJ9KVxcc2J1aWxkXFwvL2lcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ01vdG9yb2xhJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvaGJidHZcXC9cXGQrXFwuXFxkK1xcLlxcZCtcXHMrXFwoW1xcd1xcc10qO1xccyooXFx3W147XSopOyhbXjtdKikvaSAgICAgICAgICAgIC8vIEhiYlRWIGRldmljZXNcbiAgICAgICAgICAgIF0sIFtbVkVORE9SLCB1dGlsLnRyaW1dLCBbTU9ERUwsIHV0aWwudHJpbV0sIFtUWVBFLCBTTUFSVFRWXV0sIFtcblxuICAgICAgICAgICAgL2hiYnR2LittYXBsZTsoXFxkKykvaVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgL14vLCAnU21hcnRUViddLCBbVkVORE9SLCAnU2Ftc3VuZyddLCBbVFlQRSwgU01BUlRUVl1dLCBbXG5cbiAgICAgICAgICAgIC9cXChkdHZbXFwpO10uKyhhcXVvcykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaGFycFxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnU2hhcnAnXSwgW1RZUEUsIFNNQVJUVFZdXSwgW1xuXG4gICAgICAgICAgICAvYW5kcm9pZC4rKChzY2gtaVs4OV0wXFxkfHNody1tMzgwc3xndC1wXFxkezR9fGd0LW5cXGQrfHNnaC10OFs1Nl05fG5leHVzIDEwKSkvaSxcbiAgICAgICAgICAgIC8oKFNNLVRcXHcrKSkvaVxuICAgICAgICAgICAgXSwgW1tWRU5ET1IsICdTYW1zdW5nJ10sIE1PREVMLCBbVFlQRSwgVEFCTEVUXV0sIFsgICAgICAgICAgICAgICAgICAvLyBTYW1zdW5nXG4gICAgICAgICAgICAvc21hcnQtdHYuKyhzYW1zdW5nKS9pXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBbVFlQRSwgU01BUlRUVl0sIE1PREVMXSwgW1xuICAgICAgICAgICAgLygoc1tjZ3BdaC1cXHcrfGd0LVxcdyt8Z2FsYXh5XFxzbmV4dXN8c20tXFx3W1xcd1xcZF0rKSkvaSxcbiAgICAgICAgICAgIC8oc2FtW3N1bmddKilbXFxzLV0qKFxcdystP1tcXHctXSopKi9pLFxuICAgICAgICAgICAgL3NlYy0oKHNnaFxcdyspKS9pXG4gICAgICAgICAgICBdLCBbW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgTU9ERUwsIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvc2llLShcXHcrKSovaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaWVtZW5zXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdTaWVtZW5zJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKG1hZW1vfG5va2lhKS4qKG45MDB8bHVtaWFcXHNcXGQrKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gTm9raWFcbiAgICAgICAgICAgIC8obm9raWEpW1xcc18tXT8oW1xcdy1dKykqL2lcbiAgICAgICAgICAgIF0sIFtbVkVORE9SLCAnTm9raWEnXSwgTU9ERUwsIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvYW5kcm9pZFxcczNcXC5bXFxzXFx3Oy1dezEwfShhXFxkezN9KS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWNlclxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQWNlciddLCBbVFlQRSwgVEFCTEVUXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWRcXHMzXFwuW1xcc1xcdzstXXsxMH0obGc/KS0oWzA2Y3Y5XXszLDR9KS9pICAgICAgICAgICAgICAgICAgICAgLy8gTEcgVGFibGV0XG4gICAgICAgICAgICBdLCBbW1ZFTkRPUiwgJ0xHJ10sIE1PREVMLCBbVFlQRSwgVEFCTEVUXV0sIFtcbiAgICAgICAgICAgIC8obGcpIG5ldGNhc3RcXC50di9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExHIFNtYXJ0VFZcbiAgICAgICAgICAgIF0sIFtWRU5ET1IsIE1PREVMLCBbVFlQRSwgU01BUlRUVl1dLCBbXG4gICAgICAgICAgICAvKG5leHVzXFxzWzQ1XSkvaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBMR1xuICAgICAgICAgICAgL2xnW2U7XFxzXFwvLV0rKFxcdyspKi9pXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdMRyddLCBbVFlQRSwgTU9CSUxFXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuKyhpZGVhdGFiW2EtejAtOVxcLVxcc10rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExlbm92b1xuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnTGVub3ZvJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuXG4gICAgICAgICAgICAvbGludXg7LisoKGpvbGxhKSk7L2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEpvbGxhXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8oKHBlYmJsZSkpYXBwXFwvW1xcZFxcLl0rXFxzL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBlYmJsZVxuICAgICAgICAgICAgXSwgW1ZFTkRPUiwgTU9ERUwsIFtUWVBFLCBXRUFSQUJMRV1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLis7XFxzKGdsYXNzKVxcc1xcZC9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR29vZ2xlIEdsYXNzXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdHb29nbGUnXSwgW1RZUEUsIFdFQVJBQkxFXV0sIFtcblxuICAgICAgICAgICAgL2FuZHJvaWQuKyhcXHcrKVxccytidWlsZFxcL2htXFwxL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gWGlhb21pIEhvbmdtaSAnbnVtZXJpYycgbW9kZWxzXG4gICAgICAgICAgICAvYW5kcm9pZC4rKGhtW1xcc1xcLV9dKm5vdGU/W1xcc19dKig/OlxcZFxcdyk/KVxccytidWlsZC9pLCAgICAgICAgICAgICAgIC8vIFhpYW9taSBIb25nbWlcbiAgICAgICAgICAgIC9hbmRyb2lkLisobWlbXFxzXFwtX10qKD86b25lfG9uZVtcXHNfXXBsdXN8bm90ZSBsdGUpP1tcXHNfXSooPzpcXGRcXHcpPylcXHMrYnVpbGQvaSAgICAvLyBYaWFvbWkgTWlcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsIC9fL2csICcgJ10sIFtWRU5ET1IsICdYaWFvbWknXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC9hbmRyb2lkLithMDAwKDEpXFxzK2J1aWxkL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9uZVBsdXNcbiAgICAgICAgICAgIF0sIFtNT0RFTCwgW1ZFTkRPUiwgJ09uZVBsdXMnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC9cXHModGFibGV0KVs7XFwvXS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBVbmlkZW50aWZpYWJsZSBUYWJsZXRcbiAgICAgICAgICAgIC9cXHMobW9iaWxlKSg/Ols7XFwvXXxcXHNzYWZhcmkpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVW5pZGVudGlmaWFibGUgTW9iaWxlXG4gICAgICAgICAgICBdLCBbW1RZUEUsIHV0aWwubG93ZXJpemVdLCBWRU5ET1IsIE1PREVMXVxuXG4gICAgICAgICAgICAvKi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG4gICAgICAgICAgICAvLyBUT0RPOiBtb3ZlIHRvIHN0cmluZyBtYXBcbiAgICAgICAgICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cblxuICAgICAgICAgICAgLyhDNjYwMykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTb255IFhwZXJpYSBaIEM2NjAzXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnWHBlcmlhIFogQzY2MDMnXSwgW1ZFTkRPUiwgJ1NvbnknXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKEM2OTAzKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvbnkgWHBlcmlhIFogMVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ1hwZXJpYSBaIDEnXSwgW1ZFTkRPUiwgJ1NvbnknXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8oU00tRzkwMFtGfEhdKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2Ftc3VuZyBHYWxheHkgUzVcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdHYWxheHkgUzUnXSwgW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKFNNLUc3MTAyKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNhbXN1bmcgR2FsYXh5IEdyYW5kIDJcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdHYWxheHkgR3JhbmQgMiddLCBbVkVORE9SLCAnU2Ftc3VuZyddLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgIC8oU00tRzUzMEgpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2Ftc3VuZyBHYWxheHkgR3JhbmQgUHJpbWVcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdHYWxheHkgR3JhbmQgUHJpbWUnXSwgW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKFNNLUczMTNIWikvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNhbXN1bmcgR2FsYXh5IFZcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdHYWxheHkgViddLCBbVkVORE9SLCAnU2Ftc3VuZyddLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgIC8oU00tVDgwNSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2Ftc3VuZyBHYWxheHkgVGFiIFMgMTAuNVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ0dhbGF4eSBUYWIgUyAxMC41J10sIFtWRU5ET1IsICdTYW1zdW5nJ10sIFtUWVBFLCBUQUJMRVRdXSwgW1xuICAgICAgICAgICAgLyhTTS1HODAwRikvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTYW1zdW5nIEdhbGF4eSBTNSBNaW5pXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnR2FsYXh5IFM1IE1pbmknXSwgW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKFNNLVQzMTEpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNhbXN1bmcgR2FsYXh5IFRhYiAzIDguMFxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ0dhbGF4eSBUYWIgMyA4LjAnXSwgW1ZFTkRPUiwgJ1NhbXN1bmcnXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG5cbiAgICAgICAgICAgIC8oUjEwMDEpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BwbyBSMTAwMVxuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnT1BQTyddLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgIC8oWDkwMDYpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BwbyBGaW5kIDdhXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnRmluZCA3YSddLCBbVkVORE9SLCAnT3BwbyddLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgIC8oUjIwMDEpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BwbyBZT1lPIFIyMDAxXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnWW95byBSMjAwMSddLCBbVkVORE9SLCAnT3BwbyddLCBbVFlQRSwgTU9CSUxFXV0sIFtcbiAgICAgICAgICAgIC8oUjgxNSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3BwbyBDbG92ZXIgUjgxNVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ0Nsb3ZlciBSODE1J10sIFtWRU5ET1IsICdPcHBvJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuICAgICAgICAgICAgIC8oVTcwNykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPcHBvIEZpbmQgV2F5IFNcbiAgICAgICAgICAgIF0sIFtbTU9ERUwsICdGaW5kIFdheSBTJ10sIFtWRU5ET1IsICdPcHBvJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKFQzQykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFkdmFuIFZhbmRyb2lkIFQzQ1xuICAgICAgICAgICAgXSwgW01PREVMLCBbVkVORE9SLCAnQWR2YW4nXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG4gICAgICAgICAgICAvKEFEVkFOIFQxSlxcKykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBZHZhbiBWYW5kcm9pZCBUMUorXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnVmFuZHJvaWQgVDFKKyddLCBbVkVORE9SLCAnQWR2YW4nXSwgW1RZUEUsIFRBQkxFVF1dLCBbXG4gICAgICAgICAgICAvKEFEVkFOIFM0QSkvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFkdmFuIFZhbmRyb2lkIFM0QVxuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ1ZhbmRyb2lkIFM0QSddLCBbVkVORE9SLCAnQWR2YW4nXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8oVjk3Mk0pL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gWlRFIFY5NzJNXG4gICAgICAgICAgICBdLCBbTU9ERUwsIFtWRU5ET1IsICdaVEUnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG5cbiAgICAgICAgICAgIC8oaS1tb2JpbGUpXFxzKElRXFxzW1xcZFxcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGktbW9iaWxlIElRXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKElRNi4zKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGktbW9iaWxlIElRIElRIDYuM1xuICAgICAgICAgICAgXSwgW1tNT0RFTCwgJ0lRIDYuMyddLCBbVkVORE9SLCAnaS1tb2JpbGUnXSwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKGktbW9iaWxlKVxccyhpLXN0eWxlXFxzW1xcZFxcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpLW1vYmlsZSBpLVNUWUxFXG4gICAgICAgICAgICBdLCBbVkVORE9SLCBNT0RFTCwgW1RZUEUsIE1PQklMRV1dLCBbXG4gICAgICAgICAgICAvKGktU1RZTEUyLjEpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGktbW9iaWxlIGktU1RZTEUgMi4xXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnaS1TVFlMRSAyLjEnXSwgW1ZFTkRPUiwgJ2ktbW9iaWxlJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvKG1vYmlpc3RhciB0b3VjaCBMQUkgNTEyKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1vYmlpc3RhciB0b3VjaCBMQUkgNTEyXG4gICAgICAgICAgICBdLCBbW01PREVMLCAnVG91Y2ggTEFJIDUxMiddLCBbVkVORE9SLCAnbW9iaWlzdGFyJ10sIFtUWVBFLCBNT0JJTEVdXSwgW1xuXG4gICAgICAgICAgICAvLy8vLy8vLy8vLy8vXG4gICAgICAgICAgICAvLyBFTkQgVE9ET1xuICAgICAgICAgICAgLy8vLy8vLy8vLy8qL1xuXG4gICAgICAgIF0sXG5cbiAgICAgICAgZW5naW5lIDogW1tcblxuICAgICAgICAgICAgL3dpbmRvd3MuK1xcc2VkZ2VcXC8oW1xcd1xcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRWRnZUhUTUxcbiAgICAgICAgICAgIF0sIFtWRVJTSU9OLCBbTkFNRSwgJ0VkZ2VIVE1MJ11dLCBbXG5cbiAgICAgICAgICAgIC8ocHJlc3RvKVxcLyhbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUHJlc3RvXG4gICAgICAgICAgICAvKHdlYmtpdHx0cmlkZW50fG5ldGZyb250fG5ldHN1cmZ8YW1heWF8bHlueHx3M20pXFwvKFtcXHdcXC5dKykvaSwgICAgIC8vIFdlYktpdC9UcmlkZW50L05ldEZyb250L05ldFN1cmYvQW1heWEvTHlueC93M21cbiAgICAgICAgICAgIC8oa2h0bWx8dGFzbWFufGxpbmtzKVtcXC9cXHNdXFwoPyhbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBLSFRNTC9UYXNtYW4vTGlua3NcbiAgICAgICAgICAgIC8oaWNhYilbXFwvXFxzXShbMjNdXFwuW1xcZFxcLl0rKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpQ2FiXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgL3J2XFw6KFtcXHdcXC5dKykuKihnZWNrbykvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHZWNrb1xuICAgICAgICAgICAgXSwgW1ZFUlNJT04sIE5BTUVdXG4gICAgICAgIF0sXG5cbiAgICAgICAgb3MgOiBbW1xuXG4gICAgICAgICAgICAvLyBXaW5kb3dzIGJhc2VkXG4gICAgICAgICAgICAvbWljcm9zb2Z0XFxzKHdpbmRvd3MpXFxzKHZpc3RhfHhwKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gV2luZG93cyAoaVR1bmVzKVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG4gICAgICAgICAgICAvKHdpbmRvd3MpXFxzbnRcXHM2XFwuMjtcXHMoYXJtKS9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBXaW5kb3dzIFJUXG4gICAgICAgICAgICAvKHdpbmRvd3NcXHNwaG9uZSg/Olxcc29zKSopW1xcc1xcL10/KFtcXGRcXC5cXHNdK1xcdykqL2ksICAgICAgICAgICAgICAgICAgLy8gV2luZG93cyBQaG9uZVxuICAgICAgICAgICAgLyh3aW5kb3dzXFxzbW9iaWxlfHdpbmRvd3MpW1xcc1xcL10/KFtudGNlXFxkXFwuXFxzXStcXHcpL2lcbiAgICAgICAgICAgIF0sIFtOQU1FLCBbVkVSU0lPTiwgbWFwcGVyLnN0ciwgbWFwcy5vcy53aW5kb3dzLnZlcnNpb25dXSwgW1xuICAgICAgICAgICAgLyh3aW4oPz0zfDl8bil8d2luXFxzOXhcXHMpKFtudFxcZFxcLl0rKS9pXG4gICAgICAgICAgICBdLCBbW05BTUUsICdXaW5kb3dzJ10sIFtWRVJTSU9OLCBtYXBwZXIuc3RyLCBtYXBzLm9zLndpbmRvd3MudmVyc2lvbl1dLCBbXG5cbiAgICAgICAgICAgIC8vIE1vYmlsZS9FbWJlZGRlZCBPU1xuICAgICAgICAgICAgL1xcKChiYikoMTApOy9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQmxhY2tCZXJyeSAxMFxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnQmxhY2tCZXJyeSddLCBWRVJTSU9OXSwgW1xuICAgICAgICAgICAgLyhibGFja2JlcnJ5KVxcdypcXC8/KFtcXHdcXC5dKykqL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQmxhY2tiZXJyeVxuICAgICAgICAgICAgLyh0aXplbilbXFwvXFxzXShbXFx3XFwuXSspL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGl6ZW5cbiAgICAgICAgICAgIC8oYW5kcm9pZHx3ZWJvc3xwYWxtXFxzb3N8cW54fGJhZGF8cmltXFxzdGFibGV0XFxzb3N8bWVlZ298Y29udGlraSlbXFwvXFxzLV0/KFtcXHdcXC5dKykqL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFuZHJvaWQvV2ViT1MvUGFsbS9RTlgvQmFkYS9SSU0vTWVlR28vQ29udGlraVxuICAgICAgICAgICAgL2xpbnV4Oy4rKHNhaWxmaXNoKTsvaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTYWlsZmlzaCBPU1xuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLCBbXG4gICAgICAgICAgICAvKHN5bWJpYW5cXHM/b3N8c3ltYm9zfHM2MCg/PTspKVtcXC9cXHMtXT8oW1xcd1xcLl0rKSovaSAgICAgICAgICAgICAgICAgLy8gU3ltYmlhblxuICAgICAgICAgICAgXSwgW1tOQU1FLCAnU3ltYmlhbiddLCBWRVJTSU9OXSwgW1xuICAgICAgICAgICAgL1xcKChzZXJpZXM0MCk7L2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2VyaWVzIDQwXG4gICAgICAgICAgICBdLCBbTkFNRV0sIFtcbiAgICAgICAgICAgIC9tb3ppbGxhLitcXChtb2JpbGU7LitnZWNrby4rZmlyZWZveC9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZpcmVmb3ggT1NcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ0ZpcmVmb3ggT1MnXSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLy8gQ29uc29sZVxuICAgICAgICAgICAgLyhuaW50ZW5kb3xwbGF5c3RhdGlvbilcXHMoW3dpZHMzNHBvcnRhYmxldnVdKykvaSwgICAgICAgICAgICAgICAgICAgLy8gTmludGVuZG8vUGxheXN0YXRpb25cblxuICAgICAgICAgICAgLy8gR05VL0xpbnV4IGJhc2VkXG4gICAgICAgICAgICAvKG1pbnQpW1xcL1xcc1xcKF0/KFxcdyspKi9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNaW50XG4gICAgICAgICAgICAvKG1hZ2VpYXx2ZWN0b3JsaW51eClbO1xcc10vaSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNYWdlaWEvVmVjdG9yTGludXhcbiAgICAgICAgICAgIC8oam9saXxba3hsbl0/dWJ1bnR1fGRlYmlhbnxbb3Blbl0qc3VzZXxnZW50b298KD89XFxzKWFyY2h8c2xhY2t3YXJlfGZlZG9yYXxtYW5kcml2YXxjZW50b3N8cGNsaW51eG9zfHJlZGhhdHx6ZW53YWxrfGxpbnB1cylbXFwvXFxzLV0/KD8hY2hyb20pKFtcXHdcXC4tXSspKi9pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBKb2xpL1VidW50dS9EZWJpYW4vU1VTRS9HZW50b28vQXJjaC9TbGFja3dhcmVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRmVkb3JhL01hbmRyaXZhL0NlbnRPUy9QQ0xpbnV4T1MvUmVkSGF0L1plbndhbGsvTGlucHVzXG4gICAgICAgICAgICAvKGh1cmR8bGludXgpXFxzPyhbXFx3XFwuXSspKi9pLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEh1cmQvTGludXhcbiAgICAgICAgICAgIC8oZ251KVxccz8oW1xcd1xcLl0rKSovaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR05VXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sIFtcblxuICAgICAgICAgICAgLyhjcm9zKVxcc1tcXHddK1xccyhbXFx3XFwuXStcXHcpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDaHJvbWl1bSBPU1xuICAgICAgICAgICAgXSwgW1tOQU1FLCAnQ2hyb21pdW0gT1MnXSwgVkVSU0lPTl0sW1xuXG4gICAgICAgICAgICAvLyBTb2xhcmlzXG4gICAgICAgICAgICAvKHN1bm9zKVxccz8oW1xcd1xcLl0rXFxkKSovaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTb2xhcmlzXG4gICAgICAgICAgICBdLCBbW05BTUUsICdTb2xhcmlzJ10sIFZFUlNJT05dLCBbXG5cbiAgICAgICAgICAgIC8vIEJTRCBiYXNlZFxuICAgICAgICAgICAgL1xccyhbZnJlbnRvcGMtXXswLDR9YnNkfGRyYWdvbmZseSlcXHM/KFtcXHdcXC5dKykqL2kgICAgICAgICAgICAgICAgICAgLy8gRnJlZUJTRC9OZXRCU0QvT3BlbkJTRC9QQy1CU0QvRHJhZ29uRmx5XG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl0sW1xuXG4gICAgICAgICAgICAvKGhhaWt1KVxccyhcXHcrKS9pICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBIYWlrdVxuICAgICAgICAgICAgXSwgW05BTUUsIFZFUlNJT05dLFtcblxuICAgICAgICAgICAgLyhpcFtob25lYWRdKykoPzouKm9zXFxzKFtcXHddKykqXFxzbGlrZVxcc21hY3w7XFxzb3BlcmEpL2kgICAgICAgICAgICAgIC8vIGlPU1xuICAgICAgICAgICAgXSwgW1tOQU1FLCAnaU9TJ10sIFtWRVJTSU9OLCAvXy9nLCAnLiddXSwgW1xuXG4gICAgICAgICAgICAvKG1hY1xcc29zXFxzeClcXHM/KFtcXHdcXHNcXC5dK1xcdykqL2ksXG4gICAgICAgICAgICAvKG1hY2ludG9zaHxtYWMoPz1fcG93ZXJwYylcXHMpL2kgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBNYWMgT1NcbiAgICAgICAgICAgIF0sIFtbTkFNRSwgJ01hYyBPUyddLCBbVkVSU0lPTiwgL18vZywgJy4nXV0sIFtcblxuICAgICAgICAgICAgLy8gT3RoZXJcbiAgICAgICAgICAgIC8oKD86b3Blbik/c29sYXJpcylbXFwvXFxzLV0/KFtcXHdcXC5dKykqL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNvbGFyaXNcbiAgICAgICAgICAgIC8oYWl4KVxccygoXFxkKSg/PVxcLnxcXCl8XFxzKVtcXHdcXC5dKikqL2ksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFJWFxuICAgICAgICAgICAgLyhwbGFuXFxzOXxtaW5peHxiZW9zfG9zXFwvMnxhbWlnYW9zfG1vcnBob3N8cmlzY1xcc29zfG9wZW52bXMpL2ksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBsYW45L01pbml4L0JlT1MvT1MyL0FtaWdhT1MvTW9ycGhPUy9SSVNDT1MvT3BlblZNU1xuICAgICAgICAgICAgLyh1bml4KVxccz8oW1xcd1xcLl0rKSovaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBVTklYXG4gICAgICAgICAgICBdLCBbTkFNRSwgVkVSU0lPTl1cbiAgICAgICAgXVxuICAgIH07XG5cblxuICAgIC8vLy8vLy8vLy8vLy8vLy8vXG4gICAgLy8gQ29uc3RydWN0b3JcbiAgICAvLy8vLy8vLy8vLy8vLy8vXG5cblxuICAgIHZhciBVQVBhcnNlciA9IGZ1bmN0aW9uICh1YXN0cmluZywgZXh0ZW5zaW9ucykge1xuXG4gICAgICAgIGlmICghKHRoaXMgaW5zdGFuY2VvZiBVQVBhcnNlcikpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgVUFQYXJzZXIodWFzdHJpbmcsIGV4dGVuc2lvbnMpLmdldFJlc3VsdCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHVhID0gdWFzdHJpbmcgfHwgKCh3aW5kb3cgJiYgd2luZG93Lm5hdmlnYXRvciAmJiB3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudCkgPyB3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudCA6IEVNUFRZKTtcbiAgICAgICAgdmFyIHJneG1hcCA9IGV4dGVuc2lvbnMgPyB1dGlsLmV4dGVuZChyZWdleGVzLCBleHRlbnNpb25zKSA6IHJlZ2V4ZXM7XG5cbiAgICAgICAgdGhpcy5nZXRCcm93c2VyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGJyb3dzZXIgPSBtYXBwZXIucmd4LmFwcGx5KHRoaXMsIHJneG1hcC5icm93c2VyKTtcbiAgICAgICAgICAgIGJyb3dzZXIubWFqb3IgPSB1dGlsLm1ham9yKGJyb3dzZXIudmVyc2lvbik7XG4gICAgICAgICAgICByZXR1cm4gYnJvd3NlcjtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5nZXRDUFUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gbWFwcGVyLnJneC5hcHBseSh0aGlzLCByZ3htYXAuY3B1KTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5nZXREZXZpY2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gbWFwcGVyLnJneC5hcHBseSh0aGlzLCByZ3htYXAuZGV2aWNlKTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5nZXRFbmdpbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gbWFwcGVyLnJneC5hcHBseSh0aGlzLCByZ3htYXAuZW5naW5lKTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5nZXRPUyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBtYXBwZXIucmd4LmFwcGx5KHRoaXMsIHJneG1hcC5vcyk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0UmVzdWx0ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHVhICAgICAgOiB0aGlzLmdldFVBKCksXG4gICAgICAgICAgICAgICAgYnJvd3NlciA6IHRoaXMuZ2V0QnJvd3NlcigpLFxuICAgICAgICAgICAgICAgIGVuZ2luZSAgOiB0aGlzLmdldEVuZ2luZSgpLFxuICAgICAgICAgICAgICAgIG9zICAgICAgOiB0aGlzLmdldE9TKCksXG4gICAgICAgICAgICAgICAgZGV2aWNlICA6IHRoaXMuZ2V0RGV2aWNlKCksXG4gICAgICAgICAgICAgICAgY3B1ICAgICA6IHRoaXMuZ2V0Q1BVKClcbiAgICAgICAgICAgIH07XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0VUEgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdWE7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuc2V0VUEgPSBmdW5jdGlvbiAodWFzdHJpbmcpIHtcbiAgICAgICAgICAgIHVhID0gdWFzdHJpbmc7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIFVBUGFyc2VyLlZFUlNJT04gPSBMSUJWRVJTSU9OO1xuICAgIFVBUGFyc2VyLkJST1dTRVIgPSB7XG4gICAgICAgIE5BTUUgICAgOiBOQU1FLFxuICAgICAgICBNQUpPUiAgIDogTUFKT1IsIC8vIGRlcHJlY2F0ZWRcbiAgICAgICAgVkVSU0lPTiA6IFZFUlNJT05cbiAgICB9O1xuICAgIFVBUGFyc2VyLkNQVSA9IHtcbiAgICAgICAgQVJDSElURUNUVVJFIDogQVJDSElURUNUVVJFXG4gICAgfTtcbiAgICBVQVBhcnNlci5ERVZJQ0UgPSB7XG4gICAgICAgIE1PREVMICAgOiBNT0RFTCxcbiAgICAgICAgVkVORE9SICA6IFZFTkRPUixcbiAgICAgICAgVFlQRSAgICA6IFRZUEUsXG4gICAgICAgIENPTlNPTEUgOiBDT05TT0xFLFxuICAgICAgICBNT0JJTEUgIDogTU9CSUxFLFxuICAgICAgICBTTUFSVFRWIDogU01BUlRUVixcbiAgICAgICAgVEFCTEVUICA6IFRBQkxFVCxcbiAgICAgICAgV0VBUkFCTEU6IFdFQVJBQkxFLFxuICAgICAgICBFTUJFRERFRDogRU1CRURERURcbiAgICB9O1xuICAgIFVBUGFyc2VyLkVOR0lORSA9IHtcbiAgICAgICAgTkFNRSAgICA6IE5BTUUsXG4gICAgICAgIFZFUlNJT04gOiBWRVJTSU9OXG4gICAgfTtcbiAgICBVQVBhcnNlci5PUyA9IHtcbiAgICAgICAgTkFNRSAgICA6IE5BTUUsXG4gICAgICAgIFZFUlNJT04gOiBWRVJTSU9OXG4gICAgfTtcblxuXG4gICAgLy8vLy8vLy8vLy9cbiAgICAvLyBFeHBvcnRcbiAgICAvLy8vLy8vLy8vXG5cblxuICAgIC8vIGNoZWNrIGpzIGVudmlyb25tZW50XG4gICAgaWYgKHR5cGVvZihleHBvcnRzKSAhPT0gVU5ERUZfVFlQRSkge1xuICAgICAgICAvLyBub2RlanMgZW52XG4gICAgICAgIGlmICh0eXBlb2YgbW9kdWxlICE9PSBVTkRFRl9UWVBFICYmIG1vZHVsZS5leHBvcnRzKSB7XG4gICAgICAgICAgICBleHBvcnRzID0gbW9kdWxlLmV4cG9ydHMgPSBVQVBhcnNlcjtcbiAgICAgICAgfVxuICAgICAgICBleHBvcnRzLlVBUGFyc2VyID0gVUFQYXJzZXI7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8gcmVxdWlyZWpzIGVudiAob3B0aW9uYWwpXG4gICAgICAgIGlmICh0eXBlb2YoZGVmaW5lKSA9PT0gRlVOQ19UWVBFICYmIGRlZmluZS5hbWQpIHtcbiAgICAgICAgICAgIGRlZmluZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFVBUGFyc2VyO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBicm93c2VyIGVudlxuICAgICAgICAgICAgd2luZG93LlVBUGFyc2VyID0gVUFQYXJzZXI7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBqUXVlcnkvWmVwdG8gc3BlY2lmaWMgKG9wdGlvbmFsKVxuICAgIC8vIE5vdGU6XG4gICAgLy8gICBJbiBBTUQgZW52IHRoZSBnbG9iYWwgc2NvcGUgc2hvdWxkIGJlIGtlcHQgY2xlYW4sIGJ1dCBqUXVlcnkgaXMgYW4gZXhjZXB0aW9uLlxuICAgIC8vICAgalF1ZXJ5IGFsd2F5cyBleHBvcnRzIHRvIGdsb2JhbCBzY29wZSwgdW5sZXNzIGpRdWVyeS5ub0NvbmZsaWN0KHRydWUpIGlzIHVzZWQsXG4gICAgLy8gICBhbmQgd2Ugc2hvdWxkIGNhdGNoIHRoYXQuXG4gICAgdmFyICQgPSB3aW5kb3cualF1ZXJ5IHx8IHdpbmRvdy5aZXB0bztcbiAgICBpZiAodHlwZW9mICQgIT09IFVOREVGX1RZUEUpIHtcbiAgICAgICAgdmFyIHBhcnNlciA9IG5ldyBVQVBhcnNlcigpO1xuICAgICAgICAkLnVhID0gcGFyc2VyLmdldFJlc3VsdCgpO1xuICAgICAgICAkLnVhLmdldCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHBhcnNlci5nZXRVQSgpO1xuICAgICAgICB9O1xuICAgICAgICAkLnVhLnNldCA9IGZ1bmN0aW9uICh1YXN0cmluZykge1xuICAgICAgICAgICAgcGFyc2VyLnNldFVBKHVhc3RyaW5nKTtcbiAgICAgICAgICAgIHZhciByZXN1bHQgPSBwYXJzZXIuZ2V0UmVzdWx0KCk7XG4gICAgICAgICAgICBmb3IgKHZhciBwcm9wIGluIHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICQudWFbcHJvcF0gPSByZXN1bHRbcHJvcF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG59KSh0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0JyA/IHdpbmRvdyA6IHRoaXMpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgcmVxdWlyZWQgPSByZXF1aXJlKCdyZXF1aXJlcy1wb3J0JylcbiAgLCBxcyA9IHJlcXVpcmUoJ3F1ZXJ5c3RyaW5naWZ5JylcbiAgLCBwcm90b2NvbHJlID0gL14oW2Etel1bYS16MC05ListXSo6KT8oXFwvXFwvKT8oW1xcU1xcc10qKS9pXG4gICwgc2xhc2hlcyA9IC9eW0EtWmEtel1bQS1aYS16MC05Ky0uXSo6XFwvXFwvLztcblxuLyoqXG4gKiBUaGVzZSBhcmUgdGhlIHBhcnNlIHJ1bGVzIGZvciB0aGUgVVJMIHBhcnNlciwgaXQgaW5mb3JtcyB0aGUgcGFyc2VyXG4gKiBhYm91dDpcbiAqXG4gKiAwLiBUaGUgY2hhciBpdCBOZWVkcyB0byBwYXJzZSwgaWYgaXQncyBhIHN0cmluZyBpdCBzaG91bGQgYmUgZG9uZSB1c2luZ1xuICogICAgaW5kZXhPZiwgUmVnRXhwIHVzaW5nIGV4ZWMgYW5kIE5hTiBtZWFucyBzZXQgYXMgY3VycmVudCB2YWx1ZS5cbiAqIDEuIFRoZSBwcm9wZXJ0eSB3ZSBzaG91bGQgc2V0IHdoZW4gcGFyc2luZyB0aGlzIHZhbHVlLlxuICogMi4gSW5kaWNhdGlvbiBpZiBpdCdzIGJhY2t3YXJkcyBvciBmb3J3YXJkIHBhcnNpbmcsIHdoZW4gc2V0IGFzIG51bWJlciBpdCdzXG4gKiAgICB0aGUgdmFsdWUgb2YgZXh0cmEgY2hhcnMgdGhhdCBzaG91bGQgYmUgc3BsaXQgb2ZmLlxuICogMy4gSW5oZXJpdCBmcm9tIGxvY2F0aW9uIGlmIG5vbiBleGlzdGluZyBpbiB0aGUgcGFyc2VyLlxuICogNC4gYHRvTG93ZXJDYXNlYCB0aGUgcmVzdWx0aW5nIHZhbHVlLlxuICovXG52YXIgcnVsZXMgPSBbXG4gIFsnIycsICdoYXNoJ10sICAgICAgICAgICAgICAgICAgICAgICAgLy8gRXh0cmFjdCBmcm9tIHRoZSBiYWNrLlxuICBbJz8nLCAncXVlcnknXSwgICAgICAgICAgICAgICAgICAgICAgIC8vIEV4dHJhY3QgZnJvbSB0aGUgYmFjay5cbiAgWycvJywgJ3BhdGhuYW1lJ10sICAgICAgICAgICAgICAgICAgICAvLyBFeHRyYWN0IGZyb20gdGhlIGJhY2suXG4gIFsnQCcsICdhdXRoJywgMV0sICAgICAgICAgICAgICAgICAgICAgLy8gRXh0cmFjdCBmcm9tIHRoZSBmcm9udC5cbiAgW05hTiwgJ2hvc3QnLCB1bmRlZmluZWQsIDEsIDFdLCAgICAgICAvLyBTZXQgbGVmdCBvdmVyIHZhbHVlLlxuICBbLzooXFxkKykkLywgJ3BvcnQnLCB1bmRlZmluZWQsIDFdLCAgICAvLyBSZWdFeHAgdGhlIGJhY2suXG4gIFtOYU4sICdob3N0bmFtZScsIHVuZGVmaW5lZCwgMSwgMV0gICAgLy8gU2V0IGxlZnQgb3Zlci5cbl07XG5cbi8qKlxuICogVGhlc2UgcHJvcGVydGllcyBzaG91bGQgbm90IGJlIGNvcGllZCBvciBpbmhlcml0ZWQgZnJvbS4gVGhpcyBpcyBvbmx5IG5lZWRlZFxuICogZm9yIGFsbCBub24gYmxvYiBVUkwncyBhcyBhIGJsb2IgVVJMIGRvZXMgbm90IGluY2x1ZGUgYSBoYXNoLCBvbmx5IHRoZVxuICogb3JpZ2luLlxuICpcbiAqIEB0eXBlIHtPYmplY3R9XG4gKiBAcHJpdmF0ZVxuICovXG52YXIgaWdub3JlID0geyBoYXNoOiAxLCBxdWVyeTogMSB9O1xuXG4vKipcbiAqIFRoZSBsb2NhdGlvbiBvYmplY3QgZGlmZmVycyB3aGVuIHlvdXIgY29kZSBpcyBsb2FkZWQgdGhyb3VnaCBhIG5vcm1hbCBwYWdlLFxuICogV29ya2VyIG9yIHRocm91Z2ggYSB3b3JrZXIgdXNpbmcgYSBibG9iLiBBbmQgd2l0aCB0aGUgYmxvYmJsZSBiZWdpbnMgdGhlXG4gKiB0cm91YmxlIGFzIHRoZSBsb2NhdGlvbiBvYmplY3Qgd2lsbCBjb250YWluIHRoZSBVUkwgb2YgdGhlIGJsb2IsIG5vdCB0aGVcbiAqIGxvY2F0aW9uIG9mIHRoZSBwYWdlIHdoZXJlIG91ciBjb2RlIGlzIGxvYWRlZCBpbi4gVGhlIGFjdHVhbCBvcmlnaW4gaXNcbiAqIGVuY29kZWQgaW4gdGhlIGBwYXRobmFtZWAgc28gd2UgY2FuIHRoYW5rZnVsbHkgZ2VuZXJhdGUgYSBnb29kIFwiZGVmYXVsdFwiXG4gKiBsb2NhdGlvbiBmcm9tIGl0IHNvIHdlIGNhbiBnZW5lcmF0ZSBwcm9wZXIgcmVsYXRpdmUgVVJMJ3MgYWdhaW4uXG4gKlxuICogQHBhcmFtIHtPYmplY3R8U3RyaW5nfSBsb2MgT3B0aW9uYWwgZGVmYXVsdCBsb2NhdGlvbiBvYmplY3QuXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBsb2xjYXRpb24gb2JqZWN0LlxuICogQGFwaSBwdWJsaWNcbiAqL1xuZnVuY3Rpb24gbG9sY2F0aW9uKGxvYykge1xuICBsb2MgPSBsb2MgfHwgZ2xvYmFsLmxvY2F0aW9uIHx8IHt9O1xuXG4gIHZhciBmaW5hbGRlc3RpbmF0aW9uID0ge31cbiAgICAsIHR5cGUgPSB0eXBlb2YgbG9jXG4gICAgLCBrZXk7XG5cbiAgaWYgKCdibG9iOicgPT09IGxvYy5wcm90b2NvbCkge1xuICAgIGZpbmFsZGVzdGluYXRpb24gPSBuZXcgVVJMKHVuZXNjYXBlKGxvYy5wYXRobmFtZSksIHt9KTtcbiAgfSBlbHNlIGlmICgnc3RyaW5nJyA9PT0gdHlwZSkge1xuICAgIGZpbmFsZGVzdGluYXRpb24gPSBuZXcgVVJMKGxvYywge30pO1xuICAgIGZvciAoa2V5IGluIGlnbm9yZSkgZGVsZXRlIGZpbmFsZGVzdGluYXRpb25ba2V5XTtcbiAgfSBlbHNlIGlmICgnb2JqZWN0JyA9PT0gdHlwZSkge1xuICAgIGZvciAoa2V5IGluIGxvYykge1xuICAgICAgaWYgKGtleSBpbiBpZ25vcmUpIGNvbnRpbnVlO1xuICAgICAgZmluYWxkZXN0aW5hdGlvbltrZXldID0gbG9jW2tleV07XG4gICAgfVxuXG4gICAgaWYgKGZpbmFsZGVzdGluYXRpb24uc2xhc2hlcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBmaW5hbGRlc3RpbmF0aW9uLnNsYXNoZXMgPSBzbGFzaGVzLnRlc3QobG9jLmhyZWYpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmaW5hbGRlc3RpbmF0aW9uO1xufVxuXG4vKipcbiAqIEB0eXBlZGVmIFByb3RvY29sRXh0cmFjdFxuICogQHR5cGUgT2JqZWN0XG4gKiBAcHJvcGVydHkge1N0cmluZ30gcHJvdG9jb2wgUHJvdG9jb2wgbWF0Y2hlZCBpbiB0aGUgVVJMLCBpbiBsb3dlcmNhc2UuXG4gKiBAcHJvcGVydHkge0Jvb2xlYW59IHNsYXNoZXMgYHRydWVgIGlmIHByb3RvY29sIGlzIGZvbGxvd2VkIGJ5IFwiLy9cIiwgZWxzZSBgZmFsc2VgLlxuICogQHByb3BlcnR5IHtTdHJpbmd9IHJlc3QgUmVzdCBvZiB0aGUgVVJMIHRoYXQgaXMgbm90IHBhcnQgb2YgdGhlIHByb3RvY29sLlxuICovXG5cbi8qKlxuICogRXh0cmFjdCBwcm90b2NvbCBpbmZvcm1hdGlvbiBmcm9tIGEgVVJMIHdpdGgvd2l0aG91dCBkb3VibGUgc2xhc2ggKFwiLy9cIikuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IGFkZHJlc3MgVVJMIHdlIHdhbnQgdG8gZXh0cmFjdCBmcm9tLlxuICogQHJldHVybiB7UHJvdG9jb2xFeHRyYWN0fSBFeHRyYWN0ZWQgaW5mb3JtYXRpb24uXG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gZXh0cmFjdFByb3RvY29sKGFkZHJlc3MpIHtcbiAgdmFyIG1hdGNoID0gcHJvdG9jb2xyZS5leGVjKGFkZHJlc3MpO1xuXG4gIHJldHVybiB7XG4gICAgcHJvdG9jb2w6IG1hdGNoWzFdID8gbWF0Y2hbMV0udG9Mb3dlckNhc2UoKSA6ICcnLFxuICAgIHNsYXNoZXM6ICEhbWF0Y2hbMl0sXG4gICAgcmVzdDogbWF0Y2hbM11cbiAgfTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGEgcmVsYXRpdmUgVVJMIHBhdGhuYW1lIGFnYWluc3QgYSBiYXNlIFVSTCBwYXRobmFtZS5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gcmVsYXRpdmUgUGF0aG5hbWUgb2YgdGhlIHJlbGF0aXZlIFVSTC5cbiAqIEBwYXJhbSB7U3RyaW5nfSBiYXNlIFBhdGhuYW1lIG9mIHRoZSBiYXNlIFVSTC5cbiAqIEByZXR1cm4ge1N0cmluZ30gUmVzb2x2ZWQgcGF0aG5hbWUuXG4gKiBAYXBpIHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gcmVzb2x2ZShyZWxhdGl2ZSwgYmFzZSkge1xuICB2YXIgcGF0aCA9IChiYXNlIHx8ICcvJykuc3BsaXQoJy8nKS5zbGljZSgwLCAtMSkuY29uY2F0KHJlbGF0aXZlLnNwbGl0KCcvJykpXG4gICAgLCBpID0gcGF0aC5sZW5ndGhcbiAgICAsIGxhc3QgPSBwYXRoW2kgLSAxXVxuICAgICwgdW5zaGlmdCA9IGZhbHNlXG4gICAgLCB1cCA9IDA7XG5cbiAgd2hpbGUgKGktLSkge1xuICAgIGlmIChwYXRoW2ldID09PSAnLicpIHtcbiAgICAgIHBhdGguc3BsaWNlKGksIDEpO1xuICAgIH0gZWxzZSBpZiAocGF0aFtpXSA9PT0gJy4uJykge1xuICAgICAgcGF0aC5zcGxpY2UoaSwgMSk7XG4gICAgICB1cCsrO1xuICAgIH0gZWxzZSBpZiAodXApIHtcbiAgICAgIGlmIChpID09PSAwKSB1bnNoaWZ0ID0gdHJ1ZTtcbiAgICAgIHBhdGguc3BsaWNlKGksIDEpO1xuICAgICAgdXAtLTtcbiAgICB9XG4gIH1cblxuICBpZiAodW5zaGlmdCkgcGF0aC51bnNoaWZ0KCcnKTtcbiAgaWYgKGxhc3QgPT09ICcuJyB8fCBsYXN0ID09PSAnLi4nKSBwYXRoLnB1c2goJycpO1xuXG4gIHJldHVybiBwYXRoLmpvaW4oJy8nKTtcbn1cblxuLyoqXG4gKiBUaGUgYWN0dWFsIFVSTCBpbnN0YW5jZS4gSW5zdGVhZCBvZiByZXR1cm5pbmcgYW4gb2JqZWN0IHdlJ3ZlIG9wdGVkLWluIHRvXG4gKiBjcmVhdGUgYW4gYWN0dWFsIGNvbnN0cnVjdG9yIGFzIGl0J3MgbXVjaCBtb3JlIG1lbW9yeSBlZmZpY2llbnQgYW5kXG4gKiBmYXN0ZXIgYW5kIGl0IHBsZWFzZXMgbXkgT0NELlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICogQHBhcmFtIHtTdHJpbmd9IGFkZHJlc3MgVVJMIHdlIHdhbnQgdG8gcGFyc2UuXG4gKiBAcGFyYW0ge09iamVjdHxTdHJpbmd9IGxvY2F0aW9uIExvY2F0aW9uIGRlZmF1bHRzIGZvciByZWxhdGl2ZSBwYXRocy5cbiAqIEBwYXJhbSB7Qm9vbGVhbnxGdW5jdGlvbn0gcGFyc2VyIFBhcnNlciBmb3IgdGhlIHF1ZXJ5IHN0cmluZy5cbiAqIEBhcGkgcHVibGljXG4gKi9cbmZ1bmN0aW9uIFVSTChhZGRyZXNzLCBsb2NhdGlvbiwgcGFyc2VyKSB7XG4gIGlmICghKHRoaXMgaW5zdGFuY2VvZiBVUkwpKSB7XG4gICAgcmV0dXJuIG5ldyBVUkwoYWRkcmVzcywgbG9jYXRpb24sIHBhcnNlcik7XG4gIH1cblxuICB2YXIgcmVsYXRpdmUsIGV4dHJhY3RlZCwgcGFyc2UsIGluc3RydWN0aW9uLCBpbmRleCwga2V5XG4gICAgLCBpbnN0cnVjdGlvbnMgPSBydWxlcy5zbGljZSgpXG4gICAgLCB0eXBlID0gdHlwZW9mIGxvY2F0aW9uXG4gICAgLCB1cmwgPSB0aGlzXG4gICAgLCBpID0gMDtcblxuICAvL1xuICAvLyBUaGUgZm9sbG93aW5nIGlmIHN0YXRlbWVudHMgYWxsb3dzIHRoaXMgbW9kdWxlIHR3byBoYXZlIGNvbXBhdGliaWxpdHkgd2l0aFxuICAvLyAyIGRpZmZlcmVudCBBUEk6XG4gIC8vXG4gIC8vIDEuIE5vZGUuanMncyBgdXJsLnBhcnNlYCBhcGkgd2hpY2ggYWNjZXB0cyBhIFVSTCwgYm9vbGVhbiBhcyBhcmd1bWVudHNcbiAgLy8gICAgd2hlcmUgdGhlIGJvb2xlYW4gaW5kaWNhdGVzIHRoYXQgdGhlIHF1ZXJ5IHN0cmluZyBzaG91bGQgYWxzbyBiZSBwYXJzZWQuXG4gIC8vXG4gIC8vIDIuIFRoZSBgVVJMYCBpbnRlcmZhY2Ugb2YgdGhlIGJyb3dzZXIgd2hpY2ggYWNjZXB0cyBhIFVSTCwgb2JqZWN0IGFzXG4gIC8vICAgIGFyZ3VtZW50cy4gVGhlIHN1cHBsaWVkIG9iamVjdCB3aWxsIGJlIHVzZWQgYXMgZGVmYXVsdCB2YWx1ZXMgLyBmYWxsLWJhY2tcbiAgLy8gICAgZm9yIHJlbGF0aXZlIHBhdGhzLlxuICAvL1xuICBpZiAoJ29iamVjdCcgIT09IHR5cGUgJiYgJ3N0cmluZycgIT09IHR5cGUpIHtcbiAgICBwYXJzZXIgPSBsb2NhdGlvbjtcbiAgICBsb2NhdGlvbiA9IG51bGw7XG4gIH1cblxuICBpZiAocGFyc2VyICYmICdmdW5jdGlvbicgIT09IHR5cGVvZiBwYXJzZXIpIHBhcnNlciA9IHFzLnBhcnNlO1xuXG4gIGxvY2F0aW9uID0gbG9sY2F0aW9uKGxvY2F0aW9uKTtcblxuICAvL1xuICAvLyBFeHRyYWN0IHByb3RvY29sIGluZm9ybWF0aW9uIGJlZm9yZSBydW5uaW5nIHRoZSBpbnN0cnVjdGlvbnMuXG4gIC8vXG4gIGV4dHJhY3RlZCA9IGV4dHJhY3RQcm90b2NvbChhZGRyZXNzIHx8ICcnKTtcbiAgcmVsYXRpdmUgPSAhZXh0cmFjdGVkLnByb3RvY29sICYmICFleHRyYWN0ZWQuc2xhc2hlcztcbiAgdXJsLnNsYXNoZXMgPSBleHRyYWN0ZWQuc2xhc2hlcyB8fCByZWxhdGl2ZSAmJiBsb2NhdGlvbi5zbGFzaGVzO1xuICB1cmwucHJvdG9jb2wgPSBleHRyYWN0ZWQucHJvdG9jb2wgfHwgbG9jYXRpb24ucHJvdG9jb2wgfHwgJyc7XG4gIGFkZHJlc3MgPSBleHRyYWN0ZWQucmVzdDtcblxuICAvL1xuICAvLyBXaGVuIHRoZSBhdXRob3JpdHkgY29tcG9uZW50IGlzIGFic2VudCB0aGUgVVJMIHN0YXJ0cyB3aXRoIGEgcGF0aFxuICAvLyBjb21wb25lbnQuXG4gIC8vXG4gIGlmICghZXh0cmFjdGVkLnNsYXNoZXMpIGluc3RydWN0aW9uc1syXSA9IFsvKC4qKS8sICdwYXRobmFtZSddO1xuXG4gIGZvciAoOyBpIDwgaW5zdHJ1Y3Rpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgaW5zdHJ1Y3Rpb24gPSBpbnN0cnVjdGlvbnNbaV07XG4gICAgcGFyc2UgPSBpbnN0cnVjdGlvblswXTtcbiAgICBrZXkgPSBpbnN0cnVjdGlvblsxXTtcblxuICAgIGlmIChwYXJzZSAhPT0gcGFyc2UpIHtcbiAgICAgIHVybFtrZXldID0gYWRkcmVzcztcbiAgICB9IGVsc2UgaWYgKCdzdHJpbmcnID09PSB0eXBlb2YgcGFyc2UpIHtcbiAgICAgIGlmICh+KGluZGV4ID0gYWRkcmVzcy5pbmRleE9mKHBhcnNlKSkpIHtcbiAgICAgICAgaWYgKCdudW1iZXInID09PSB0eXBlb2YgaW5zdHJ1Y3Rpb25bMl0pIHtcbiAgICAgICAgICB1cmxba2V5XSA9IGFkZHJlc3Muc2xpY2UoMCwgaW5kZXgpO1xuICAgICAgICAgIGFkZHJlc3MgPSBhZGRyZXNzLnNsaWNlKGluZGV4ICsgaW5zdHJ1Y3Rpb25bMl0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHVybFtrZXldID0gYWRkcmVzcy5zbGljZShpbmRleCk7XG4gICAgICAgICAgYWRkcmVzcyA9IGFkZHJlc3Muc2xpY2UoMCwgaW5kZXgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICgoaW5kZXggPSBwYXJzZS5leGVjKGFkZHJlc3MpKSkge1xuICAgICAgdXJsW2tleV0gPSBpbmRleFsxXTtcbiAgICAgIGFkZHJlc3MgPSBhZGRyZXNzLnNsaWNlKDAsIGluZGV4LmluZGV4KTtcbiAgICB9XG5cbiAgICB1cmxba2V5XSA9IHVybFtrZXldIHx8IChcbiAgICAgIHJlbGF0aXZlICYmIGluc3RydWN0aW9uWzNdID8gbG9jYXRpb25ba2V5XSB8fCAnJyA6ICcnXG4gICAgKTtcblxuICAgIC8vXG4gICAgLy8gSG9zdG5hbWUsIGhvc3QgYW5kIHByb3RvY29sIHNob3VsZCBiZSBsb3dlcmNhc2VkIHNvIHRoZXkgY2FuIGJlIHVzZWQgdG9cbiAgICAvLyBjcmVhdGUgYSBwcm9wZXIgYG9yaWdpbmAuXG4gICAgLy9cbiAgICBpZiAoaW5zdHJ1Y3Rpb25bNF0pIHVybFtrZXldID0gdXJsW2tleV0udG9Mb3dlckNhc2UoKTtcbiAgfVxuXG4gIC8vXG4gIC8vIEFsc28gcGFyc2UgdGhlIHN1cHBsaWVkIHF1ZXJ5IHN0cmluZyBpbiB0byBhbiBvYmplY3QuIElmIHdlJ3JlIHN1cHBsaWVkXG4gIC8vIHdpdGggYSBjdXN0b20gcGFyc2VyIGFzIGZ1bmN0aW9uIHVzZSB0aGF0IGluc3RlYWQgb2YgdGhlIGRlZmF1bHQgYnVpbGQtaW5cbiAgLy8gcGFyc2VyLlxuICAvL1xuICBpZiAocGFyc2VyKSB1cmwucXVlcnkgPSBwYXJzZXIodXJsLnF1ZXJ5KTtcblxuICAvL1xuICAvLyBJZiB0aGUgVVJMIGlzIHJlbGF0aXZlLCByZXNvbHZlIHRoZSBwYXRobmFtZSBhZ2FpbnN0IHRoZSBiYXNlIFVSTC5cbiAgLy9cbiAgaWYgKFxuICAgICAgcmVsYXRpdmVcbiAgICAmJiBsb2NhdGlvbi5zbGFzaGVzXG4gICAgJiYgdXJsLnBhdGhuYW1lLmNoYXJBdCgwKSAhPT0gJy8nXG4gICAgJiYgKHVybC5wYXRobmFtZSAhPT0gJycgfHwgbG9jYXRpb24ucGF0aG5hbWUgIT09ICcnKVxuICApIHtcbiAgICB1cmwucGF0aG5hbWUgPSByZXNvbHZlKHVybC5wYXRobmFtZSwgbG9jYXRpb24ucGF0aG5hbWUpO1xuICB9XG5cbiAgLy9cbiAgLy8gV2Ugc2hvdWxkIG5vdCBhZGQgcG9ydCBudW1iZXJzIGlmIHRoZXkgYXJlIGFscmVhZHkgdGhlIGRlZmF1bHQgcG9ydCBudW1iZXJcbiAgLy8gZm9yIGEgZ2l2ZW4gcHJvdG9jb2wuIEFzIHRoZSBob3N0IGFsc28gY29udGFpbnMgdGhlIHBvcnQgbnVtYmVyIHdlJ3JlIGdvaW5nXG4gIC8vIG92ZXJyaWRlIGl0IHdpdGggdGhlIGhvc3RuYW1lIHdoaWNoIGNvbnRhaW5zIG5vIHBvcnQgbnVtYmVyLlxuICAvL1xuICBpZiAoIXJlcXVpcmVkKHVybC5wb3J0LCB1cmwucHJvdG9jb2wpKSB7XG4gICAgdXJsLmhvc3QgPSB1cmwuaG9zdG5hbWU7XG4gICAgdXJsLnBvcnQgPSAnJztcbiAgfVxuXG4gIC8vXG4gIC8vIFBhcnNlIGRvd24gdGhlIGBhdXRoYCBmb3IgdGhlIHVzZXJuYW1lIGFuZCBwYXNzd29yZC5cbiAgLy9cbiAgdXJsLnVzZXJuYW1lID0gdXJsLnBhc3N3b3JkID0gJyc7XG4gIGlmICh1cmwuYXV0aCkge1xuICAgIGluc3RydWN0aW9uID0gdXJsLmF1dGguc3BsaXQoJzonKTtcbiAgICB1cmwudXNlcm5hbWUgPSBpbnN0cnVjdGlvblswXSB8fCAnJztcbiAgICB1cmwucGFzc3dvcmQgPSBpbnN0cnVjdGlvblsxXSB8fCAnJztcbiAgfVxuXG4gIHVybC5vcmlnaW4gPSB1cmwucHJvdG9jb2wgJiYgdXJsLmhvc3QgJiYgdXJsLnByb3RvY29sICE9PSAnZmlsZTonXG4gICAgPyB1cmwucHJvdG9jb2wgKycvLycrIHVybC5ob3N0XG4gICAgOiAnbnVsbCc7XG5cbiAgLy9cbiAgLy8gVGhlIGhyZWYgaXMganVzdCB0aGUgY29tcGlsZWQgcmVzdWx0LlxuICAvL1xuICB1cmwuaHJlZiA9IHVybC50b1N0cmluZygpO1xufVxuXG4vKipcbiAqIFRoaXMgaXMgY29udmVuaWVuY2UgbWV0aG9kIGZvciBjaGFuZ2luZyBwcm9wZXJ0aWVzIGluIHRoZSBVUkwgaW5zdGFuY2UgdG9cbiAqIGluc3VyZSB0aGF0IHRoZXkgYWxsIHByb3BhZ2F0ZSBjb3JyZWN0bHkuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHBhcnQgICAgICAgICAgUHJvcGVydHkgd2UgbmVlZCB0byBhZGp1c3QuXG4gKiBAcGFyYW0ge01peGVkfSB2YWx1ZSAgICAgICAgICBUaGUgbmV3bHkgYXNzaWduZWQgdmFsdWUuXG4gKiBAcGFyYW0ge0Jvb2xlYW58RnVuY3Rpb259IGZuICBXaGVuIHNldHRpbmcgdGhlIHF1ZXJ5LCBpdCB3aWxsIGJlIHRoZSBmdW5jdGlvblxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlZCB0byBwYXJzZSB0aGUgcXVlcnkuXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXaGVuIHNldHRpbmcgdGhlIHByb3RvY29sLCBkb3VibGUgc2xhc2ggd2lsbCBiZVxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlZCBmcm9tIHRoZSBmaW5hbCB1cmwgaWYgaXQgaXMgdHJ1ZS5cbiAqIEByZXR1cm5zIHtVUkx9XG4gKiBAYXBpIHB1YmxpY1xuICovXG5mdW5jdGlvbiBzZXQocGFydCwgdmFsdWUsIGZuKSB7XG4gIHZhciB1cmwgPSB0aGlzO1xuXG4gIHN3aXRjaCAocGFydCkge1xuICAgIGNhc2UgJ3F1ZXJ5JzpcbiAgICAgIGlmICgnc3RyaW5nJyA9PT0gdHlwZW9mIHZhbHVlICYmIHZhbHVlLmxlbmd0aCkge1xuICAgICAgICB2YWx1ZSA9IChmbiB8fCBxcy5wYXJzZSkodmFsdWUpO1xuICAgICAgfVxuXG4gICAgICB1cmxbcGFydF0gPSB2YWx1ZTtcbiAgICAgIGJyZWFrO1xuXG4gICAgY2FzZSAncG9ydCc6XG4gICAgICB1cmxbcGFydF0gPSB2YWx1ZTtcblxuICAgICAgaWYgKCFyZXF1aXJlZCh2YWx1ZSwgdXJsLnByb3RvY29sKSkge1xuICAgICAgICB1cmwuaG9zdCA9IHVybC5ob3N0bmFtZTtcbiAgICAgICAgdXJsW3BhcnRdID0gJyc7XG4gICAgICB9IGVsc2UgaWYgKHZhbHVlKSB7XG4gICAgICAgIHVybC5ob3N0ID0gdXJsLmhvc3RuYW1lICsnOicrIHZhbHVlO1xuICAgICAgfVxuXG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ2hvc3RuYW1lJzpcbiAgICAgIHVybFtwYXJ0XSA9IHZhbHVlO1xuXG4gICAgICBpZiAodXJsLnBvcnQpIHZhbHVlICs9ICc6JysgdXJsLnBvcnQ7XG4gICAgICB1cmwuaG9zdCA9IHZhbHVlO1xuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICdob3N0JzpcbiAgICAgIHVybFtwYXJ0XSA9IHZhbHVlO1xuXG4gICAgICBpZiAoLzpcXGQrJC8udGVzdCh2YWx1ZSkpIHtcbiAgICAgICAgdmFsdWUgPSB2YWx1ZS5zcGxpdCgnOicpO1xuICAgICAgICB1cmwucG9ydCA9IHZhbHVlLnBvcCgpO1xuICAgICAgICB1cmwuaG9zdG5hbWUgPSB2YWx1ZS5qb2luKCc6Jyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB1cmwuaG9zdG5hbWUgPSB2YWx1ZTtcbiAgICAgICAgdXJsLnBvcnQgPSAnJztcbiAgICAgIH1cblxuICAgICAgYnJlYWs7XG5cbiAgICBjYXNlICdwcm90b2NvbCc6XG4gICAgICB1cmwucHJvdG9jb2wgPSB2YWx1ZS50b0xvd2VyQ2FzZSgpO1xuICAgICAgdXJsLnNsYXNoZXMgPSAhZm47XG4gICAgICBicmVhaztcblxuICAgIGNhc2UgJ3BhdGhuYW1lJzpcbiAgICAgIHVybC5wYXRobmFtZSA9IHZhbHVlLmxlbmd0aCAmJiB2YWx1ZS5jaGFyQXQoMCkgIT09ICcvJyA/ICcvJyArIHZhbHVlIDogdmFsdWU7XG5cbiAgICAgIGJyZWFrO1xuXG4gICAgZGVmYXVsdDpcbiAgICAgIHVybFtwYXJ0XSA9IHZhbHVlO1xuICB9XG5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBydWxlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBpbnMgPSBydWxlc1tpXTtcblxuICAgIGlmIChpbnNbNF0pIHVybFtpbnNbMV1dID0gdXJsW2luc1sxXV0udG9Mb3dlckNhc2UoKTtcbiAgfVxuXG4gIHVybC5vcmlnaW4gPSB1cmwucHJvdG9jb2wgJiYgdXJsLmhvc3QgJiYgdXJsLnByb3RvY29sICE9PSAnZmlsZTonXG4gICAgPyB1cmwucHJvdG9jb2wgKycvLycrIHVybC5ob3N0XG4gICAgOiAnbnVsbCc7XG5cbiAgdXJsLmhyZWYgPSB1cmwudG9TdHJpbmcoKTtcblxuICByZXR1cm4gdXJsO1xufVxuXG4vKipcbiAqIFRyYW5zZm9ybSB0aGUgcHJvcGVydGllcyBiYWNrIGluIHRvIGEgdmFsaWQgYW5kIGZ1bGwgVVJMIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBzdHJpbmdpZnkgT3B0aW9uYWwgcXVlcnkgc3RyaW5naWZ5IGZ1bmN0aW9uLlxuICogQHJldHVybnMge1N0cmluZ31cbiAqIEBhcGkgcHVibGljXG4gKi9cbmZ1bmN0aW9uIHRvU3RyaW5nKHN0cmluZ2lmeSkge1xuICBpZiAoIXN0cmluZ2lmeSB8fCAnZnVuY3Rpb24nICE9PSB0eXBlb2Ygc3RyaW5naWZ5KSBzdHJpbmdpZnkgPSBxcy5zdHJpbmdpZnk7XG5cbiAgdmFyIHF1ZXJ5XG4gICAgLCB1cmwgPSB0aGlzXG4gICAgLCBwcm90b2NvbCA9IHVybC5wcm90b2NvbDtcblxuICBpZiAocHJvdG9jb2wgJiYgcHJvdG9jb2wuY2hhckF0KHByb3RvY29sLmxlbmd0aCAtIDEpICE9PSAnOicpIHByb3RvY29sICs9ICc6JztcblxuICB2YXIgcmVzdWx0ID0gcHJvdG9jb2wgKyAodXJsLnNsYXNoZXMgPyAnLy8nIDogJycpO1xuXG4gIGlmICh1cmwudXNlcm5hbWUpIHtcbiAgICByZXN1bHQgKz0gdXJsLnVzZXJuYW1lO1xuICAgIGlmICh1cmwucGFzc3dvcmQpIHJlc3VsdCArPSAnOicrIHVybC5wYXNzd29yZDtcbiAgICByZXN1bHQgKz0gJ0AnO1xuICB9XG5cbiAgcmVzdWx0ICs9IHVybC5ob3N0ICsgdXJsLnBhdGhuYW1lO1xuXG4gIHF1ZXJ5ID0gJ29iamVjdCcgPT09IHR5cGVvZiB1cmwucXVlcnkgPyBzdHJpbmdpZnkodXJsLnF1ZXJ5KSA6IHVybC5xdWVyeTtcbiAgaWYgKHF1ZXJ5KSByZXN1bHQgKz0gJz8nICE9PSBxdWVyeS5jaGFyQXQoMCkgPyAnPycrIHF1ZXJ5IDogcXVlcnk7XG5cbiAgaWYgKHVybC5oYXNoKSByZXN1bHQgKz0gdXJsLmhhc2g7XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuVVJMLnByb3RvdHlwZSA9IHsgc2V0OiBzZXQsIHRvU3RyaW5nOiB0b1N0cmluZyB9O1xuXG4vL1xuLy8gRXhwb3NlIHRoZSBVUkwgcGFyc2VyIGFuZCBzb21lIGFkZGl0aW9uYWwgcHJvcGVydGllcyB0aGF0IG1pZ2h0IGJlIHVzZWZ1bCBmb3Jcbi8vIG90aGVycyBvciB0ZXN0aW5nLlxuLy9cblVSTC5leHRyYWN0UHJvdG9jb2wgPSBleHRyYWN0UHJvdG9jb2w7XG5VUkwubG9jYXRpb24gPSBsb2xjYXRpb247XG5VUkwucXMgPSBxcztcblxubW9kdWxlLmV4cG9ydHMgPSBVUkw7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBoYXMgPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5O1xuXG4vKipcbiAqIERlY29kZSBhIFVSSSBlbmNvZGVkIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgVGhlIFVSSSBlbmNvZGVkIHN0cmluZy5cbiAqIEByZXR1cm5zIHtTdHJpbmd9IFRoZSBkZWNvZGVkIHN0cmluZy5cbiAqIEBhcGkgcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBkZWNvZGUoaW5wdXQpIHtcbiAgcmV0dXJuIGRlY29kZVVSSUNvbXBvbmVudChpbnB1dC5yZXBsYWNlKC9cXCsvZywgJyAnKSk7XG59XG5cbi8qKlxuICogU2ltcGxlIHF1ZXJ5IHN0cmluZyBwYXJzZXIuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHF1ZXJ5IFRoZSBxdWVyeSBzdHJpbmcgdGhhdCBuZWVkcyB0byBiZSBwYXJzZWQuXG4gKiBAcmV0dXJucyB7T2JqZWN0fVxuICogQGFwaSBwdWJsaWNcbiAqL1xuZnVuY3Rpb24gcXVlcnlzdHJpbmcocXVlcnkpIHtcbiAgdmFyIHBhcnNlciA9IC8oW149PyZdKyk9PyhbXiZdKikvZ1xuICAgICwgcmVzdWx0ID0ge31cbiAgICAsIHBhcnQ7XG5cbiAgLy9cbiAgLy8gTGl0dGxlIG5pZnR5IHBhcnNpbmcgaGFjaywgbGV2ZXJhZ2UgdGhlIGZhY3QgdGhhdCBSZWdFeHAuZXhlYyBpbmNyZW1lbnRzXG4gIC8vIHRoZSBsYXN0SW5kZXggcHJvcGVydHkgc28gd2UgY2FuIGNvbnRpbnVlIGV4ZWN1dGluZyB0aGlzIGxvb3AgdW50aWwgd2UndmVcbiAgLy8gcGFyc2VkIGFsbCByZXN1bHRzLlxuICAvL1xuICBmb3IgKDtcbiAgICBwYXJ0ID0gcGFyc2VyLmV4ZWMocXVlcnkpO1xuICAgIHJlc3VsdFtkZWNvZGUocGFydFsxXSldID0gZGVjb2RlKHBhcnRbMl0pXG4gICk7XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqXG4gKiBUcmFuc2Zvcm0gYSBxdWVyeSBzdHJpbmcgdG8gYW4gb2JqZWN0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogT2JqZWN0IHRoYXQgc2hvdWxkIGJlIHRyYW5zZm9ybWVkLlxuICogQHBhcmFtIHtTdHJpbmd9IHByZWZpeCBPcHRpb25hbCBwcmVmaXguXG4gKiBAcmV0dXJucyB7U3RyaW5nfVxuICogQGFwaSBwdWJsaWNcbiAqL1xuZnVuY3Rpb24gcXVlcnlzdHJpbmdpZnkob2JqLCBwcmVmaXgpIHtcbiAgcHJlZml4ID0gcHJlZml4IHx8ICcnO1xuXG4gIHZhciBwYWlycyA9IFtdO1xuXG4gIC8vXG4gIC8vIE9wdGlvbmFsbHkgcHJlZml4IHdpdGggYSAnPycgaWYgbmVlZGVkXG4gIC8vXG4gIGlmICgnc3RyaW5nJyAhPT0gdHlwZW9mIHByZWZpeCkgcHJlZml4ID0gJz8nO1xuXG4gIGZvciAodmFyIGtleSBpbiBvYmopIHtcbiAgICBpZiAoaGFzLmNhbGwob2JqLCBrZXkpKSB7XG4gICAgICBwYWlycy5wdXNoKGVuY29kZVVSSUNvbXBvbmVudChrZXkpICsnPScrIGVuY29kZVVSSUNvbXBvbmVudChvYmpba2V5XSkpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBwYWlycy5sZW5ndGggPyBwcmVmaXggKyBwYWlycy5qb2luKCcmJykgOiAnJztcbn1cblxuLy9cbi8vIEV4cG9zZSB0aGUgbW9kdWxlLlxuLy9cbmV4cG9ydHMuc3RyaW5naWZ5ID0gcXVlcnlzdHJpbmdpZnk7XG5leHBvcnRzLnBhcnNlID0gcXVlcnlzdHJpbmc7XG4iLCJcbnZhciBybmc7XG5cbnZhciBjcnlwdG8gPSBnbG9iYWwuY3J5cHRvIHx8IGdsb2JhbC5tc0NyeXB0bzsgLy8gZm9yIElFIDExXG5pZiAoY3J5cHRvICYmIGNyeXB0by5nZXRSYW5kb21WYWx1ZXMpIHtcbiAgLy8gV0hBVFdHIGNyeXB0by1iYXNlZCBSTkcgLSBodHRwOi8vd2lraS53aGF0d2cub3JnL3dpa2kvQ3J5cHRvXG4gIC8vIE1vZGVyYXRlbHkgZmFzdCwgaGlnaCBxdWFsaXR5XG4gIHZhciBfcm5kczggPSBuZXcgVWludDhBcnJheSgxNik7XG4gIHJuZyA9IGZ1bmN0aW9uIHdoYXR3Z1JORygpIHtcbiAgICBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKF9ybmRzOCk7XG4gICAgcmV0dXJuIF9ybmRzODtcbiAgfTtcbn1cblxuaWYgKCFybmcpIHtcbiAgLy8gTWF0aC5yYW5kb20oKS1iYXNlZCAoUk5HKVxuICAvL1xuICAvLyBJZiBhbGwgZWxzZSBmYWlscywgdXNlIE1hdGgucmFuZG9tKCkuICBJdCdzIGZhc3QsIGJ1dCBpcyBvZiB1bnNwZWNpZmllZFxuICAvLyBxdWFsaXR5LlxuICB2YXIgIF9ybmRzID0gbmV3IEFycmF5KDE2KTtcbiAgcm5nID0gZnVuY3Rpb24oKSB7XG4gICAgZm9yICh2YXIgaSA9IDAsIHI7IGkgPCAxNjsgaSsrKSB7XG4gICAgICBpZiAoKGkgJiAweDAzKSA9PT0gMCkgciA9IE1hdGgucmFuZG9tKCkgKiAweDEwMDAwMDAwMDtcbiAgICAgIF9ybmRzW2ldID0gciA+Pj4gKChpICYgMHgwMykgPDwgMykgJiAweGZmO1xuICAgIH1cblxuICAgIHJldHVybiBfcm5kcztcbiAgfTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBybmc7XG5cbiIsIi8vICAgICB1dWlkLmpzXG4vL1xuLy8gICAgIENvcHlyaWdodCAoYykgMjAxMC0yMDEyIFJvYmVydCBLaWVmZmVyXG4vLyAgICAgTUlUIExpY2Vuc2UgLSBodHRwOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvbWl0LWxpY2Vuc2UucGhwXG5cbi8vIFVuaXF1ZSBJRCBjcmVhdGlvbiByZXF1aXJlcyBhIGhpZ2ggcXVhbGl0eSByYW5kb20gIyBnZW5lcmF0b3IuICBXZSBmZWF0dXJlXG4vLyBkZXRlY3QgdG8gZGV0ZXJtaW5lIHRoZSBiZXN0IFJORyBzb3VyY2UsIG5vcm1hbGl6aW5nIHRvIGEgZnVuY3Rpb24gdGhhdFxuLy8gcmV0dXJucyAxMjgtYml0cyBvZiByYW5kb21uZXNzLCBzaW5jZSB0aGF0J3Mgd2hhdCdzIHVzdWFsbHkgcmVxdWlyZWRcbnZhciBfcm5nID0gcmVxdWlyZSgnLi9ybmcnKTtcblxuLy8gTWFwcyBmb3IgbnVtYmVyIDwtPiBoZXggc3RyaW5nIGNvbnZlcnNpb25cbnZhciBfYnl0ZVRvSGV4ID0gW107XG52YXIgX2hleFRvQnl0ZSA9IHt9O1xuZm9yICh2YXIgaSA9IDA7IGkgPCAyNTY7IGkrKykge1xuICBfYnl0ZVRvSGV4W2ldID0gKGkgKyAweDEwMCkudG9TdHJpbmcoMTYpLnN1YnN0cigxKTtcbiAgX2hleFRvQnl0ZVtfYnl0ZVRvSGV4W2ldXSA9IGk7XG59XG5cbi8vICoqYHBhcnNlKClgIC0gUGFyc2UgYSBVVUlEIGludG8gaXQncyBjb21wb25lbnQgYnl0ZXMqKlxuZnVuY3Rpb24gcGFyc2UocywgYnVmLCBvZmZzZXQpIHtcbiAgdmFyIGkgPSAoYnVmICYmIG9mZnNldCkgfHwgMCwgaWkgPSAwO1xuXG4gIGJ1ZiA9IGJ1ZiB8fCBbXTtcbiAgcy50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1swLTlhLWZdezJ9L2csIGZ1bmN0aW9uKG9jdCkge1xuICAgIGlmIChpaSA8IDE2KSB7IC8vIERvbid0IG92ZXJmbG93IVxuICAgICAgYnVmW2kgKyBpaSsrXSA9IF9oZXhUb0J5dGVbb2N0XTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFplcm8gb3V0IHJlbWFpbmluZyBieXRlcyBpZiBzdHJpbmcgd2FzIHNob3J0XG4gIHdoaWxlIChpaSA8IDE2KSB7XG4gICAgYnVmW2kgKyBpaSsrXSA9IDA7XG4gIH1cblxuICByZXR1cm4gYnVmO1xufVxuXG4vLyAqKmB1bnBhcnNlKClgIC0gQ29udmVydCBVVUlEIGJ5dGUgYXJyYXkgKGFsYSBwYXJzZSgpKSBpbnRvIGEgc3RyaW5nKipcbmZ1bmN0aW9uIHVucGFyc2UoYnVmLCBvZmZzZXQpIHtcbiAgdmFyIGkgPSBvZmZzZXQgfHwgMCwgYnRoID0gX2J5dGVUb0hleDtcbiAgcmV0dXJuICBidGhbYnVmW2krK11dICsgYnRoW2J1ZltpKytdXSArXG4gICAgICAgICAgYnRoW2J1ZltpKytdXSArIGJ0aFtidWZbaSsrXV0gKyAnLScgK1xuICAgICAgICAgIGJ0aFtidWZbaSsrXV0gKyBidGhbYnVmW2krK11dICsgJy0nICtcbiAgICAgICAgICBidGhbYnVmW2krK11dICsgYnRoW2J1ZltpKytdXSArICctJyArXG4gICAgICAgICAgYnRoW2J1ZltpKytdXSArIGJ0aFtidWZbaSsrXV0gKyAnLScgK1xuICAgICAgICAgIGJ0aFtidWZbaSsrXV0gKyBidGhbYnVmW2krK11dICtcbiAgICAgICAgICBidGhbYnVmW2krK11dICsgYnRoW2J1ZltpKytdXSArXG4gICAgICAgICAgYnRoW2J1ZltpKytdXSArIGJ0aFtidWZbaSsrXV07XG59XG5cbi8vICoqYHYxKClgIC0gR2VuZXJhdGUgdGltZS1iYXNlZCBVVUlEKipcbi8vXG4vLyBJbnNwaXJlZCBieSBodHRwczovL2dpdGh1Yi5jb20vTGlvc0svVVVJRC5qc1xuLy8gYW5kIGh0dHA6Ly9kb2NzLnB5dGhvbi5vcmcvbGlicmFyeS91dWlkLmh0bWxcblxuLy8gcmFuZG9tICMncyB3ZSBuZWVkIHRvIGluaXQgbm9kZSBhbmQgY2xvY2tzZXFcbnZhciBfc2VlZEJ5dGVzID0gX3JuZygpO1xuXG4vLyBQZXIgNC41LCBjcmVhdGUgYW5kIDQ4LWJpdCBub2RlIGlkLCAoNDcgcmFuZG9tIGJpdHMgKyBtdWx0aWNhc3QgYml0ID0gMSlcbnZhciBfbm9kZUlkID0gW1xuICBfc2VlZEJ5dGVzWzBdIHwgMHgwMSxcbiAgX3NlZWRCeXRlc1sxXSwgX3NlZWRCeXRlc1syXSwgX3NlZWRCeXRlc1szXSwgX3NlZWRCeXRlc1s0XSwgX3NlZWRCeXRlc1s1XVxuXTtcblxuLy8gUGVyIDQuMi4yLCByYW5kb21pemUgKDE0IGJpdCkgY2xvY2tzZXFcbnZhciBfY2xvY2tzZXEgPSAoX3NlZWRCeXRlc1s2XSA8PCA4IHwgX3NlZWRCeXRlc1s3XSkgJiAweDNmZmY7XG5cbi8vIFByZXZpb3VzIHV1aWQgY3JlYXRpb24gdGltZVxudmFyIF9sYXN0TVNlY3MgPSAwLCBfbGFzdE5TZWNzID0gMDtcblxuLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9icm9vZmEvbm9kZS11dWlkIGZvciBBUEkgZGV0YWlsc1xuZnVuY3Rpb24gdjEob3B0aW9ucywgYnVmLCBvZmZzZXQpIHtcbiAgdmFyIGkgPSBidWYgJiYgb2Zmc2V0IHx8IDA7XG4gIHZhciBiID0gYnVmIHx8IFtdO1xuXG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gIHZhciBjbG9ja3NlcSA9IG9wdGlvbnMuY2xvY2tzZXEgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuY2xvY2tzZXEgOiBfY2xvY2tzZXE7XG5cbiAgLy8gVVVJRCB0aW1lc3RhbXBzIGFyZSAxMDAgbmFuby1zZWNvbmQgdW5pdHMgc2luY2UgdGhlIEdyZWdvcmlhbiBlcG9jaCxcbiAgLy8gKDE1ODItMTAtMTUgMDA6MDApLiAgSlNOdW1iZXJzIGFyZW4ndCBwcmVjaXNlIGVub3VnaCBmb3IgdGhpcywgc29cbiAgLy8gdGltZSBpcyBoYW5kbGVkIGludGVybmFsbHkgYXMgJ21zZWNzJyAoaW50ZWdlciBtaWxsaXNlY29uZHMpIGFuZCAnbnNlY3MnXG4gIC8vICgxMDAtbmFub3NlY29uZHMgb2Zmc2V0IGZyb20gbXNlY3MpIHNpbmNlIHVuaXggZXBvY2gsIDE5NzAtMDEtMDEgMDA6MDAuXG4gIHZhciBtc2VjcyA9IG9wdGlvbnMubXNlY3MgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMubXNlY3MgOiBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcblxuICAvLyBQZXIgNC4yLjEuMiwgdXNlIGNvdW50IG9mIHV1aWQncyBnZW5lcmF0ZWQgZHVyaW5nIHRoZSBjdXJyZW50IGNsb2NrXG4gIC8vIGN5Y2xlIHRvIHNpbXVsYXRlIGhpZ2hlciByZXNvbHV0aW9uIGNsb2NrXG4gIHZhciBuc2VjcyA9IG9wdGlvbnMubnNlY3MgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMubnNlY3MgOiBfbGFzdE5TZWNzICsgMTtcblxuICAvLyBUaW1lIHNpbmNlIGxhc3QgdXVpZCBjcmVhdGlvbiAoaW4gbXNlY3MpXG4gIHZhciBkdCA9IChtc2VjcyAtIF9sYXN0TVNlY3MpICsgKG5zZWNzIC0gX2xhc3ROU2VjcykvMTAwMDA7XG5cbiAgLy8gUGVyIDQuMi4xLjIsIEJ1bXAgY2xvY2tzZXEgb24gY2xvY2sgcmVncmVzc2lvblxuICBpZiAoZHQgPCAwICYmIG9wdGlvbnMuY2xvY2tzZXEgPT09IHVuZGVmaW5lZCkge1xuICAgIGNsb2Nrc2VxID0gY2xvY2tzZXEgKyAxICYgMHgzZmZmO1xuICB9XG5cbiAgLy8gUmVzZXQgbnNlY3MgaWYgY2xvY2sgcmVncmVzc2VzIChuZXcgY2xvY2tzZXEpIG9yIHdlJ3ZlIG1vdmVkIG9udG8gYSBuZXdcbiAgLy8gdGltZSBpbnRlcnZhbFxuICBpZiAoKGR0IDwgMCB8fCBtc2VjcyA+IF9sYXN0TVNlY3MpICYmIG9wdGlvbnMubnNlY3MgPT09IHVuZGVmaW5lZCkge1xuICAgIG5zZWNzID0gMDtcbiAgfVxuXG4gIC8vIFBlciA0LjIuMS4yIFRocm93IGVycm9yIGlmIHRvbyBtYW55IHV1aWRzIGFyZSByZXF1ZXN0ZWRcbiAgaWYgKG5zZWNzID49IDEwMDAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCd1dWlkLnYxKCk6IENhblxcJ3QgY3JlYXRlIG1vcmUgdGhhbiAxME0gdXVpZHMvc2VjJyk7XG4gIH1cblxuICBfbGFzdE1TZWNzID0gbXNlY3M7XG4gIF9sYXN0TlNlY3MgPSBuc2VjcztcbiAgX2Nsb2Nrc2VxID0gY2xvY2tzZXE7XG5cbiAgLy8gUGVyIDQuMS40IC0gQ29udmVydCBmcm9tIHVuaXggZXBvY2ggdG8gR3JlZ29yaWFuIGVwb2NoXG4gIG1zZWNzICs9IDEyMjE5MjkyODAwMDAwO1xuXG4gIC8vIGB0aW1lX2xvd2BcbiAgdmFyIHRsID0gKChtc2VjcyAmIDB4ZmZmZmZmZikgKiAxMDAwMCArIG5zZWNzKSAlIDB4MTAwMDAwMDAwO1xuICBiW2krK10gPSB0bCA+Pj4gMjQgJiAweGZmO1xuICBiW2krK10gPSB0bCA+Pj4gMTYgJiAweGZmO1xuICBiW2krK10gPSB0bCA+Pj4gOCAmIDB4ZmY7XG4gIGJbaSsrXSA9IHRsICYgMHhmZjtcblxuICAvLyBgdGltZV9taWRgXG4gIHZhciB0bWggPSAobXNlY3MgLyAweDEwMDAwMDAwMCAqIDEwMDAwKSAmIDB4ZmZmZmZmZjtcbiAgYltpKytdID0gdG1oID4+PiA4ICYgMHhmZjtcbiAgYltpKytdID0gdG1oICYgMHhmZjtcblxuICAvLyBgdGltZV9oaWdoX2FuZF92ZXJzaW9uYFxuICBiW2krK10gPSB0bWggPj4+IDI0ICYgMHhmIHwgMHgxMDsgLy8gaW5jbHVkZSB2ZXJzaW9uXG4gIGJbaSsrXSA9IHRtaCA+Pj4gMTYgJiAweGZmO1xuXG4gIC8vIGBjbG9ja19zZXFfaGlfYW5kX3Jlc2VydmVkYCAoUGVyIDQuMi4yIC0gaW5jbHVkZSB2YXJpYW50KVxuICBiW2krK10gPSBjbG9ja3NlcSA+Pj4gOCB8IDB4ODA7XG5cbiAgLy8gYGNsb2NrX3NlcV9sb3dgXG4gIGJbaSsrXSA9IGNsb2Nrc2VxICYgMHhmZjtcblxuICAvLyBgbm9kZWBcbiAgdmFyIG5vZGUgPSBvcHRpb25zLm5vZGUgfHwgX25vZGVJZDtcbiAgZm9yICh2YXIgbiA9IDA7IG4gPCA2OyBuKyspIHtcbiAgICBiW2kgKyBuXSA9IG5vZGVbbl07XG4gIH1cblxuICByZXR1cm4gYnVmID8gYnVmIDogdW5wYXJzZShiKTtcbn1cblxuLy8gKipgdjQoKWAgLSBHZW5lcmF0ZSByYW5kb20gVVVJRCoqXG5cbi8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vYnJvb2ZhL25vZGUtdXVpZCBmb3IgQVBJIGRldGFpbHNcbmZ1bmN0aW9uIHY0KG9wdGlvbnMsIGJ1Ziwgb2Zmc2V0KSB7XG4gIC8vIERlcHJlY2F0ZWQgLSAnZm9ybWF0JyBhcmd1bWVudCwgYXMgc3VwcG9ydGVkIGluIHYxLjJcbiAgdmFyIGkgPSBidWYgJiYgb2Zmc2V0IHx8IDA7XG5cbiAgaWYgKHR5cGVvZihvcHRpb25zKSA9PSAnc3RyaW5nJykge1xuICAgIGJ1ZiA9IG9wdGlvbnMgPT0gJ2JpbmFyeScgPyBuZXcgQXJyYXkoMTYpIDogbnVsbDtcbiAgICBvcHRpb25zID0gbnVsbDtcbiAgfVxuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICB2YXIgcm5kcyA9IG9wdGlvbnMucmFuZG9tIHx8IChvcHRpb25zLnJuZyB8fCBfcm5nKSgpO1xuXG4gIC8vIFBlciA0LjQsIHNldCBiaXRzIGZvciB2ZXJzaW9uIGFuZCBgY2xvY2tfc2VxX2hpX2FuZF9yZXNlcnZlZGBcbiAgcm5kc1s2XSA9IChybmRzWzZdICYgMHgwZikgfCAweDQwO1xuICBybmRzWzhdID0gKHJuZHNbOF0gJiAweDNmKSB8IDB4ODA7XG5cbiAgLy8gQ29weSBieXRlcyB0byBidWZmZXIsIGlmIHByb3ZpZGVkXG4gIGlmIChidWYpIHtcbiAgICBmb3IgKHZhciBpaSA9IDA7IGlpIDwgMTY7IGlpKyspIHtcbiAgICAgIGJ1ZltpICsgaWldID0gcm5kc1tpaV07XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGJ1ZiB8fCB1bnBhcnNlKHJuZHMpO1xufVxuXG4vLyBFeHBvcnQgcHVibGljIEFQSVxudmFyIHV1aWQgPSB2NDtcbnV1aWQudjEgPSB2MTtcbnV1aWQudjQgPSB2NDtcbnV1aWQucGFyc2UgPSBwYXJzZTtcbnV1aWQudW5wYXJzZSA9IHVucGFyc2U7XG5cbm1vZHVsZS5leHBvcnRzID0gdXVpZDtcbiIsIi8qXG4gKiAgQ29weXJpZ2h0IChjKSAyMDE2IFRoZSBXZWJSVEMgcHJvamVjdCBhdXRob3JzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqICBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZSBsaWNlbnNlXG4gKiAgdGhhdCBjYW4gYmUgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBvZiB0aGUgc291cmNlXG4gKiAgdHJlZS5cbiAqL1xuIC8qIGVzbGludC1lbnYgbm9kZSAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbi8vIFNoaW1taW5nIHN0YXJ0cyBoZXJlLlxuKGZ1bmN0aW9uKCkge1xuICAvLyBVdGlscy5cbiAgdmFyIHV0aWxzID0gcmVxdWlyZSgnLi91dGlscycpO1xuICB2YXIgbG9nZ2luZyA9IHV0aWxzLmxvZztcbiAgdmFyIGJyb3dzZXJEZXRhaWxzID0gdXRpbHMuYnJvd3NlckRldGFpbHM7XG4gIC8vIEV4cG9ydCB0byB0aGUgYWRhcHRlciBnbG9iYWwgb2JqZWN0IHZpc2libGUgaW4gdGhlIGJyb3dzZXIuXG4gIG1vZHVsZS5leHBvcnRzLmJyb3dzZXJEZXRhaWxzID0gYnJvd3NlckRldGFpbHM7XG4gIG1vZHVsZS5leHBvcnRzLmV4dHJhY3RWZXJzaW9uID0gdXRpbHMuZXh0cmFjdFZlcnNpb247XG4gIG1vZHVsZS5leHBvcnRzLmRpc2FibGVMb2cgPSB1dGlscy5kaXNhYmxlTG9nO1xuXG4gIC8vIFVuY29tbWVudCB0aGUgbGluZSBiZWxvdyBpZiB5b3Ugd2FudCBsb2dnaW5nIHRvIG9jY3VyLCBpbmNsdWRpbmcgbG9nZ2luZ1xuICAvLyBmb3IgdGhlIHN3aXRjaCBzdGF0ZW1lbnQgYmVsb3cuIENhbiBhbHNvIGJlIHR1cm5lZCBvbiBpbiB0aGUgYnJvd3NlciB2aWFcbiAgLy8gYWRhcHRlci5kaXNhYmxlTG9nKGZhbHNlKSwgYnV0IHRoZW4gbG9nZ2luZyBmcm9tIHRoZSBzd2l0Y2ggc3RhdGVtZW50IGJlbG93XG4gIC8vIHdpbGwgbm90IGFwcGVhci5cbiAgLy8gcmVxdWlyZSgnLi91dGlscycpLmRpc2FibGVMb2coZmFsc2UpO1xuXG4gIC8vIEJyb3dzZXIgc2hpbXMuXG4gIHZhciBjaHJvbWVTaGltID0gcmVxdWlyZSgnLi9jaHJvbWUvY2hyb21lX3NoaW0nKSB8fCBudWxsO1xuICB2YXIgZWRnZVNoaW0gPSByZXF1aXJlKCcuL2VkZ2UvZWRnZV9zaGltJykgfHwgbnVsbDtcbiAgdmFyIGZpcmVmb3hTaGltID0gcmVxdWlyZSgnLi9maXJlZm94L2ZpcmVmb3hfc2hpbScpIHx8IG51bGw7XG4gIHZhciBzYWZhcmlTaGltID0gcmVxdWlyZSgnLi9zYWZhcmkvc2FmYXJpX3NoaW0nKSB8fCBudWxsO1xuXG4gIC8vIFNoaW0gYnJvd3NlciBpZiBmb3VuZC5cbiAgc3dpdGNoIChicm93c2VyRGV0YWlscy5icm93c2VyKSB7XG4gICAgY2FzZSAnY2hyb21lJzpcbiAgICAgIGlmICghY2hyb21lU2hpbSB8fCAhY2hyb21lU2hpbS5zaGltUGVlckNvbm5lY3Rpb24pIHtcbiAgICAgICAgbG9nZ2luZygnQ2hyb21lIHNoaW0gaXMgbm90IGluY2x1ZGVkIGluIHRoaXMgYWRhcHRlciByZWxlYXNlLicpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBsb2dnaW5nKCdhZGFwdGVyLmpzIHNoaW1taW5nIGNocm9tZS4nKTtcbiAgICAgIC8vIEV4cG9ydCB0byB0aGUgYWRhcHRlciBnbG9iYWwgb2JqZWN0IHZpc2libGUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICBtb2R1bGUuZXhwb3J0cy5icm93c2VyU2hpbSA9IGNocm9tZVNoaW07XG5cbiAgICAgIGNocm9tZVNoaW0uc2hpbUdldFVzZXJNZWRpYSgpO1xuICAgICAgY2hyb21lU2hpbS5zaGltTWVkaWFTdHJlYW0oKTtcbiAgICAgIHV0aWxzLnNoaW1DcmVhdGVPYmplY3RVUkwoKTtcbiAgICAgIGNocm9tZVNoaW0uc2hpbVNvdXJjZU9iamVjdCgpO1xuICAgICAgY2hyb21lU2hpbS5zaGltUGVlckNvbm5lY3Rpb24oKTtcbiAgICAgIGNocm9tZVNoaW0uc2hpbU9uVHJhY2soKTtcbiAgICAgIGNocm9tZVNoaW0uc2hpbUdldFNlbmRlcnNXaXRoRHRtZigpO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAnZmlyZWZveCc6XG4gICAgICBpZiAoIWZpcmVmb3hTaGltIHx8ICFmaXJlZm94U2hpbS5zaGltUGVlckNvbm5lY3Rpb24pIHtcbiAgICAgICAgbG9nZ2luZygnRmlyZWZveCBzaGltIGlzIG5vdCBpbmNsdWRlZCBpbiB0aGlzIGFkYXB0ZXIgcmVsZWFzZS4nKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgbG9nZ2luZygnYWRhcHRlci5qcyBzaGltbWluZyBmaXJlZm94LicpO1xuICAgICAgLy8gRXhwb3J0IHRvIHRoZSBhZGFwdGVyIGdsb2JhbCBvYmplY3QgdmlzaWJsZSBpbiB0aGUgYnJvd3Nlci5cbiAgICAgIG1vZHVsZS5leHBvcnRzLmJyb3dzZXJTaGltID0gZmlyZWZveFNoaW07XG5cbiAgICAgIGZpcmVmb3hTaGltLnNoaW1HZXRVc2VyTWVkaWEoKTtcbiAgICAgIHV0aWxzLnNoaW1DcmVhdGVPYmplY3RVUkwoKTtcbiAgICAgIGZpcmVmb3hTaGltLnNoaW1Tb3VyY2VPYmplY3QoKTtcbiAgICAgIGZpcmVmb3hTaGltLnNoaW1QZWVyQ29ubmVjdGlvbigpO1xuICAgICAgZmlyZWZveFNoaW0uc2hpbU9uVHJhY2soKTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgJ2VkZ2UnOlxuICAgICAgaWYgKCFlZGdlU2hpbSB8fCAhZWRnZVNoaW0uc2hpbVBlZXJDb25uZWN0aW9uKSB7XG4gICAgICAgIGxvZ2dpbmcoJ01TIGVkZ2Ugc2hpbSBpcyBub3QgaW5jbHVkZWQgaW4gdGhpcyBhZGFwdGVyIHJlbGVhc2UuJyk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGxvZ2dpbmcoJ2FkYXB0ZXIuanMgc2hpbW1pbmcgZWRnZS4nKTtcbiAgICAgIC8vIEV4cG9ydCB0byB0aGUgYWRhcHRlciBnbG9iYWwgb2JqZWN0IHZpc2libGUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICBtb2R1bGUuZXhwb3J0cy5icm93c2VyU2hpbSA9IGVkZ2VTaGltO1xuXG4gICAgICBlZGdlU2hpbS5zaGltR2V0VXNlck1lZGlhKCk7XG4gICAgICB1dGlscy5zaGltQ3JlYXRlT2JqZWN0VVJMKCk7XG4gICAgICBlZGdlU2hpbS5zaGltUGVlckNvbm5lY3Rpb24oKTtcbiAgICAgIGVkZ2VTaGltLnNoaW1SZXBsYWNlVHJhY2soKTtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgJ3NhZmFyaSc6XG4gICAgICBpZiAoIXNhZmFyaVNoaW0pIHtcbiAgICAgICAgbG9nZ2luZygnU2FmYXJpIHNoaW0gaXMgbm90IGluY2x1ZGVkIGluIHRoaXMgYWRhcHRlciByZWxlYXNlLicpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBsb2dnaW5nKCdhZGFwdGVyLmpzIHNoaW1taW5nIHNhZmFyaS4nKTtcbiAgICAgIC8vIEV4cG9ydCB0byB0aGUgYWRhcHRlciBnbG9iYWwgb2JqZWN0IHZpc2libGUgaW4gdGhlIGJyb3dzZXIuXG4gICAgICBtb2R1bGUuZXhwb3J0cy5icm93c2VyU2hpbSA9IHNhZmFyaVNoaW07XG5cbiAgICAgIHNhZmFyaVNoaW0uc2hpbU9uQWRkU3RyZWFtKCk7XG4gICAgICBzYWZhcmlTaGltLnNoaW1HZXRVc2VyTWVkaWEoKTtcbiAgICAgIGJyZWFrO1xuICAgIGRlZmF1bHQ6XG4gICAgICBsb2dnaW5nKCdVbnN1cHBvcnRlZCBicm93c2VyIScpO1xuICB9XG59KSgpO1xuIiwiXG4vKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcbnZhciBsb2dnaW5nID0gcmVxdWlyZSgnLi4vdXRpbHMuanMnKS5sb2c7XG52YXIgYnJvd3NlckRldGFpbHMgPSByZXF1aXJlKCcuLi91dGlscy5qcycpLmJyb3dzZXJEZXRhaWxzO1xuXG52YXIgY2hyb21lU2hpbSA9IHtcbiAgc2hpbU1lZGlhU3RyZWFtOiBmdW5jdGlvbigpIHtcbiAgICB3aW5kb3cuTWVkaWFTdHJlYW0gPSB3aW5kb3cuTWVkaWFTdHJlYW0gfHwgd2luZG93LndlYmtpdE1lZGlhU3RyZWFtO1xuICB9LFxuXG4gIHNoaW1PblRyYWNrOiBmdW5jdGlvbigpIHtcbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PT0gJ29iamVjdCcgJiYgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uICYmICEoJ29udHJhY2snIGluXG4gICAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUpKSB7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSwgJ29udHJhY2snLCB7XG4gICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMuX29udHJhY2s7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24oZikge1xuICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgICBpZiAodGhpcy5fb250cmFjaykge1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVyKCd0cmFjaycsIHRoaXMuX29udHJhY2spO1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVyKCdhZGRzdHJlYW0nLCB0aGlzLl9vbnRyYWNrcG9seSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcigndHJhY2snLCB0aGlzLl9vbnRyYWNrID0gZik7XG4gICAgICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVyKCdhZGRzdHJlYW0nLCB0aGlzLl9vbnRyYWNrcG9seSA9IGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgICAgIC8vIG9uYWRkc3RyZWFtIGRvZXMgbm90IGZpcmUgd2hlbiBhIHRyYWNrIGlzIGFkZGVkIHRvIGFuIGV4aXN0aW5nXG4gICAgICAgICAgICAvLyBzdHJlYW0uIEJ1dCBzdHJlYW0ub25hZGR0cmFjayBpcyBpbXBsZW1lbnRlZCBzbyB3ZSB1c2UgdGhhdC5cbiAgICAgICAgICAgIGUuc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ2FkZHRyYWNrJywgZnVuY3Rpb24odGUpIHtcbiAgICAgICAgICAgICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCd0cmFjaycpO1xuICAgICAgICAgICAgICBldmVudC50cmFjayA9IHRlLnRyYWNrO1xuICAgICAgICAgICAgICBldmVudC5yZWNlaXZlciA9IHt0cmFjazogdGUudHJhY2t9O1xuICAgICAgICAgICAgICBldmVudC5zdHJlYW1zID0gW2Uuc3RyZWFtXTtcbiAgICAgICAgICAgICAgc2VsZi5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgZS5zdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbih0cmFjaykge1xuICAgICAgICAgICAgICB2YXIgZXZlbnQgPSBuZXcgRXZlbnQoJ3RyYWNrJyk7XG4gICAgICAgICAgICAgIGV2ZW50LnRyYWNrID0gdHJhY2s7XG4gICAgICAgICAgICAgIGV2ZW50LnJlY2VpdmVyID0ge3RyYWNrOiB0cmFja307XG4gICAgICAgICAgICAgIGV2ZW50LnN0cmVhbXMgPSBbZS5zdHJlYW1dO1xuICAgICAgICAgICAgICB0aGlzLmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuICAgICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH0sXG5cbiAgc2hpbUdldFNlbmRlcnNXaXRoRHRtZjogZnVuY3Rpb24oKSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnICYmIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbiAmJlxuICAgICAgICAhKCdnZXRTZW5kZXJzJyBpbiBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUpICYmXG4gICAgICAgICdjcmVhdGVEVE1GU2VuZGVyJyBpbiBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUpIHtcbiAgICAgIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRTZW5kZXJzID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9zZW5kZXJzO1xuICAgICAgfTtcbiAgICAgIHZhciBvcmlnQWRkU3RyZWFtID0gUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZFN0cmVhbTtcbiAgICAgIHZhciBvcmlnUmVtb3ZlU3RyZWFtID0gUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnJlbW92ZVN0cmVhbTtcblxuICAgICAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZFN0cmVhbSA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICB2YXIgcGMgPSB0aGlzO1xuICAgICAgICBwYy5fc2VuZGVycyA9IHBjLl9zZW5kZXJzIHx8IFtdO1xuICAgICAgICBvcmlnQWRkU3RyZWFtLmFwcGx5KHBjLCBbc3RyZWFtXSk7XG4gICAgICAgIHN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgICAgICAgcGMuX3NlbmRlcnMucHVzaCh7XG4gICAgICAgICAgICB0cmFjazogdHJhY2ssXG4gICAgICAgICAgICBnZXQgZHRtZigpIHtcbiAgICAgICAgICAgICAgaWYgKHRoaXMuX2R0bWYgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIGlmICh0cmFjay5raW5kID09PSAnYXVkaW8nKSB7XG4gICAgICAgICAgICAgICAgICB0aGlzLl9kdG1mID0gcGMuY3JlYXRlRFRNRlNlbmRlcih0cmFjayk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgIHRoaXMuX2R0bWYgPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fZHRtZjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9O1xuXG4gICAgICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUucmVtb3ZlU3RyZWFtID0gZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgIHZhciBwYyA9IHRoaXM7XG4gICAgICAgIHBjLl9zZW5kZXJzID0gcGMuX3NlbmRlcnMgfHwgW107XG4gICAgICAgIG9yaWdSZW1vdmVTdHJlYW0uYXBwbHkocGMsIFtzdHJlYW1dKTtcbiAgICAgICAgc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2spIHtcbiAgICAgICAgICB2YXIgc2VuZGVyID0gcGMuX3NlbmRlcnMuZmluZChmdW5jdGlvbihzKSB7XG4gICAgICAgICAgICByZXR1cm4gcy50cmFjayA9PT0gdHJhY2s7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgaWYgKHNlbmRlcikge1xuICAgICAgICAgICAgcGMuX3NlbmRlcnMuc3BsaWNlKHBjLl9zZW5kZXJzLmluZGV4T2Yoc2VuZGVyKSwgMSk7IC8vIHJlbW92ZSBzZW5kZXJcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfTtcbiAgICB9XG4gIH0sXG5cbiAgc2hpbVNvdXJjZU9iamVjdDogZnVuY3Rpb24oKSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnKSB7XG4gICAgICBpZiAod2luZG93LkhUTUxNZWRpYUVsZW1lbnQgJiZcbiAgICAgICAgISgnc3JjT2JqZWN0JyBpbiB3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUpKSB7XG4gICAgICAgIC8vIFNoaW0gdGhlIHNyY09iamVjdCBwcm9wZXJ0eSwgb25jZSwgd2hlbiBIVE1MTWVkaWFFbGVtZW50IGlzIGZvdW5kLlxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LkhUTUxNZWRpYUVsZW1lbnQucHJvdG90eXBlLCAnc3JjT2JqZWN0Jywge1xuICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fc3JjT2JqZWN0O1xuICAgICAgICAgIH0sXG4gICAgICAgICAgc2V0OiBmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgICAgIC8vIFVzZSBfc3JjT2JqZWN0IGFzIGEgcHJpdmF0ZSBwcm9wZXJ0eSBmb3IgdGhpcyBzaGltXG4gICAgICAgICAgICB0aGlzLl9zcmNPYmplY3QgPSBzdHJlYW07XG4gICAgICAgICAgICBpZiAodGhpcy5zcmMpIHtcbiAgICAgICAgICAgICAgVVJMLnJldm9rZU9iamVjdFVSTCh0aGlzLnNyYyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghc3RyZWFtKSB7XG4gICAgICAgICAgICAgIHRoaXMuc3JjID0gJyc7XG4gICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnNyYyA9IFVSTC5jcmVhdGVPYmplY3RVUkwoc3RyZWFtKTtcbiAgICAgICAgICAgIC8vIFdlIG5lZWQgdG8gcmVjcmVhdGUgdGhlIGJsb2IgdXJsIHdoZW4gYSB0cmFjayBpcyBhZGRlZCBvclxuICAgICAgICAgICAgLy8gcmVtb3ZlZC4gRG9pbmcgaXQgbWFudWFsbHkgc2luY2Ugd2Ugd2FudCB0byBhdm9pZCBhIHJlY3Vyc2lvbi5cbiAgICAgICAgICAgIHN0cmVhbS5hZGRFdmVudExpc3RlbmVyKCdhZGR0cmFjaycsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICBpZiAoc2VsZi5zcmMpIHtcbiAgICAgICAgICAgICAgICBVUkwucmV2b2tlT2JqZWN0VVJMKHNlbGYuc3JjKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBzZWxmLnNyYyA9IFVSTC5jcmVhdGVPYmplY3RVUkwoc3RyZWFtKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ3JlbW92ZXRyYWNrJywgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgIGlmIChzZWxmLnNyYykge1xuICAgICAgICAgICAgICAgIFVSTC5yZXZva2VPYmplY3RVUkwoc2VsZi5zcmMpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHNlbGYuc3JjID0gVVJMLmNyZWF0ZU9iamVjdFVSTChzdHJlYW0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG5cbiAgc2hpbVBlZXJDb25uZWN0aW9uOiBmdW5jdGlvbigpIHtcbiAgICAvLyBUaGUgUlRDUGVlckNvbm5lY3Rpb24gb2JqZWN0LlxuICAgIGlmICghd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uKSB7XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gPSBmdW5jdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cykge1xuICAgICAgICAvLyBUcmFuc2xhdGUgaWNlVHJhbnNwb3J0UG9saWN5IHRvIGljZVRyYW5zcG9ydHMsXG4gICAgICAgIC8vIHNlZSBodHRwczovL2NvZGUuZ29vZ2xlLmNvbS9wL3dlYnJ0Yy9pc3N1ZXMvZGV0YWlsP2lkPTQ4NjlcbiAgICAgICAgLy8gdGhpcyB3YXMgZml4ZWQgaW4gTTU2IGFsb25nIHdpdGggdW5wcmVmaXhpbmcgUlRDUGVlckNvbm5lY3Rpb24uXG4gICAgICAgIGxvZ2dpbmcoJ1BlZXJDb25uZWN0aW9uJyk7XG4gICAgICAgIGlmIChwY0NvbmZpZyAmJiBwY0NvbmZpZy5pY2VUcmFuc3BvcnRQb2xpY3kpIHtcbiAgICAgICAgICBwY0NvbmZpZy5pY2VUcmFuc3BvcnRzID0gcGNDb25maWcuaWNlVHJhbnNwb3J0UG9saWN5O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ldyB3ZWJraXRSVENQZWVyQ29ubmVjdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cyk7XG4gICAgICB9O1xuICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSA9IHdlYmtpdFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZTtcbiAgICAgIC8vIHdyYXAgc3RhdGljIG1ldGhvZHMuIEN1cnJlbnRseSBqdXN0IGdlbmVyYXRlQ2VydGlmaWNhdGUuXG4gICAgICBpZiAod2Via2l0UlRDUGVlckNvbm5lY3Rpb24uZ2VuZXJhdGVDZXJ0aWZpY2F0ZSkge1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLCAnZ2VuZXJhdGVDZXJ0aWZpY2F0ZScsIHtcbiAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHdlYmtpdFJUQ1BlZXJDb25uZWN0aW9uLmdlbmVyYXRlQ2VydGlmaWNhdGU7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gbWlncmF0ZSBmcm9tIG5vbi1zcGVjIFJUQ0ljZVNlcnZlci51cmwgdG8gUlRDSWNlU2VydmVyLnVybHNcbiAgICAgIHZhciBPcmlnUGVlckNvbm5lY3Rpb24gPSBSVENQZWVyQ29ubmVjdGlvbjtcbiAgICAgIHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbiA9IGZ1bmN0aW9uKHBjQ29uZmlnLCBwY0NvbnN0cmFpbnRzKSB7XG4gICAgICAgIGlmIChwY0NvbmZpZyAmJiBwY0NvbmZpZy5pY2VTZXJ2ZXJzKSB7XG4gICAgICAgICAgdmFyIG5ld0ljZVNlcnZlcnMgPSBbXTtcbiAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBjQ29uZmlnLmljZVNlcnZlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBzZXJ2ZXIgPSBwY0NvbmZpZy5pY2VTZXJ2ZXJzW2ldO1xuICAgICAgICAgICAgaWYgKCFzZXJ2ZXIuaGFzT3duUHJvcGVydHkoJ3VybHMnKSAmJlxuICAgICAgICAgICAgICAgIHNlcnZlci5oYXNPd25Qcm9wZXJ0eSgndXJsJykpIHtcbiAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdSVENJY2VTZXJ2ZXIudXJsIGlzIGRlcHJlY2F0ZWQhIFVzZSB1cmxzIGluc3RlYWQuJyk7XG4gICAgICAgICAgICAgIHNlcnZlciA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoc2VydmVyKSk7XG4gICAgICAgICAgICAgIHNlcnZlci51cmxzID0gc2VydmVyLnVybDtcbiAgICAgICAgICAgICAgbmV3SWNlU2VydmVycy5wdXNoKHNlcnZlcik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBuZXdJY2VTZXJ2ZXJzLnB1c2gocGNDb25maWcuaWNlU2VydmVyc1tpXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHBjQ29uZmlnLmljZVNlcnZlcnMgPSBuZXdJY2VTZXJ2ZXJzO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgT3JpZ1BlZXJDb25uZWN0aW9uKHBjQ29uZmlnLCBwY0NvbnN0cmFpbnRzKTtcbiAgICAgIH07XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlID0gT3JpZ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZTtcbiAgICAgIC8vIHdyYXAgc3RhdGljIG1ldGhvZHMuIEN1cnJlbnRseSBqdXN0IGdlbmVyYXRlQ2VydGlmaWNhdGUuXG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLCAnZ2VuZXJhdGVDZXJ0aWZpY2F0ZScsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gT3JpZ1BlZXJDb25uZWN0aW9uLmdlbmVyYXRlQ2VydGlmaWNhdGU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHZhciBvcmlnR2V0U3RhdHMgPSBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0U3RhdHM7XG4gICAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFN0YXRzID0gZnVuY3Rpb24oc2VsZWN0b3IsXG4gICAgICAgIHN1Y2Nlc3NDYWxsYmFjaywgZXJyb3JDYWxsYmFjaykge1xuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG5cbiAgICAgIC8vIElmIHNlbGVjdG9yIGlzIGEgZnVuY3Rpb24gdGhlbiB3ZSBhcmUgaW4gdGhlIG9sZCBzdHlsZSBzdGF0cyBzbyBqdXN0XG4gICAgICAvLyBwYXNzIGJhY2sgdGhlIG9yaWdpbmFsIGdldFN0YXRzIGZvcm1hdCB0byBhdm9pZCBicmVha2luZyBvbGQgdXNlcnMuXG4gICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDAgJiYgdHlwZW9mIHNlbGVjdG9yID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHJldHVybiBvcmlnR2V0U3RhdHMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgIH1cblxuICAgICAgLy8gV2hlbiBzcGVjLXN0eWxlIGdldFN0YXRzIGlzIHN1cHBvcnRlZCwgcmV0dXJuIHRob3NlIHdoZW4gY2FsbGVkIHdpdGhcbiAgICAgIC8vIGVpdGhlciBubyBhcmd1bWVudHMgb3IgdGhlIHNlbGVjdG9yIGFyZ3VtZW50IGlzIG51bGwuXG4gICAgICBpZiAob3JpZ0dldFN0YXRzLmxlbmd0aCA9PT0gMCAmJiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCB8fFxuICAgICAgICAgIHR5cGVvZiBhcmd1bWVudHNbMF0gIT09ICdmdW5jdGlvbicpKSB7XG4gICAgICAgIHJldHVybiBvcmlnR2V0U3RhdHMuYXBwbHkodGhpcywgW10pO1xuICAgICAgfVxuXG4gICAgICB2YXIgZml4Q2hyb21lU3RhdHNfID0gZnVuY3Rpb24ocmVzcG9uc2UpIHtcbiAgICAgICAgdmFyIHN0YW5kYXJkUmVwb3J0ID0ge307XG4gICAgICAgIHZhciByZXBvcnRzID0gcmVzcG9uc2UucmVzdWx0KCk7XG4gICAgICAgIHJlcG9ydHMuZm9yRWFjaChmdW5jdGlvbihyZXBvcnQpIHtcbiAgICAgICAgICB2YXIgc3RhbmRhcmRTdGF0cyA9IHtcbiAgICAgICAgICAgIGlkOiByZXBvcnQuaWQsXG4gICAgICAgICAgICB0aW1lc3RhbXA6IHJlcG9ydC50aW1lc3RhbXAsXG4gICAgICAgICAgICB0eXBlOiB7XG4gICAgICAgICAgICAgIGxvY2FsY2FuZGlkYXRlOiAnbG9jYWwtY2FuZGlkYXRlJyxcbiAgICAgICAgICAgICAgcmVtb3RlY2FuZGlkYXRlOiAncmVtb3RlLWNhbmRpZGF0ZSdcbiAgICAgICAgICAgIH1bcmVwb3J0LnR5cGVdIHx8IHJlcG9ydC50eXBlXG4gICAgICAgICAgfTtcbiAgICAgICAgICByZXBvcnQubmFtZXMoKS5mb3JFYWNoKGZ1bmN0aW9uKG5hbWUpIHtcbiAgICAgICAgICAgIHN0YW5kYXJkU3RhdHNbbmFtZV0gPSByZXBvcnQuc3RhdChuYW1lKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBzdGFuZGFyZFJlcG9ydFtzdGFuZGFyZFN0YXRzLmlkXSA9IHN0YW5kYXJkU3RhdHM7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBzdGFuZGFyZFJlcG9ydDtcbiAgICAgIH07XG5cbiAgICAgIC8vIHNoaW0gZ2V0U3RhdHMgd2l0aCBtYXBsaWtlIHN1cHBvcnRcbiAgICAgIHZhciBtYWtlTWFwU3RhdHMgPSBmdW5jdGlvbihzdGF0cykge1xuICAgICAgICByZXR1cm4gbmV3IE1hcChPYmplY3Qua2V5cyhzdGF0cykubWFwKGZ1bmN0aW9uKGtleSkge1xuICAgICAgICAgIHJldHVybltrZXksIHN0YXRzW2tleV1dO1xuICAgICAgICB9KSk7XG4gICAgICB9O1xuXG4gICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+PSAyKSB7XG4gICAgICAgIHZhciBzdWNjZXNzQ2FsbGJhY2tXcmFwcGVyXyA9IGZ1bmN0aW9uKHJlc3BvbnNlKSB7XG4gICAgICAgICAgYXJnc1sxXShtYWtlTWFwU3RhdHMoZml4Q2hyb21lU3RhdHNfKHJlc3BvbnNlKSkpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiBvcmlnR2V0U3RhdHMuYXBwbHkodGhpcywgW3N1Y2Nlc3NDYWxsYmFja1dyYXBwZXJfLFxuICAgICAgICAgICAgYXJndW1lbnRzWzBdXSk7XG4gICAgICB9XG5cbiAgICAgIC8vIHByb21pc2Utc3VwcG9ydFxuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgICBvcmlnR2V0U3RhdHMuYXBwbHkoc2VsZiwgW1xuICAgICAgICAgIGZ1bmN0aW9uKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICByZXNvbHZlKG1ha2VNYXBTdGF0cyhmaXhDaHJvbWVTdGF0c18ocmVzcG9uc2UpKSk7XG4gICAgICAgICAgfSwgcmVqZWN0XSk7XG4gICAgICB9KS50aGVuKHN1Y2Nlc3NDYWxsYmFjaywgZXJyb3JDYWxsYmFjayk7XG4gICAgfTtcblxuICAgIC8vIGFkZCBwcm9taXNlIHN1cHBvcnQgLS0gbmF0aXZlbHkgYXZhaWxhYmxlIGluIENocm9tZSA1MVxuICAgIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgNTEpIHtcbiAgICAgIFsnc2V0TG9jYWxEZXNjcmlwdGlvbicsICdzZXRSZW1vdGVEZXNjcmlwdGlvbicsICdhZGRJY2VDYW5kaWRhdGUnXVxuICAgICAgICAgIC5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZCkge1xuICAgICAgICAgICAgdmFyIG5hdGl2ZU1ldGhvZCA9IFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdO1xuICAgICAgICAgICAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlW21ldGhvZF0gPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgdmFyIGFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgICAgICAgdmFyIHByb21pc2UgPSBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgICAgICAgICAgICBuYXRpdmVNZXRob2QuYXBwbHkoc2VsZiwgW2FyZ3NbMF0sIHJlc29sdmUsIHJlamVjdF0pO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgaWYgKGFyZ3MubGVuZ3RoIDwgMikge1xuICAgICAgICAgICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybiBwcm9taXNlLnRoZW4oZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgYXJnc1sxXS5hcHBseShudWxsLCBbXSk7XG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGZ1bmN0aW9uKGVycikge1xuICAgICAgICAgICAgICAgIGlmIChhcmdzLmxlbmd0aCA+PSAzKSB7XG4gICAgICAgICAgICAgICAgICBhcmdzWzJdLmFwcGx5KG51bGwsIFtlcnJdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBwcm9taXNlIHN1cHBvcnQgZm9yIGNyZWF0ZU9mZmVyIGFuZCBjcmVhdGVBbnN3ZXIuIEF2YWlsYWJsZSAod2l0aG91dFxuICAgIC8vIGJ1Z3MpIHNpbmNlIE01MjogY3JidWcvNjE5Mjg5XG4gICAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA1Mikge1xuICAgICAgWydjcmVhdGVPZmZlcicsICdjcmVhdGVBbnN3ZXInXS5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZCkge1xuICAgICAgICB2YXIgbmF0aXZlTWV0aG9kID0gUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlW21ldGhvZF07XG4gICAgICAgIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoIDwgMSB8fCAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICAgICAgICB0eXBlb2YgYXJndW1lbnRzWzBdID09PSAnb2JqZWN0JykpIHtcbiAgICAgICAgICAgIHZhciBvcHRzID0gYXJndW1lbnRzLmxlbmd0aCA9PT0gMSA/IGFyZ3VtZW50c1swXSA6IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgICAgICAgICAgbmF0aXZlTWV0aG9kLmFwcGx5KHNlbGYsIFtyZXNvbHZlLCByZWplY3QsIG9wdHNdKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gbmF0aXZlTWV0aG9kLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH07XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBzaGltIGltcGxpY2l0IGNyZWF0aW9uIG9mIFJUQ1Nlc3Npb25EZXNjcmlwdGlvbi9SVENJY2VDYW5kaWRhdGVcbiAgICBbJ3NldExvY2FsRGVzY3JpcHRpb24nLCAnc2V0UmVtb3RlRGVzY3JpcHRpb24nLCAnYWRkSWNlQ2FuZGlkYXRlJ11cbiAgICAgICAgLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICAgICAgdmFyIG5hdGl2ZU1ldGhvZCA9IFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdO1xuICAgICAgICAgIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBhcmd1bWVudHNbMF0gPSBuZXcgKChtZXRob2QgPT09ICdhZGRJY2VDYW5kaWRhdGUnKSA/XG4gICAgICAgICAgICAgICAgUlRDSWNlQ2FuZGlkYXRlIDogUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKShhcmd1bWVudHNbMF0pO1xuICAgICAgICAgICAgcmV0dXJuIG5hdGl2ZU1ldGhvZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuXG4gICAgLy8gc3VwcG9ydCBmb3IgYWRkSWNlQ2FuZGlkYXRlKG51bGwgb3IgdW5kZWZpbmVkKVxuICAgIHZhciBuYXRpdmVBZGRJY2VDYW5kaWRhdGUgPVxuICAgICAgICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkSWNlQ2FuZGlkYXRlO1xuICAgIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRJY2VDYW5kaWRhdGUgPSBmdW5jdGlvbigpIHtcbiAgICAgIGlmICghYXJndW1lbnRzWzBdKSB7XG4gICAgICAgIGlmIChhcmd1bWVudHNbMV0pIHtcbiAgICAgICAgICBhcmd1bWVudHNbMV0uYXBwbHkobnVsbCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5hdGl2ZUFkZEljZUNhbmRpZGF0ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH07XG4gIH1cbn07XG5cblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHNoaW1NZWRpYVN0cmVhbTogY2hyb21lU2hpbS5zaGltTWVkaWFTdHJlYW0sXG4gIHNoaW1PblRyYWNrOiBjaHJvbWVTaGltLnNoaW1PblRyYWNrLFxuICBzaGltR2V0U2VuZGVyc1dpdGhEdG1mOiBjaHJvbWVTaGltLnNoaW1HZXRTZW5kZXJzV2l0aER0bWYsXG4gIHNoaW1Tb3VyY2VPYmplY3Q6IGNocm9tZVNoaW0uc2hpbVNvdXJjZU9iamVjdCxcbiAgc2hpbVBlZXJDb25uZWN0aW9uOiBjaHJvbWVTaGltLnNoaW1QZWVyQ29ubmVjdGlvbixcbiAgc2hpbUdldFVzZXJNZWRpYTogcmVxdWlyZSgnLi9nZXR1c2VybWVkaWEnKVxufTtcbiIsIi8qXG4gKiAgQ29weXJpZ2h0IChjKSAyMDE2IFRoZSBXZWJSVEMgcHJvamVjdCBhdXRob3JzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqICBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZSBsaWNlbnNlXG4gKiAgdGhhdCBjYW4gYmUgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBvZiB0aGUgc291cmNlXG4gKiAgdHJlZS5cbiAqL1xuIC8qIGVzbGludC1lbnYgbm9kZSAqL1xuJ3VzZSBzdHJpY3QnO1xudmFyIGxvZ2dpbmcgPSByZXF1aXJlKCcuLi91dGlscy5qcycpLmxvZztcbnZhciBicm93c2VyRGV0YWlscyA9IHJlcXVpcmUoJy4uL3V0aWxzLmpzJykuYnJvd3NlckRldGFpbHM7XG5cbi8vIEV4cG9zZSBwdWJsaWMgbWV0aG9kcy5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oKSB7XG4gIHZhciBjb25zdHJhaW50c1RvQ2hyb21lXyA9IGZ1bmN0aW9uKGMpIHtcbiAgICBpZiAodHlwZW9mIGMgIT09ICdvYmplY3QnIHx8IGMubWFuZGF0b3J5IHx8IGMub3B0aW9uYWwpIHtcbiAgICAgIHJldHVybiBjO1xuICAgIH1cbiAgICB2YXIgY2MgPSB7fTtcbiAgICBPYmplY3Qua2V5cyhjKS5mb3JFYWNoKGZ1bmN0aW9uKGtleSkge1xuICAgICAgaWYgKGtleSA9PT0gJ3JlcXVpcmUnIHx8IGtleSA9PT0gJ2FkdmFuY2VkJyB8fCBrZXkgPT09ICdtZWRpYVNvdXJjZScpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdmFyIHIgPSAodHlwZW9mIGNba2V5XSA9PT0gJ29iamVjdCcpID8gY1trZXldIDoge2lkZWFsOiBjW2tleV19O1xuICAgICAgaWYgKHIuZXhhY3QgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygci5leGFjdCA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgci5taW4gPSByLm1heCA9IHIuZXhhY3Q7XG4gICAgICB9XG4gICAgICB2YXIgb2xkbmFtZV8gPSBmdW5jdGlvbihwcmVmaXgsIG5hbWUpIHtcbiAgICAgICAgaWYgKHByZWZpeCkge1xuICAgICAgICAgIHJldHVybiBwcmVmaXggKyBuYW1lLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgbmFtZS5zbGljZSgxKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gKG5hbWUgPT09ICdkZXZpY2VJZCcpID8gJ3NvdXJjZUlkJyA6IG5hbWU7XG4gICAgICB9O1xuICAgICAgaWYgKHIuaWRlYWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjYy5vcHRpb25hbCA9IGNjLm9wdGlvbmFsIHx8IFtdO1xuICAgICAgICB2YXIgb2MgPSB7fTtcbiAgICAgICAgaWYgKHR5cGVvZiByLmlkZWFsID09PSAnbnVtYmVyJykge1xuICAgICAgICAgIG9jW29sZG5hbWVfKCdtaW4nLCBrZXkpXSA9IHIuaWRlYWw7XG4gICAgICAgICAgY2Mub3B0aW9uYWwucHVzaChvYyk7XG4gICAgICAgICAgb2MgPSB7fTtcbiAgICAgICAgICBvY1tvbGRuYW1lXygnbWF4Jywga2V5KV0gPSByLmlkZWFsO1xuICAgICAgICAgIGNjLm9wdGlvbmFsLnB1c2gob2MpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG9jW29sZG5hbWVfKCcnLCBrZXkpXSA9IHIuaWRlYWw7XG4gICAgICAgICAgY2Mub3B0aW9uYWwucHVzaChvYyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmIChyLmV4YWN0ICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHIuZXhhY3QgIT09ICdudW1iZXInKSB7XG4gICAgICAgIGNjLm1hbmRhdG9yeSA9IGNjLm1hbmRhdG9yeSB8fCB7fTtcbiAgICAgICAgY2MubWFuZGF0b3J5W29sZG5hbWVfKCcnLCBrZXkpXSA9IHIuZXhhY3Q7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBbJ21pbicsICdtYXgnXS5mb3JFYWNoKGZ1bmN0aW9uKG1peCkge1xuICAgICAgICAgIGlmIChyW21peF0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgY2MubWFuZGF0b3J5ID0gY2MubWFuZGF0b3J5IHx8IHt9O1xuICAgICAgICAgICAgY2MubWFuZGF0b3J5W29sZG5hbWVfKG1peCwga2V5KV0gPSByW21peF07XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBpZiAoYy5hZHZhbmNlZCkge1xuICAgICAgY2Mub3B0aW9uYWwgPSAoY2Mub3B0aW9uYWwgfHwgW10pLmNvbmNhdChjLmFkdmFuY2VkKTtcbiAgICB9XG4gICAgcmV0dXJuIGNjO1xuICB9O1xuXG4gIHZhciBzaGltQ29uc3RyYWludHNfID0gZnVuY3Rpb24oY29uc3RyYWludHMsIGZ1bmMpIHtcbiAgICBjb25zdHJhaW50cyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoY29uc3RyYWludHMpKTtcbiAgICBpZiAoY29uc3RyYWludHMgJiYgY29uc3RyYWludHMuYXVkaW8pIHtcbiAgICAgIGNvbnN0cmFpbnRzLmF1ZGlvID0gY29uc3RyYWludHNUb0Nocm9tZV8oY29uc3RyYWludHMuYXVkaW8pO1xuICAgIH1cbiAgICBpZiAoY29uc3RyYWludHMgJiYgdHlwZW9mIGNvbnN0cmFpbnRzLnZpZGVvID09PSAnb2JqZWN0Jykge1xuICAgICAgLy8gU2hpbSBmYWNpbmdNb2RlIGZvciBtb2JpbGUgJiBzdXJmYWNlIHByby5cbiAgICAgIHZhciBmYWNlID0gY29uc3RyYWludHMudmlkZW8uZmFjaW5nTW9kZTtcbiAgICAgIGZhY2UgPSBmYWNlICYmICgodHlwZW9mIGZhY2UgPT09ICdvYmplY3QnKSA/IGZhY2UgOiB7aWRlYWw6IGZhY2V9KTtcbiAgICAgIHZhciBnZXRTdXBwb3J0ZWRGYWNpbmdNb2RlTGllcyA9IGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA2MTtcblxuICAgICAgaWYgKChmYWNlICYmIChmYWNlLmV4YWN0ID09PSAndXNlcicgfHwgZmFjZS5leGFjdCA9PT0gJ2Vudmlyb25tZW50JyB8fFxuICAgICAgICAgICAgICAgICAgICBmYWNlLmlkZWFsID09PSAndXNlcicgfHwgZmFjZS5pZGVhbCA9PT0gJ2Vudmlyb25tZW50JykpICYmXG4gICAgICAgICAgIShuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFN1cHBvcnRlZENvbnN0cmFpbnRzICYmXG4gICAgICAgICAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFN1cHBvcnRlZENvbnN0cmFpbnRzKCkuZmFjaW5nTW9kZSAmJlxuICAgICAgICAgICAgIWdldFN1cHBvcnRlZEZhY2luZ01vZGVMaWVzKSkge1xuICAgICAgICBkZWxldGUgY29uc3RyYWludHMudmlkZW8uZmFjaW5nTW9kZTtcbiAgICAgICAgdmFyIG1hdGNoZXM7XG4gICAgICAgIGlmIChmYWNlLmV4YWN0ID09PSAnZW52aXJvbm1lbnQnIHx8IGZhY2UuaWRlYWwgPT09ICdlbnZpcm9ubWVudCcpIHtcbiAgICAgICAgICBtYXRjaGVzID0gWydiYWNrJywgJ3JlYXInXTtcbiAgICAgICAgfSBlbHNlIGlmIChmYWNlLmV4YWN0ID09PSAndXNlcicgfHwgZmFjZS5pZGVhbCA9PT0gJ3VzZXInKSB7XG4gICAgICAgICAgbWF0Y2hlcyA9IFsnZnJvbnQnXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobWF0Y2hlcykge1xuICAgICAgICAgIC8vIExvb2sgZm9yIG1hdGNoZXMgaW4gbGFiZWwsIG9yIHVzZSBsYXN0IGNhbSBmb3IgYmFjayAodHlwaWNhbCkuXG4gICAgICAgICAgcmV0dXJuIG5hdmlnYXRvci5tZWRpYURldmljZXMuZW51bWVyYXRlRGV2aWNlcygpXG4gICAgICAgICAgLnRoZW4oZnVuY3Rpb24oZGV2aWNlcykge1xuICAgICAgICAgICAgZGV2aWNlcyA9IGRldmljZXMuZmlsdGVyKGZ1bmN0aW9uKGQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGQua2luZCA9PT0gJ3ZpZGVvaW5wdXQnO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB2YXIgZGV2ID0gZGV2aWNlcy5maW5kKGZ1bmN0aW9uKGQpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIG1hdGNoZXMuc29tZShmdW5jdGlvbihtYXRjaCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBkLmxhYmVsLnRvTG93ZXJDYXNlKCkuaW5kZXhPZihtYXRjaCkgIT09IC0xO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKCFkZXYgJiYgZGV2aWNlcy5sZW5ndGggJiYgbWF0Y2hlcy5pbmRleE9mKCdiYWNrJykgIT09IC0xKSB7XG4gICAgICAgICAgICAgIGRldiA9IGRldmljZXNbZGV2aWNlcy5sZW5ndGggLSAxXTsgLy8gbW9yZSBsaWtlbHkgdGhlIGJhY2sgY2FtXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZGV2KSB7XG4gICAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLmRldmljZUlkID0gZmFjZS5leGFjdCA/IHtleGFjdDogZGV2LmRldmljZUlkfSA6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtpZGVhbDogZGV2LmRldmljZUlkfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvID0gY29uc3RyYWludHNUb0Nocm9tZV8oY29uc3RyYWludHMudmlkZW8pO1xuICAgICAgICAgICAgbG9nZ2luZygnY2hyb21lOiAnICsgSlNPTi5zdHJpbmdpZnkoY29uc3RyYWludHMpKTtcbiAgICAgICAgICAgIHJldHVybiBmdW5jKGNvbnN0cmFpbnRzKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY29uc3RyYWludHMudmlkZW8gPSBjb25zdHJhaW50c1RvQ2hyb21lXyhjb25zdHJhaW50cy52aWRlbyk7XG4gICAgfVxuICAgIGxvZ2dpbmcoJ2Nocm9tZTogJyArIEpTT04uc3RyaW5naWZ5KGNvbnN0cmFpbnRzKSk7XG4gICAgcmV0dXJuIGZ1bmMoY29uc3RyYWludHMpO1xuICB9O1xuXG4gIHZhciBzaGltRXJyb3JfID0gZnVuY3Rpb24oZSkge1xuICAgIHJldHVybiB7XG4gICAgICBuYW1lOiB7XG4gICAgICAgIFBlcm1pc3Npb25EZW5pZWRFcnJvcjogJ05vdEFsbG93ZWRFcnJvcicsXG4gICAgICAgIENvbnN0cmFpbnROb3RTYXRpc2ZpZWRFcnJvcjogJ092ZXJjb25zdHJhaW5lZEVycm9yJ1xuICAgICAgfVtlLm5hbWVdIHx8IGUubmFtZSxcbiAgICAgIG1lc3NhZ2U6IGUubWVzc2FnZSxcbiAgICAgIGNvbnN0cmFpbnQ6IGUuY29uc3RyYWludE5hbWUsXG4gICAgICB0b1N0cmluZzogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm5hbWUgKyAodGhpcy5tZXNzYWdlICYmICc6ICcpICsgdGhpcy5tZXNzYWdlO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgdmFyIGdldFVzZXJNZWRpYV8gPSBmdW5jdGlvbihjb25zdHJhaW50cywgb25TdWNjZXNzLCBvbkVycm9yKSB7XG4gICAgc2hpbUNvbnN0cmFpbnRzXyhjb25zdHJhaW50cywgZnVuY3Rpb24oYykge1xuICAgICAgbmF2aWdhdG9yLndlYmtpdEdldFVzZXJNZWRpYShjLCBvblN1Y2Nlc3MsIGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgb25FcnJvcihzaGltRXJyb3JfKGUpKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9O1xuXG4gIG5hdmlnYXRvci5nZXRVc2VyTWVkaWEgPSBnZXRVc2VyTWVkaWFfO1xuXG4gIC8vIFJldHVybnMgdGhlIHJlc3VsdCBvZiBnZXRVc2VyTWVkaWEgYXMgYSBQcm9taXNlLlxuICB2YXIgZ2V0VXNlck1lZGlhUHJvbWlzZV8gPSBmdW5jdGlvbihjb25zdHJhaW50cykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgIG5hdmlnYXRvci5nZXRVc2VyTWVkaWEoY29uc3RyYWludHMsIHJlc29sdmUsIHJlamVjdCk7XG4gICAgfSk7XG4gIH07XG5cbiAgaWYgKCFuYXZpZ2F0b3IubWVkaWFEZXZpY2VzKSB7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcyA9IHtcbiAgICAgIGdldFVzZXJNZWRpYTogZ2V0VXNlck1lZGlhUHJvbWlzZV8sXG4gICAgICBlbnVtZXJhdGVEZXZpY2VzOiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUpIHtcbiAgICAgICAgICB2YXIga2luZHMgPSB7YXVkaW86ICdhdWRpb2lucHV0JywgdmlkZW86ICd2aWRlb2lucHV0J307XG4gICAgICAgICAgcmV0dXJuIE1lZGlhU3RyZWFtVHJhY2suZ2V0U291cmNlcyhmdW5jdGlvbihkZXZpY2VzKSB7XG4gICAgICAgICAgICByZXNvbHZlKGRldmljZXMubWFwKGZ1bmN0aW9uKGRldmljZSkge1xuICAgICAgICAgICAgICByZXR1cm4ge2xhYmVsOiBkZXZpY2UubGFiZWwsXG4gICAgICAgICAgICAgICAgICAgICAga2luZDoga2luZHNbZGV2aWNlLmtpbmRdLFxuICAgICAgICAgICAgICAgICAgICAgIGRldmljZUlkOiBkZXZpY2UuaWQsXG4gICAgICAgICAgICAgICAgICAgICAgZ3JvdXBJZDogJyd9O1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgICBnZXRTdXBwb3J0ZWRDb25zdHJhaW50czogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZGV2aWNlSWQ6IHRydWUsIGVjaG9DYW5jZWxsYXRpb246IHRydWUsIGZhY2luZ01vZGU6IHRydWUsXG4gICAgICAgICAgZnJhbWVSYXRlOiB0cnVlLCBoZWlnaHQ6IHRydWUsIHdpZHRoOiB0cnVlXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8vIEEgc2hpbSBmb3IgZ2V0VXNlck1lZGlhIG1ldGhvZCBvbiB0aGUgbWVkaWFEZXZpY2VzIG9iamVjdC5cbiAgLy8gVE9ETyhLYXB0ZW5KYW5zc29uKSByZW1vdmUgb25jZSBpbXBsZW1lbnRlZCBpbiBDaHJvbWUgc3RhYmxlLlxuICBpZiAoIW5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKSB7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEgPSBmdW5jdGlvbihjb25zdHJhaW50cykge1xuICAgICAgcmV0dXJuIGdldFVzZXJNZWRpYVByb21pc2VfKGNvbnN0cmFpbnRzKTtcbiAgICB9O1xuICB9IGVsc2Uge1xuICAgIC8vIEV2ZW4gdGhvdWdoIENocm9tZSA0NSBoYXMgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcyBhbmQgYSBnZXRVc2VyTWVkaWFcbiAgICAvLyBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGEgUHJvbWlzZSwgaXQgZG9lcyBub3QgYWNjZXB0IHNwZWMtc3R5bGVcbiAgICAvLyBjb25zdHJhaW50cy5cbiAgICB2YXIgb3JpZ0dldFVzZXJNZWRpYSA9IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhLlxuICAgICAgICBiaW5kKG5hdmlnYXRvci5tZWRpYURldmljZXMpO1xuICAgIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhID0gZnVuY3Rpb24oY3MpIHtcbiAgICAgIHJldHVybiBzaGltQ29uc3RyYWludHNfKGNzLCBmdW5jdGlvbihjKSB7XG4gICAgICAgIHJldHVybiBvcmlnR2V0VXNlck1lZGlhKGMpLnRoZW4oZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgICAgaWYgKGMuYXVkaW8gJiYgIXN0cmVhbS5nZXRBdWRpb1RyYWNrcygpLmxlbmd0aCB8fFxuICAgICAgICAgICAgICBjLnZpZGVvICYmICFzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGgpIHtcbiAgICAgICAgICAgIHN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgICAgICAgICAgIHRyYWNrLnN0b3AoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhyb3cgbmV3IERPTUV4Y2VwdGlvbignJywgJ05vdEZvdW5kRXJyb3InKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHN0cmVhbTtcbiAgICAgICAgfSwgZnVuY3Rpb24oZSkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChzaGltRXJyb3JfKGUpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9O1xuICB9XG5cbiAgLy8gRHVtbXkgZGV2aWNlY2hhbmdlIGV2ZW50IG1ldGhvZHMuXG4gIC8vIFRPRE8oS2FwdGVuSmFuc3NvbikgcmVtb3ZlIG9uY2UgaW1wbGVtZW50ZWQgaW4gQ2hyb21lIHN0YWJsZS5cbiAgaWYgKHR5cGVvZiBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmFkZEV2ZW50TGlzdGVuZXIgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5hZGRFdmVudExpc3RlbmVyID0gZnVuY3Rpb24oKSB7XG4gICAgICBsb2dnaW5nKCdEdW1teSBtZWRpYURldmljZXMuYWRkRXZlbnRMaXN0ZW5lciBjYWxsZWQuJyk7XG4gICAgfTtcbiAgfVxuICBpZiAodHlwZW9mIG5hdmlnYXRvci5tZWRpYURldmljZXMucmVtb3ZlRXZlbnRMaXN0ZW5lciA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLnJlbW92ZUV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbigpIHtcbiAgICAgIGxvZ2dpbmcoJ0R1bW15IG1lZGlhRGV2aWNlcy5yZW1vdmVFdmVudExpc3RlbmVyIGNhbGxlZC4nKTtcbiAgICB9O1xuICB9XG59O1xuIiwiLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4gLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG5cbnZhciBicm93c2VyRGV0YWlscyA9IHJlcXVpcmUoJy4uL3V0aWxzJykuYnJvd3NlckRldGFpbHM7XG52YXIgc2hpbVJUQ1BlZXJDb25uZWN0aW9uID0gcmVxdWlyZSgnLi9ydGNwZWVyY29ubmVjdGlvbl9zaGltJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBzaGltR2V0VXNlck1lZGlhOiByZXF1aXJlKCcuL2dldHVzZXJtZWRpYScpLFxuICBzaGltUGVlckNvbm5lY3Rpb246IGZ1bmN0aW9uKCkge1xuICAgIGlmICh3aW5kb3cuUlRDSWNlR2F0aGVyZXIpIHtcbiAgICAgIC8vIE9SVEMgZGVmaW5lcyBhbiBSVENJY2VDYW5kaWRhdGUgb2JqZWN0IGJ1dCBubyBjb25zdHJ1Y3Rvci5cbiAgICAgIC8vIE5vdCBpbXBsZW1lbnRlZCBpbiBFZGdlLlxuICAgICAgaWYgKCF3aW5kb3cuUlRDSWNlQ2FuZGlkYXRlKSB7XG4gICAgICAgIHdpbmRvdy5SVENJY2VDYW5kaWRhdGUgPSBmdW5jdGlvbihhcmdzKSB7XG4gICAgICAgICAgcmV0dXJuIGFyZ3M7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICAvLyBPUlRDIGRvZXMgbm90IGhhdmUgYSBzZXNzaW9uIGRlc2NyaXB0aW9uIG9iamVjdCBidXRcbiAgICAgIC8vIG90aGVyIGJyb3dzZXJzIChpLmUuIENocm9tZSkgdGhhdCB3aWxsIHN1cHBvcnQgYm90aCBQQyBhbmQgT1JUQ1xuICAgICAgLy8gaW4gdGhlIGZ1dHVyZSBtaWdodCBoYXZlIHRoaXMgZGVmaW5lZCBhbHJlYWR5LlxuICAgICAgaWYgKCF3aW5kb3cuUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKSB7XG4gICAgICAgIHdpbmRvdy5SVENTZXNzaW9uRGVzY3JpcHRpb24gPSBmdW5jdGlvbihhcmdzKSB7XG4gICAgICAgICAgcmV0dXJuIGFyZ3M7XG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICAvLyB0aGlzIGFkZHMgYW4gYWRkaXRpb25hbCBldmVudCBsaXN0ZW5lciB0byBNZWRpYVN0cmFja1RyYWNrIHRoYXQgc2lnbmFsc1xuICAgICAgLy8gd2hlbiBhIHRyYWNrcyBlbmFibGVkIHByb3BlcnR5IHdhcyBjaGFuZ2VkLiBXb3JrYXJvdW5kIGZvciBhIGJ1ZyBpblxuICAgICAgLy8gYWRkU3RyZWFtLCBzZWUgYmVsb3cuIE5vIGxvbmdlciByZXF1aXJlZCBpbiAxNTAyNStcbiAgICAgIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgMTUwMjUpIHtcbiAgICAgICAgdmFyIG9yaWdNU1RFbmFibGVkID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihcbiAgICAgICAgICAgIE1lZGlhU3RyZWFtVHJhY2sucHJvdG90eXBlLCAnZW5hYmxlZCcpO1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoTWVkaWFTdHJlYW1UcmFjay5wcm90b3R5cGUsICdlbmFibGVkJywge1xuICAgICAgICAgIHNldDogZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgICAgICAgIG9yaWdNU1RFbmFibGVkLnNldC5jYWxsKHRoaXMsIHZhbHVlKTtcbiAgICAgICAgICAgIHZhciBldiA9IG5ldyBFdmVudCgnZW5hYmxlZCcpO1xuICAgICAgICAgICAgZXYuZW5hYmxlZCA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KGV2KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gPSBzaGltUlRDUGVlckNvbm5lY3Rpb24oYnJvd3NlckRldGFpbHMudmVyc2lvbik7XG4gIH0sXG4gIHNoaW1SZXBsYWNlVHJhY2s6IGZ1bmN0aW9uKCkge1xuICAgIC8vIE9SVEMgaGFzIHJlcGxhY2VUcmFjayAtLSBodHRwczovL2dpdGh1Yi5jb20vdzNjL29ydGMvaXNzdWVzLzYxNFxuICAgIGlmICh3aW5kb3cuUlRDUnRwU2VuZGVyICYmICEoJ3JlcGxhY2VUcmFjaycgaW4gUlRDUnRwU2VuZGVyLnByb3RvdHlwZSkpIHtcbiAgICAgIFJUQ1J0cFNlbmRlci5wcm90b3R5cGUucmVwbGFjZVRyYWNrID0gUlRDUnRwU2VuZGVyLnByb3RvdHlwZS5zZXRUcmFjaztcbiAgICB9XG4gIH1cbn07XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbigpIHtcbiAgdmFyIHNoaW1FcnJvcl8gPSBmdW5jdGlvbihlKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6IHtQZXJtaXNzaW9uRGVuaWVkRXJyb3I6ICdOb3RBbGxvd2VkRXJyb3InfVtlLm5hbWVdIHx8IGUubmFtZSxcbiAgICAgIG1lc3NhZ2U6IGUubWVzc2FnZSxcbiAgICAgIGNvbnN0cmFpbnQ6IGUuY29uc3RyYWludCxcbiAgICAgIHRvU3RyaW5nOiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubmFtZTtcbiAgICAgIH1cbiAgICB9O1xuICB9O1xuXG4gIC8vIGdldFVzZXJNZWRpYSBlcnJvciBzaGltLlxuICB2YXIgb3JpZ0dldFVzZXJNZWRpYSA9IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhLlxuICAgICAgYmluZChuYXZpZ2F0b3IubWVkaWFEZXZpY2VzKTtcbiAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEgPSBmdW5jdGlvbihjKSB7XG4gICAgcmV0dXJuIG9yaWdHZXRVc2VyTWVkaWEoYykuY2F0Y2goZnVuY3Rpb24oZSkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KHNoaW1FcnJvcl8oZSkpO1xuICAgIH0pO1xuICB9O1xufTtcbiIsIi8qXG4gKiAgQ29weXJpZ2h0IChjKSAyMDE3IFRoZSBXZWJSVEMgcHJvamVjdCBhdXRob3JzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqICBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZSBsaWNlbnNlXG4gKiAgdGhhdCBjYW4gYmUgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBvZiB0aGUgc291cmNlXG4gKiAgdHJlZS5cbiAqL1xuIC8qIGVzbGludC1lbnYgbm9kZSAqL1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgU0RQVXRpbHMgPSByZXF1aXJlKCdzZHAnKTtcblxuLy8gc29ydCB0cmFja3Mgc3VjaCB0aGF0IHRoZXkgZm9sbG93IGFuIGEtdi1hLXYuLi5cbi8vIHBhdHRlcm4uXG5mdW5jdGlvbiBzb3J0VHJhY2tzKHRyYWNrcykge1xuICB2YXIgYXVkaW9UcmFja3MgPSB0cmFja3MuZmlsdGVyKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgcmV0dXJuIHRyYWNrLmtpbmQgPT09ICdhdWRpbyc7XG4gIH0pO1xuICB2YXIgdmlkZW9UcmFja3MgPSB0cmFja3MuZmlsdGVyKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgcmV0dXJuIHRyYWNrLmtpbmQgPT09ICd2aWRlbyc7XG4gIH0pO1xuICB0cmFja3MgPSBbXTtcbiAgd2hpbGUgKGF1ZGlvVHJhY2tzLmxlbmd0aCB8fCB2aWRlb1RyYWNrcy5sZW5ndGgpIHtcbiAgICBpZiAoYXVkaW9UcmFja3MubGVuZ3RoKSB7XG4gICAgICB0cmFja3MucHVzaChhdWRpb1RyYWNrcy5zaGlmdCgpKTtcbiAgICB9XG4gICAgaWYgKHZpZGVvVHJhY2tzLmxlbmd0aCkge1xuICAgICAgdHJhY2tzLnB1c2godmlkZW9UcmFja3Muc2hpZnQoKSk7XG4gICAgfVxuICB9XG4gIHJldHVybiB0cmFja3M7XG59XG5cbi8vIEVkZ2UgZG9lcyBub3QgbGlrZVxuLy8gMSkgc3R1bjpcbi8vIDIpIHR1cm46IHRoYXQgZG9lcyBub3QgaGF2ZSBhbGwgb2YgdHVybjpob3N0OnBvcnQ/dHJhbnNwb3J0PXVkcFxuLy8gMykgdHVybjogd2l0aCBpcHY2IGFkZHJlc3Nlc1xuLy8gNCkgdHVybjogb2NjdXJyaW5nIG11bGlwbGUgdGltZXNcbmZ1bmN0aW9uIGZpbHRlckljZVNlcnZlcnMoaWNlU2VydmVycywgZWRnZVZlcnNpb24pIHtcbiAgdmFyIGhhc1R1cm4gPSBmYWxzZTtcbiAgaWNlU2VydmVycyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoaWNlU2VydmVycykpO1xuICByZXR1cm4gaWNlU2VydmVycy5maWx0ZXIoZnVuY3Rpb24oc2VydmVyKSB7XG4gICAgaWYgKHNlcnZlciAmJiAoc2VydmVyLnVybHMgfHwgc2VydmVyLnVybCkpIHtcbiAgICAgIHZhciB1cmxzID0gc2VydmVyLnVybHMgfHwgc2VydmVyLnVybDtcbiAgICAgIGlmIChzZXJ2ZXIudXJsICYmICFzZXJ2ZXIudXJscykge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1JUQ0ljZVNlcnZlci51cmwgaXMgZGVwcmVjYXRlZCEgVXNlIHVybHMgaW5zdGVhZC4nKTtcbiAgICAgIH1cbiAgICAgIHZhciBpc1N0cmluZyA9IHR5cGVvZiB1cmxzID09PSAnc3RyaW5nJztcbiAgICAgIGlmIChpc1N0cmluZykge1xuICAgICAgICB1cmxzID0gW3VybHNdO1xuICAgICAgfVxuICAgICAgdXJscyA9IHVybHMuZmlsdGVyKGZ1bmN0aW9uKHVybCkge1xuICAgICAgICB2YXIgdmFsaWRUdXJuID0gdXJsLmluZGV4T2YoJ3R1cm46JykgPT09IDAgJiZcbiAgICAgICAgICAgIHVybC5pbmRleE9mKCd0cmFuc3BvcnQ9dWRwJykgIT09IC0xICYmXG4gICAgICAgICAgICB1cmwuaW5kZXhPZigndHVybjpbJykgPT09IC0xICYmXG4gICAgICAgICAgICAhaGFzVHVybjtcblxuICAgICAgICBpZiAodmFsaWRUdXJuKSB7XG4gICAgICAgICAgaGFzVHVybiA9IHRydWU7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVybC5pbmRleE9mKCdzdHVuOicpID09PSAwICYmIGVkZ2VWZXJzaW9uID49IDE0MzkzO1xuICAgICAgfSk7XG5cbiAgICAgIGRlbGV0ZSBzZXJ2ZXIudXJsO1xuICAgICAgc2VydmVyLnVybHMgPSBpc1N0cmluZyA/IHVybHNbMF0gOiB1cmxzO1xuICAgICAgcmV0dXJuICEhdXJscy5sZW5ndGg7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfSk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oZWRnZVZlcnNpb24pIHtcbiAgdmFyIFJUQ1BlZXJDb25uZWN0aW9uID0gZnVuY3Rpb24oY29uZmlnKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgdmFyIF9ldmVudFRhcmdldCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcbiAgICBbJ2FkZEV2ZW50TGlzdGVuZXInLCAncmVtb3ZlRXZlbnRMaXN0ZW5lcicsICdkaXNwYXRjaEV2ZW50J11cbiAgICAgICAgLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICAgICAgc2VsZlttZXRob2RdID0gX2V2ZW50VGFyZ2V0W21ldGhvZF0uYmluZChfZXZlbnRUYXJnZXQpO1xuICAgICAgICB9KTtcblxuICAgIHRoaXMub25pY2VjYW5kaWRhdGUgPSBudWxsO1xuICAgIHRoaXMub25hZGRzdHJlYW0gPSBudWxsO1xuICAgIHRoaXMub250cmFjayA9IG51bGw7XG4gICAgdGhpcy5vbnJlbW92ZXN0cmVhbSA9IG51bGw7XG4gICAgdGhpcy5vbnNpZ25hbGluZ3N0YXRlY2hhbmdlID0gbnVsbDtcbiAgICB0aGlzLm9uaWNlY29ubmVjdGlvbnN0YXRlY2hhbmdlID0gbnVsbDtcbiAgICB0aGlzLm9uaWNlZ2F0aGVyaW5nc3RhdGVjaGFuZ2UgPSBudWxsO1xuICAgIHRoaXMub25uZWdvdGlhdGlvbm5lZWRlZCA9IG51bGw7XG4gICAgdGhpcy5vbmRhdGFjaGFubmVsID0gbnVsbDtcbiAgICB0aGlzLmNhblRyaWNrbGVJY2VDYW5kaWRhdGVzID0gbnVsbDtcblxuICAgIHRoaXMubG9jYWxTdHJlYW1zID0gW107XG4gICAgdGhpcy5yZW1vdGVTdHJlYW1zID0gW107XG4gICAgdGhpcy5nZXRMb2NhbFN0cmVhbXMgPSBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiBzZWxmLmxvY2FsU3RyZWFtcztcbiAgICB9O1xuICAgIHRoaXMuZ2V0UmVtb3RlU3RyZWFtcyA9IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIHNlbGYucmVtb3RlU3RyZWFtcztcbiAgICB9O1xuXG4gICAgdGhpcy5sb2NhbERlc2NyaXB0aW9uID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICB0eXBlOiAnJyxcbiAgICAgIHNkcDogJydcbiAgICB9KTtcbiAgICB0aGlzLnJlbW90ZURlc2NyaXB0aW9uID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICB0eXBlOiAnJyxcbiAgICAgIHNkcDogJydcbiAgICB9KTtcbiAgICB0aGlzLnNpZ25hbGluZ1N0YXRlID0gJ3N0YWJsZSc7XG4gICAgdGhpcy5pY2VDb25uZWN0aW9uU3RhdGUgPSAnbmV3JztcbiAgICB0aGlzLmljZUdhdGhlcmluZ1N0YXRlID0gJ25ldyc7XG5cbiAgICB0aGlzLmljZU9wdGlvbnMgPSB7XG4gICAgICBnYXRoZXJQb2xpY3k6ICdhbGwnLFxuICAgICAgaWNlU2VydmVyczogW11cbiAgICB9O1xuICAgIGlmIChjb25maWcgJiYgY29uZmlnLmljZVRyYW5zcG9ydFBvbGljeSkge1xuICAgICAgc3dpdGNoIChjb25maWcuaWNlVHJhbnNwb3J0UG9saWN5KSB7XG4gICAgICAgIGNhc2UgJ2FsbCc6XG4gICAgICAgIGNhc2UgJ3JlbGF5JzpcbiAgICAgICAgICB0aGlzLmljZU9wdGlvbnMuZ2F0aGVyUG9saWN5ID0gY29uZmlnLmljZVRyYW5zcG9ydFBvbGljeTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAvLyBkb24ndCBzZXQgaWNlVHJhbnNwb3J0UG9saWN5LlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLnVzaW5nQnVuZGxlID0gY29uZmlnICYmIGNvbmZpZy5idW5kbGVQb2xpY3kgPT09ICdtYXgtYnVuZGxlJztcblxuICAgIGlmIChjb25maWcgJiYgY29uZmlnLmljZVNlcnZlcnMpIHtcbiAgICAgIHRoaXMuaWNlT3B0aW9ucy5pY2VTZXJ2ZXJzID0gZmlsdGVySWNlU2VydmVycyhjb25maWcuaWNlU2VydmVycyxcbiAgICAgICAgICBlZGdlVmVyc2lvbik7XG4gICAgfVxuICAgIHRoaXMuX2NvbmZpZyA9IGNvbmZpZyB8fCB7fTtcblxuICAgIC8vIHBlci10cmFjayBpY2VHYXRoZXJzLCBpY2VUcmFuc3BvcnRzLCBkdGxzVHJhbnNwb3J0cywgcnRwU2VuZGVycywgLi4uXG4gICAgLy8gZXZlcnl0aGluZyB0aGF0IGlzIG5lZWRlZCB0byBkZXNjcmliZSBhIFNEUCBtLWxpbmUuXG4gICAgdGhpcy50cmFuc2NlaXZlcnMgPSBbXTtcblxuICAgIC8vIHNpbmNlIHRoZSBpY2VHYXRoZXJlciBpcyBjdXJyZW50bHkgY3JlYXRlZCBpbiBjcmVhdGVPZmZlciBidXQgd2VcbiAgICAvLyBtdXN0IG5vdCBlbWl0IGNhbmRpZGF0ZXMgdW50aWwgYWZ0ZXIgc2V0TG9jYWxEZXNjcmlwdGlvbiB3ZSBidWZmZXJcbiAgICAvLyB0aGVtIGluIHRoaXMgYXJyYXkuXG4gICAgdGhpcy5fbG9jYWxJY2VDYW5kaWRhdGVzQnVmZmVyID0gW107XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl9lbWl0R2F0aGVyaW5nU3RhdGVDaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgZXZlbnQgPSBuZXcgRXZlbnQoJ2ljZWdhdGhlcmluZ3N0YXRlY2hhbmdlJyk7XG4gICAgdGhpcy5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICBpZiAodGhpcy5vbmljZWdhdGhlcmluZ3N0YXRlY2hhbmdlICE9PSBudWxsKSB7XG4gICAgICB0aGlzLm9uaWNlZ2F0aGVyaW5nc3RhdGVjaGFuZ2UoZXZlbnQpO1xuICAgIH1cbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX2VtaXRCdWZmZXJlZENhbmRpZGF0ZXMgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIHNlY3Rpb25zID0gU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyhzZWxmLmxvY2FsRGVzY3JpcHRpb24uc2RwKTtcbiAgICAvLyBGSVhNRTogbmVlZCB0byBhcHBseSBpY2UgY2FuZGlkYXRlcyBpbiBhIHdheSB3aGljaCBpcyBhc3luYyBidXRcbiAgICAvLyBpbi1vcmRlclxuICAgIHRoaXMuX2xvY2FsSWNlQ2FuZGlkYXRlc0J1ZmZlci5mb3JFYWNoKGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICB2YXIgZW5kID0gIWV2ZW50LmNhbmRpZGF0ZSB8fCBPYmplY3Qua2V5cyhldmVudC5jYW5kaWRhdGUpLmxlbmd0aCA9PT0gMDtcbiAgICAgIGlmIChlbmQpIHtcbiAgICAgICAgZm9yICh2YXIgaiA9IDE7IGogPCBzZWN0aW9ucy5sZW5ndGg7IGorKykge1xuICAgICAgICAgIGlmIChzZWN0aW9uc1tqXS5pbmRleE9mKCdcXHJcXG5hPWVuZC1vZi1jYW5kaWRhdGVzXFxyXFxuJykgPT09IC0xKSB7XG4gICAgICAgICAgICBzZWN0aW9uc1tqXSArPSAnYT1lbmQtb2YtY2FuZGlkYXRlc1xcclxcbic7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzZWN0aW9uc1tldmVudC5jYW5kaWRhdGUuc2RwTUxpbmVJbmRleCArIDFdICs9XG4gICAgICAgICAgICAnYT0nICsgZXZlbnQuY2FuZGlkYXRlLmNhbmRpZGF0ZSArICdcXHJcXG4nO1xuICAgICAgfVxuICAgICAgc2VsZi5sb2NhbERlc2NyaXB0aW9uLnNkcCA9IHNlY3Rpb25zLmpvaW4oJycpO1xuICAgICAgc2VsZi5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICAgIGlmIChzZWxmLm9uaWNlY2FuZGlkYXRlICE9PSBudWxsKSB7XG4gICAgICAgIHNlbGYub25pY2VjYW5kaWRhdGUoZXZlbnQpO1xuICAgICAgfVxuICAgICAgaWYgKCFldmVudC5jYW5kaWRhdGUgJiYgc2VsZi5pY2VHYXRoZXJpbmdTdGF0ZSAhPT0gJ2NvbXBsZXRlJykge1xuICAgICAgICB2YXIgY29tcGxldGUgPSBzZWxmLnRyYW5zY2VpdmVycy5ldmVyeShmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgICAgIHJldHVybiB0cmFuc2NlaXZlci5pY2VHYXRoZXJlciAmJlxuICAgICAgICAgICAgICB0cmFuc2NlaXZlci5pY2VHYXRoZXJlci5zdGF0ZSA9PT0gJ2NvbXBsZXRlZCc7XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoY29tcGxldGUgJiYgc2VsZi5pY2VHYXRoZXJpbmdTdGF0ZUNoYW5nZSAhPT0gJ2NvbXBsZXRlJykge1xuICAgICAgICAgIHNlbGYuaWNlR2F0aGVyaW5nU3RhdGUgPSAnY29tcGxldGUnO1xuICAgICAgICAgIHNlbGYuX2VtaXRHYXRoZXJpbmdTdGF0ZUNoYW5nZSgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgdGhpcy5fbG9jYWxJY2VDYW5kaWRhdGVzQnVmZmVyID0gW107XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldENvbmZpZ3VyYXRpb24gPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5fY29uZmlnO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRTdHJlYW0gPSBmdW5jdGlvbihzdHJlYW0pIHtcbiAgICBpZiAoZWRnZVZlcnNpb24gPj0gMTUwMjUpIHtcbiAgICAgIHRoaXMubG9jYWxTdHJlYW1zLnB1c2goc3RyZWFtKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQ2xvbmUgaXMgbmVjZXNzYXJ5IGZvciBsb2NhbCBkZW1vcyBtb3N0bHksIGF0dGFjaGluZyBkaXJlY3RseVxuICAgICAgLy8gdG8gdHdvIGRpZmZlcmVudCBzZW5kZXJzIGRvZXMgbm90IHdvcmsgKGJ1aWxkIDEwNTQ3KS5cbiAgICAgIC8vIEZpeGVkIGluIDE1MDI1IChvciBlYXJsaWVyKVxuICAgICAgdmFyIGNsb25lZFN0cmVhbSA9IHN0cmVhbS5jbG9uZSgpO1xuICAgICAgc3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2ssIGlkeCkge1xuICAgICAgICB2YXIgY2xvbmVkVHJhY2sgPSBjbG9uZWRTdHJlYW0uZ2V0VHJhY2tzKClbaWR4XTtcbiAgICAgICAgdHJhY2suYWRkRXZlbnRMaXN0ZW5lcignZW5hYmxlZCcsIGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICAgICAgY2xvbmVkVHJhY2suZW5hYmxlZCA9IGV2ZW50LmVuYWJsZWQ7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgICB0aGlzLmxvY2FsU3RyZWFtcy5wdXNoKGNsb25lZFN0cmVhbSk7XG4gICAgfVxuICAgIHRoaXMuX21heWJlRmlyZU5lZ290aWF0aW9uTmVlZGVkKCk7XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnJlbW92ZVN0cmVhbSA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgIHZhciBpZHggPSB0aGlzLmxvY2FsU3RyZWFtcy5pbmRleE9mKHN0cmVhbSk7XG4gICAgaWYgKGlkeCA+IC0xKSB7XG4gICAgICB0aGlzLmxvY2FsU3RyZWFtcy5zcGxpY2UoaWR4LCAxKTtcbiAgICAgIHRoaXMuX21heWJlRmlyZU5lZ290aWF0aW9uTmVlZGVkKCk7XG4gICAgfVxuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRTZW5kZXJzID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNjZWl2ZXJzLmZpbHRlcihmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgcmV0dXJuICEhdHJhbnNjZWl2ZXIucnRwU2VuZGVyO1xuICAgIH0pXG4gICAgLm1hcChmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgcmV0dXJuIHRyYW5zY2VpdmVyLnJ0cFNlbmRlcjtcbiAgICB9KTtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuZ2V0UmVjZWl2ZXJzID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMudHJhbnNjZWl2ZXJzLmZpbHRlcihmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgcmV0dXJuICEhdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXI7XG4gICAgfSlcbiAgICAubWFwKGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICByZXR1cm4gdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXI7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gRGV0ZXJtaW5lcyB0aGUgaW50ZXJzZWN0aW9uIG9mIGxvY2FsIGFuZCByZW1vdGUgY2FwYWJpbGl0aWVzLlxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX2dldENvbW1vbkNhcGFiaWxpdGllcyA9IGZ1bmN0aW9uKFxuICAgICAgbG9jYWxDYXBhYmlsaXRpZXMsIHJlbW90ZUNhcGFiaWxpdGllcykge1xuICAgIHZhciBjb21tb25DYXBhYmlsaXRpZXMgPSB7XG4gICAgICBjb2RlY3M6IFtdLFxuICAgICAgaGVhZGVyRXh0ZW5zaW9uczogW10sXG4gICAgICBmZWNNZWNoYW5pc21zOiBbXVxuICAgIH07XG5cbiAgICB2YXIgZmluZENvZGVjQnlQYXlsb2FkVHlwZSA9IGZ1bmN0aW9uKHB0LCBjb2RlY3MpIHtcbiAgICAgIHB0ID0gcGFyc2VJbnQocHQsIDEwKTtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY29kZWNzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChjb2RlY3NbaV0ucGF5bG9hZFR5cGUgPT09IHB0IHx8XG4gICAgICAgICAgICBjb2RlY3NbaV0ucHJlZmVycmVkUGF5bG9hZFR5cGUgPT09IHB0KSB7XG4gICAgICAgICAgcmV0dXJuIGNvZGVjc1tpXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcnR4Q2FwYWJpbGl0eU1hdGNoZXMgPSBmdW5jdGlvbihsUnR4LCByUnR4LCBsQ29kZWNzLCByQ29kZWNzKSB7XG4gICAgICB2YXIgbENvZGVjID0gZmluZENvZGVjQnlQYXlsb2FkVHlwZShsUnR4LnBhcmFtZXRlcnMuYXB0LCBsQ29kZWNzKTtcbiAgICAgIHZhciByQ29kZWMgPSBmaW5kQ29kZWNCeVBheWxvYWRUeXBlKHJSdHgucGFyYW1ldGVycy5hcHQsIHJDb2RlY3MpO1xuICAgICAgcmV0dXJuIGxDb2RlYyAmJiByQ29kZWMgJiZcbiAgICAgICAgICBsQ29kZWMubmFtZS50b0xvd2VyQ2FzZSgpID09PSByQ29kZWMubmFtZS50b0xvd2VyQ2FzZSgpO1xuICAgIH07XG5cbiAgICBsb2NhbENhcGFiaWxpdGllcy5jb2RlY3MuZm9yRWFjaChmdW5jdGlvbihsQ29kZWMpIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmVtb3RlQ2FwYWJpbGl0aWVzLmNvZGVjcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgckNvZGVjID0gcmVtb3RlQ2FwYWJpbGl0aWVzLmNvZGVjc1tpXTtcbiAgICAgICAgaWYgKGxDb2RlYy5uYW1lLnRvTG93ZXJDYXNlKCkgPT09IHJDb2RlYy5uYW1lLnRvTG93ZXJDYXNlKCkgJiZcbiAgICAgICAgICAgIGxDb2RlYy5jbG9ja1JhdGUgPT09IHJDb2RlYy5jbG9ja1JhdGUpIHtcbiAgICAgICAgICBpZiAobENvZGVjLm5hbWUudG9Mb3dlckNhc2UoKSA9PT0gJ3J0eCcgJiZcbiAgICAgICAgICAgICAgbENvZGVjLnBhcmFtZXRlcnMgJiYgckNvZGVjLnBhcmFtZXRlcnMuYXB0KSB7XG4gICAgICAgICAgICAvLyBmb3IgUlRYIHdlIG5lZWQgdG8gZmluZCB0aGUgbG9jYWwgcnR4IHRoYXQgaGFzIGEgYXB0XG4gICAgICAgICAgICAvLyB3aGljaCBwb2ludHMgdG8gdGhlIHNhbWUgbG9jYWwgY29kZWMgYXMgdGhlIHJlbW90ZSBvbmUuXG4gICAgICAgICAgICBpZiAoIXJ0eENhcGFiaWxpdHlNYXRjaGVzKGxDb2RlYywgckNvZGVjLFxuICAgICAgICAgICAgICAgIGxvY2FsQ2FwYWJpbGl0aWVzLmNvZGVjcywgcmVtb3RlQ2FwYWJpbGl0aWVzLmNvZGVjcykpIHtcbiAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJDb2RlYyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkockNvZGVjKSk7IC8vIGRlZXBjb3B5XG4gICAgICAgICAgLy8gbnVtYmVyIG9mIGNoYW5uZWxzIGlzIHRoZSBoaWdoZXN0IGNvbW1vbiBudW1iZXIgb2YgY2hhbm5lbHNcbiAgICAgICAgICByQ29kZWMubnVtQ2hhbm5lbHMgPSBNYXRoLm1pbihsQ29kZWMubnVtQ2hhbm5lbHMsXG4gICAgICAgICAgICAgIHJDb2RlYy5udW1DaGFubmVscyk7XG4gICAgICAgICAgLy8gcHVzaCByQ29kZWMgc28gd2UgcmVwbHkgd2l0aCBvZmZlcmVyIHBheWxvYWQgdHlwZVxuICAgICAgICAgIGNvbW1vbkNhcGFiaWxpdGllcy5jb2RlY3MucHVzaChyQ29kZWMpO1xuXG4gICAgICAgICAgLy8gZGV0ZXJtaW5lIGNvbW1vbiBmZWVkYmFjayBtZWNoYW5pc21zXG4gICAgICAgICAgckNvZGVjLnJ0Y3BGZWVkYmFjayA9IHJDb2RlYy5ydGNwRmVlZGJhY2suZmlsdGVyKGZ1bmN0aW9uKGZiKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGxDb2RlYy5ydGNwRmVlZGJhY2subGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgaWYgKGxDb2RlYy5ydGNwRmVlZGJhY2tbal0udHlwZSA9PT0gZmIudHlwZSAmJlxuICAgICAgICAgICAgICAgICAgbENvZGVjLnJ0Y3BGZWVkYmFja1tqXS5wYXJhbWV0ZXIgPT09IGZiLnBhcmFtZXRlcikge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgLy8gRklYTUU6IGFsc28gbmVlZCB0byBkZXRlcm1pbmUgLnBhcmFtZXRlcnNcbiAgICAgICAgICAvLyAgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9vcGVucGVlci9vcnRjL2lzc3Vlcy81NjlcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgbG9jYWxDYXBhYmlsaXRpZXMuaGVhZGVyRXh0ZW5zaW9uc1xuICAgICAgICAuZm9yRWFjaChmdW5jdGlvbihsSGVhZGVyRXh0ZW5zaW9uKSB7XG4gICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZW1vdGVDYXBhYmlsaXRpZXMuaGVhZGVyRXh0ZW5zaW9ucy5sZW5ndGg7XG4gICAgICAgICAgICAgICBpKyspIHtcbiAgICAgICAgICAgIHZhciBySGVhZGVyRXh0ZW5zaW9uID0gcmVtb3RlQ2FwYWJpbGl0aWVzLmhlYWRlckV4dGVuc2lvbnNbaV07XG4gICAgICAgICAgICBpZiAobEhlYWRlckV4dGVuc2lvbi51cmkgPT09IHJIZWFkZXJFeHRlbnNpb24udXJpKSB7XG4gICAgICAgICAgICAgIGNvbW1vbkNhcGFiaWxpdGllcy5oZWFkZXJFeHRlbnNpb25zLnB1c2gockhlYWRlckV4dGVuc2lvbik7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAvLyBGSVhNRTogZmVjTWVjaGFuaXNtc1xuICAgIHJldHVybiBjb21tb25DYXBhYmlsaXRpZXM7XG4gIH07XG5cbiAgLy8gQ3JlYXRlIElDRSBnYXRoZXJlciwgSUNFIHRyYW5zcG9ydCBhbmQgRFRMUyB0cmFuc3BvcnQuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5fY3JlYXRlSWNlQW5kRHRsc1RyYW5zcG9ydHMgPSBmdW5jdGlvbihtaWQsXG4gICAgICBzZHBNTGluZUluZGV4KSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBpY2VHYXRoZXJlciA9IG5ldyBSVENJY2VHYXRoZXJlcihzZWxmLmljZU9wdGlvbnMpO1xuICAgIHZhciBpY2VUcmFuc3BvcnQgPSBuZXcgUlRDSWNlVHJhbnNwb3J0KGljZUdhdGhlcmVyKTtcbiAgICBpY2VHYXRoZXJlci5vbmxvY2FsY2FuZGlkYXRlID0gZnVuY3Rpb24oZXZ0KSB7XG4gICAgICB2YXIgZXZlbnQgPSBuZXcgRXZlbnQoJ2ljZWNhbmRpZGF0ZScpO1xuICAgICAgZXZlbnQuY2FuZGlkYXRlID0ge3NkcE1pZDogbWlkLCBzZHBNTGluZUluZGV4OiBzZHBNTGluZUluZGV4fTtcblxuICAgICAgdmFyIGNhbmQgPSBldnQuY2FuZGlkYXRlO1xuICAgICAgdmFyIGVuZCA9ICFjYW5kIHx8IE9iamVjdC5rZXlzKGNhbmQpLmxlbmd0aCA9PT0gMDtcbiAgICAgIC8vIEVkZ2UgZW1pdHMgYW4gZW1wdHkgb2JqZWN0IGZvciBSVENJY2VDYW5kaWRhdGVDb21wbGV0ZeKApVxuICAgICAgaWYgKGVuZCkge1xuICAgICAgICAvLyBwb2x5ZmlsbCBzaW5jZSBSVENJY2VHYXRoZXJlci5zdGF0ZSBpcyBub3QgaW1wbGVtZW50ZWQgaW5cbiAgICAgICAgLy8gRWRnZSAxMDU0NyB5ZXQuXG4gICAgICAgIGlmIChpY2VHYXRoZXJlci5zdGF0ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgaWNlR2F0aGVyZXIuc3RhdGUgPSAnY29tcGxldGVkJztcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gUlRDSWNlQ2FuZGlkYXRlIGRvZXNuJ3QgaGF2ZSBhIGNvbXBvbmVudCwgbmVlZHMgdG8gYmUgYWRkZWRcbiAgICAgICAgY2FuZC5jb21wb25lbnQgPSBpY2VUcmFuc3BvcnQuY29tcG9uZW50ID09PSAnUlRDUCcgPyAyIDogMTtcbiAgICAgICAgZXZlbnQuY2FuZGlkYXRlLmNhbmRpZGF0ZSA9IFNEUFV0aWxzLndyaXRlQ2FuZGlkYXRlKGNhbmQpO1xuICAgICAgfVxuXG4gICAgICAvLyB1cGRhdGUgbG9jYWwgZGVzY3JpcHRpb24uXG4gICAgICB2YXIgc2VjdGlvbnMgPSBTRFBVdGlscy5zcGxpdFNlY3Rpb25zKHNlbGYubG9jYWxEZXNjcmlwdGlvbi5zZHApO1xuICAgICAgaWYgKCFlbmQpIHtcbiAgICAgICAgc2VjdGlvbnNbZXZlbnQuY2FuZGlkYXRlLnNkcE1MaW5lSW5kZXggKyAxXSArPVxuICAgICAgICAgICAgJ2E9JyArIGV2ZW50LmNhbmRpZGF0ZS5jYW5kaWRhdGUgKyAnXFxyXFxuJztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNlY3Rpb25zW2V2ZW50LmNhbmRpZGF0ZS5zZHBNTGluZUluZGV4ICsgMV0gKz1cbiAgICAgICAgICAgICdhPWVuZC1vZi1jYW5kaWRhdGVzXFxyXFxuJztcbiAgICAgIH1cbiAgICAgIHNlbGYubG9jYWxEZXNjcmlwdGlvbi5zZHAgPSBzZWN0aW9ucy5qb2luKCcnKTtcbiAgICAgIHZhciB0cmFuc2NlaXZlcnMgPSBzZWxmLl9wZW5kaW5nT2ZmZXIgPyBzZWxmLl9wZW5kaW5nT2ZmZXIgOlxuICAgICAgICAgIHNlbGYudHJhbnNjZWl2ZXJzO1xuICAgICAgdmFyIGNvbXBsZXRlID0gdHJhbnNjZWl2ZXJzLmV2ZXJ5KGZ1bmN0aW9uKHRyYW5zY2VpdmVyKSB7XG4gICAgICAgIHJldHVybiB0cmFuc2NlaXZlci5pY2VHYXRoZXJlciAmJlxuICAgICAgICAgICAgdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXIuc3RhdGUgPT09ICdjb21wbGV0ZWQnO1xuICAgICAgfSk7XG5cbiAgICAgIC8vIEVtaXQgY2FuZGlkYXRlIGlmIGxvY2FsRGVzY3JpcHRpb24gaXMgc2V0LlxuICAgICAgLy8gQWxzbyBlbWl0cyBudWxsIGNhbmRpZGF0ZSB3aGVuIGFsbCBnYXRoZXJlcnMgYXJlIGNvbXBsZXRlLlxuICAgICAgc3dpdGNoIChzZWxmLmljZUdhdGhlcmluZ1N0YXRlKSB7XG4gICAgICAgIGNhc2UgJ25ldyc6XG4gICAgICAgICAgaWYgKCFlbmQpIHtcbiAgICAgICAgICAgIHNlbGYuX2xvY2FsSWNlQ2FuZGlkYXRlc0J1ZmZlci5wdXNoKGV2ZW50KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGVuZCAmJiBjb21wbGV0ZSkge1xuICAgICAgICAgICAgc2VsZi5fbG9jYWxJY2VDYW5kaWRhdGVzQnVmZmVyLnB1c2goXG4gICAgICAgICAgICAgICAgbmV3IEV2ZW50KCdpY2VjYW5kaWRhdGUnKSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdnYXRoZXJpbmcnOlxuICAgICAgICAgIHNlbGYuX2VtaXRCdWZmZXJlZENhbmRpZGF0ZXMoKTtcbiAgICAgICAgICBpZiAoIWVuZCkge1xuICAgICAgICAgICAgc2VsZi5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcbiAgICAgICAgICAgIGlmIChzZWxmLm9uaWNlY2FuZGlkYXRlICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgIHNlbGYub25pY2VjYW5kaWRhdGUoZXZlbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoY29tcGxldGUpIHtcbiAgICAgICAgICAgIHNlbGYuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoJ2ljZWNhbmRpZGF0ZScpKTtcbiAgICAgICAgICAgIGlmIChzZWxmLm9uaWNlY2FuZGlkYXRlICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgIHNlbGYub25pY2VjYW5kaWRhdGUobmV3IEV2ZW50KCdpY2VjYW5kaWRhdGUnKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzZWxmLmljZUdhdGhlcmluZ1N0YXRlID0gJ2NvbXBsZXRlJztcbiAgICAgICAgICAgIHNlbGYuX2VtaXRHYXRoZXJpbmdTdGF0ZUNoYW5nZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnY29tcGxldGUnOlxuICAgICAgICAgIC8vIHNob3VsZCBub3QgaGFwcGVuLi4uIGN1cnJlbnRseSFcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDogLy8gbm8tb3AuXG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfTtcbiAgICBpY2VUcmFuc3BvcnQub25pY2VzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgc2VsZi5fdXBkYXRlQ29ubmVjdGlvblN0YXRlKCk7XG4gICAgfTtcblxuICAgIHZhciBkdGxzVHJhbnNwb3J0ID0gbmV3IFJUQ0R0bHNUcmFuc3BvcnQoaWNlVHJhbnNwb3J0KTtcbiAgICBkdGxzVHJhbnNwb3J0Lm9uZHRsc3N0YXRlY2hhbmdlID0gZnVuY3Rpb24oKSB7XG4gICAgICBzZWxmLl91cGRhdGVDb25uZWN0aW9uU3RhdGUoKTtcbiAgICB9O1xuICAgIGR0bHNUcmFuc3BvcnQub25lcnJvciA9IGZ1bmN0aW9uKCkge1xuICAgICAgLy8gb25lcnJvciBkb2VzIG5vdCBzZXQgc3RhdGUgdG8gZmFpbGVkIGJ5IGl0c2VsZi5cbiAgICAgIGR0bHNUcmFuc3BvcnQuc3RhdGUgPSAnZmFpbGVkJztcbiAgICAgIHNlbGYuX3VwZGF0ZUNvbm5lY3Rpb25TdGF0ZSgpO1xuICAgIH07XG5cbiAgICByZXR1cm4ge1xuICAgICAgaWNlR2F0aGVyZXI6IGljZUdhdGhlcmVyLFxuICAgICAgaWNlVHJhbnNwb3J0OiBpY2VUcmFuc3BvcnQsXG4gICAgICBkdGxzVHJhbnNwb3J0OiBkdGxzVHJhbnNwb3J0XG4gICAgfTtcbiAgfTtcblxuICAvLyBEZXN0cm95IElDRSBnYXRoZXJlciwgSUNFIHRyYW5zcG9ydCBhbmQgRFRMUyB0cmFuc3BvcnQuXG4gIC8vIFdpdGhvdXQgdHJpZ2dlcmluZyB0aGUgY2FsbGJhY2tzLlxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX2Rpc3Bvc2VJY2VBbmREdGxzVHJhbnNwb3J0cyA9IGZ1bmN0aW9uKFxuICAgICAgc2RwTUxpbmVJbmRleCkge1xuICAgIHZhciBpY2VHYXRoZXJlciA9IHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmljZUdhdGhlcmVyO1xuICAgIGlmIChpY2VHYXRoZXJlcikge1xuICAgICAgZGVsZXRlIGljZUdhdGhlcmVyLm9ubG9jYWxjYW5kaWRhdGU7XG4gICAgICBkZWxldGUgdGhpcy50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uaWNlR2F0aGVyZXI7XG4gICAgfVxuICAgIHZhciBpY2VUcmFuc3BvcnQgPSB0aGlzLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5pY2VUcmFuc3BvcnQ7XG4gICAgaWYgKGljZVRyYW5zcG9ydCkge1xuICAgICAgZGVsZXRlIGljZVRyYW5zcG9ydC5vbmljZXN0YXRlY2hhbmdlO1xuICAgICAgZGVsZXRlIHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmljZVRyYW5zcG9ydDtcbiAgICB9XG4gICAgdmFyIGR0bHNUcmFuc3BvcnQgPSB0aGlzLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5kdGxzVHJhbnNwb3J0O1xuICAgIGlmIChkdGxzVHJhbnNwb3J0KSB7XG4gICAgICBkZWxldGUgZHRsc1RyYW5zcG9ydC5vbmR0bHNzdHRhdGVjaGFuZ2U7XG4gICAgICBkZWxldGUgZHRsc1RyYW5zcG9ydC5vbmVycm9yO1xuICAgICAgZGVsZXRlIHRoaXMudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLmR0bHNUcmFuc3BvcnQ7XG4gICAgfVxuICB9O1xuXG4gIC8vIFN0YXJ0IHRoZSBSVFAgU2VuZGVyIGFuZCBSZWNlaXZlciBmb3IgYSB0cmFuc2NlaXZlci5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl90cmFuc2NlaXZlID0gZnVuY3Rpb24odHJhbnNjZWl2ZXIsXG4gICAgICBzZW5kLCByZWN2KSB7XG4gICAgdmFyIHBhcmFtcyA9IHRoaXMuX2dldENvbW1vbkNhcGFiaWxpdGllcyh0cmFuc2NlaXZlci5sb2NhbENhcGFiaWxpdGllcyxcbiAgICAgICAgdHJhbnNjZWl2ZXIucmVtb3RlQ2FwYWJpbGl0aWVzKTtcbiAgICBpZiAoc2VuZCAmJiB0cmFuc2NlaXZlci5ydHBTZW5kZXIpIHtcbiAgICAgIHBhcmFtcy5lbmNvZGluZ3MgPSB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzO1xuICAgICAgcGFyYW1zLnJ0Y3AgPSB7XG4gICAgICAgIGNuYW1lOiBTRFBVdGlscy5sb2NhbENOYW1lLFxuICAgICAgICBjb21wb3VuZDogdHJhbnNjZWl2ZXIucnRjcFBhcmFtZXRlcnMuY29tcG91bmRcbiAgICAgIH07XG4gICAgICBpZiAodHJhbnNjZWl2ZXIucmVjdkVuY29kaW5nUGFyYW1ldGVycy5sZW5ndGgpIHtcbiAgICAgICAgcGFyYW1zLnJ0Y3Auc3NyYyA9IHRyYW5zY2VpdmVyLnJlY3ZFbmNvZGluZ1BhcmFtZXRlcnNbMF0uc3NyYztcbiAgICAgIH1cbiAgICAgIHRyYW5zY2VpdmVyLnJ0cFNlbmRlci5zZW5kKHBhcmFtcyk7XG4gICAgfVxuICAgIGlmIChyZWN2ICYmIHRyYW5zY2VpdmVyLnJ0cFJlY2VpdmVyKSB7XG4gICAgICAvLyByZW1vdmUgUlRYIGZpZWxkIGluIEVkZ2UgMTQ5NDJcbiAgICAgIGlmICh0cmFuc2NlaXZlci5raW5kID09PSAndmlkZW8nXG4gICAgICAgICAgJiYgdHJhbnNjZWl2ZXIucmVjdkVuY29kaW5nUGFyYW1ldGVyc1xuICAgICAgICAgICYmIGVkZ2VWZXJzaW9uIDwgMTUwMTkpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIucmVjdkVuY29kaW5nUGFyYW1ldGVycy5mb3JFYWNoKGZ1bmN0aW9uKHApIHtcbiAgICAgICAgICBkZWxldGUgcC5ydHg7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgcGFyYW1zLmVuY29kaW5ncyA9IHRyYW5zY2VpdmVyLnJlY3ZFbmNvZGluZ1BhcmFtZXRlcnM7XG4gICAgICBwYXJhbXMucnRjcCA9IHtcbiAgICAgICAgY25hbWU6IHRyYW5zY2VpdmVyLnJ0Y3BQYXJhbWV0ZXJzLmNuYW1lLFxuICAgICAgICBjb21wb3VuZDogdHJhbnNjZWl2ZXIucnRjcFBhcmFtZXRlcnMuY29tcG91bmRcbiAgICAgIH07XG4gICAgICBpZiAodHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVycy5sZW5ndGgpIHtcbiAgICAgICAgcGFyYW1zLnJ0Y3Auc3NyYyA9IHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnNbMF0uc3NyYztcbiAgICAgIH1cbiAgICAgIHRyYW5zY2VpdmVyLnJ0cFJlY2VpdmVyLnJlY2VpdmUocGFyYW1zKTtcbiAgICB9XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLnNldExvY2FsRGVzY3JpcHRpb24gPSBmdW5jdGlvbihkZXNjcmlwdGlvbikge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgc2VjdGlvbnM7XG4gICAgdmFyIHNlc3Npb25wYXJ0O1xuICAgIGlmIChkZXNjcmlwdGlvbi50eXBlID09PSAnb2ZmZXInKSB7XG4gICAgICAvLyBGSVhNRTogV2hhdCB3YXMgdGhlIHB1cnBvc2Ugb2YgdGhpcyBlbXB0eSBpZiBzdGF0ZW1lbnQ/XG4gICAgICAvLyBpZiAoIXRoaXMuX3BlbmRpbmdPZmZlcikge1xuICAgICAgLy8gfSBlbHNlIHtcbiAgICAgIGlmICh0aGlzLl9wZW5kaW5nT2ZmZXIpIHtcbiAgICAgICAgLy8gVkVSWSBsaW1pdGVkIHN1cHBvcnQgZm9yIFNEUCBtdW5naW5nLiBMaW1pdGVkIHRvOlxuICAgICAgICAvLyAqIGNoYW5naW5nIHRoZSBvcmRlciBvZiBjb2RlY3NcbiAgICAgICAgc2VjdGlvbnMgPSBTRFBVdGlscy5zcGxpdFNlY3Rpb25zKGRlc2NyaXB0aW9uLnNkcCk7XG4gICAgICAgIHNlc3Npb25wYXJ0ID0gc2VjdGlvbnMuc2hpZnQoKTtcbiAgICAgICAgc2VjdGlvbnMuZm9yRWFjaChmdW5jdGlvbihtZWRpYVNlY3Rpb24sIHNkcE1MaW5lSW5kZXgpIHtcbiAgICAgICAgICB2YXIgY2FwcyA9IFNEUFV0aWxzLnBhcnNlUnRwUGFyYW1ldGVycyhtZWRpYVNlY3Rpb24pO1xuICAgICAgICAgIHNlbGYuX3BlbmRpbmdPZmZlcltzZHBNTGluZUluZGV4XS5sb2NhbENhcGFiaWxpdGllcyA9IGNhcHM7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnRyYW5zY2VpdmVycyA9IHRoaXMuX3BlbmRpbmdPZmZlcjtcbiAgICAgICAgZGVsZXRlIHRoaXMuX3BlbmRpbmdPZmZlcjtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGRlc2NyaXB0aW9uLnR5cGUgPT09ICdhbnN3ZXInKSB7XG4gICAgICBzZWN0aW9ucyA9IFNEUFV0aWxzLnNwbGl0U2VjdGlvbnMoc2VsZi5yZW1vdGVEZXNjcmlwdGlvbi5zZHApO1xuICAgICAgc2Vzc2lvbnBhcnQgPSBzZWN0aW9ucy5zaGlmdCgpO1xuICAgICAgdmFyIGlzSWNlTGl0ZSA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KHNlc3Npb25wYXJ0LFxuICAgICAgICAgICdhPWljZS1saXRlJykubGVuZ3RoID4gMDtcbiAgICAgIHNlY3Rpb25zLmZvckVhY2goZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZHBNTGluZUluZGV4KSB7XG4gICAgICAgIHZhciB0cmFuc2NlaXZlciA9IHNlbGYudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdO1xuICAgICAgICB2YXIgaWNlR2F0aGVyZXIgPSB0cmFuc2NlaXZlci5pY2VHYXRoZXJlcjtcbiAgICAgICAgdmFyIGljZVRyYW5zcG9ydCA9IHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydDtcbiAgICAgICAgdmFyIGR0bHNUcmFuc3BvcnQgPSB0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0O1xuICAgICAgICB2YXIgbG9jYWxDYXBhYmlsaXRpZXMgPSB0cmFuc2NlaXZlci5sb2NhbENhcGFiaWxpdGllcztcbiAgICAgICAgdmFyIHJlbW90ZUNhcGFiaWxpdGllcyA9IHRyYW5zY2VpdmVyLnJlbW90ZUNhcGFiaWxpdGllcztcblxuICAgICAgICB2YXIgcmVqZWN0ZWQgPSBtZWRpYVNlY3Rpb24uc3BsaXQoJ1xcbicsIDEpWzBdXG4gICAgICAgICAgICAuc3BsaXQoJyAnLCAyKVsxXSA9PT0gJzAnO1xuXG4gICAgICAgIGlmICghcmVqZWN0ZWQgJiYgIXRyYW5zY2VpdmVyLmlzRGF0YWNoYW5uZWwpIHtcbiAgICAgICAgICB2YXIgcmVtb3RlSWNlUGFyYW1ldGVycyA9IFNEUFV0aWxzLmdldEljZVBhcmFtZXRlcnMoXG4gICAgICAgICAgICAgIG1lZGlhU2VjdGlvbiwgc2Vzc2lvbnBhcnQpO1xuICAgICAgICAgIHZhciByZW1vdGVEdGxzUGFyYW1ldGVycyA9IFNEUFV0aWxzLmdldER0bHNQYXJhbWV0ZXJzKFxuICAgICAgICAgICAgICBtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KTtcbiAgICAgICAgICBpZiAoaXNJY2VMaXRlKSB7XG4gICAgICAgICAgICByZW1vdGVEdGxzUGFyYW1ldGVycy5yb2xlID0gJ3NlcnZlcic7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFzZWxmLnVzaW5nQnVuZGxlIHx8IHNkcE1MaW5lSW5kZXggPT09IDApIHtcbiAgICAgICAgICAgIGljZVRyYW5zcG9ydC5zdGFydChpY2VHYXRoZXJlciwgcmVtb3RlSWNlUGFyYW1ldGVycyxcbiAgICAgICAgICAgICAgICBpc0ljZUxpdGUgPyAnY29udHJvbGxpbmcnIDogJ2NvbnRyb2xsZWQnKTtcbiAgICAgICAgICAgIGR0bHNUcmFuc3BvcnQuc3RhcnQocmVtb3RlRHRsc1BhcmFtZXRlcnMpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIENhbGN1bGF0ZSBpbnRlcnNlY3Rpb24gb2YgY2FwYWJpbGl0aWVzLlxuICAgICAgICAgIHZhciBwYXJhbXMgPSBzZWxmLl9nZXRDb21tb25DYXBhYmlsaXRpZXMobG9jYWxDYXBhYmlsaXRpZXMsXG4gICAgICAgICAgICAgIHJlbW90ZUNhcGFiaWxpdGllcyk7XG5cbiAgICAgICAgICAvLyBTdGFydCB0aGUgUlRDUnRwU2VuZGVyLiBUaGUgUlRDUnRwUmVjZWl2ZXIgZm9yIHRoaXNcbiAgICAgICAgICAvLyB0cmFuc2NlaXZlciBoYXMgYWxyZWFkeSBiZWVuIHN0YXJ0ZWQgaW4gc2V0UmVtb3RlRGVzY3JpcHRpb24uXG4gICAgICAgICAgc2VsZi5fdHJhbnNjZWl2ZSh0cmFuc2NlaXZlcixcbiAgICAgICAgICAgICAgcGFyYW1zLmNvZGVjcy5sZW5ndGggPiAwLFxuICAgICAgICAgICAgICBmYWxzZSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHRoaXMubG9jYWxEZXNjcmlwdGlvbiA9IHtcbiAgICAgIHR5cGU6IGRlc2NyaXB0aW9uLnR5cGUsXG4gICAgICBzZHA6IGRlc2NyaXB0aW9uLnNkcFxuICAgIH07XG4gICAgc3dpdGNoIChkZXNjcmlwdGlvbi50eXBlKSB7XG4gICAgICBjYXNlICdvZmZlcic6XG4gICAgICAgIHRoaXMuX3VwZGF0ZVNpZ25hbGluZ1N0YXRlKCdoYXZlLWxvY2FsLW9mZmVyJyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnYW5zd2VyJzpcbiAgICAgICAgdGhpcy5fdXBkYXRlU2lnbmFsaW5nU3RhdGUoJ3N0YWJsZScpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3Vuc3VwcG9ydGVkIHR5cGUgXCInICsgZGVzY3JpcHRpb24udHlwZSArXG4gICAgICAgICAgICAnXCInKTtcbiAgICB9XG5cbiAgICAvLyBJZiBhIHN1Y2Nlc3MgY2FsbGJhY2sgd2FzIHByb3ZpZGVkLCBlbWl0IElDRSBjYW5kaWRhdGVzIGFmdGVyIGl0XG4gICAgLy8gaGFzIGJlZW4gZXhlY3V0ZWQuIE90aGVyd2lzZSwgZW1pdCBjYWxsYmFjayBhZnRlciB0aGUgUHJvbWlzZSBpc1xuICAgIC8vIHJlc29sdmVkLlxuICAgIHZhciBoYXNDYWxsYmFjayA9IGFyZ3VtZW50cy5sZW5ndGggPiAxICYmXG4gICAgICB0eXBlb2YgYXJndW1lbnRzWzFdID09PSAnZnVuY3Rpb24nO1xuICAgIGlmIChoYXNDYWxsYmFjaykge1xuICAgICAgdmFyIGNiID0gYXJndW1lbnRzWzFdO1xuICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgIGNiKCk7XG4gICAgICAgIGlmIChzZWxmLmljZUdhdGhlcmluZ1N0YXRlID09PSAnbmV3Jykge1xuICAgICAgICAgIHNlbGYuaWNlR2F0aGVyaW5nU3RhdGUgPSAnZ2F0aGVyaW5nJztcbiAgICAgICAgICBzZWxmLl9lbWl0R2F0aGVyaW5nU3RhdGVDaGFuZ2UoKTtcbiAgICAgICAgfVxuICAgICAgICBzZWxmLl9lbWl0QnVmZmVyZWRDYW5kaWRhdGVzKCk7XG4gICAgICB9LCAwKTtcbiAgICB9XG4gICAgdmFyIHAgPSBQcm9taXNlLnJlc29sdmUoKTtcbiAgICBwLnRoZW4oZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoIWhhc0NhbGxiYWNrKSB7XG4gICAgICAgIGlmIChzZWxmLmljZUdhdGhlcmluZ1N0YXRlID09PSAnbmV3Jykge1xuICAgICAgICAgIHNlbGYuaWNlR2F0aGVyaW5nU3RhdGUgPSAnZ2F0aGVyaW5nJztcbiAgICAgICAgICBzZWxmLl9lbWl0R2F0aGVyaW5nU3RhdGVDaGFuZ2UoKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBVc3VhbGx5IGNhbmRpZGF0ZXMgd2lsbCBiZSBlbWl0dGVkIGVhcmxpZXIuXG4gICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KHNlbGYuX2VtaXRCdWZmZXJlZENhbmRpZGF0ZXMuYmluZChzZWxmKSwgNTAwKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gcDtcbiAgfTtcblxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuc2V0UmVtb3RlRGVzY3JpcHRpb24gPSBmdW5jdGlvbihkZXNjcmlwdGlvbikge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgc3RyZWFtcyA9IHt9O1xuICAgIHZhciByZWNlaXZlckxpc3QgPSBbXTtcbiAgICB2YXIgc2VjdGlvbnMgPSBTRFBVdGlscy5zcGxpdFNlY3Rpb25zKGRlc2NyaXB0aW9uLnNkcCk7XG4gICAgdmFyIHNlc3Npb25wYXJ0ID0gc2VjdGlvbnMuc2hpZnQoKTtcbiAgICB2YXIgaXNJY2VMaXRlID0gU0RQVXRpbHMubWF0Y2hQcmVmaXgoc2Vzc2lvbnBhcnQsXG4gICAgICAgICdhPWljZS1saXRlJykubGVuZ3RoID4gMDtcbiAgICB2YXIgdXNpbmdCdW5kbGUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChzZXNzaW9ucGFydCxcbiAgICAgICAgJ2E9Z3JvdXA6QlVORExFICcpLmxlbmd0aCA+IDA7XG4gICAgdmFyIGljZU9wdGlvbnMgPSBTRFBVdGlscy5tYXRjaFByZWZpeChzZXNzaW9ucGFydCxcbiAgICAgICAgJ2E9aWNlLW9wdGlvbnM6JylbMF07XG4gICAgaWYgKGljZU9wdGlvbnMpIHtcbiAgICAgIHRoaXMuY2FuVHJpY2tsZUljZUNhbmRpZGF0ZXMgPSBpY2VPcHRpb25zLnN1YnN0cigxNCkuc3BsaXQoJyAnKVxuICAgICAgICAgIC5pbmRleE9mKCd0cmlja2xlJykgPj0gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5jYW5Ucmlja2xlSWNlQ2FuZGlkYXRlcyA9IGZhbHNlO1xuICAgIH1cblxuICAgIHNlY3Rpb25zLmZvckVhY2goZnVuY3Rpb24obWVkaWFTZWN0aW9uLCBzZHBNTGluZUluZGV4KSB7XG4gICAgICB2YXIgbGluZXMgPSBTRFBVdGlscy5zcGxpdExpbmVzKG1lZGlhU2VjdGlvbik7XG4gICAgICB2YXIgbWxpbmUgPSBsaW5lc1swXS5zdWJzdHIoMikuc3BsaXQoJyAnKTtcbiAgICAgIHZhciBraW5kID0gbWxpbmVbMF07XG4gICAgICB2YXIgcmVqZWN0ZWQgPSBtbGluZVsxXSA9PT0gJzAnO1xuICAgICAgdmFyIGRpcmVjdGlvbiA9IFNEUFV0aWxzLmdldERpcmVjdGlvbihtZWRpYVNlY3Rpb24sIHNlc3Npb25wYXJ0KTtcbiAgICAgIHZhciByZW1vdGVNc2lkID0gU0RQVXRpbHMucGFyc2VNc2lkKG1lZGlhU2VjdGlvbik7XG5cbiAgICAgIHZhciBtaWQgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sICdhPW1pZDonKTtcbiAgICAgIGlmIChtaWQubGVuZ3RoKSB7XG4gICAgICAgIG1pZCA9IG1pZFswXS5zdWJzdHIoNik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBtaWQgPSBTRFBVdGlscy5nZW5lcmF0ZUlkZW50aWZpZXIoKTtcbiAgICAgIH1cblxuICAgICAgLy8gUmVqZWN0IGRhdGFjaGFubmVscyB3aGljaCBhcmUgbm90IGltcGxlbWVudGVkIHlldC5cbiAgICAgIGlmIChraW5kID09PSAnYXBwbGljYXRpb24nICYmIG1saW5lWzJdID09PSAnRFRMUy9TQ1RQJykge1xuICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XSA9IHtcbiAgICAgICAgICBtaWQ6IG1pZCxcbiAgICAgICAgICBpc0RhdGFjaGFubmVsOiB0cnVlXG4gICAgICAgIH07XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdmFyIHRyYW5zY2VpdmVyO1xuICAgICAgdmFyIGljZUdhdGhlcmVyO1xuICAgICAgdmFyIGljZVRyYW5zcG9ydDtcbiAgICAgIHZhciBkdGxzVHJhbnNwb3J0O1xuICAgICAgdmFyIHJ0cFNlbmRlcjtcbiAgICAgIHZhciBydHBSZWNlaXZlcjtcbiAgICAgIHZhciBzZW5kRW5jb2RpbmdQYXJhbWV0ZXJzO1xuICAgICAgdmFyIHJlY3ZFbmNvZGluZ1BhcmFtZXRlcnM7XG4gICAgICB2YXIgbG9jYWxDYXBhYmlsaXRpZXM7XG5cbiAgICAgIHZhciB0cmFjaztcbiAgICAgIC8vIEZJWE1FOiBlbnN1cmUgdGhlIG1lZGlhU2VjdGlvbiBoYXMgcnRjcC1tdXggc2V0LlxuICAgICAgdmFyIHJlbW90ZUNhcGFiaWxpdGllcyA9IFNEUFV0aWxzLnBhcnNlUnRwUGFyYW1ldGVycyhtZWRpYVNlY3Rpb24pO1xuICAgICAgdmFyIHJlbW90ZUljZVBhcmFtZXRlcnM7XG4gICAgICB2YXIgcmVtb3RlRHRsc1BhcmFtZXRlcnM7XG4gICAgICBpZiAoIXJlamVjdGVkKSB7XG4gICAgICAgIHJlbW90ZUljZVBhcmFtZXRlcnMgPSBTRFBVdGlscy5nZXRJY2VQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbixcbiAgICAgICAgICAgIHNlc3Npb25wYXJ0KTtcbiAgICAgICAgcmVtb3RlRHRsc1BhcmFtZXRlcnMgPSBTRFBVdGlscy5nZXREdGxzUGFyYW1ldGVycyhtZWRpYVNlY3Rpb24sXG4gICAgICAgICAgICBzZXNzaW9ucGFydCk7XG4gICAgICAgIHJlbW90ZUR0bHNQYXJhbWV0ZXJzLnJvbGUgPSAnY2xpZW50JztcbiAgICAgIH1cbiAgICAgIHJlY3ZFbmNvZGluZ1BhcmFtZXRlcnMgPVxuICAgICAgICAgIFNEUFV0aWxzLnBhcnNlUnRwRW5jb2RpbmdQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbik7XG5cbiAgICAgIHZhciBydGNwUGFyYW1ldGVycyA9IFNEUFV0aWxzLnBhcnNlUnRjcFBhcmFtZXRlcnMobWVkaWFTZWN0aW9uKTtcblxuICAgICAgdmFyIGlzQ29tcGxldGUgPSBTRFBVdGlscy5tYXRjaFByZWZpeChtZWRpYVNlY3Rpb24sXG4gICAgICAgICAgJ2E9ZW5kLW9mLWNhbmRpZGF0ZXMnLCBzZXNzaW9ucGFydCkubGVuZ3RoID4gMDtcbiAgICAgIHZhciBjYW5kcyA9IFNEUFV0aWxzLm1hdGNoUHJlZml4KG1lZGlhU2VjdGlvbiwgJ2E9Y2FuZGlkYXRlOicpXG4gICAgICAgICAgLm1hcChmdW5jdGlvbihjYW5kKSB7XG4gICAgICAgICAgICByZXR1cm4gU0RQVXRpbHMucGFyc2VDYW5kaWRhdGUoY2FuZCk7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuZmlsdGVyKGZ1bmN0aW9uKGNhbmQpIHtcbiAgICAgICAgICAgIHJldHVybiBjYW5kLmNvbXBvbmVudCA9PT0gJzEnO1xuICAgICAgICAgIH0pO1xuICAgICAgaWYgKGRlc2NyaXB0aW9uLnR5cGUgPT09ICdvZmZlcicgJiYgIXJlamVjdGVkKSB7XG4gICAgICAgIHZhciB0cmFuc3BvcnRzID0gdXNpbmdCdW5kbGUgJiYgc2RwTUxpbmVJbmRleCA+IDAgPyB7XG4gICAgICAgICAgaWNlR2F0aGVyZXI6IHNlbGYudHJhbnNjZWl2ZXJzWzBdLmljZUdhdGhlcmVyLFxuICAgICAgICAgIGljZVRyYW5zcG9ydDogc2VsZi50cmFuc2NlaXZlcnNbMF0uaWNlVHJhbnNwb3J0LFxuICAgICAgICAgIGR0bHNUcmFuc3BvcnQ6IHNlbGYudHJhbnNjZWl2ZXJzWzBdLmR0bHNUcmFuc3BvcnRcbiAgICAgICAgfSA6IHNlbGYuX2NyZWF0ZUljZUFuZER0bHNUcmFuc3BvcnRzKG1pZCwgc2RwTUxpbmVJbmRleCk7XG5cbiAgICAgICAgaWYgKGlzQ29tcGxldGUgJiYgKCF1c2luZ0J1bmRsZSB8fCBzZHBNTGluZUluZGV4ID09PSAwKSkge1xuICAgICAgICAgIHRyYW5zcG9ydHMuaWNlVHJhbnNwb3J0LnNldFJlbW90ZUNhbmRpZGF0ZXMoY2FuZHMpO1xuICAgICAgICB9XG5cbiAgICAgICAgbG9jYWxDYXBhYmlsaXRpZXMgPSBSVENSdHBSZWNlaXZlci5nZXRDYXBhYmlsaXRpZXMoa2luZCk7XG5cbiAgICAgICAgLy8gZmlsdGVyIFJUWCB1bnRpbCBhZGRpdGlvbmFsIHN0dWZmIG5lZWRlZCBmb3IgUlRYIGlzIGltcGxlbWVudGVkXG4gICAgICAgIC8vIGluIGFkYXB0ZXIuanNcbiAgICAgICAgaWYgKGVkZ2VWZXJzaW9uIDwgMTUwMTkpIHtcbiAgICAgICAgICBsb2NhbENhcGFiaWxpdGllcy5jb2RlY3MgPSBsb2NhbENhcGFiaWxpdGllcy5jb2RlY3MuZmlsdGVyKFxuICAgICAgICAgICAgICBmdW5jdGlvbihjb2RlYykge1xuICAgICAgICAgICAgICAgIHJldHVybiBjb2RlYy5uYW1lICE9PSAncnR4JztcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBzZW5kRW5jb2RpbmdQYXJhbWV0ZXJzID0gW3tcbiAgICAgICAgICBzc3JjOiAoMiAqIHNkcE1MaW5lSW5kZXggKyAyKSAqIDEwMDFcbiAgICAgICAgfV07XG5cbiAgICAgICAgaWYgKGRpcmVjdGlvbiA9PT0gJ3NlbmRyZWN2JyB8fCBkaXJlY3Rpb24gPT09ICdzZW5kb25seScpIHtcbiAgICAgICAgICBydHBSZWNlaXZlciA9IG5ldyBSVENSdHBSZWNlaXZlcih0cmFuc3BvcnRzLmR0bHNUcmFuc3BvcnQsXG4gICAgICAgICAgICAgIGtpbmQpO1xuXG4gICAgICAgICAgdHJhY2sgPSBydHBSZWNlaXZlci50cmFjaztcbiAgICAgICAgICAvLyBGSVhNRTogZG9lcyBub3Qgd29yayB3aXRoIFBsYW4gQi5cbiAgICAgICAgICBpZiAocmVtb3RlTXNpZCkge1xuICAgICAgICAgICAgaWYgKCFzdHJlYW1zW3JlbW90ZU1zaWQuc3RyZWFtXSkge1xuICAgICAgICAgICAgICBzdHJlYW1zW3JlbW90ZU1zaWQuc3RyZWFtXSA9IG5ldyBNZWRpYVN0cmVhbSgpO1xuICAgICAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoc3RyZWFtc1tyZW1vdGVNc2lkLnN0cmVhbV0sICdpZCcsIHtcbiAgICAgICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlbW90ZU1zaWQuc3RyZWFtO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodHJhY2ssICdpZCcsIHtcbiAgICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVtb3RlTXNpZC50cmFjaztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBzdHJlYW1zW3JlbW90ZU1zaWQuc3RyZWFtXS5hZGRUcmFjayh0cmFjayk7XG4gICAgICAgICAgICByZWNlaXZlckxpc3QucHVzaChbdHJhY2ssIHJ0cFJlY2VpdmVyLFxuICAgICAgICAgICAgICAgIHN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dXSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmICghc3RyZWFtcy5kZWZhdWx0KSB7XG4gICAgICAgICAgICAgIHN0cmVhbXMuZGVmYXVsdCA9IG5ldyBNZWRpYVN0cmVhbSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc3RyZWFtcy5kZWZhdWx0LmFkZFRyYWNrKHRyYWNrKTtcbiAgICAgICAgICAgIHJlY2VpdmVyTGlzdC5wdXNoKFt0cmFjaywgcnRwUmVjZWl2ZXIsIHN0cmVhbXMuZGVmYXVsdF0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEZJWE1FOiBsb29rIGF0IGRpcmVjdGlvbi5cbiAgICAgICAgaWYgKHNlbGYubG9jYWxTdHJlYW1zLmxlbmd0aCA+IDAgJiZcbiAgICAgICAgICAgIHNlbGYubG9jYWxTdHJlYW1zWzBdLmdldFRyYWNrcygpLmxlbmd0aCA+PSBzZHBNTGluZUluZGV4KSB7XG4gICAgICAgICAgdmFyIGxvY2FsVHJhY2s7XG4gICAgICAgICAgaWYgKGtpbmQgPT09ICdhdWRpbycpIHtcbiAgICAgICAgICAgIGxvY2FsVHJhY2sgPSBzZWxmLmxvY2FsU3RyZWFtc1swXS5nZXRBdWRpb1RyYWNrcygpWzBdO1xuICAgICAgICAgIH0gZWxzZSBpZiAoa2luZCA9PT0gJ3ZpZGVvJykge1xuICAgICAgICAgICAgbG9jYWxUcmFjayA9IHNlbGYubG9jYWxTdHJlYW1zWzBdLmdldFZpZGVvVHJhY2tzKClbMF07XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChsb2NhbFRyYWNrKSB7XG4gICAgICAgICAgICAvLyBhZGQgUlRYXG4gICAgICAgICAgICBpZiAoZWRnZVZlcnNpb24gPj0gMTUwMTkgJiYga2luZCA9PT0gJ3ZpZGVvJykge1xuICAgICAgICAgICAgICBzZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eCA9IHtcbiAgICAgICAgICAgICAgICBzc3JjOiAoMiAqIHNkcE1MaW5lSW5kZXggKyAyKSAqIDEwMDEgKyAxXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBydHBTZW5kZXIgPSBuZXcgUlRDUnRwU2VuZGVyKGxvY2FsVHJhY2ssXG4gICAgICAgICAgICAgICAgdHJhbnNwb3J0cy5kdGxzVHJhbnNwb3J0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XSA9IHtcbiAgICAgICAgICBpY2VHYXRoZXJlcjogdHJhbnNwb3J0cy5pY2VHYXRoZXJlcixcbiAgICAgICAgICBpY2VUcmFuc3BvcnQ6IHRyYW5zcG9ydHMuaWNlVHJhbnNwb3J0LFxuICAgICAgICAgIGR0bHNUcmFuc3BvcnQ6IHRyYW5zcG9ydHMuZHRsc1RyYW5zcG9ydCxcbiAgICAgICAgICBsb2NhbENhcGFiaWxpdGllczogbG9jYWxDYXBhYmlsaXRpZXMsXG4gICAgICAgICAgcmVtb3RlQ2FwYWJpbGl0aWVzOiByZW1vdGVDYXBhYmlsaXRpZXMsXG4gICAgICAgICAgcnRwU2VuZGVyOiBydHBTZW5kZXIsXG4gICAgICAgICAgcnRwUmVjZWl2ZXI6IHJ0cFJlY2VpdmVyLFxuICAgICAgICAgIGtpbmQ6IGtpbmQsXG4gICAgICAgICAgbWlkOiBtaWQsXG4gICAgICAgICAgcnRjcFBhcmFtZXRlcnM6IHJ0Y3BQYXJhbWV0ZXJzLFxuICAgICAgICAgIHNlbmRFbmNvZGluZ1BhcmFtZXRlcnM6IHNlbmRFbmNvZGluZ1BhcmFtZXRlcnMsXG4gICAgICAgICAgcmVjdkVuY29kaW5nUGFyYW1ldGVyczogcmVjdkVuY29kaW5nUGFyYW1ldGVyc1xuICAgICAgICB9O1xuICAgICAgICAvLyBTdGFydCB0aGUgUlRDUnRwUmVjZWl2ZXIgbm93LiBUaGUgUlRQU2VuZGVyIGlzIHN0YXJ0ZWQgaW5cbiAgICAgICAgLy8gc2V0TG9jYWxEZXNjcmlwdGlvbi5cbiAgICAgICAgc2VsZi5fdHJhbnNjZWl2ZShzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XSxcbiAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnIHx8IGRpcmVjdGlvbiA9PT0gJ3NlbmRvbmx5Jyk7XG4gICAgICB9IGVsc2UgaWYgKGRlc2NyaXB0aW9uLnR5cGUgPT09ICdhbnN3ZXInICYmICFyZWplY3RlZCkge1xuICAgICAgICBpZiAodXNpbmdCdW5kbGUgJiYgc2RwTUxpbmVJbmRleCA+IDApIHtcbiAgICAgICAgICBzZWxmLl9kaXNwb3NlSWNlQW5kRHRsc1RyYW5zcG9ydHMoc2RwTUxpbmVJbmRleCk7XG4gICAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uaWNlR2F0aGVyZXIgPVxuICAgICAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1swXS5pY2VHYXRoZXJlcjtcbiAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5pY2VUcmFuc3BvcnQgPVxuICAgICAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1swXS5pY2VUcmFuc3BvcnQ7XG4gICAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0uZHRsc1RyYW5zcG9ydCA9XG4gICAgICAgICAgICAgIHNlbGYudHJhbnNjZWl2ZXJzWzBdLmR0bHNUcmFuc3BvcnQ7XG4gICAgICAgICAgaWYgKHNlbGYudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLnJ0cFNlbmRlcikge1xuICAgICAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0ucnRwU2VuZGVyLnNldFRyYW5zcG9ydChcbiAgICAgICAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1swXS5kdGxzVHJhbnNwb3J0KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHNlbGYudHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdLnJ0cFJlY2VpdmVyKSB7XG4gICAgICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5ydHBSZWNlaXZlci5zZXRUcmFuc3BvcnQoXG4gICAgICAgICAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbMF0uZHRsc1RyYW5zcG9ydCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRyYW5zY2VpdmVyID0gc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF07XG4gICAgICAgIGljZUdhdGhlcmVyID0gdHJhbnNjZWl2ZXIuaWNlR2F0aGVyZXI7XG4gICAgICAgIGljZVRyYW5zcG9ydCA9IHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydDtcbiAgICAgICAgZHRsc1RyYW5zcG9ydCA9IHRyYW5zY2VpdmVyLmR0bHNUcmFuc3BvcnQ7XG4gICAgICAgIHJ0cFNlbmRlciA9IHRyYW5zY2VpdmVyLnJ0cFNlbmRlcjtcbiAgICAgICAgcnRwUmVjZWl2ZXIgPSB0cmFuc2NlaXZlci5ydHBSZWNlaXZlcjtcbiAgICAgICAgc2VuZEVuY29kaW5nUGFyYW1ldGVycyA9IHRyYW5zY2VpdmVyLnNlbmRFbmNvZGluZ1BhcmFtZXRlcnM7XG4gICAgICAgIGxvY2FsQ2FwYWJpbGl0aWVzID0gdHJhbnNjZWl2ZXIubG9jYWxDYXBhYmlsaXRpZXM7XG5cbiAgICAgICAgc2VsZi50cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0ucmVjdkVuY29kaW5nUGFyYW1ldGVycyA9XG4gICAgICAgICAgICByZWN2RW5jb2RpbmdQYXJhbWV0ZXJzO1xuICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5yZW1vdGVDYXBhYmlsaXRpZXMgPVxuICAgICAgICAgICAgcmVtb3RlQ2FwYWJpbGl0aWVzO1xuICAgICAgICBzZWxmLnRyYW5zY2VpdmVyc1tzZHBNTGluZUluZGV4XS5ydGNwUGFyYW1ldGVycyA9IHJ0Y3BQYXJhbWV0ZXJzO1xuXG4gICAgICAgIGlmICgoaXNJY2VMaXRlIHx8IGlzQ29tcGxldGUpICYmIGNhbmRzLmxlbmd0aCkge1xuICAgICAgICAgIGljZVRyYW5zcG9ydC5zZXRSZW1vdGVDYW5kaWRhdGVzKGNhbmRzKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXVzaW5nQnVuZGxlIHx8IHNkcE1MaW5lSW5kZXggPT09IDApIHtcbiAgICAgICAgICBpY2VUcmFuc3BvcnQuc3RhcnQoaWNlR2F0aGVyZXIsIHJlbW90ZUljZVBhcmFtZXRlcnMsXG4gICAgICAgICAgICAgICdjb250cm9sbGluZycpO1xuICAgICAgICAgIGR0bHNUcmFuc3BvcnQuc3RhcnQocmVtb3RlRHRsc1BhcmFtZXRlcnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgc2VsZi5fdHJhbnNjZWl2ZSh0cmFuc2NlaXZlcixcbiAgICAgICAgICAgIGRpcmVjdGlvbiA9PT0gJ3NlbmRyZWN2JyB8fCBkaXJlY3Rpb24gPT09ICdyZWN2b25seScsXG4gICAgICAgICAgICBkaXJlY3Rpb24gPT09ICdzZW5kcmVjdicgfHwgZGlyZWN0aW9uID09PSAnc2VuZG9ubHknKTtcblxuICAgICAgICBpZiAocnRwUmVjZWl2ZXIgJiZcbiAgICAgICAgICAgIChkaXJlY3Rpb24gPT09ICdzZW5kcmVjdicgfHwgZGlyZWN0aW9uID09PSAnc2VuZG9ubHknKSkge1xuICAgICAgICAgIHRyYWNrID0gcnRwUmVjZWl2ZXIudHJhY2s7XG4gICAgICAgICAgcmVjZWl2ZXJMaXN0LnB1c2goW3RyYWNrLCBydHBSZWNlaXZlcl0pO1xuICAgICAgICAgIGlmIChyZW1vdGVNc2lkKSB7XG4gICAgICAgICAgICBpZiAoIXN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dKSB7XG4gICAgICAgICAgICAgIHN0cmVhbXNbcmVtb3RlTXNpZC5zdHJlYW1dID0gbmV3IE1lZGlhU3RyZWFtKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzdHJlYW1zW3JlbW90ZU1zaWQuc3RyZWFtXS5hZGRUcmFjayh0cmFjayk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmICghc3RyZWFtcy5kZWZhdWx0KSB7XG4gICAgICAgICAgICAgIHN0cmVhbXMuZGVmYXVsdCA9IG5ldyBNZWRpYVN0cmVhbSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc3RyZWFtcy5kZWZhdWx0LmFkZFRyYWNrKHRyYWNrKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gRklYTUU6IGFjdHVhbGx5IHRoZSByZWNlaXZlciBzaG91bGQgYmUgY3JlYXRlZCBsYXRlci5cbiAgICAgICAgICBkZWxldGUgdHJhbnNjZWl2ZXIucnRwUmVjZWl2ZXI7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLnVzaW5nQnVuZGxlID0gdXNpbmdCdW5kbGU7XG5cbiAgICB0aGlzLnJlbW90ZURlc2NyaXB0aW9uID0ge1xuICAgICAgdHlwZTogZGVzY3JpcHRpb24udHlwZSxcbiAgICAgIHNkcDogZGVzY3JpcHRpb24uc2RwXG4gICAgfTtcbiAgICBzd2l0Y2ggKGRlc2NyaXB0aW9uLnR5cGUpIHtcbiAgICAgIGNhc2UgJ29mZmVyJzpcbiAgICAgICAgdGhpcy5fdXBkYXRlU2lnbmFsaW5nU3RhdGUoJ2hhdmUtcmVtb3RlLW9mZmVyJyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnYW5zd2VyJzpcbiAgICAgICAgdGhpcy5fdXBkYXRlU2lnbmFsaW5nU3RhdGUoJ3N0YWJsZScpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ3Vuc3VwcG9ydGVkIHR5cGUgXCInICsgZGVzY3JpcHRpb24udHlwZSArXG4gICAgICAgICAgICAnXCInKTtcbiAgICB9XG4gICAgT2JqZWN0LmtleXMoc3RyZWFtcykuZm9yRWFjaChmdW5jdGlvbihzaWQpIHtcbiAgICAgIHZhciBzdHJlYW0gPSBzdHJlYW1zW3NpZF07XG4gICAgICBpZiAoc3RyZWFtLmdldFRyYWNrcygpLmxlbmd0aCkge1xuICAgICAgICBzZWxmLnJlbW90ZVN0cmVhbXMucHVzaChzdHJlYW0pO1xuICAgICAgICB2YXIgZXZlbnQgPSBuZXcgRXZlbnQoJ2FkZHN0cmVhbScpO1xuICAgICAgICBldmVudC5zdHJlYW0gPSBzdHJlYW07XG4gICAgICAgIHNlbGYuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgICAgIGlmIChzZWxmLm9uYWRkc3RyZWFtICE9PSBudWxsKSB7XG4gICAgICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBzZWxmLm9uYWRkc3RyZWFtKGV2ZW50KTtcbiAgICAgICAgICB9LCAwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlY2VpdmVyTGlzdC5mb3JFYWNoKGZ1bmN0aW9uKGl0ZW0pIHtcbiAgICAgICAgICB2YXIgdHJhY2sgPSBpdGVtWzBdO1xuICAgICAgICAgIHZhciByZWNlaXZlciA9IGl0ZW1bMV07XG4gICAgICAgICAgaWYgKHN0cmVhbS5pZCAhPT0gaXRlbVsyXS5pZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICB2YXIgdHJhY2tFdmVudCA9IG5ldyBFdmVudCgndHJhY2snKTtcbiAgICAgICAgICB0cmFja0V2ZW50LnRyYWNrID0gdHJhY2s7XG4gICAgICAgICAgdHJhY2tFdmVudC5yZWNlaXZlciA9IHJlY2VpdmVyO1xuICAgICAgICAgIHRyYWNrRXZlbnQuc3RyZWFtcyA9IFtzdHJlYW1dO1xuICAgICAgICAgIHNlbGYuZGlzcGF0Y2hFdmVudCh0cmFja0V2ZW50KTtcbiAgICAgICAgICBpZiAoc2VsZi5vbnRyYWNrICE9PSBudWxsKSB7XG4gICAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgc2VsZi5vbnRyYWNrKHRyYWNrRXZlbnQpO1xuICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgdHlwZW9mIGFyZ3VtZW50c1sxXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgd2luZG93LnNldFRpbWVvdXQoYXJndW1lbnRzWzFdLCAwKTtcbiAgICB9XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMudHJhbnNjZWl2ZXJzLmZvckVhY2goZnVuY3Rpb24odHJhbnNjZWl2ZXIpIHtcbiAgICAgIC8qIG5vdCB5ZXRcbiAgICAgIGlmICh0cmFuc2NlaXZlci5pY2VHYXRoZXJlcikge1xuICAgICAgICB0cmFuc2NlaXZlci5pY2VHYXRoZXJlci5jbG9zZSgpO1xuICAgICAgfVxuICAgICAgKi9cbiAgICAgIGlmICh0cmFuc2NlaXZlci5pY2VUcmFuc3BvcnQpIHtcbiAgICAgICAgdHJhbnNjZWl2ZXIuaWNlVHJhbnNwb3J0LnN0b3AoKTtcbiAgICAgIH1cbiAgICAgIGlmICh0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0KSB7XG4gICAgICAgIHRyYW5zY2VpdmVyLmR0bHNUcmFuc3BvcnQuc3RvcCgpO1xuICAgICAgfVxuICAgICAgaWYgKHRyYW5zY2VpdmVyLnJ0cFNlbmRlcikge1xuICAgICAgICB0cmFuc2NlaXZlci5ydHBTZW5kZXIuc3RvcCgpO1xuICAgICAgfVxuICAgICAgaWYgKHRyYW5zY2VpdmVyLnJ0cFJlY2VpdmVyKSB7XG4gICAgICAgIHRyYW5zY2VpdmVyLnJ0cFJlY2VpdmVyLnN0b3AoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICAvLyBGSVhNRTogY2xlYW4gdXAgdHJhY2tzLCBsb2NhbCBzdHJlYW1zLCByZW1vdGUgc3RyZWFtcywgZXRjXG4gICAgdGhpcy5fdXBkYXRlU2lnbmFsaW5nU3RhdGUoJ2Nsb3NlZCcpO1xuICB9O1xuXG4gIC8vIFVwZGF0ZSB0aGUgc2lnbmFsaW5nIHN0YXRlLlxuICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX3VwZGF0ZVNpZ25hbGluZ1N0YXRlID0gZnVuY3Rpb24obmV3U3RhdGUpIHtcbiAgICB0aGlzLnNpZ25hbGluZ1N0YXRlID0gbmV3U3RhdGU7XG4gICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCdzaWduYWxpbmdzdGF0ZWNoYW5nZScpO1xuICAgIHRoaXMuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgaWYgKHRoaXMub25zaWduYWxpbmdzdGF0ZWNoYW5nZSAhPT0gbnVsbCkge1xuICAgICAgdGhpcy5vbnNpZ25hbGluZ3N0YXRlY2hhbmdlKGV2ZW50KTtcbiAgICB9XG4gIH07XG5cbiAgLy8gRGV0ZXJtaW5lIHdoZXRoZXIgdG8gZmlyZSB0aGUgbmVnb3RpYXRpb25uZWVkZWQgZXZlbnQuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5fbWF5YmVGaXJlTmVnb3RpYXRpb25OZWVkZWQgPSBmdW5jdGlvbigpIHtcbiAgICAvLyBGaXJlIGF3YXkgKGZvciBub3cpLlxuICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgnbmVnb3RpYXRpb25uZWVkZWQnKTtcbiAgICB0aGlzLmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuICAgIGlmICh0aGlzLm9ubmVnb3RpYXRpb25uZWVkZWQgIT09IG51bGwpIHtcbiAgICAgIHRoaXMub25uZWdvdGlhdGlvbm5lZWRlZChldmVudCk7XG4gICAgfVxuICB9O1xuXG4gIC8vIFVwZGF0ZSB0aGUgY29ubmVjdGlvbiBzdGF0ZS5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl91cGRhdGVDb25uZWN0aW9uU3RhdGUgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIG5ld1N0YXRlO1xuICAgIHZhciBzdGF0ZXMgPSB7XG4gICAgICAnbmV3JzogMCxcbiAgICAgIGNsb3NlZDogMCxcbiAgICAgIGNvbm5lY3Rpbmc6IDAsXG4gICAgICBjaGVja2luZzogMCxcbiAgICAgIGNvbm5lY3RlZDogMCxcbiAgICAgIGNvbXBsZXRlZDogMCxcbiAgICAgIGZhaWxlZDogMFxuICAgIH07XG4gICAgdGhpcy50cmFuc2NlaXZlcnMuZm9yRWFjaChmdW5jdGlvbih0cmFuc2NlaXZlcikge1xuICAgICAgc3RhdGVzW3RyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5zdGF0ZV0rKztcbiAgICAgIHN0YXRlc1t0cmFuc2NlaXZlci5kdGxzVHJhbnNwb3J0LnN0YXRlXSsrO1xuICAgIH0pO1xuICAgIC8vIElDRVRyYW5zcG9ydC5jb21wbGV0ZWQgYW5kIGNvbm5lY3RlZCBhcmUgdGhlIHNhbWUgZm9yIHRoaXMgcHVycG9zZS5cbiAgICBzdGF0ZXMuY29ubmVjdGVkICs9IHN0YXRlcy5jb21wbGV0ZWQ7XG5cbiAgICBuZXdTdGF0ZSA9ICduZXcnO1xuICAgIGlmIChzdGF0ZXMuZmFpbGVkID4gMCkge1xuICAgICAgbmV3U3RhdGUgPSAnZmFpbGVkJztcbiAgICB9IGVsc2UgaWYgKHN0YXRlcy5jb25uZWN0aW5nID4gMCB8fCBzdGF0ZXMuY2hlY2tpbmcgPiAwKSB7XG4gICAgICBuZXdTdGF0ZSA9ICdjb25uZWN0aW5nJztcbiAgICB9IGVsc2UgaWYgKHN0YXRlcy5kaXNjb25uZWN0ZWQgPiAwKSB7XG4gICAgICBuZXdTdGF0ZSA9ICdkaXNjb25uZWN0ZWQnO1xuICAgIH0gZWxzZSBpZiAoc3RhdGVzLm5ldyA+IDApIHtcbiAgICAgIG5ld1N0YXRlID0gJ25ldyc7XG4gICAgfSBlbHNlIGlmIChzdGF0ZXMuY29ubmVjdGVkID4gMCB8fCBzdGF0ZXMuY29tcGxldGVkID4gMCkge1xuICAgICAgbmV3U3RhdGUgPSAnY29ubmVjdGVkJztcbiAgICB9XG5cbiAgICBpZiAobmV3U3RhdGUgIT09IHNlbGYuaWNlQ29ubmVjdGlvblN0YXRlKSB7XG4gICAgICBzZWxmLmljZUNvbm5lY3Rpb25TdGF0ZSA9IG5ld1N0YXRlO1xuICAgICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCdpY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2UnKTtcbiAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgICBpZiAodGhpcy5vbmljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZSAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLm9uaWNlY29ubmVjdGlvbnN0YXRlY2hhbmdlKGV2ZW50KTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmNyZWF0ZU9mZmVyID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGlmICh0aGlzLl9wZW5kaW5nT2ZmZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY3JlYXRlT2ZmZXIgY2FsbGVkIHdoaWxlIHRoZXJlIGlzIGEgcGVuZGluZyBvZmZlci4nKTtcbiAgICB9XG4gICAgdmFyIG9mZmVyT3B0aW9ucztcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSAmJiB0eXBlb2YgYXJndW1lbnRzWzBdICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICBvZmZlck9wdGlvbnMgPSBhcmd1bWVudHNbMF07XG4gICAgfSBlbHNlIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAzKSB7XG4gICAgICBvZmZlck9wdGlvbnMgPSBhcmd1bWVudHNbMl07XG4gICAgfVxuXG4gICAgdmFyIHRyYWNrcyA9IFtdO1xuICAgIHZhciBudW1BdWRpb1RyYWNrcyA9IDA7XG4gICAgdmFyIG51bVZpZGVvVHJhY2tzID0gMDtcbiAgICAvLyBEZWZhdWx0IHRvIHNlbmRyZWN2LlxuICAgIGlmICh0aGlzLmxvY2FsU3RyZWFtcy5sZW5ndGgpIHtcbiAgICAgIG51bUF1ZGlvVHJhY2tzID0gdGhpcy5sb2NhbFN0cmVhbXMucmVkdWNlKGZ1bmN0aW9uKG51bVRyYWNrcywgc3RyZWFtKSB7XG4gICAgICAgIHJldHVybiBudW1UcmFja3MgKyBzdHJlYW0uZ2V0QXVkaW9UcmFja3MoKS5sZW5ndGg7XG4gICAgICB9LCAwKTtcbiAgICAgIG51bVZpZGVvVHJhY2tzID0gdGhpcy5sb2NhbFN0cmVhbXMucmVkdWNlKGZ1bmN0aW9uKG51bVRyYWNrcywgc3RyZWFtKSB7XG4gICAgICAgIHJldHVybiBudW1UcmFja3MgKyBzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGg7XG4gICAgICB9LCAwKTtcbiAgICB9XG4gICAgLy8gRGV0ZXJtaW5lIG51bWJlciBvZiBhdWRpbyBhbmQgdmlkZW8gdHJhY2tzIHdlIG5lZWQgdG8gc2VuZC9yZWN2LlxuICAgIGlmIChvZmZlck9wdGlvbnMpIHtcbiAgICAgIC8vIFJlamVjdCBDaHJvbWUgbGVnYWN5IGNvbnN0cmFpbnRzLlxuICAgICAgaWYgKG9mZmVyT3B0aW9ucy5tYW5kYXRvcnkgfHwgb2ZmZXJPcHRpb25zLm9wdGlvbmFsKSB7XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXG4gICAgICAgICAgICAnTGVnYWN5IG1hbmRhdG9yeS9vcHRpb25hbCBjb25zdHJhaW50cyBub3Qgc3VwcG9ydGVkLicpO1xuICAgICAgfVxuICAgICAgaWYgKG9mZmVyT3B0aW9ucy5vZmZlclRvUmVjZWl2ZUF1ZGlvICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbnVtQXVkaW9UcmFja3MgPSBvZmZlck9wdGlvbnMub2ZmZXJUb1JlY2VpdmVBdWRpbztcbiAgICAgIH1cbiAgICAgIGlmIChvZmZlck9wdGlvbnMub2ZmZXJUb1JlY2VpdmVWaWRlbyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIG51bVZpZGVvVHJhY2tzID0gb2ZmZXJPcHRpb25zLm9mZmVyVG9SZWNlaXZlVmlkZW87XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUHVzaCBsb2NhbCBzdHJlYW1zLlxuICAgIHRoaXMubG9jYWxTdHJlYW1zLmZvckVhY2goZnVuY3Rpb24obG9jYWxTdHJlYW0pIHtcbiAgICAgIGxvY2FsU3RyZWFtLmdldFRyYWNrcygpLmZvckVhY2goZnVuY3Rpb24odHJhY2spIHtcbiAgICAgICAgdHJhY2tzLnB1c2goe1xuICAgICAgICAgIGtpbmQ6IHRyYWNrLmtpbmQsXG4gICAgICAgICAgdHJhY2s6IHRyYWNrLFxuICAgICAgICAgIHN0cmVhbTogbG9jYWxTdHJlYW0sXG4gICAgICAgICAgd2FudFJlY2VpdmU6IHRyYWNrLmtpbmQgPT09ICdhdWRpbycgP1xuICAgICAgICAgICAgICBudW1BdWRpb1RyYWNrcyA+IDAgOiBudW1WaWRlb1RyYWNrcyA+IDBcbiAgICAgICAgfSk7XG4gICAgICAgIGlmICh0cmFjay5raW5kID09PSAnYXVkaW8nKSB7XG4gICAgICAgICAgbnVtQXVkaW9UcmFja3MtLTtcbiAgICAgICAgfSBlbHNlIGlmICh0cmFjay5raW5kID09PSAndmlkZW8nKSB7XG4gICAgICAgICAgbnVtVmlkZW9UcmFja3MtLTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICAvLyBDcmVhdGUgTS1saW5lcyBmb3IgcmVjdm9ubHkgc3RyZWFtcy5cbiAgICB3aGlsZSAobnVtQXVkaW9UcmFja3MgPiAwIHx8IG51bVZpZGVvVHJhY2tzID4gMCkge1xuICAgICAgaWYgKG51bUF1ZGlvVHJhY2tzID4gMCkge1xuICAgICAgICB0cmFja3MucHVzaCh7XG4gICAgICAgICAga2luZDogJ2F1ZGlvJyxcbiAgICAgICAgICB3YW50UmVjZWl2ZTogdHJ1ZVxuICAgICAgICB9KTtcbiAgICAgICAgbnVtQXVkaW9UcmFja3MtLTtcbiAgICAgIH1cbiAgICAgIGlmIChudW1WaWRlb1RyYWNrcyA+IDApIHtcbiAgICAgICAgdHJhY2tzLnB1c2goe1xuICAgICAgICAgIGtpbmQ6ICd2aWRlbycsXG4gICAgICAgICAgd2FudFJlY2VpdmU6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICAgIG51bVZpZGVvVHJhY2tzLS07XG4gICAgICB9XG4gICAgfVxuICAgIC8vIHJlb3JkZXIgdHJhY2tzXG4gICAgdHJhY2tzID0gc29ydFRyYWNrcyh0cmFja3MpO1xuXG4gICAgdmFyIHNkcCA9IFNEUFV0aWxzLndyaXRlU2Vzc2lvbkJvaWxlcnBsYXRlKCk7XG4gICAgdmFyIHRyYW5zY2VpdmVycyA9IFtdO1xuICAgIHRyYWNrcy5mb3JFYWNoKGZ1bmN0aW9uKG1saW5lLCBzZHBNTGluZUluZGV4KSB7XG4gICAgICAvLyBGb3IgZWFjaCB0cmFjaywgY3JlYXRlIGFuIGljZSBnYXRoZXJlciwgaWNlIHRyYW5zcG9ydCxcbiAgICAgIC8vIGR0bHMgdHJhbnNwb3J0LCBwb3RlbnRpYWxseSBydHBzZW5kZXIgYW5kIHJ0cHJlY2VpdmVyLlxuICAgICAgdmFyIHRyYWNrID0gbWxpbmUudHJhY2s7XG4gICAgICB2YXIga2luZCA9IG1saW5lLmtpbmQ7XG4gICAgICB2YXIgbWlkID0gU0RQVXRpbHMuZ2VuZXJhdGVJZGVudGlmaWVyKCk7XG5cbiAgICAgIHZhciB0cmFuc3BvcnRzID0gc2VsZi51c2luZ0J1bmRsZSAmJiBzZHBNTGluZUluZGV4ID4gMCA/IHtcbiAgICAgICAgaWNlR2F0aGVyZXI6IHRyYW5zY2VpdmVyc1swXS5pY2VHYXRoZXJlcixcbiAgICAgICAgaWNlVHJhbnNwb3J0OiB0cmFuc2NlaXZlcnNbMF0uaWNlVHJhbnNwb3J0LFxuICAgICAgICBkdGxzVHJhbnNwb3J0OiB0cmFuc2NlaXZlcnNbMF0uZHRsc1RyYW5zcG9ydFxuICAgICAgfSA6IHNlbGYuX2NyZWF0ZUljZUFuZER0bHNUcmFuc3BvcnRzKG1pZCwgc2RwTUxpbmVJbmRleCk7XG5cbiAgICAgIHZhciBsb2NhbENhcGFiaWxpdGllcyA9IFJUQ1J0cFNlbmRlci5nZXRDYXBhYmlsaXRpZXMoa2luZCk7XG4gICAgICAvLyBmaWx0ZXIgUlRYIHVudGlsIGFkZGl0aW9uYWwgc3R1ZmYgbmVlZGVkIGZvciBSVFggaXMgaW1wbGVtZW50ZWRcbiAgICAgIC8vIGluIGFkYXB0ZXIuanNcbiAgICAgIGlmIChlZGdlVmVyc2lvbiA8IDE1MDE5KSB7XG4gICAgICAgIGxvY2FsQ2FwYWJpbGl0aWVzLmNvZGVjcyA9IGxvY2FsQ2FwYWJpbGl0aWVzLmNvZGVjcy5maWx0ZXIoXG4gICAgICAgICAgICBmdW5jdGlvbihjb2RlYykge1xuICAgICAgICAgICAgICByZXR1cm4gY29kZWMubmFtZSAhPT0gJ3J0eCc7XG4gICAgICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIGxvY2FsQ2FwYWJpbGl0aWVzLmNvZGVjcy5mb3JFYWNoKGZ1bmN0aW9uKGNvZGVjKSB7XG4gICAgICAgIC8vIHdvcmsgYXJvdW5kIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC93ZWJydGMvaXNzdWVzL2RldGFpbD9pZD02NTUyXG4gICAgICAgIC8vIGJ5IGFkZGluZyBsZXZlbC1hc3ltbWV0cnktYWxsb3dlZD0xXG4gICAgICAgIGlmIChjb2RlYy5uYW1lID09PSAnSDI2NCcgJiZcbiAgICAgICAgICAgIGNvZGVjLnBhcmFtZXRlcnNbJ2xldmVsLWFzeW1tZXRyeS1hbGxvd2VkJ10gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGNvZGVjLnBhcmFtZXRlcnNbJ2xldmVsLWFzeW1tZXRyeS1hbGxvd2VkJ10gPSAnMSc7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICB2YXIgcnRwU2VuZGVyO1xuICAgICAgdmFyIHJ0cFJlY2VpdmVyO1xuXG4gICAgICAvLyBnZW5lcmF0ZSBhbiBzc3JjIG5vdywgdG8gYmUgdXNlZCBsYXRlciBpbiBydHBTZW5kZXIuc2VuZFxuICAgICAgdmFyIHNlbmRFbmNvZGluZ1BhcmFtZXRlcnMgPSBbe1xuICAgICAgICBzc3JjOiAoMiAqIHNkcE1MaW5lSW5kZXggKyAxKSAqIDEwMDFcbiAgICAgIH1dO1xuICAgICAgaWYgKHRyYWNrKSB7XG4gICAgICAgIC8vIGFkZCBSVFhcbiAgICAgICAgaWYgKGVkZ2VWZXJzaW9uID49IDE1MDE5ICYmIGtpbmQgPT09ICd2aWRlbycpIHtcbiAgICAgICAgICBzZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eCA9IHtcbiAgICAgICAgICAgIHNzcmM6ICgyICogc2RwTUxpbmVJbmRleCArIDEpICogMTAwMSArIDFcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIHJ0cFNlbmRlciA9IG5ldyBSVENSdHBTZW5kZXIodHJhY2ssIHRyYW5zcG9ydHMuZHRsc1RyYW5zcG9ydCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChtbGluZS53YW50UmVjZWl2ZSkge1xuICAgICAgICBydHBSZWNlaXZlciA9IG5ldyBSVENSdHBSZWNlaXZlcih0cmFuc3BvcnRzLmR0bHNUcmFuc3BvcnQsIGtpbmQpO1xuICAgICAgfVxuXG4gICAgICB0cmFuc2NlaXZlcnNbc2RwTUxpbmVJbmRleF0gPSB7XG4gICAgICAgIGljZUdhdGhlcmVyOiB0cmFuc3BvcnRzLmljZUdhdGhlcmVyLFxuICAgICAgICBpY2VUcmFuc3BvcnQ6IHRyYW5zcG9ydHMuaWNlVHJhbnNwb3J0LFxuICAgICAgICBkdGxzVHJhbnNwb3J0OiB0cmFuc3BvcnRzLmR0bHNUcmFuc3BvcnQsXG4gICAgICAgIGxvY2FsQ2FwYWJpbGl0aWVzOiBsb2NhbENhcGFiaWxpdGllcyxcbiAgICAgICAgcmVtb3RlQ2FwYWJpbGl0aWVzOiBudWxsLFxuICAgICAgICBydHBTZW5kZXI6IHJ0cFNlbmRlcixcbiAgICAgICAgcnRwUmVjZWl2ZXI6IHJ0cFJlY2VpdmVyLFxuICAgICAgICBraW5kOiBraW5kLFxuICAgICAgICBtaWQ6IG1pZCxcbiAgICAgICAgc2VuZEVuY29kaW5nUGFyYW1ldGVyczogc2VuZEVuY29kaW5nUGFyYW1ldGVycyxcbiAgICAgICAgcmVjdkVuY29kaW5nUGFyYW1ldGVyczogbnVsbFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIC8vIGFsd2F5cyBvZmZlciBCVU5ETEUgYW5kIGRpc3Bvc2Ugb24gcmV0dXJuIGlmIG5vdCBzdXBwb3J0ZWQuXG4gICAgaWYgKHRoaXMuX2NvbmZpZy5idW5kbGVQb2xpY3kgIT09ICdtYXgtY29tcGF0Jykge1xuICAgICAgc2RwICs9ICdhPWdyb3VwOkJVTkRMRSAnICsgdHJhbnNjZWl2ZXJzLm1hcChmdW5jdGlvbih0KSB7XG4gICAgICAgIHJldHVybiB0Lm1pZDtcbiAgICAgIH0pLmpvaW4oJyAnKSArICdcXHJcXG4nO1xuICAgIH1cbiAgICBzZHAgKz0gJ2E9aWNlLW9wdGlvbnM6dHJpY2tsZVxcclxcbic7XG5cbiAgICB0cmFja3MuZm9yRWFjaChmdW5jdGlvbihtbGluZSwgc2RwTUxpbmVJbmRleCkge1xuICAgICAgdmFyIHRyYW5zY2VpdmVyID0gdHJhbnNjZWl2ZXJzW3NkcE1MaW5lSW5kZXhdO1xuICAgICAgc2RwICs9IFNEUFV0aWxzLndyaXRlTWVkaWFTZWN0aW9uKHRyYW5zY2VpdmVyLFxuICAgICAgICAgIHRyYW5zY2VpdmVyLmxvY2FsQ2FwYWJpbGl0aWVzLCAnb2ZmZXInLCBtbGluZS5zdHJlYW0pO1xuICAgICAgc2RwICs9ICdhPXJ0Y3AtcnNpemVcXHJcXG4nO1xuICAgIH0pO1xuXG4gICAgdGhpcy5fcGVuZGluZ09mZmVyID0gdHJhbnNjZWl2ZXJzO1xuICAgIHZhciBkZXNjID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICB0eXBlOiAnb2ZmZXInLFxuICAgICAgc2RwOiBzZHBcbiAgICB9KTtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCAmJiB0eXBlb2YgYXJndW1lbnRzWzBdID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB3aW5kb3cuc2V0VGltZW91dChhcmd1bWVudHNbMF0sIDAsIGRlc2MpO1xuICAgIH1cbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGRlc2MpO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5jcmVhdGVBbnN3ZXIgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICB2YXIgc2RwID0gU0RQVXRpbHMud3JpdGVTZXNzaW9uQm9pbGVycGxhdGUoKTtcbiAgICBpZiAodGhpcy51c2luZ0J1bmRsZSkge1xuICAgICAgc2RwICs9ICdhPWdyb3VwOkJVTkRMRSAnICsgdGhpcy50cmFuc2NlaXZlcnMubWFwKGZ1bmN0aW9uKHQpIHtcbiAgICAgICAgcmV0dXJuIHQubWlkO1xuICAgICAgfSkuam9pbignICcpICsgJ1xcclxcbic7XG4gICAgfVxuICAgIHRoaXMudHJhbnNjZWl2ZXJzLmZvckVhY2goZnVuY3Rpb24odHJhbnNjZWl2ZXIpIHtcbiAgICAgIGlmICh0cmFuc2NlaXZlci5pc0RhdGFjaGFubmVsKSB7XG4gICAgICAgIHNkcCArPSAnbT1hcHBsaWNhdGlvbiAwIERUTFMvU0NUUCA1MDAwXFxyXFxuJyArXG4gICAgICAgICAgICAnYz1JTiBJUDQgMC4wLjAuMFxcclxcbicgK1xuICAgICAgICAgICAgJ2E9bWlkOicgKyB0cmFuc2NlaXZlci5taWQgKyAnXFxyXFxuJztcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgLy8gQ2FsY3VsYXRlIGludGVyc2VjdGlvbiBvZiBjYXBhYmlsaXRpZXMuXG4gICAgICB2YXIgY29tbW9uQ2FwYWJpbGl0aWVzID0gc2VsZi5fZ2V0Q29tbW9uQ2FwYWJpbGl0aWVzKFxuICAgICAgICAgIHRyYW5zY2VpdmVyLmxvY2FsQ2FwYWJpbGl0aWVzLFxuICAgICAgICAgIHRyYW5zY2VpdmVyLnJlbW90ZUNhcGFiaWxpdGllcyk7XG5cbiAgICAgIHZhciBoYXNSdHggPSBjb21tb25DYXBhYmlsaXRpZXMuY29kZWNzLmZpbHRlcihmdW5jdGlvbihjKSB7XG4gICAgICAgIHJldHVybiBjLm5hbWUudG9Mb3dlckNhc2UoKSA9PT0gJ3J0eCc7XG4gICAgICB9KS5sZW5ndGg7XG4gICAgICBpZiAoIWhhc1J0eCAmJiB0cmFuc2NlaXZlci5zZW5kRW5jb2RpbmdQYXJhbWV0ZXJzWzBdLnJ0eCkge1xuICAgICAgICBkZWxldGUgdHJhbnNjZWl2ZXIuc2VuZEVuY29kaW5nUGFyYW1ldGVyc1swXS5ydHg7XG4gICAgICB9XG5cbiAgICAgIHNkcCArPSBTRFBVdGlscy53cml0ZU1lZGlhU2VjdGlvbih0cmFuc2NlaXZlciwgY29tbW9uQ2FwYWJpbGl0aWVzLFxuICAgICAgICAgICdhbnN3ZXInLCBzZWxmLmxvY2FsU3RyZWFtc1swXSk7XG4gICAgICBpZiAodHJhbnNjZWl2ZXIucnRjcFBhcmFtZXRlcnMgJiZcbiAgICAgICAgICB0cmFuc2NlaXZlci5ydGNwUGFyYW1ldGVycy5yZWR1Y2VkU2l6ZSkge1xuICAgICAgICBzZHAgKz0gJ2E9cnRjcC1yc2l6ZVxcclxcbic7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB2YXIgZGVzYyA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgdHlwZTogJ2Fuc3dlcicsXG4gICAgICBzZHA6IHNkcFxuICAgIH0pO1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoICYmIHR5cGVvZiBhcmd1bWVudHNbMF0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGFyZ3VtZW50c1swXSwgMCwgZGVzYyk7XG4gICAgfVxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoZGVzYyk7XG4gIH07XG5cbiAgUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZEljZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uKGNhbmRpZGF0ZSkge1xuICAgIGlmICghY2FuZGlkYXRlKSB7XG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHRoaXMudHJhbnNjZWl2ZXJzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgIHRoaXMudHJhbnNjZWl2ZXJzW2pdLmljZVRyYW5zcG9ydC5hZGRSZW1vdGVDYW5kaWRhdGUoe30pO1xuICAgICAgICBpZiAodGhpcy51c2luZ0J1bmRsZSkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgbUxpbmVJbmRleCA9IGNhbmRpZGF0ZS5zZHBNTGluZUluZGV4O1xuICAgICAgaWYgKGNhbmRpZGF0ZS5zZHBNaWQpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRyYW5zY2VpdmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGlmICh0aGlzLnRyYW5zY2VpdmVyc1tpXS5taWQgPT09IGNhbmRpZGF0ZS5zZHBNaWQpIHtcbiAgICAgICAgICAgIG1MaW5lSW5kZXggPSBpO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICB2YXIgdHJhbnNjZWl2ZXIgPSB0aGlzLnRyYW5zY2VpdmVyc1ttTGluZUluZGV4XTtcbiAgICAgIGlmICh0cmFuc2NlaXZlcikge1xuICAgICAgICB2YXIgY2FuZCA9IE9iamVjdC5rZXlzKGNhbmRpZGF0ZS5jYW5kaWRhdGUpLmxlbmd0aCA+IDAgP1xuICAgICAgICAgICAgU0RQVXRpbHMucGFyc2VDYW5kaWRhdGUoY2FuZGlkYXRlLmNhbmRpZGF0ZSkgOiB7fTtcbiAgICAgICAgLy8gSWdub3JlIENocm9tZSdzIGludmFsaWQgY2FuZGlkYXRlcyBzaW5jZSBFZGdlIGRvZXMgbm90IGxpa2UgdGhlbS5cbiAgICAgICAgaWYgKGNhbmQucHJvdG9jb2wgPT09ICd0Y3AnICYmIChjYW5kLnBvcnQgPT09IDAgfHwgY2FuZC5wb3J0ID09PSA5KSkge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBJZ25vcmUgUlRDUCBjYW5kaWRhdGVzLCB3ZSBhc3N1bWUgUlRDUC1NVVguXG4gICAgICAgIGlmIChjYW5kLmNvbXBvbmVudCAhPT0gJzEnKSB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgICB9XG4gICAgICAgIHRyYW5zY2VpdmVyLmljZVRyYW5zcG9ydC5hZGRSZW1vdGVDYW5kaWRhdGUoY2FuZCk7XG5cbiAgICAgICAgLy8gdXBkYXRlIHRoZSByZW1vdGVEZXNjcmlwdGlvbi5cbiAgICAgICAgdmFyIHNlY3Rpb25zID0gU0RQVXRpbHMuc3BsaXRTZWN0aW9ucyh0aGlzLnJlbW90ZURlc2NyaXB0aW9uLnNkcCk7XG4gICAgICAgIHNlY3Rpb25zW21MaW5lSW5kZXggKyAxXSArPSAoY2FuZC50eXBlID8gY2FuZGlkYXRlLmNhbmRpZGF0ZS50cmltKClcbiAgICAgICAgICAgIDogJ2E9ZW5kLW9mLWNhbmRpZGF0ZXMnKSArICdcXHJcXG4nO1xuICAgICAgICB0aGlzLnJlbW90ZURlc2NyaXB0aW9uLnNkcCA9IHNlY3Rpb25zLmpvaW4oJycpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgdHlwZW9mIGFyZ3VtZW50c1sxXSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgd2luZG93LnNldFRpbWVvdXQoYXJndW1lbnRzWzFdLCAwKTtcbiAgICB9XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICB9O1xuXG4gIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRTdGF0cyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBwcm9taXNlcyA9IFtdO1xuICAgIHRoaXMudHJhbnNjZWl2ZXJzLmZvckVhY2goZnVuY3Rpb24odHJhbnNjZWl2ZXIpIHtcbiAgICAgIFsncnRwU2VuZGVyJywgJ3J0cFJlY2VpdmVyJywgJ2ljZUdhdGhlcmVyJywgJ2ljZVRyYW5zcG9ydCcsXG4gICAgICAgICAgJ2R0bHNUcmFuc3BvcnQnXS5mb3JFYWNoKGZ1bmN0aW9uKG1ldGhvZCkge1xuICAgICAgICAgICAgaWYgKHRyYW5zY2VpdmVyW21ldGhvZF0pIHtcbiAgICAgICAgICAgICAgcHJvbWlzZXMucHVzaCh0cmFuc2NlaXZlclttZXRob2RdLmdldFN0YXRzKCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgIH0pO1xuICAgIHZhciBjYiA9IGFyZ3VtZW50cy5sZW5ndGggPiAxICYmIHR5cGVvZiBhcmd1bWVudHNbMV0gPT09ICdmdW5jdGlvbicgJiZcbiAgICAgICAgYXJndW1lbnRzWzFdO1xuICAgIHZhciBmaXhTdGF0c1R5cGUgPSBmdW5jdGlvbihzdGF0KSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBpbmJvdW5kcnRwOiAnaW5ib3VuZC1ydHAnLFxuICAgICAgICBvdXRib3VuZHJ0cDogJ291dGJvdW5kLXJ0cCcsXG4gICAgICAgIGNhbmRpZGF0ZXBhaXI6ICdjYW5kaWRhdGUtcGFpcicsXG4gICAgICAgIGxvY2FsY2FuZGlkYXRlOiAnbG9jYWwtY2FuZGlkYXRlJyxcbiAgICAgICAgcmVtb3RlY2FuZGlkYXRlOiAncmVtb3RlLWNhbmRpZGF0ZSdcbiAgICAgIH1bc3RhdC50eXBlXSB8fCBzdGF0LnR5cGU7XG4gICAgfTtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSkge1xuICAgICAgLy8gc2hpbSBnZXRTdGF0cyB3aXRoIG1hcGxpa2Ugc3VwcG9ydFxuICAgICAgdmFyIHJlc3VsdHMgPSBuZXcgTWFwKCk7XG4gICAgICBQcm9taXNlLmFsbChwcm9taXNlcykudGhlbihmdW5jdGlvbihyZXMpIHtcbiAgICAgICAgcmVzLmZvckVhY2goZnVuY3Rpb24ocmVzdWx0KSB7XG4gICAgICAgICAgT2JqZWN0LmtleXMocmVzdWx0KS5mb3JFYWNoKGZ1bmN0aW9uKGlkKSB7XG4gICAgICAgICAgICByZXN1bHRbaWRdLnR5cGUgPSBmaXhTdGF0c1R5cGUocmVzdWx0W2lkXSk7XG4gICAgICAgICAgICByZXN1bHRzLnNldChpZCwgcmVzdWx0W2lkXSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoY2IpIHtcbiAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dChjYiwgMCwgcmVzdWx0cyk7XG4gICAgICAgIH1cbiAgICAgICAgcmVzb2x2ZShyZXN1bHRzKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9O1xuICByZXR1cm4gUlRDUGVlckNvbm5lY3Rpb247XG59O1xuIiwiLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4gLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG5cbnZhciBicm93c2VyRGV0YWlscyA9IHJlcXVpcmUoJy4uL3V0aWxzJykuYnJvd3NlckRldGFpbHM7XG5cbnZhciBmaXJlZm94U2hpbSA9IHtcbiAgc2hpbU9uVHJhY2s6IGZ1bmN0aW9uKCkge1xuICAgIGlmICh0eXBlb2Ygd2luZG93ID09PSAnb2JqZWN0JyAmJiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gJiYgISgnb250cmFjaycgaW5cbiAgICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSkpIHtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLCAnb250cmFjaycsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5fb250cmFjaztcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbihmKSB7XG4gICAgICAgICAgaWYgKHRoaXMuX29udHJhY2spIHtcbiAgICAgICAgICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcigndHJhY2snLCB0aGlzLl9vbnRyYWNrKTtcbiAgICAgICAgICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcignYWRkc3RyZWFtJywgdGhpcy5fb250cmFja3BvbHkpO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmFkZEV2ZW50TGlzdGVuZXIoJ3RyYWNrJywgdGhpcy5fb250cmFjayA9IGYpO1xuICAgICAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcignYWRkc3RyZWFtJywgdGhpcy5fb250cmFja3BvbHkgPSBmdW5jdGlvbihlKSB7XG4gICAgICAgICAgICBlLnN0cmVhbS5nZXRUcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uKHRyYWNrKSB7XG4gICAgICAgICAgICAgIHZhciBldmVudCA9IG5ldyBFdmVudCgndHJhY2snKTtcbiAgICAgICAgICAgICAgZXZlbnQudHJhY2sgPSB0cmFjaztcbiAgICAgICAgICAgICAgZXZlbnQucmVjZWl2ZXIgPSB7dHJhY2s6IHRyYWNrfTtcbiAgICAgICAgICAgICAgZXZlbnQuc3RyZWFtcyA9IFtlLnN0cmVhbV07XG4gICAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgICAgICAgICB9LmJpbmQodGhpcykpO1xuICAgICAgICAgIH0uYmluZCh0aGlzKSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfSxcblxuICBzaGltU291cmNlT2JqZWN0OiBmdW5jdGlvbigpIHtcbiAgICAvLyBGaXJlZm94IGhhcyBzdXBwb3J0ZWQgbW96U3JjT2JqZWN0IHNpbmNlIEZGMjIsIHVucHJlZml4ZWQgaW4gNDIuXG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnKSB7XG4gICAgICBpZiAod2luZG93LkhUTUxNZWRpYUVsZW1lbnQgJiZcbiAgICAgICAgISgnc3JjT2JqZWN0JyBpbiB3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUpKSB7XG4gICAgICAgIC8vIFNoaW0gdGhlIHNyY09iamVjdCBwcm9wZXJ0eSwgb25jZSwgd2hlbiBIVE1MTWVkaWFFbGVtZW50IGlzIGZvdW5kLlxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkod2luZG93LkhUTUxNZWRpYUVsZW1lbnQucHJvdG90eXBlLCAnc3JjT2JqZWN0Jywge1xuICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5tb3pTcmNPYmplY3Q7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBzZXQ6IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICAgICAgdGhpcy5tb3pTcmNPYmplY3QgPSBzdHJlYW07XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG5cbiAgc2hpbVBlZXJDb25uZWN0aW9uOiBmdW5jdGlvbigpIHtcbiAgICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ29iamVjdCcgfHwgISh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gfHxcbiAgICAgICAgd2luZG93Lm1velJUQ1BlZXJDb25uZWN0aW9uKSkge1xuICAgICAgcmV0dXJuOyAvLyBwcm9iYWJseSBtZWRpYS5wZWVyY29ubmVjdGlvbi5lbmFibGVkPWZhbHNlIGluIGFib3V0OmNvbmZpZ1xuICAgIH1cbiAgICAvLyBUaGUgUlRDUGVlckNvbm5lY3Rpb24gb2JqZWN0LlxuICAgIGlmICghd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uKSB7XG4gICAgICB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24gPSBmdW5jdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cykge1xuICAgICAgICBpZiAoYnJvd3NlckRldGFpbHMudmVyc2lvbiA8IDM4KSB7XG4gICAgICAgICAgLy8gLnVybHMgaXMgbm90IHN1cHBvcnRlZCBpbiBGRiA8IDM4LlxuICAgICAgICAgIC8vIGNyZWF0ZSBSVENJY2VTZXJ2ZXJzIHdpdGggYSBzaW5nbGUgdXJsLlxuICAgICAgICAgIGlmIChwY0NvbmZpZyAmJiBwY0NvbmZpZy5pY2VTZXJ2ZXJzKSB7XG4gICAgICAgICAgICB2YXIgbmV3SWNlU2VydmVycyA9IFtdO1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwY0NvbmZpZy5pY2VTZXJ2ZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgIHZhciBzZXJ2ZXIgPSBwY0NvbmZpZy5pY2VTZXJ2ZXJzW2ldO1xuICAgICAgICAgICAgICBpZiAoc2VydmVyLmhhc093blByb3BlcnR5KCd1cmxzJykpIHtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHNlcnZlci51cmxzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICB2YXIgbmV3U2VydmVyID0ge1xuICAgICAgICAgICAgICAgICAgICB1cmw6IHNlcnZlci51cmxzW2pdXG4gICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgaWYgKHNlcnZlci51cmxzW2pdLmluZGV4T2YoJ3R1cm4nKSA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBuZXdTZXJ2ZXIudXNlcm5hbWUgPSBzZXJ2ZXIudXNlcm5hbWU7XG4gICAgICAgICAgICAgICAgICAgIG5ld1NlcnZlci5jcmVkZW50aWFsID0gc2VydmVyLmNyZWRlbnRpYWw7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBuZXdJY2VTZXJ2ZXJzLnB1c2gobmV3U2VydmVyKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbmV3SWNlU2VydmVycy5wdXNoKHBjQ29uZmlnLmljZVNlcnZlcnNbaV0pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBwY0NvbmZpZy5pY2VTZXJ2ZXJzID0gbmV3SWNlU2VydmVycztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBtb3pSVENQZWVyQ29ubmVjdGlvbihwY0NvbmZpZywgcGNDb25zdHJhaW50cyk7XG4gICAgICB9O1xuICAgICAgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZSA9IG1velJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZTtcblxuICAgICAgLy8gd3JhcCBzdGF0aWMgbWV0aG9kcy4gQ3VycmVudGx5IGp1c3QgZ2VuZXJhdGVDZXJ0aWZpY2F0ZS5cbiAgICAgIGlmIChtb3pSVENQZWVyQ29ubmVjdGlvbi5nZW5lcmF0ZUNlcnRpZmljYXRlKSB7XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24sICdnZW5lcmF0ZUNlcnRpZmljYXRlJywge1xuICAgICAgICAgIGdldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gbW96UlRDUGVlckNvbm5lY3Rpb24uZ2VuZXJhdGVDZXJ0aWZpY2F0ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICB3aW5kb3cuUlRDU2Vzc2lvbkRlc2NyaXB0aW9uID0gbW96UlRDU2Vzc2lvbkRlc2NyaXB0aW9uO1xuICAgICAgd2luZG93LlJUQ0ljZUNhbmRpZGF0ZSA9IG1velJUQ0ljZUNhbmRpZGF0ZTtcbiAgICB9XG5cbiAgICAvLyBzaGltIGF3YXkgbmVlZCBmb3Igb2Jzb2xldGUgUlRDSWNlQ2FuZGlkYXRlL1JUQ1Nlc3Npb25EZXNjcmlwdGlvbi5cbiAgICBbJ3NldExvY2FsRGVzY3JpcHRpb24nLCAnc2V0UmVtb3RlRGVzY3JpcHRpb24nLCAnYWRkSWNlQ2FuZGlkYXRlJ11cbiAgICAgICAgLmZvckVhY2goZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgICAgICAgdmFyIG5hdGl2ZU1ldGhvZCA9IFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdO1xuICAgICAgICAgIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZVttZXRob2RdID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBhcmd1bWVudHNbMF0gPSBuZXcgKChtZXRob2QgPT09ICdhZGRJY2VDYW5kaWRhdGUnKSA/XG4gICAgICAgICAgICAgICAgUlRDSWNlQ2FuZGlkYXRlIDogUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKShhcmd1bWVudHNbMF0pO1xuICAgICAgICAgICAgcmV0dXJuIG5hdGl2ZU1ldGhvZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuXG4gICAgLy8gc3VwcG9ydCBmb3IgYWRkSWNlQ2FuZGlkYXRlKG51bGwgb3IgdW5kZWZpbmVkKVxuICAgIHZhciBuYXRpdmVBZGRJY2VDYW5kaWRhdGUgPVxuICAgICAgICBSVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuYWRkSWNlQ2FuZGlkYXRlO1xuICAgIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRJY2VDYW5kaWRhdGUgPSBmdW5jdGlvbigpIHtcbiAgICAgIGlmICghYXJndW1lbnRzWzBdKSB7XG4gICAgICAgIGlmIChhcmd1bWVudHNbMV0pIHtcbiAgICAgICAgICBhcmd1bWVudHNbMV0uYXBwbHkobnVsbCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5hdGl2ZUFkZEljZUNhbmRpZGF0ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH07XG5cbiAgICAvLyBzaGltIGdldFN0YXRzIHdpdGggbWFwbGlrZSBzdXBwb3J0XG4gICAgdmFyIG1ha2VNYXBTdGF0cyA9IGZ1bmN0aW9uKHN0YXRzKSB7XG4gICAgICB2YXIgbWFwID0gbmV3IE1hcCgpO1xuICAgICAgT2JqZWN0LmtleXMoc3RhdHMpLmZvckVhY2goZnVuY3Rpb24oa2V5KSB7XG4gICAgICAgIG1hcC5zZXQoa2V5LCBzdGF0c1trZXldKTtcbiAgICAgICAgbWFwW2tleV0gPSBzdGF0c1trZXldO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gbWFwO1xuICAgIH07XG5cbiAgICB2YXIgbW9kZXJuU3RhdHNUeXBlcyA9IHtcbiAgICAgIGluYm91bmRydHA6ICdpbmJvdW5kLXJ0cCcsXG4gICAgICBvdXRib3VuZHJ0cDogJ291dGJvdW5kLXJ0cCcsXG4gICAgICBjYW5kaWRhdGVwYWlyOiAnY2FuZGlkYXRlLXBhaXInLFxuICAgICAgbG9jYWxjYW5kaWRhdGU6ICdsb2NhbC1jYW5kaWRhdGUnLFxuICAgICAgcmVtb3RlY2FuZGlkYXRlOiAncmVtb3RlLWNhbmRpZGF0ZSdcbiAgICB9O1xuXG4gICAgdmFyIG5hdGl2ZUdldFN0YXRzID0gUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFN0YXRzO1xuICAgIFJUQ1BlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5nZXRTdGF0cyA9IGZ1bmN0aW9uKHNlbGVjdG9yLCBvblN1Y2MsIG9uRXJyKSB7XG4gICAgICByZXR1cm4gbmF0aXZlR2V0U3RhdHMuYXBwbHkodGhpcywgW3NlbGVjdG9yIHx8IG51bGxdKVxuICAgICAgICAudGhlbihmdW5jdGlvbihzdGF0cykge1xuICAgICAgICAgIGlmIChicm93c2VyRGV0YWlscy52ZXJzaW9uIDwgNDgpIHtcbiAgICAgICAgICAgIHN0YXRzID0gbWFrZU1hcFN0YXRzKHN0YXRzKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA1MyAmJiAhb25TdWNjKSB7XG4gICAgICAgICAgICAvLyBTaGltIG9ubHkgcHJvbWlzZSBnZXRTdGF0cyB3aXRoIHNwZWMtaHlwaGVucyBpbiB0eXBlIG5hbWVzXG4gICAgICAgICAgICAvLyBMZWF2ZSBjYWxsYmFjayB2ZXJzaW9uIGFsb25lOyBtaXNjIG9sZCB1c2VzIG9mIGZvckVhY2ggYmVmb3JlIE1hcFxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgc3RhdHMuZm9yRWFjaChmdW5jdGlvbihzdGF0KSB7XG4gICAgICAgICAgICAgICAgc3RhdC50eXBlID0gbW9kZXJuU3RhdHNUeXBlc1tzdGF0LnR5cGVdIHx8IHN0YXQudHlwZTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgIGlmIChlLm5hbWUgIT09ICdUeXBlRXJyb3InKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAvLyBBdm9pZCBUeXBlRXJyb3I6IFwidHlwZVwiIGlzIHJlYWQtb25seSwgaW4gb2xkIHZlcnNpb25zLiAzNC00M2lzaFxuICAgICAgICAgICAgICBzdGF0cy5mb3JFYWNoKGZ1bmN0aW9uKHN0YXQsIGkpIHtcbiAgICAgICAgICAgICAgICBzdGF0cy5zZXQoaSwgT2JqZWN0LmFzc2lnbih7fSwgc3RhdCwge1xuICAgICAgICAgICAgICAgICAgdHlwZTogbW9kZXJuU3RhdHNUeXBlc1tzdGF0LnR5cGVdIHx8IHN0YXQudHlwZVxuICAgICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBzdGF0cztcbiAgICAgICAgfSlcbiAgICAgICAgLnRoZW4ob25TdWNjLCBvbkVycik7XG4gICAgfTtcbiAgfVxufTtcblxuLy8gRXhwb3NlIHB1YmxpYyBtZXRob2RzLlxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHNoaW1PblRyYWNrOiBmaXJlZm94U2hpbS5zaGltT25UcmFjayxcbiAgc2hpbVNvdXJjZU9iamVjdDogZmlyZWZveFNoaW0uc2hpbVNvdXJjZU9iamVjdCxcbiAgc2hpbVBlZXJDb25uZWN0aW9uOiBmaXJlZm94U2hpbS5zaGltUGVlckNvbm5lY3Rpb24sXG4gIHNoaW1HZXRVc2VyTWVkaWE6IHJlcXVpcmUoJy4vZ2V0dXNlcm1lZGlhJylcbn07XG4iLCIvKlxuICogIENvcHlyaWdodCAoYykgMjAxNiBUaGUgV2ViUlRDIHByb2plY3QgYXV0aG9ycy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiAgVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYSBCU0Qtc3R5bGUgbGljZW5zZVxuICogIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3Qgb2YgdGhlIHNvdXJjZVxuICogIHRyZWUuXG4gKi9cbiAvKiBlc2xpbnQtZW52IG5vZGUgKi9cbid1c2Ugc3RyaWN0JztcblxudmFyIGxvZ2dpbmcgPSByZXF1aXJlKCcuLi91dGlscycpLmxvZztcbnZhciBicm93c2VyRGV0YWlscyA9IHJlcXVpcmUoJy4uL3V0aWxzJykuYnJvd3NlckRldGFpbHM7XG5cbi8vIEV4cG9zZSBwdWJsaWMgbWV0aG9kcy5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oKSB7XG4gIHZhciBzaGltRXJyb3JfID0gZnVuY3Rpb24oZSkge1xuICAgIHJldHVybiB7XG4gICAgICBuYW1lOiB7XG4gICAgICAgIE5vdFN1cHBvcnRlZEVycm9yOiAnVHlwZUVycm9yJyxcbiAgICAgICAgU2VjdXJpdHlFcnJvcjogJ05vdEFsbG93ZWRFcnJvcicsXG4gICAgICAgIFBlcm1pc3Npb25EZW5pZWRFcnJvcjogJ05vdEFsbG93ZWRFcnJvcidcbiAgICAgIH1bZS5uYW1lXSB8fCBlLm5hbWUsXG4gICAgICBtZXNzYWdlOiB7XG4gICAgICAgICdUaGUgb3BlcmF0aW9uIGlzIGluc2VjdXJlLic6ICdUaGUgcmVxdWVzdCBpcyBub3QgYWxsb3dlZCBieSB0aGUgJyArXG4gICAgICAgICd1c2VyIGFnZW50IG9yIHRoZSBwbGF0Zm9ybSBpbiB0aGUgY3VycmVudCBjb250ZXh0LidcbiAgICAgIH1bZS5tZXNzYWdlXSB8fCBlLm1lc3NhZ2UsXG4gICAgICBjb25zdHJhaW50OiBlLmNvbnN0cmFpbnQsXG4gICAgICB0b1N0cmluZzogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm5hbWUgKyAodGhpcy5tZXNzYWdlICYmICc6ICcpICsgdGhpcy5tZXNzYWdlO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgLy8gZ2V0VXNlck1lZGlhIGNvbnN0cmFpbnRzIHNoaW0uXG4gIHZhciBnZXRVc2VyTWVkaWFfID0gZnVuY3Rpb24oY29uc3RyYWludHMsIG9uU3VjY2Vzcywgb25FcnJvcikge1xuICAgIHZhciBjb25zdHJhaW50c1RvRkYzN18gPSBmdW5jdGlvbihjKSB7XG4gICAgICBpZiAodHlwZW9mIGMgIT09ICdvYmplY3QnIHx8IGMucmVxdWlyZSkge1xuICAgICAgICByZXR1cm4gYztcbiAgICAgIH1cbiAgICAgIHZhciByZXF1aXJlID0gW107XG4gICAgICBPYmplY3Qua2V5cyhjKS5mb3JFYWNoKGZ1bmN0aW9uKGtleSkge1xuICAgICAgICBpZiAoa2V5ID09PSAncmVxdWlyZScgfHwga2V5ID09PSAnYWR2YW5jZWQnIHx8IGtleSA9PT0gJ21lZGlhU291cmNlJykge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB2YXIgciA9IGNba2V5XSA9ICh0eXBlb2YgY1trZXldID09PSAnb2JqZWN0JykgP1xuICAgICAgICAgICAgY1trZXldIDoge2lkZWFsOiBjW2tleV19O1xuICAgICAgICBpZiAoci5taW4gIT09IHVuZGVmaW5lZCB8fFxuICAgICAgICAgICAgci5tYXggIT09IHVuZGVmaW5lZCB8fCByLmV4YWN0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICByZXF1aXJlLnB1c2goa2V5KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoci5leGFjdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgaWYgKHR5cGVvZiByLmV4YWN0ID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgci4gbWluID0gci5tYXggPSByLmV4YWN0O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjW2tleV0gPSByLmV4YWN0O1xuICAgICAgICAgIH1cbiAgICAgICAgICBkZWxldGUgci5leGFjdDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoci5pZGVhbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgYy5hZHZhbmNlZCA9IGMuYWR2YW5jZWQgfHwgW107XG4gICAgICAgICAgdmFyIG9jID0ge307XG4gICAgICAgICAgaWYgKHR5cGVvZiByLmlkZWFsID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgb2Nba2V5XSA9IHttaW46IHIuaWRlYWwsIG1heDogci5pZGVhbH07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG9jW2tleV0gPSByLmlkZWFsO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjLmFkdmFuY2VkLnB1c2gob2MpO1xuICAgICAgICAgIGRlbGV0ZSByLmlkZWFsO1xuICAgICAgICAgIGlmICghT2JqZWN0LmtleXMocikubGVuZ3RoKSB7XG4gICAgICAgICAgICBkZWxldGUgY1trZXldO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICBpZiAocmVxdWlyZS5sZW5ndGgpIHtcbiAgICAgICAgYy5yZXF1aXJlID0gcmVxdWlyZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjO1xuICAgIH07XG4gICAgY29uc3RyYWludHMgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGNvbnN0cmFpbnRzKSk7XG4gICAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCAzOCkge1xuICAgICAgbG9nZ2luZygnc3BlYzogJyArIEpTT04uc3RyaW5naWZ5KGNvbnN0cmFpbnRzKSk7XG4gICAgICBpZiAoY29uc3RyYWludHMuYXVkaW8pIHtcbiAgICAgICAgY29uc3RyYWludHMuYXVkaW8gPSBjb25zdHJhaW50c1RvRkYzN18oY29uc3RyYWludHMuYXVkaW8pO1xuICAgICAgfVxuICAgICAgaWYgKGNvbnN0cmFpbnRzLnZpZGVvKSB7XG4gICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvID0gY29uc3RyYWludHNUb0ZGMzdfKGNvbnN0cmFpbnRzLnZpZGVvKTtcbiAgICAgIH1cbiAgICAgIGxvZ2dpbmcoJ2ZmMzc6ICcgKyBKU09OLnN0cmluZ2lmeShjb25zdHJhaW50cykpO1xuICAgIH1cbiAgICByZXR1cm4gbmF2aWdhdG9yLm1vekdldFVzZXJNZWRpYShjb25zdHJhaW50cywgb25TdWNjZXNzLCBmdW5jdGlvbihlKSB7XG4gICAgICBvbkVycm9yKHNoaW1FcnJvcl8oZSkpO1xuICAgIH0pO1xuICB9O1xuXG4gIC8vIFJldHVybnMgdGhlIHJlc3VsdCBvZiBnZXRVc2VyTWVkaWEgYXMgYSBQcm9taXNlLlxuICB2YXIgZ2V0VXNlck1lZGlhUHJvbWlzZV8gPSBmdW5jdGlvbihjb25zdHJhaW50cykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgIGdldFVzZXJNZWRpYV8oY29uc3RyYWludHMsIHJlc29sdmUsIHJlamVjdCk7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gU2hpbSBmb3IgbWVkaWFEZXZpY2VzIG9uIG9sZGVyIHZlcnNpb25zLlxuICBpZiAoIW5hdmlnYXRvci5tZWRpYURldmljZXMpIHtcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzID0ge2dldFVzZXJNZWRpYTogZ2V0VXNlck1lZGlhUHJvbWlzZV8sXG4gICAgICBhZGRFdmVudExpc3RlbmVyOiBmdW5jdGlvbigpIHsgfSxcbiAgICAgIHJlbW92ZUV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uKCkgeyB9XG4gICAgfTtcbiAgfVxuICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmVudW1lcmF0ZURldmljZXMgPVxuICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzIHx8IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24ocmVzb2x2ZSkge1xuICAgICAgICAgIHZhciBpbmZvcyA9IFtcbiAgICAgICAgICAgIHtraW5kOiAnYXVkaW9pbnB1dCcsIGRldmljZUlkOiAnZGVmYXVsdCcsIGxhYmVsOiAnJywgZ3JvdXBJZDogJyd9LFxuICAgICAgICAgICAge2tpbmQ6ICd2aWRlb2lucHV0JywgZGV2aWNlSWQ6ICdkZWZhdWx0JywgbGFiZWw6ICcnLCBncm91cElkOiAnJ31cbiAgICAgICAgICBdO1xuICAgICAgICAgIHJlc29sdmUoaW5mb3MpO1xuICAgICAgICB9KTtcbiAgICAgIH07XG5cbiAgaWYgKGJyb3dzZXJEZXRhaWxzLnZlcnNpb24gPCA0MSkge1xuICAgIC8vIFdvcmsgYXJvdW5kIGh0dHA6Ly9idWd6aWwubGEvMTE2OTY2NVxuICAgIHZhciBvcmdFbnVtZXJhdGVEZXZpY2VzID1cbiAgICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzLmJpbmQobmF2aWdhdG9yLm1lZGlhRGV2aWNlcyk7XG4gICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzID0gZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gb3JnRW51bWVyYXRlRGV2aWNlcygpLnRoZW4odW5kZWZpbmVkLCBmdW5jdGlvbihlKSB7XG4gICAgICAgIGlmIChlLm5hbWUgPT09ICdOb3RGb3VuZEVycm9yJykge1xuICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlO1xuICAgICAgfSk7XG4gICAgfTtcbiAgfVxuICBpZiAoYnJvd3NlckRldGFpbHMudmVyc2lvbiA8IDQ5KSB7XG4gICAgdmFyIG9yaWdHZXRVc2VyTWVkaWEgPSBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYS5cbiAgICAgICAgYmluZChuYXZpZ2F0b3IubWVkaWFEZXZpY2VzKTtcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uKGMpIHtcbiAgICAgIHJldHVybiBvcmlnR2V0VXNlck1lZGlhKGMpLnRoZW4oZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgIC8vIFdvcmsgYXJvdW5kIGh0dHBzOi8vYnVnemlsLmxhLzgwMjMyNlxuICAgICAgICBpZiAoYy5hdWRpbyAmJiAhc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCkubGVuZ3RoIHx8XG4gICAgICAgICAgICBjLnZpZGVvICYmICFzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGgpIHtcbiAgICAgICAgICBzdHJlYW0uZ2V0VHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbih0cmFjaykge1xuICAgICAgICAgICAgdHJhY2suc3RvcCgpO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRocm93IG5ldyBET01FeGNlcHRpb24oJ1RoZSBvYmplY3QgY2FuIG5vdCBiZSBmb3VuZCBoZXJlLicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTm90Rm91bmRFcnJvcicpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdHJlYW07XG4gICAgICB9LCBmdW5jdGlvbihlKSB7XG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdChzaGltRXJyb3JfKGUpKTtcbiAgICAgIH0pO1xuICAgIH07XG4gIH1cbiAgbmF2aWdhdG9yLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uKGNvbnN0cmFpbnRzLCBvblN1Y2Nlc3MsIG9uRXJyb3IpIHtcbiAgICBpZiAoYnJvd3NlckRldGFpbHMudmVyc2lvbiA8IDQ0KSB7XG4gICAgICByZXR1cm4gZ2V0VXNlck1lZGlhXyhjb25zdHJhaW50cywgb25TdWNjZXNzLCBvbkVycm9yKTtcbiAgICB9XG4gICAgLy8gUmVwbGFjZSBGaXJlZm94IDQ0KydzIGRlcHJlY2F0aW9uIHdhcm5pbmcgd2l0aCB1bnByZWZpeGVkIHZlcnNpb24uXG4gICAgY29uc29sZS53YXJuKCduYXZpZ2F0b3IuZ2V0VXNlck1lZGlhIGhhcyBiZWVuIHJlcGxhY2VkIGJ5ICcgK1xuICAgICAgICAgICAgICAgICAnbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEnKTtcbiAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYShjb25zdHJhaW50cykudGhlbihvblN1Y2Nlc3MsIG9uRXJyb3IpO1xuICB9O1xufTtcbiIsIi8qXG4gKiAgQ29weXJpZ2h0IChjKSAyMDE2IFRoZSBXZWJSVEMgcHJvamVjdCBhdXRob3JzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqICBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZSBsaWNlbnNlXG4gKiAgdGhhdCBjYW4gYmUgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBvZiB0aGUgc291cmNlXG4gKiAgdHJlZS5cbiAqL1xuJ3VzZSBzdHJpY3QnO1xudmFyIHNhZmFyaVNoaW0gPSB7XG4gIC8vIFRPRE86IERyQWxleCwgc2hvdWxkIGJlIGhlcmUsIGRvdWJsZSBjaGVjayBhZ2FpbnN0IExheW91dFRlc3RzXG5cbiAgLy8gVE9ETzogb25jZSB0aGUgYmFjay1lbmQgZm9yIHRoZSBtYWMgcG9ydCBpcyBkb25lLCBhZGQuXG4gIC8vIFRPRE86IGNoZWNrIGZvciB3ZWJraXRHVEsrXG4gIC8vIHNoaW1QZWVyQ29ubmVjdGlvbjogZnVuY3Rpb24oKSB7IH0sXG5cbiAgc2hpbU9uQWRkU3RyZWFtOiBmdW5jdGlvbigpIHtcbiAgICBpZiAodHlwZW9mIHdpbmRvdyA9PT0gJ29iamVjdCcgJiYgd2luZG93LlJUQ1BlZXJDb25uZWN0aW9uICYmXG4gICAgICAgICEoJ29uYWRkc3RyZWFtJyBpbiB3aW5kb3cuUlRDUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlKSkge1xuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHdpbmRvdy5SVENQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUsICdvbmFkZHN0cmVhbScsIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5fb25hZGRzdHJlYW07XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24oZikge1xuICAgICAgICAgIGlmICh0aGlzLl9vbmFkZHN0cmVhbSkge1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVFdmVudExpc3RlbmVyKCdhZGRzdHJlYW0nLCB0aGlzLl9vbmFkZHN0cmVhbSk7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RyYWNrJywgdGhpcy5fb25hZGRzdHJlYW1wb2x5KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVyKCdhZGRzdHJlYW0nLCB0aGlzLl9vbmFkZHN0cmVhbSA9IGYpO1xuICAgICAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcigndHJhY2snLCB0aGlzLl9vbmFkZHN0cmVhbXBvbHkgPSBmdW5jdGlvbihlKSB7XG4gICAgICAgICAgICB2YXIgc3RyZWFtID0gZS5zdHJlYW1zWzBdO1xuICAgICAgICAgICAgaWYgKCF0aGlzLl9zdHJlYW1zKSB7XG4gICAgICAgICAgICAgIHRoaXMuX3N0cmVhbXMgPSBbXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0aGlzLl9zdHJlYW1zLmluZGV4T2Yoc3RyZWFtKSA+PSAwKSB7XG4gICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuX3N0cmVhbXMucHVzaChzdHJlYW0pO1xuICAgICAgICAgICAgdmFyIGV2ZW50ID0gbmV3IEV2ZW50KCdhZGRzdHJlYW0nKTtcbiAgICAgICAgICAgIGV2ZW50LnN0cmVhbSA9IGUuc3RyZWFtc1swXTtcbiAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChldmVudCk7XG4gICAgICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9LFxuXG4gIHNoaW1HZXRVc2VyTWVkaWE6IGZ1bmN0aW9uKCkge1xuICAgIGlmICghbmF2aWdhdG9yLmdldFVzZXJNZWRpYSkge1xuICAgICAgaWYgKG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgbmF2aWdhdG9yLmdldFVzZXJNZWRpYSA9IG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEuYmluZChuYXZpZ2F0b3IpO1xuICAgICAgfSBlbHNlIGlmIChuYXZpZ2F0b3IubWVkaWFEZXZpY2VzICYmXG4gICAgICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgbmF2aWdhdG9yLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uKGNvbnN0cmFpbnRzLCBjYiwgZXJyY2IpIHtcbiAgICAgICAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYShjb25zdHJhaW50cylcbiAgICAgICAgICAudGhlbihjYiwgZXJyY2IpO1xuICAgICAgICB9LmJpbmQobmF2aWdhdG9yKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn07XG5cbi8vIEV4cG9zZSBwdWJsaWMgbWV0aG9kcy5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBzaGltT25BZGRTdHJlYW06IHNhZmFyaVNoaW0uc2hpbU9uQWRkU3RyZWFtLFxuICBzaGltR2V0VXNlck1lZGlhOiBzYWZhcmlTaGltLnNoaW1HZXRVc2VyTWVkaWFcbiAgLy8gVE9ET1xuICAvLyBzaGltUGVlckNvbm5lY3Rpb246IHNhZmFyaVNoaW0uc2hpbVBlZXJDb25uZWN0aW9uXG59O1xuIiwiLypcbiAqICBDb3B5cmlnaHQgKGMpIDIwMTYgVGhlIFdlYlJUQyBwcm9qZWN0IGF1dGhvcnMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlIGxpY2Vuc2VcbiAqICB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGluIHRoZSByb290IG9mIHRoZSBzb3VyY2VcbiAqICB0cmVlLlxuICovXG4gLyogZXNsaW50LWVudiBub2RlICovXG4ndXNlIHN0cmljdCc7XG5cbnZhciBsb2dEaXNhYmxlZF8gPSB0cnVlO1xuXG4vLyBVdGlsaXR5IG1ldGhvZHMuXG52YXIgdXRpbHMgPSB7XG4gIGRpc2FibGVMb2c6IGZ1bmN0aW9uKGJvb2wpIHtcbiAgICBpZiAodHlwZW9mIGJvb2wgIT09ICdib29sZWFuJykge1xuICAgICAgcmV0dXJuIG5ldyBFcnJvcignQXJndW1lbnQgdHlwZTogJyArIHR5cGVvZiBib29sICtcbiAgICAgICAgICAnLiBQbGVhc2UgdXNlIGEgYm9vbGVhbi4nKTtcbiAgICB9XG4gICAgbG9nRGlzYWJsZWRfID0gYm9vbDtcbiAgICByZXR1cm4gKGJvb2wpID8gJ2FkYXB0ZXIuanMgbG9nZ2luZyBkaXNhYmxlZCcgOlxuICAgICAgICAnYWRhcHRlci5qcyBsb2dnaW5nIGVuYWJsZWQnO1xuICB9LFxuXG4gIGxvZzogZnVuY3Rpb24oKSB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnKSB7XG4gICAgICBpZiAobG9nRGlzYWJsZWRfKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmICh0eXBlb2YgY29uc29sZSAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIGNvbnNvbGUubG9nID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIGNvbnNvbGUubG9nLmFwcGx5KGNvbnNvbGUsIGFyZ3VtZW50cyk7XG4gICAgICB9XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBFeHRyYWN0IGJyb3dzZXIgdmVyc2lvbiBvdXQgb2YgdGhlIHByb3ZpZGVkIHVzZXIgYWdlbnQgc3RyaW5nLlxuICAgKlxuICAgKiBAcGFyYW0geyFzdHJpbmd9IHVhc3RyaW5nIHVzZXJBZ2VudCBzdHJpbmcuXG4gICAqIEBwYXJhbSB7IXN0cmluZ30gZXhwciBSZWd1bGFyIGV4cHJlc3Npb24gdXNlZCBhcyBtYXRjaCBjcml0ZXJpYS5cbiAgICogQHBhcmFtIHshbnVtYmVyfSBwb3MgcG9zaXRpb24gaW4gdGhlIHZlcnNpb24gc3RyaW5nIHRvIGJlIHJldHVybmVkLlxuICAgKiBAcmV0dXJuIHshbnVtYmVyfSBicm93c2VyIHZlcnNpb24uXG4gICAqL1xuICBleHRyYWN0VmVyc2lvbjogZnVuY3Rpb24odWFzdHJpbmcsIGV4cHIsIHBvcykge1xuICAgIHZhciBtYXRjaCA9IHVhc3RyaW5nLm1hdGNoKGV4cHIpO1xuICAgIHJldHVybiBtYXRjaCAmJiBtYXRjaC5sZW5ndGggPj0gcG9zICYmIHBhcnNlSW50KG1hdGNoW3Bvc10sIDEwKTtcbiAgfSxcblxuICAvKipcbiAgICogQnJvd3NlciBkZXRlY3Rvci5cbiAgICpcbiAgICogQHJldHVybiB7b2JqZWN0fSByZXN1bHQgY29udGFpbmluZyBicm93c2VyIGFuZCB2ZXJzaW9uXG4gICAqICAgICBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgZGV0ZWN0QnJvd3NlcjogZnVuY3Rpb24oKSB7XG4gICAgLy8gUmV0dXJuZWQgcmVzdWx0IG9iamVjdC5cbiAgICB2YXIgcmVzdWx0ID0ge307XG4gICAgcmVzdWx0LmJyb3dzZXIgPSBudWxsO1xuICAgIHJlc3VsdC52ZXJzaW9uID0gbnVsbDtcblxuICAgIC8vIEZhaWwgZWFybHkgaWYgaXQncyBub3QgYSBicm93c2VyXG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICd1bmRlZmluZWQnIHx8ICF3aW5kb3cubmF2aWdhdG9yKSB7XG4gICAgICByZXN1bHQuYnJvd3NlciA9ICdOb3QgYSBicm93c2VyLic7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8vIEZpcmVmb3guXG4gICAgaWYgKG5hdmlnYXRvci5tb3pHZXRVc2VyTWVkaWEpIHtcbiAgICAgIHJlc3VsdC5icm93c2VyID0gJ2ZpcmVmb3gnO1xuICAgICAgcmVzdWx0LnZlcnNpb24gPSB0aGlzLmV4dHJhY3RWZXJzaW9uKG5hdmlnYXRvci51c2VyQWdlbnQsXG4gICAgICAgICAgL0ZpcmVmb3hcXC8oXFxkKylcXC4vLCAxKTtcbiAgICB9IGVsc2UgaWYgKG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEpIHtcbiAgICAgIC8vIENocm9tZSwgQ2hyb21pdW0sIFdlYnZpZXcsIE9wZXJhLCBhbGwgdXNlIHRoZSBjaHJvbWUgc2hpbSBmb3Igbm93XG4gICAgICBpZiAod2luZG93LndlYmtpdFJUQ1BlZXJDb25uZWN0aW9uKSB7XG4gICAgICAgIHJlc3VsdC5icm93c2VyID0gJ2Nocm9tZSc7XG4gICAgICAgIHJlc3VsdC52ZXJzaW9uID0gdGhpcy5leHRyYWN0VmVyc2lvbihuYXZpZ2F0b3IudXNlckFnZW50LFxuICAgICAgICAgIC9DaHJvbShlfGl1bSlcXC8oXFxkKylcXC4vLCAyKTtcbiAgICAgIH0gZWxzZSB7IC8vIFNhZmFyaSAoaW4gYW4gdW5wdWJsaXNoZWQgdmVyc2lvbikgb3IgdW5rbm93biB3ZWJraXQtYmFzZWQuXG4gICAgICAgIGlmIChuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC9WZXJzaW9uXFwvKFxcZCspLihcXGQrKS8pKSB7XG4gICAgICAgICAgcmVzdWx0LmJyb3dzZXIgPSAnc2FmYXJpJztcbiAgICAgICAgICByZXN1bHQudmVyc2lvbiA9IHRoaXMuZXh0cmFjdFZlcnNpb24obmF2aWdhdG9yLnVzZXJBZ2VudCxcbiAgICAgICAgICAgIC9BcHBsZVdlYktpdFxcLyhcXGQrKVxcLi8sIDEpO1xuICAgICAgICB9IGVsc2UgeyAvLyB1bmtub3duIHdlYmtpdC1iYXNlZCBicm93c2VyLlxuICAgICAgICAgIHJlc3VsdC5icm93c2VyID0gJ1Vuc3VwcG9ydGVkIHdlYmtpdC1iYXNlZCBicm93c2VyICcgK1xuICAgICAgICAgICAgICAnd2l0aCBHVU0gc3VwcG9ydCBidXQgbm8gV2ViUlRDIHN1cHBvcnQuJztcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChuYXZpZ2F0b3IubWVkaWFEZXZpY2VzICYmXG4gICAgICAgIG5hdmlnYXRvci51c2VyQWdlbnQubWF0Y2goL0VkZ2VcXC8oXFxkKykuKFxcZCspJC8pKSB7IC8vIEVkZ2UuXG4gICAgICByZXN1bHQuYnJvd3NlciA9ICdlZGdlJztcbiAgICAgIHJlc3VsdC52ZXJzaW9uID0gdGhpcy5leHRyYWN0VmVyc2lvbihuYXZpZ2F0b3IudXNlckFnZW50LFxuICAgICAgICAgIC9FZGdlXFwvKFxcZCspLihcXGQrKSQvLCAyKTtcbiAgICB9IGVsc2UgaWYgKG5hdmlnYXRvci5tZWRpYURldmljZXMgJiZcbiAgICAgICAgbmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvQXBwbGVXZWJLaXRcXC8oXFxkKylcXC4vKSkge1xuICAgICAgICAvLyBTYWZhcmksIHdpdGggd2Via2l0R2V0VXNlck1lZGlhIHJlbW92ZWQuXG4gICAgICByZXN1bHQuYnJvd3NlciA9ICdzYWZhcmknO1xuICAgICAgcmVzdWx0LnZlcnNpb24gPSB0aGlzLmV4dHJhY3RWZXJzaW9uKG5hdmlnYXRvci51c2VyQWdlbnQsXG4gICAgICAgICAgL0FwcGxlV2ViS2l0XFwvKFxcZCspXFwuLywgMSk7XG4gICAgfSBlbHNlIHsgLy8gRGVmYXVsdCBmYWxsdGhyb3VnaDogbm90IHN1cHBvcnRlZC5cbiAgICAgIHJlc3VsdC5icm93c2VyID0gJ05vdCBhIHN1cHBvcnRlZCBicm93c2VyLic7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH0sXG5cbiAgLy8gc2hpbUNyZWF0ZU9iamVjdFVSTCBtdXN0IGJlIGNhbGxlZCBiZWZvcmUgc2hpbVNvdXJjZU9iamVjdCB0byBhdm9pZCBsb29wLlxuXG4gIHNoaW1DcmVhdGVPYmplY3RVUkw6IGZ1bmN0aW9uKCkge1xuICAgIGlmICghKHR5cGVvZiB3aW5kb3cgPT09ICdvYmplY3QnICYmIHdpbmRvdy5IVE1MTWVkaWFFbGVtZW50ICYmXG4gICAgICAgICAgJ3NyY09iamVjdCcgaW4gd2luZG93LkhUTUxNZWRpYUVsZW1lbnQucHJvdG90eXBlKSkge1xuICAgICAgLy8gT25seSBzaGltIENyZWF0ZU9iamVjdFVSTCB1c2luZyBzcmNPYmplY3QgaWYgc3JjT2JqZWN0IGV4aXN0cy5cbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgdmFyIG5hdGl2ZUNyZWF0ZU9iamVjdFVSTCA9IFVSTC5jcmVhdGVPYmplY3RVUkwuYmluZChVUkwpO1xuICAgIHZhciBuYXRpdmVSZXZva2VPYmplY3RVUkwgPSBVUkwucmV2b2tlT2JqZWN0VVJMLmJpbmQoVVJMKTtcbiAgICB2YXIgc3RyZWFtcyA9IG5ldyBNYXAoKSwgbmV3SWQgPSAwO1xuXG4gICAgVVJMLmNyZWF0ZU9iamVjdFVSTCA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgaWYgKCdnZXRUcmFja3MnIGluIHN0cmVhbSkge1xuICAgICAgICB2YXIgdXJsID0gJ3BvbHlibG9iOicgKyAoKytuZXdJZCk7XG4gICAgICAgIHN0cmVhbXMuc2V0KHVybCwgc3RyZWFtKTtcbiAgICAgICAgY29uc29sZS5sb2coJ1VSTC5jcmVhdGVPYmplY3RVUkwoc3RyZWFtKSBpcyBkZXByZWNhdGVkISAnICtcbiAgICAgICAgICAgICAgICAgICAgJ1VzZSBlbGVtLnNyY09iamVjdCA9IHN0cmVhbSBpbnN0ZWFkIScpO1xuICAgICAgICByZXR1cm4gdXJsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5hdGl2ZUNyZWF0ZU9iamVjdFVSTChzdHJlYW0pO1xuICAgIH07XG4gICAgVVJMLnJldm9rZU9iamVjdFVSTCA9IGZ1bmN0aW9uKHVybCkge1xuICAgICAgbmF0aXZlUmV2b2tlT2JqZWN0VVJMKHVybCk7XG4gICAgICBzdHJlYW1zLmRlbGV0ZSh1cmwpO1xuICAgIH07XG5cbiAgICB2YXIgZHNjID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3NyYycpO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3aW5kb3cuSFRNTE1lZGlhRWxlbWVudC5wcm90b3R5cGUsICdzcmMnLCB7XG4gICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gZHNjLmdldC5hcHBseSh0aGlzKTtcbiAgICAgIH0sXG4gICAgICBzZXQ6IGZ1bmN0aW9uKHVybCkge1xuICAgICAgICB0aGlzLnNyY09iamVjdCA9IHN0cmVhbXMuZ2V0KHVybCkgfHwgbnVsbDtcbiAgICAgICAgcmV0dXJuIGRzYy5zZXQuYXBwbHkodGhpcywgW3VybF0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdmFyIG5hdGl2ZVNldEF0dHJpYnV0ZSA9IEhUTUxNZWRpYUVsZW1lbnQucHJvdG90eXBlLnNldEF0dHJpYnV0ZTtcbiAgICBIVE1MTWVkaWFFbGVtZW50LnByb3RvdHlwZS5zZXRBdHRyaWJ1dGUgPSBmdW5jdGlvbigpIHtcbiAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAyICYmXG4gICAgICAgICAgKCcnICsgYXJndW1lbnRzWzBdKS50b0xvd2VyQ2FzZSgpID09PSAnc3JjJykge1xuICAgICAgICB0aGlzLnNyY09iamVjdCA9IHN0cmVhbXMuZ2V0KGFyZ3VtZW50c1sxXSkgfHwgbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBuYXRpdmVTZXRBdHRyaWJ1dGUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9O1xuICB9XG59O1xuXG4vLyBFeHBvcnQuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgbG9nOiB1dGlscy5sb2csXG4gIGRpc2FibGVMb2c6IHV0aWxzLmRpc2FibGVMb2csXG4gIGJyb3dzZXJEZXRhaWxzOiB1dGlscy5kZXRlY3RCcm93c2VyKCksXG4gIGV4dHJhY3RWZXJzaW9uOiB1dGlscy5leHRyYWN0VmVyc2lvbixcbiAgc2hpbUNyZWF0ZU9iamVjdFVSTDogdXRpbHMuc2hpbUNyZWF0ZU9iamVjdFVSTCxcbiAgZGV0ZWN0QnJvd3NlcjogdXRpbHMuZGV0ZWN0QnJvd3Nlci5iaW5kKHV0aWxzKVxufTtcbiIsIi8qXHJcbldpbGRFbWl0dGVyLmpzIGlzIGEgc2xpbSBsaXR0bGUgZXZlbnQgZW1pdHRlciBieSBAaGVucmlram9yZXRlZyBsYXJnZWx5IGJhc2VkXHJcbm9uIEB2aXNpb25tZWRpYSdzIEVtaXR0ZXIgZnJvbSBVSSBLaXQuXHJcblxyXG5XaHk/IEkgd2FudGVkIGl0IHN0YW5kYWxvbmUuXHJcblxyXG5JIGFsc28gd2FudGVkIHN1cHBvcnQgZm9yIHdpbGRjYXJkIGVtaXR0ZXJzIGxpa2UgdGhpczpcclxuXHJcbmVtaXR0ZXIub24oJyonLCBmdW5jdGlvbiAoZXZlbnROYW1lLCBvdGhlciwgZXZlbnQsIHBheWxvYWRzKSB7XHJcblxyXG59KTtcclxuXHJcbmVtaXR0ZXIub24oJ3NvbWVuYW1lc3BhY2UqJywgZnVuY3Rpb24gKGV2ZW50TmFtZSwgcGF5bG9hZHMpIHtcclxuXHJcbn0pO1xyXG5cclxuUGxlYXNlIG5vdGUgdGhhdCBjYWxsYmFja3MgdHJpZ2dlcmVkIGJ5IHdpbGRjYXJkIHJlZ2lzdGVyZWQgZXZlbnRzIGFsc28gZ2V0XHJcbnRoZSBldmVudCBuYW1lIGFzIHRoZSBmaXJzdCBhcmd1bWVudC5cclxuKi9cclxuXHJcbm1vZHVsZS5leHBvcnRzID0gV2lsZEVtaXR0ZXI7XHJcblxyXG5mdW5jdGlvbiBXaWxkRW1pdHRlcigpIHsgfVxyXG5cclxuV2lsZEVtaXR0ZXIubWl4aW4gPSBmdW5jdGlvbiAoY29uc3RydWN0b3IpIHtcclxuICAgIHZhciBwcm90b3R5cGUgPSBjb25zdHJ1Y3Rvci5wcm90b3R5cGUgfHwgY29uc3RydWN0b3I7XHJcblxyXG4gICAgcHJvdG90eXBlLmlzV2lsZEVtaXR0ZXI9IHRydWU7XHJcblxyXG4gICAgLy8gTGlzdGVuIG9uIHRoZSBnaXZlbiBgZXZlbnRgIHdpdGggYGZuYC4gU3RvcmUgYSBncm91cCBuYW1lIGlmIHByZXNlbnQuXHJcbiAgICBwcm90b3R5cGUub24gPSBmdW5jdGlvbiAoZXZlbnQsIGdyb3VwTmFtZSwgZm4pIHtcclxuICAgICAgICB0aGlzLmNhbGxiYWNrcyA9IHRoaXMuY2FsbGJhY2tzIHx8IHt9O1xyXG4gICAgICAgIHZhciBoYXNHcm91cCA9IChhcmd1bWVudHMubGVuZ3RoID09PSAzKSxcclxuICAgICAgICAgICAgZ3JvdXAgPSBoYXNHcm91cCA/IGFyZ3VtZW50c1sxXSA6IHVuZGVmaW5lZCxcclxuICAgICAgICAgICAgZnVuYyA9IGhhc0dyb3VwID8gYXJndW1lbnRzWzJdIDogYXJndW1lbnRzWzFdO1xyXG4gICAgICAgIGZ1bmMuX2dyb3VwTmFtZSA9IGdyb3VwO1xyXG4gICAgICAgICh0aGlzLmNhbGxiYWNrc1tldmVudF0gPSB0aGlzLmNhbGxiYWNrc1tldmVudF0gfHwgW10pLnB1c2goZnVuYyk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9O1xyXG5cclxuICAgIC8vIEFkZHMgYW4gYGV2ZW50YCBsaXN0ZW5lciB0aGF0IHdpbGwgYmUgaW52b2tlZCBhIHNpbmdsZVxyXG4gICAgLy8gdGltZSB0aGVuIGF1dG9tYXRpY2FsbHkgcmVtb3ZlZC5cclxuICAgIHByb3RvdHlwZS5vbmNlID0gZnVuY3Rpb24gKGV2ZW50LCBncm91cE5hbWUsIGZuKSB7XHJcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgICAgICBoYXNHcm91cCA9IChhcmd1bWVudHMubGVuZ3RoID09PSAzKSxcclxuICAgICAgICAgICAgZ3JvdXAgPSBoYXNHcm91cCA/IGFyZ3VtZW50c1sxXSA6IHVuZGVmaW5lZCxcclxuICAgICAgICAgICAgZnVuYyA9IGhhc0dyb3VwID8gYXJndW1lbnRzWzJdIDogYXJndW1lbnRzWzFdO1xyXG4gICAgICAgIGZ1bmN0aW9uIG9uKCkge1xyXG4gICAgICAgICAgICBzZWxmLm9mZihldmVudCwgb24pO1xyXG4gICAgICAgICAgICBmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMub24oZXZlbnQsIGdyb3VwLCBvbik7XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9O1xyXG5cclxuICAgIC8vIFVuYmluZHMgYW4gZW50aXJlIGdyb3VwXHJcbiAgICBwcm90b3R5cGUucmVsZWFzZUdyb3VwID0gZnVuY3Rpb24gKGdyb3VwTmFtZSkge1xyXG4gICAgICAgIHRoaXMuY2FsbGJhY2tzID0gdGhpcy5jYWxsYmFja3MgfHwge307XHJcbiAgICAgICAgdmFyIGl0ZW0sIGksIGxlbiwgaGFuZGxlcnM7XHJcbiAgICAgICAgZm9yIChpdGVtIGluIHRoaXMuY2FsbGJhY2tzKSB7XHJcbiAgICAgICAgICAgIGhhbmRsZXJzID0gdGhpcy5jYWxsYmFja3NbaXRlbV07XHJcbiAgICAgICAgICAgIGZvciAoaSA9IDAsIGxlbiA9IGhhbmRsZXJzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoaGFuZGxlcnNbaV0uX2dyb3VwTmFtZSA9PT0gZ3JvdXBOYW1lKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmxvZygncmVtb3ZpbmcnKTtcclxuICAgICAgICAgICAgICAgICAgICAvLyByZW1vdmUgaXQgYW5kIHNob3J0ZW4gdGhlIGFycmF5IHdlJ3JlIGxvb3BpbmcgdGhyb3VnaFxyXG4gICAgICAgICAgICAgICAgICAgIGhhbmRsZXJzLnNwbGljZShpLCAxKTtcclxuICAgICAgICAgICAgICAgICAgICBpLS07XHJcbiAgICAgICAgICAgICAgICAgICAgbGVuLS07XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9O1xyXG5cclxuICAgIC8vIFJlbW92ZSB0aGUgZ2l2ZW4gY2FsbGJhY2sgZm9yIGBldmVudGAgb3IgYWxsXHJcbiAgICAvLyByZWdpc3RlcmVkIGNhbGxiYWNrcy5cclxuICAgIHByb3RvdHlwZS5vZmYgPSBmdW5jdGlvbiAoZXZlbnQsIGZuKSB7XHJcbiAgICAgICAgdGhpcy5jYWxsYmFja3MgPSB0aGlzLmNhbGxiYWNrcyB8fCB7fTtcclxuICAgICAgICB2YXIgY2FsbGJhY2tzID0gdGhpcy5jYWxsYmFja3NbZXZlbnRdLFxyXG4gICAgICAgICAgICBpO1xyXG5cclxuICAgICAgICBpZiAoIWNhbGxiYWNrcykgcmV0dXJuIHRoaXM7XHJcblxyXG4gICAgICAgIC8vIHJlbW92ZSBhbGwgaGFuZGxlcnNcclxuICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSkge1xyXG4gICAgICAgICAgICBkZWxldGUgdGhpcy5jYWxsYmFja3NbZXZlbnRdO1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcztcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIHJlbW92ZSBzcGVjaWZpYyBoYW5kbGVyXHJcbiAgICAgICAgaSA9IGNhbGxiYWNrcy5pbmRleE9mKGZuKTtcclxuICAgICAgICBjYWxsYmFja3Muc3BsaWNlKGksIDEpO1xyXG4gICAgICAgIGlmIChjYWxsYmFja3MubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmNhbGxiYWNrc1tldmVudF07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfTtcclxuXHJcbiAgICAvLy8gRW1pdCBgZXZlbnRgIHdpdGggdGhlIGdpdmVuIGFyZ3MuXHJcbiAgICAvLyBhbHNvIGNhbGxzIGFueSBgKmAgaGFuZGxlcnNcclxuICAgIHByb3RvdHlwZS5lbWl0ID0gZnVuY3Rpb24gKGV2ZW50KSB7XHJcbiAgICAgICAgdGhpcy5jYWxsYmFja3MgPSB0aGlzLmNhbGxiYWNrcyB8fCB7fTtcclxuICAgICAgICB2YXIgYXJncyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSxcclxuICAgICAgICAgICAgY2FsbGJhY2tzID0gdGhpcy5jYWxsYmFja3NbZXZlbnRdLFxyXG4gICAgICAgICAgICBzcGVjaWFsQ2FsbGJhY2tzID0gdGhpcy5nZXRXaWxkY2FyZENhbGxiYWNrcyhldmVudCksXHJcbiAgICAgICAgICAgIGksXHJcbiAgICAgICAgICAgIGxlbixcclxuICAgICAgICAgICAgaXRlbSxcclxuICAgICAgICAgICAgbGlzdGVuZXJzO1xyXG5cclxuICAgICAgICBpZiAoY2FsbGJhY2tzKSB7XHJcbiAgICAgICAgICAgIGxpc3RlbmVycyA9IGNhbGxiYWNrcy5zbGljZSgpO1xyXG4gICAgICAgICAgICBmb3IgKGkgPSAwLCBsZW4gPSBsaXN0ZW5lcnMubGVuZ3RoOyBpIDwgbGVuOyArK2kpIHtcclxuICAgICAgICAgICAgICAgIGlmICghbGlzdGVuZXJzW2ldKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBsaXN0ZW5lcnNbaV0uYXBwbHkodGhpcywgYXJncyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChzcGVjaWFsQ2FsbGJhY2tzKSB7XHJcbiAgICAgICAgICAgIGxlbiA9IHNwZWNpYWxDYWxsYmFja3MubGVuZ3RoO1xyXG4gICAgICAgICAgICBsaXN0ZW5lcnMgPSBzcGVjaWFsQ2FsbGJhY2tzLnNsaWNlKCk7XHJcbiAgICAgICAgICAgIGZvciAoaSA9IDAsIGxlbiA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBsZW47ICsraSkge1xyXG4gICAgICAgICAgICAgICAgaWYgKCFsaXN0ZW5lcnNbaV0pIHtcclxuICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGxpc3RlbmVyc1tpXS5hcHBseSh0aGlzLCBbZXZlbnRdLmNvbmNhdChhcmdzKSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfTtcclxuXHJcbiAgICAvLyBIZWxwZXIgZm9yIGZvciBmaW5kaW5nIHNwZWNpYWwgd2lsZGNhcmQgZXZlbnQgaGFuZGxlcnMgdGhhdCBtYXRjaCB0aGUgZXZlbnRcclxuICAgIHByb3RvdHlwZS5nZXRXaWxkY2FyZENhbGxiYWNrcyA9IGZ1bmN0aW9uIChldmVudE5hbWUpIHtcclxuICAgICAgICB0aGlzLmNhbGxiYWNrcyA9IHRoaXMuY2FsbGJhY2tzIHx8IHt9O1xyXG4gICAgICAgIHZhciBpdGVtLFxyXG4gICAgICAgICAgICBzcGxpdCxcclxuICAgICAgICAgICAgcmVzdWx0ID0gW107XHJcblxyXG4gICAgICAgIGZvciAoaXRlbSBpbiB0aGlzLmNhbGxiYWNrcykge1xyXG4gICAgICAgICAgICBzcGxpdCA9IGl0ZW0uc3BsaXQoJyonKTtcclxuICAgICAgICAgICAgaWYgKGl0ZW0gPT09ICcqJyB8fCAoc3BsaXQubGVuZ3RoID09PSAyICYmIGV2ZW50TmFtZS5zbGljZSgwLCBzcGxpdFswXS5sZW5ndGgpID09PSBzcGxpdFswXSkpIHtcclxuICAgICAgICAgICAgICAgIHJlc3VsdCA9IHJlc3VsdC5jb25jYXQodGhpcy5jYWxsYmFja3NbaXRlbV0pO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9O1xyXG5cclxufTtcclxuXHJcbldpbGRFbWl0dGVyLm1peGluKFdpbGRFbWl0dGVyKTtcclxuIiwiLyohXG4gKiBFdmVudEVtaXR0ZXIgdjQuMi45IC0gZ2l0LmlvL2VlXG4gKiBPbGl2ZXIgQ2FsZHdlbGxcbiAqIE1JVCBsaWNlbnNlXG4gKiBAcHJlc2VydmVcbiAqL1xuXG4oZnVuY3Rpb24gKCkge1xuICAgICd1c2Ugc3RyaWN0JztcblxuICAgIC8qKlxuICAgICAqIENsYXNzIGZvciBtYW5hZ2luZyBldmVudHMuXG4gICAgICogQ2FuIGJlIGV4dGVuZGVkIHRvIHByb3ZpZGUgZXZlbnQgZnVuY3Rpb25hbGl0eSBpbiBvdGhlciBjbGFzc2VzLlxuICAgICAqXG4gICAgICogQGNsYXNzIEV2ZW50RW1pdHRlciBNYW5hZ2VzIGV2ZW50IHJlZ2lzdGVyaW5nIGFuZCBlbWl0dGluZy5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBFdmVudEVtaXR0ZXIoKSB7fVxuXG4gICAgLy8gU2hvcnRjdXRzIHRvIGltcHJvdmUgc3BlZWQgYW5kIHNpemVcbiAgICB2YXIgcHJvdG8gPSBFdmVudEVtaXR0ZXIucHJvdG90eXBlO1xuICAgIHZhciBleHBvcnRzID0gdGhpcztcbiAgICB2YXIgb3JpZ2luYWxHbG9iYWxWYWx1ZSA9IGV4cG9ydHMuRXZlbnRFbWl0dGVyO1xuXG4gICAgLyoqXG4gICAgICogRmluZHMgdGhlIGluZGV4IG9mIHRoZSBsaXN0ZW5lciBmb3IgdGhlIGV2ZW50IGluIGl0cyBzdG9yYWdlIGFycmF5LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbltdfSBsaXN0ZW5lcnMgQXJyYXkgb2YgbGlzdGVuZXJzIHRvIHNlYXJjaCB0aHJvdWdoLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGxpc3RlbmVyIE1ldGhvZCB0byBsb29rIGZvci5cbiAgICAgKiBAcmV0dXJuIHtOdW1iZXJ9IEluZGV4IG9mIHRoZSBzcGVjaWZpZWQgbGlzdGVuZXIsIC0xIGlmIG5vdCBmb3VuZFxuICAgICAqIEBhcGkgcHJpdmF0ZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGluZGV4T2ZMaXN0ZW5lcihsaXN0ZW5lcnMsIGxpc3RlbmVyKSB7XG4gICAgICAgIHZhciBpID0gbGlzdGVuZXJzLmxlbmd0aDtcbiAgICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICAgICAgaWYgKGxpc3RlbmVyc1tpXS5saXN0ZW5lciA9PT0gbGlzdGVuZXIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gaTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAtMTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBbGlhcyBhIG1ldGhvZCB3aGlsZSBrZWVwaW5nIHRoZSBjb250ZXh0IGNvcnJlY3QsIHRvIGFsbG93IGZvciBvdmVyd3JpdGluZyBvZiB0YXJnZXQgbWV0aG9kLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IG5hbWUgVGhlIG5hbWUgb2YgdGhlIHRhcmdldCBtZXRob2QuXG4gICAgICogQHJldHVybiB7RnVuY3Rpb259IFRoZSBhbGlhc2VkIG1ldGhvZFxuICAgICAqIEBhcGkgcHJpdmF0ZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGFsaWFzKG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIGFsaWFzQ2xvc3VyZSgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzW25hbWVdLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgbGlzdGVuZXIgYXJyYXkgZm9yIHRoZSBzcGVjaWZpZWQgZXZlbnQuXG4gICAgICogV2lsbCBpbml0aWFsaXNlIHRoZSBldmVudCBvYmplY3QgYW5kIGxpc3RlbmVyIGFycmF5cyBpZiByZXF1aXJlZC5cbiAgICAgKiBXaWxsIHJldHVybiBhbiBvYmplY3QgaWYgeW91IHVzZSBhIHJlZ2V4IHNlYXJjaC4gVGhlIG9iamVjdCBjb250YWlucyBrZXlzIGZvciBlYWNoIG1hdGNoZWQgZXZlbnQuIFNvIC9iYVtyel0vIG1pZ2h0IHJldHVybiBhbiBvYmplY3QgY29udGFpbmluZyBiYXIgYW5kIGJhei4gQnV0IG9ubHkgaWYgeW91IGhhdmUgZWl0aGVyIGRlZmluZWQgdGhlbSB3aXRoIGRlZmluZUV2ZW50IG9yIGFkZGVkIHNvbWUgbGlzdGVuZXJzIHRvIHRoZW0uXG4gICAgICogRWFjaCBwcm9wZXJ0eSBpbiB0aGUgb2JqZWN0IHJlc3BvbnNlIGlzIGFuIGFycmF5IG9mIGxpc3RlbmVyIGZ1bmN0aW9ucy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIHJldHVybiB0aGUgbGlzdGVuZXJzIGZyb20uXG4gICAgICogQHJldHVybiB7RnVuY3Rpb25bXXxPYmplY3R9IEFsbCBsaXN0ZW5lciBmdW5jdGlvbnMgZm9yIHRoZSBldmVudC5cbiAgICAgKi9cbiAgICBwcm90by5nZXRMaXN0ZW5lcnMgPSBmdW5jdGlvbiBnZXRMaXN0ZW5lcnMoZXZ0KSB7XG4gICAgICAgIHZhciBldmVudHMgPSB0aGlzLl9nZXRFdmVudHMoKTtcbiAgICAgICAgdmFyIHJlc3BvbnNlO1xuICAgICAgICB2YXIga2V5O1xuXG4gICAgICAgIC8vIFJldHVybiBhIGNvbmNhdGVuYXRlZCBhcnJheSBvZiBhbGwgbWF0Y2hpbmcgZXZlbnRzIGlmXG4gICAgICAgIC8vIHRoZSBzZWxlY3RvciBpcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbi5cbiAgICAgICAgaWYgKGV2dCBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICAgICAgcmVzcG9uc2UgPSB7fTtcbiAgICAgICAgICAgIGZvciAoa2V5IGluIGV2ZW50cykge1xuICAgICAgICAgICAgICAgIGlmIChldmVudHMuaGFzT3duUHJvcGVydHkoa2V5KSAmJiBldnQudGVzdChrZXkpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlW2tleV0gPSBldmVudHNba2V5XTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXNwb25zZSA9IGV2ZW50c1tldnRdIHx8IChldmVudHNbZXZ0XSA9IFtdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXNwb25zZTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVGFrZXMgYSBsaXN0IG9mIGxpc3RlbmVyIG9iamVjdHMgYW5kIGZsYXR0ZW5zIGl0IGludG8gYSBsaXN0IG9mIGxpc3RlbmVyIGZ1bmN0aW9ucy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0W119IGxpc3RlbmVycyBSYXcgbGlzdGVuZXIgb2JqZWN0cy5cbiAgICAgKiBAcmV0dXJuIHtGdW5jdGlvbltdfSBKdXN0IHRoZSBsaXN0ZW5lciBmdW5jdGlvbnMuXG4gICAgICovXG4gICAgcHJvdG8uZmxhdHRlbkxpc3RlbmVycyA9IGZ1bmN0aW9uIGZsYXR0ZW5MaXN0ZW5lcnMobGlzdGVuZXJzKSB7XG4gICAgICAgIHZhciBmbGF0TGlzdGVuZXJzID0gW107XG4gICAgICAgIHZhciBpO1xuXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsaXN0ZW5lcnMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgICAgIGZsYXRMaXN0ZW5lcnMucHVzaChsaXN0ZW5lcnNbaV0ubGlzdGVuZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZsYXRMaXN0ZW5lcnM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEZldGNoZXMgdGhlIHJlcXVlc3RlZCBsaXN0ZW5lcnMgdmlhIGdldExpc3RlbmVycyBidXQgd2lsbCBhbHdheXMgcmV0dXJuIHRoZSByZXN1bHRzIGluc2lkZSBhbiBvYmplY3QuIFRoaXMgaXMgbWFpbmx5IGZvciBpbnRlcm5hbCB1c2UgYnV0IG90aGVycyBtYXkgZmluZCBpdCB1c2VmdWwuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ3xSZWdFeHB9IGV2dCBOYW1lIG9mIHRoZSBldmVudCB0byByZXR1cm4gdGhlIGxpc3RlbmVycyBmcm9tLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQWxsIGxpc3RlbmVyIGZ1bmN0aW9ucyBmb3IgYW4gZXZlbnQgaW4gYW4gb2JqZWN0LlxuICAgICAqL1xuICAgIHByb3RvLmdldExpc3RlbmVyc0FzT2JqZWN0ID0gZnVuY3Rpb24gZ2V0TGlzdGVuZXJzQXNPYmplY3QoZXZ0KSB7XG4gICAgICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLmdldExpc3RlbmVycyhldnQpO1xuICAgICAgICB2YXIgcmVzcG9uc2U7XG5cbiAgICAgICAgaWYgKGxpc3RlbmVycyBpbnN0YW5jZW9mIEFycmF5KSB7XG4gICAgICAgICAgICByZXNwb25zZSA9IHt9O1xuICAgICAgICAgICAgcmVzcG9uc2VbZXZ0XSA9IGxpc3RlbmVycztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXNwb25zZSB8fCBsaXN0ZW5lcnM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiB0byB0aGUgc3BlY2lmaWVkIGV2ZW50LlxuICAgICAqIFRoZSBsaXN0ZW5lciB3aWxsIG5vdCBiZSBhZGRlZCBpZiBpdCBpcyBhIGR1cGxpY2F0ZS5cbiAgICAgKiBJZiB0aGUgbGlzdGVuZXIgcmV0dXJucyB0cnVlIHRoZW4gaXQgd2lsbCBiZSByZW1vdmVkIGFmdGVyIGl0IGlzIGNhbGxlZC5cbiAgICAgKiBJZiB5b3UgcGFzcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiBhcyB0aGUgZXZlbnQgbmFtZSB0aGVuIHRoZSBsaXN0ZW5lciB3aWxsIGJlIGFkZGVkIHRvIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIGF0dGFjaCB0aGUgbGlzdGVuZXIgdG8uXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gbGlzdGVuZXIgTWV0aG9kIHRvIGJlIGNhbGxlZCB3aGVuIHRoZSBldmVudCBpcyBlbWl0dGVkLiBJZiB0aGUgZnVuY3Rpb24gcmV0dXJucyB0cnVlIHRoZW4gaXQgd2lsbCBiZSByZW1vdmVkIGFmdGVyIGNhbGxpbmcuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBDdXJyZW50IGluc3RhbmNlIG9mIEV2ZW50RW1pdHRlciBmb3IgY2hhaW5pbmcuXG4gICAgICovXG4gICAgcHJvdG8uYWRkTGlzdGVuZXIgPSBmdW5jdGlvbiBhZGRMaXN0ZW5lcihldnQsIGxpc3RlbmVyKSB7XG4gICAgICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLmdldExpc3RlbmVyc0FzT2JqZWN0KGV2dCk7XG4gICAgICAgIHZhciBsaXN0ZW5lcklzV3JhcHBlZCA9IHR5cGVvZiBsaXN0ZW5lciA9PT0gJ29iamVjdCc7XG4gICAgICAgIHZhciBrZXk7XG5cbiAgICAgICAgZm9yIChrZXkgaW4gbGlzdGVuZXJzKSB7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzLmhhc093blByb3BlcnR5KGtleSkgJiYgaW5kZXhPZkxpc3RlbmVyKGxpc3RlbmVyc1trZXldLCBsaXN0ZW5lcikgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgbGlzdGVuZXJzW2tleV0ucHVzaChsaXN0ZW5lcklzV3JhcHBlZCA/IGxpc3RlbmVyIDoge1xuICAgICAgICAgICAgICAgICAgICBsaXN0ZW5lcjogbGlzdGVuZXIsXG4gICAgICAgICAgICAgICAgICAgIG9uY2U6IGZhbHNlXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQWxpYXMgb2YgYWRkTGlzdGVuZXJcbiAgICAgKi9cbiAgICBwcm90by5vbiA9IGFsaWFzKCdhZGRMaXN0ZW5lcicpO1xuXG4gICAgLyoqXG4gICAgICogU2VtaS1hbGlhcyBvZiBhZGRMaXN0ZW5lci4gSXQgd2lsbCBhZGQgYSBsaXN0ZW5lciB0aGF0IHdpbGwgYmVcbiAgICAgKiBhdXRvbWF0aWNhbGx5IHJlbW92ZWQgYWZ0ZXIgaXRzIGZpcnN0IGV4ZWN1dGlvbi5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIGF0dGFjaCB0aGUgbGlzdGVuZXIgdG8uXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gbGlzdGVuZXIgTWV0aG9kIHRvIGJlIGNhbGxlZCB3aGVuIHRoZSBldmVudCBpcyBlbWl0dGVkLiBJZiB0aGUgZnVuY3Rpb24gcmV0dXJucyB0cnVlIHRoZW4gaXQgd2lsbCBiZSByZW1vdmVkIGFmdGVyIGNhbGxpbmcuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBDdXJyZW50IGluc3RhbmNlIG9mIEV2ZW50RW1pdHRlciBmb3IgY2hhaW5pbmcuXG4gICAgICovXG4gICAgcHJvdG8uYWRkT25jZUxpc3RlbmVyID0gZnVuY3Rpb24gYWRkT25jZUxpc3RlbmVyKGV2dCwgbGlzdGVuZXIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRkTGlzdGVuZXIoZXZ0LCB7XG4gICAgICAgICAgICBsaXN0ZW5lcjogbGlzdGVuZXIsXG4gICAgICAgICAgICBvbmNlOiB0cnVlXG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBbGlhcyBvZiBhZGRPbmNlTGlzdGVuZXIuXG4gICAgICovXG4gICAgcHJvdG8ub25jZSA9IGFsaWFzKCdhZGRPbmNlTGlzdGVuZXInKTtcblxuICAgIC8qKlxuICAgICAqIERlZmluZXMgYW4gZXZlbnQgbmFtZS4gVGhpcyBpcyByZXF1aXJlZCBpZiB5b3Ugd2FudCB0byB1c2UgYSByZWdleCB0byBhZGQgYSBsaXN0ZW5lciB0byBtdWx0aXBsZSBldmVudHMgYXQgb25jZS4gSWYgeW91IGRvbid0IGRvIHRoaXMgdGhlbiBob3cgZG8geW91IGV4cGVjdCBpdCB0byBrbm93IHdoYXQgZXZlbnQgdG8gYWRkIHRvPyBTaG91bGQgaXQganVzdCBhZGQgdG8gZXZlcnkgcG9zc2libGUgbWF0Y2ggZm9yIGEgcmVnZXg/IE5vLiBUaGF0IGlzIHNjYXJ5IGFuZCBiYWQuXG4gICAgICogWW91IG5lZWQgdG8gdGVsbCBpdCB3aGF0IGV2ZW50IG5hbWVzIHNob3VsZCBiZSBtYXRjaGVkIGJ5IGEgcmVnZXguXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIGNyZWF0ZS5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5kZWZpbmVFdmVudCA9IGZ1bmN0aW9uIGRlZmluZUV2ZW50KGV2dCkge1xuICAgICAgICB0aGlzLmdldExpc3RlbmVycyhldnQpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVXNlcyBkZWZpbmVFdmVudCB0byBkZWZpbmUgbXVsdGlwbGUgZXZlbnRzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmdbXX0gZXZ0cyBBbiBhcnJheSBvZiBldmVudCBuYW1lcyB0byBkZWZpbmUuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBDdXJyZW50IGluc3RhbmNlIG9mIEV2ZW50RW1pdHRlciBmb3IgY2hhaW5pbmcuXG4gICAgICovXG4gICAgcHJvdG8uZGVmaW5lRXZlbnRzID0gZnVuY3Rpb24gZGVmaW5lRXZlbnRzKGV2dHMpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBldnRzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgICAgICB0aGlzLmRlZmluZUV2ZW50KGV2dHNbaV0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIGEgbGlzdGVuZXIgZnVuY3Rpb24gZnJvbSB0aGUgc3BlY2lmaWVkIGV2ZW50LlxuICAgICAqIFdoZW4gcGFzc2VkIGEgcmVndWxhciBleHByZXNzaW9uIGFzIHRoZSBldmVudCBuYW1lLCBpdCB3aWxsIHJlbW92ZSB0aGUgbGlzdGVuZXIgZnJvbSBhbGwgZXZlbnRzIHRoYXQgbWF0Y2ggaXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ3xSZWdFeHB9IGV2dCBOYW1lIG9mIHRoZSBldmVudCB0byByZW1vdmUgdGhlIGxpc3RlbmVyIGZyb20uXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gbGlzdGVuZXIgTWV0aG9kIHRvIHJlbW92ZSBmcm9tIHRoZSBldmVudC5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5yZW1vdmVMaXN0ZW5lciA9IGZ1bmN0aW9uIHJlbW92ZUxpc3RlbmVyKGV2dCwgbGlzdGVuZXIpIHtcbiAgICAgICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuZ2V0TGlzdGVuZXJzQXNPYmplY3QoZXZ0KTtcbiAgICAgICAgdmFyIGluZGV4O1xuICAgICAgICB2YXIga2V5O1xuXG4gICAgICAgIGZvciAoa2V5IGluIGxpc3RlbmVycykge1xuICAgICAgICAgICAgaWYgKGxpc3RlbmVycy5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICAgICAgaW5kZXggPSBpbmRleE9mTGlzdGVuZXIobGlzdGVuZXJzW2tleV0sIGxpc3RlbmVyKTtcblxuICAgICAgICAgICAgICAgIGlmIChpbmRleCAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgbGlzdGVuZXJzW2tleV0uc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQWxpYXMgb2YgcmVtb3ZlTGlzdGVuZXJcbiAgICAgKi9cbiAgICBwcm90by5vZmYgPSBhbGlhcygncmVtb3ZlTGlzdGVuZXInKTtcblxuICAgIC8qKlxuICAgICAqIEFkZHMgbGlzdGVuZXJzIGluIGJ1bGsgdXNpbmcgdGhlIG1hbmlwdWxhdGVMaXN0ZW5lcnMgbWV0aG9kLlxuICAgICAqIElmIHlvdSBwYXNzIGFuIG9iamVjdCBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IHlvdSBjYW4gYWRkIHRvIG11bHRpcGxlIGV2ZW50cyBhdCBvbmNlLiBUaGUgb2JqZWN0IHNob3VsZCBjb250YWluIGtleSB2YWx1ZSBwYWlycyBvZiBldmVudHMgYW5kIGxpc3RlbmVycyBvciBsaXN0ZW5lciBhcnJheXMuIFlvdSBjYW4gYWxzbyBwYXNzIGl0IGFuIGV2ZW50IG5hbWUgYW5kIGFuIGFycmF5IG9mIGxpc3RlbmVycyB0byBiZSBhZGRlZC5cbiAgICAgKiBZb3UgY2FuIGFsc28gcGFzcyBpdCBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBhZGQgdGhlIGFycmF5IG9mIGxpc3RlbmVycyB0byBhbGwgZXZlbnRzIHRoYXQgbWF0Y2ggaXQuXG4gICAgICogWWVhaCwgdGhpcyBmdW5jdGlvbiBkb2VzIHF1aXRlIGEgYml0LiBUaGF0J3MgcHJvYmFibHkgYSBiYWQgdGhpbmcuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R8UmVnRXhwfSBldnQgQW4gZXZlbnQgbmFtZSBpZiB5b3Ugd2lsbCBwYXNzIGFuIGFycmF5IG9mIGxpc3RlbmVycyBuZXh0LiBBbiBvYmplY3QgaWYgeW91IHdpc2ggdG8gYWRkIHRvIG11bHRpcGxlIGV2ZW50cyBhdCBvbmNlLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb25bXX0gW2xpc3RlbmVyc10gQW4gb3B0aW9uYWwgYXJyYXkgb2YgbGlzdGVuZXIgZnVuY3Rpb25zIHRvIGFkZC5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5hZGRMaXN0ZW5lcnMgPSBmdW5jdGlvbiBhZGRMaXN0ZW5lcnMoZXZ0LCBsaXN0ZW5lcnMpIHtcbiAgICAgICAgLy8gUGFzcyB0aHJvdWdoIHRvIG1hbmlwdWxhdGVMaXN0ZW5lcnNcbiAgICAgICAgcmV0dXJuIHRoaXMubWFuaXB1bGF0ZUxpc3RlbmVycyhmYWxzZSwgZXZ0LCBsaXN0ZW5lcnMpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIGxpc3RlbmVycyBpbiBidWxrIHVzaW5nIHRoZSBtYW5pcHVsYXRlTGlzdGVuZXJzIG1ldGhvZC5cbiAgICAgKiBJZiB5b3UgcGFzcyBhbiBvYmplY3QgYXMgdGhlIHNlY29uZCBhcmd1bWVudCB5b3UgY2FuIHJlbW92ZSBmcm9tIG11bHRpcGxlIGV2ZW50cyBhdCBvbmNlLiBUaGUgb2JqZWN0IHNob3VsZCBjb250YWluIGtleSB2YWx1ZSBwYWlycyBvZiBldmVudHMgYW5kIGxpc3RlbmVycyBvciBsaXN0ZW5lciBhcnJheXMuXG4gICAgICogWW91IGNhbiBhbHNvIHBhc3MgaXQgYW4gZXZlbnQgbmFtZSBhbmQgYW4gYXJyYXkgb2YgbGlzdGVuZXJzIHRvIGJlIHJlbW92ZWQuXG4gICAgICogWW91IGNhbiBhbHNvIHBhc3MgaXQgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gcmVtb3ZlIHRoZSBsaXN0ZW5lcnMgZnJvbSBhbGwgZXZlbnRzIHRoYXQgbWF0Y2ggaXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R8UmVnRXhwfSBldnQgQW4gZXZlbnQgbmFtZSBpZiB5b3Ugd2lsbCBwYXNzIGFuIGFycmF5IG9mIGxpc3RlbmVycyBuZXh0LiBBbiBvYmplY3QgaWYgeW91IHdpc2ggdG8gcmVtb3ZlIGZyb20gbXVsdGlwbGUgZXZlbnRzIGF0IG9uY2UuXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbltdfSBbbGlzdGVuZXJzXSBBbiBvcHRpb25hbCBhcnJheSBvZiBsaXN0ZW5lciBmdW5jdGlvbnMgdG8gcmVtb3ZlLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLnJlbW92ZUxpc3RlbmVycyA9IGZ1bmN0aW9uIHJlbW92ZUxpc3RlbmVycyhldnQsIGxpc3RlbmVycykge1xuICAgICAgICAvLyBQYXNzIHRocm91Z2ggdG8gbWFuaXB1bGF0ZUxpc3RlbmVyc1xuICAgICAgICByZXR1cm4gdGhpcy5tYW5pcHVsYXRlTGlzdGVuZXJzKHRydWUsIGV2dCwgbGlzdGVuZXJzKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogRWRpdHMgbGlzdGVuZXJzIGluIGJ1bGsuIFRoZSBhZGRMaXN0ZW5lcnMgYW5kIHJlbW92ZUxpc3RlbmVycyBtZXRob2RzIGJvdGggdXNlIHRoaXMgdG8gZG8gdGhlaXIgam9iLiBZb3Ugc2hvdWxkIHJlYWxseSB1c2UgdGhvc2UgaW5zdGVhZCwgdGhpcyBpcyBhIGxpdHRsZSBsb3dlciBsZXZlbC5cbiAgICAgKiBUaGUgZmlyc3QgYXJndW1lbnQgd2lsbCBkZXRlcm1pbmUgaWYgdGhlIGxpc3RlbmVycyBhcmUgcmVtb3ZlZCAodHJ1ZSkgb3IgYWRkZWQgKGZhbHNlKS5cbiAgICAgKiBJZiB5b3UgcGFzcyBhbiBvYmplY3QgYXMgdGhlIHNlY29uZCBhcmd1bWVudCB5b3UgY2FuIGFkZC9yZW1vdmUgZnJvbSBtdWx0aXBsZSBldmVudHMgYXQgb25jZS4gVGhlIG9iamVjdCBzaG91bGQgY29udGFpbiBrZXkgdmFsdWUgcGFpcnMgb2YgZXZlbnRzIGFuZCBsaXN0ZW5lcnMgb3IgbGlzdGVuZXIgYXJyYXlzLlxuICAgICAqIFlvdSBjYW4gYWxzbyBwYXNzIGl0IGFuIGV2ZW50IG5hbWUgYW5kIGFuIGFycmF5IG9mIGxpc3RlbmVycyB0byBiZSBhZGRlZC9yZW1vdmVkLlxuICAgICAqIFlvdSBjYW4gYWxzbyBwYXNzIGl0IGEgcmVndWxhciBleHByZXNzaW9uIHRvIG1hbmlwdWxhdGUgdGhlIGxpc3RlbmVycyBvZiBhbGwgZXZlbnRzIHRoYXQgbWF0Y2ggaXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0Jvb2xlYW59IHJlbW92ZSBUcnVlIGlmIHlvdSB3YW50IHRvIHJlbW92ZSBsaXN0ZW5lcnMsIGZhbHNlIGlmIHlvdSB3YW50IHRvIGFkZC5cbiAgICAgKiBAcGFyYW0ge1N0cmluZ3xPYmplY3R8UmVnRXhwfSBldnQgQW4gZXZlbnQgbmFtZSBpZiB5b3Ugd2lsbCBwYXNzIGFuIGFycmF5IG9mIGxpc3RlbmVycyBuZXh0LiBBbiBvYmplY3QgaWYgeW91IHdpc2ggdG8gYWRkL3JlbW92ZSBmcm9tIG11bHRpcGxlIGV2ZW50cyBhdCBvbmNlLlxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb25bXX0gW2xpc3RlbmVyc10gQW4gb3B0aW9uYWwgYXJyYXkgb2YgbGlzdGVuZXIgZnVuY3Rpb25zIHRvIGFkZC9yZW1vdmUuXG4gICAgICogQHJldHVybiB7T2JqZWN0fSBDdXJyZW50IGluc3RhbmNlIG9mIEV2ZW50RW1pdHRlciBmb3IgY2hhaW5pbmcuXG4gICAgICovXG4gICAgcHJvdG8ubWFuaXB1bGF0ZUxpc3RlbmVycyA9IGZ1bmN0aW9uIG1hbmlwdWxhdGVMaXN0ZW5lcnMocmVtb3ZlLCBldnQsIGxpc3RlbmVycykge1xuICAgICAgICB2YXIgaTtcbiAgICAgICAgdmFyIHZhbHVlO1xuICAgICAgICB2YXIgc2luZ2xlID0gcmVtb3ZlID8gdGhpcy5yZW1vdmVMaXN0ZW5lciA6IHRoaXMuYWRkTGlzdGVuZXI7XG4gICAgICAgIHZhciBtdWx0aXBsZSA9IHJlbW92ZSA/IHRoaXMucmVtb3ZlTGlzdGVuZXJzIDogdGhpcy5hZGRMaXN0ZW5lcnM7XG5cbiAgICAgICAgLy8gSWYgZXZ0IGlzIGFuIG9iamVjdCB0aGVuIHBhc3MgZWFjaCBvZiBpdHMgcHJvcGVydGllcyB0byB0aGlzIG1ldGhvZFxuICAgICAgICBpZiAodHlwZW9mIGV2dCA9PT0gJ29iamVjdCcgJiYgIShldnQgaW5zdGFuY2VvZiBSZWdFeHApKSB7XG4gICAgICAgICAgICBmb3IgKGkgaW4gZXZ0KSB7XG4gICAgICAgICAgICAgICAgaWYgKGV2dC5oYXNPd25Qcm9wZXJ0eShpKSAmJiAodmFsdWUgPSBldnRbaV0pKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFBhc3MgdGhlIHNpbmdsZSBsaXN0ZW5lciBzdHJhaWdodCB0aHJvdWdoIHRvIHRoZSBzaW5ndWxhciBtZXRob2RcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2luZ2xlLmNhbGwodGhpcywgaSwgdmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3RoZXJ3aXNlIHBhc3MgYmFjayB0byB0aGUgbXVsdGlwbGUgZnVuY3Rpb25cbiAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpcGxlLmNhbGwodGhpcywgaSwgdmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gU28gZXZ0IG11c3QgYmUgYSBzdHJpbmdcbiAgICAgICAgICAgIC8vIEFuZCBsaXN0ZW5lcnMgbXVzdCBiZSBhbiBhcnJheSBvZiBsaXN0ZW5lcnNcbiAgICAgICAgICAgIC8vIExvb3Agb3ZlciBpdCBhbmQgcGFzcyBlYWNoIG9uZSB0byB0aGUgbXVsdGlwbGUgbWV0aG9kXG4gICAgICAgICAgICBpID0gbGlzdGVuZXJzLmxlbmd0aDtcbiAgICAgICAgICAgIHdoaWxlIChpLS0pIHtcbiAgICAgICAgICAgICAgICBzaW5nbGUuY2FsbCh0aGlzLCBldnQsIGxpc3RlbmVyc1tpXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyBhbGwgbGlzdGVuZXJzIGZyb20gYSBzcGVjaWZpZWQgZXZlbnQuXG4gICAgICogSWYgeW91IGRvIG5vdCBzcGVjaWZ5IGFuIGV2ZW50IHRoZW4gYWxsIGxpc3RlbmVycyB3aWxsIGJlIHJlbW92ZWQuXG4gICAgICogVGhhdCBtZWFucyBldmVyeSBldmVudCB3aWxsIGJlIGVtcHRpZWQuXG4gICAgICogWW91IGNhbiBhbHNvIHBhc3MgYSByZWdleCB0byByZW1vdmUgYWxsIGV2ZW50cyB0aGF0IG1hdGNoIGl0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd8UmVnRXhwfSBbZXZ0XSBPcHRpb25hbCBuYW1lIG9mIHRoZSBldmVudCB0byByZW1vdmUgYWxsIGxpc3RlbmVycyBmb3IuIFdpbGwgcmVtb3ZlIGZyb20gZXZlcnkgZXZlbnQgaWYgbm90IHBhc3NlZC5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5yZW1vdmVFdmVudCA9IGZ1bmN0aW9uIHJlbW92ZUV2ZW50KGV2dCkge1xuICAgICAgICB2YXIgdHlwZSA9IHR5cGVvZiBldnQ7XG4gICAgICAgIHZhciBldmVudHMgPSB0aGlzLl9nZXRFdmVudHMoKTtcbiAgICAgICAgdmFyIGtleTtcblxuICAgICAgICAvLyBSZW1vdmUgZGlmZmVyZW50IHRoaW5ncyBkZXBlbmRpbmcgb24gdGhlIHN0YXRlIG9mIGV2dFxuICAgICAgICBpZiAodHlwZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIC8vIFJlbW92ZSBhbGwgbGlzdGVuZXJzIGZvciB0aGUgc3BlY2lmaWVkIGV2ZW50XG4gICAgICAgICAgICBkZWxldGUgZXZlbnRzW2V2dF07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZXZ0IGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgICAgICAgICAvLyBSZW1vdmUgYWxsIGV2ZW50cyBtYXRjaGluZyB0aGUgcmVnZXguXG4gICAgICAgICAgICBmb3IgKGtleSBpbiBldmVudHMpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXZlbnRzLmhhc093blByb3BlcnR5KGtleSkgJiYgZXZ0LnRlc3Qoa2V5KSkge1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgZXZlbnRzW2tleV07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gUmVtb3ZlIGFsbCBsaXN0ZW5lcnMgaW4gYWxsIGV2ZW50c1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMuX2V2ZW50cztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBBbGlhcyBvZiByZW1vdmVFdmVudC5cbiAgICAgKlxuICAgICAqIEFkZGVkIHRvIG1pcnJvciB0aGUgbm9kZSBBUEkuXG4gICAgICovXG4gICAgcHJvdG8ucmVtb3ZlQWxsTGlzdGVuZXJzID0gYWxpYXMoJ3JlbW92ZUV2ZW50Jyk7XG5cbiAgICAvKipcbiAgICAgKiBFbWl0cyBhbiBldmVudCBvZiB5b3VyIGNob2ljZS5cbiAgICAgKiBXaGVuIGVtaXR0ZWQsIGV2ZXJ5IGxpc3RlbmVyIGF0dGFjaGVkIHRvIHRoYXQgZXZlbnQgd2lsbCBiZSBleGVjdXRlZC5cbiAgICAgKiBJZiB5b3UgcGFzcyB0aGUgb3B0aW9uYWwgYXJndW1lbnQgYXJyYXkgdGhlbiB0aG9zZSBhcmd1bWVudHMgd2lsbCBiZSBwYXNzZWQgdG8gZXZlcnkgbGlzdGVuZXIgdXBvbiBleGVjdXRpb24uXG4gICAgICogQmVjYXVzZSBpdCB1c2VzIGBhcHBseWAsIHlvdXIgYXJyYXkgb2YgYXJndW1lbnRzIHdpbGwgYmUgcGFzc2VkIGFzIGlmIHlvdSB3cm90ZSB0aGVtIG91dCBzZXBhcmF0ZWx5LlxuICAgICAqIFNvIHRoZXkgd2lsbCBub3QgYXJyaXZlIHdpdGhpbiB0aGUgYXJyYXkgb24gdGhlIG90aGVyIHNpZGUsIHRoZXkgd2lsbCBiZSBzZXBhcmF0ZS5cbiAgICAgKiBZb3UgY2FuIGFsc28gcGFzcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBlbWl0IHRvIGFsbCBldmVudHMgdGhhdCBtYXRjaCBpdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3RyaW5nfFJlZ0V4cH0gZXZ0IE5hbWUgb2YgdGhlIGV2ZW50IHRvIGVtaXQgYW5kIGV4ZWN1dGUgbGlzdGVuZXJzIGZvci5cbiAgICAgKiBAcGFyYW0ge0FycmF5fSBbYXJnc10gT3B0aW9uYWwgYXJyYXkgb2YgYXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byBlYWNoIGxpc3RlbmVyLlxuICAgICAqIEByZXR1cm4ge09iamVjdH0gQ3VycmVudCBpbnN0YW5jZSBvZiBFdmVudEVtaXR0ZXIgZm9yIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHByb3RvLmVtaXRFdmVudCA9IGZ1bmN0aW9uIGVtaXRFdmVudChldnQsIGFyZ3MpIHtcbiAgICAgICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuZ2V0TGlzdGVuZXJzQXNPYmplY3QoZXZ0KTtcbiAgICAgICAgdmFyIGxpc3RlbmVyO1xuICAgICAgICB2YXIgaTtcbiAgICAgICAgdmFyIGtleTtcbiAgICAgICAgdmFyIHJlc3BvbnNlO1xuXG4gICAgICAgIGZvciAoa2V5IGluIGxpc3RlbmVycykge1xuICAgICAgICAgICAgaWYgKGxpc3RlbmVycy5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICAgICAgaSA9IGxpc3RlbmVyc1trZXldLmxlbmd0aDtcblxuICAgICAgICAgICAgICAgIHdoaWxlIChpLS0pIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlIGxpc3RlbmVyIHJldHVybnMgdHJ1ZSB0aGVuIGl0IHNoYWxsIGJlIHJlbW92ZWQgZnJvbSB0aGUgZXZlbnRcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGZ1bmN0aW9uIGlzIGV4ZWN1dGVkIGVpdGhlciB3aXRoIGEgYmFzaWMgY2FsbCBvciBhbiBhcHBseSBpZiB0aGVyZSBpcyBhbiBhcmdzIGFycmF5XG4gICAgICAgICAgICAgICAgICAgIGxpc3RlbmVyID0gbGlzdGVuZXJzW2tleV1baV07XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGxpc3RlbmVyLm9uY2UgPT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIoZXZ0LCBsaXN0ZW5lci5saXN0ZW5lcik7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICByZXNwb25zZSA9IGxpc3RlbmVyLmxpc3RlbmVyLmFwcGx5KHRoaXMsIGFyZ3MgfHwgW10pO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZSA9PT0gdGhpcy5fZ2V0T25jZVJldHVyblZhbHVlKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIoZXZ0LCBsaXN0ZW5lci5saXN0ZW5lcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQWxpYXMgb2YgZW1pdEV2ZW50XG4gICAgICovXG4gICAgcHJvdG8udHJpZ2dlciA9IGFsaWFzKCdlbWl0RXZlbnQnKTtcblxuICAgIC8qKlxuICAgICAqIFN1YnRseSBkaWZmZXJlbnQgZnJvbSBlbWl0RXZlbnQgaW4gdGhhdCBpdCB3aWxsIHBhc3MgaXRzIGFyZ3VtZW50cyBvbiB0byB0aGUgbGlzdGVuZXJzLCBhcyBvcHBvc2VkIHRvIHRha2luZyBhIHNpbmdsZSBhcnJheSBvZiBhcmd1bWVudHMgdG8gcGFzcyBvbi5cbiAgICAgKiBBcyB3aXRoIGVtaXRFdmVudCwgeW91IGNhbiBwYXNzIGEgcmVnZXggaW4gcGxhY2Ugb2YgdGhlIGV2ZW50IG5hbWUgdG8gZW1pdCB0byBhbGwgZXZlbnRzIHRoYXQgbWF0Y2ggaXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N0cmluZ3xSZWdFeHB9IGV2dCBOYW1lIG9mIHRoZSBldmVudCB0byBlbWl0IGFuZCBleGVjdXRlIGxpc3RlbmVycyBmb3IuXG4gICAgICogQHBhcmFtIHsuLi4qfSBPcHRpb25hbCBhZGRpdGlvbmFsIGFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gZWFjaCBsaXN0ZW5lci5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5lbWl0ID0gZnVuY3Rpb24gZW1pdChldnQpIHtcbiAgICAgICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgICAgICByZXR1cm4gdGhpcy5lbWl0RXZlbnQoZXZ0LCBhcmdzKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgY3VycmVudCB2YWx1ZSB0byBjaGVjayBhZ2FpbnN0IHdoZW4gZXhlY3V0aW5nIGxpc3RlbmVycy4gSWYgYVxuICAgICAqIGxpc3RlbmVycyByZXR1cm4gdmFsdWUgbWF0Y2hlcyB0aGUgb25lIHNldCBoZXJlIHRoZW4gaXQgd2lsbCBiZSByZW1vdmVkXG4gICAgICogYWZ0ZXIgZXhlY3V0aW9uLiBUaGlzIHZhbHVlIGRlZmF1bHRzIHRvIHRydWUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0geyp9IHZhbHVlIFRoZSBuZXcgdmFsdWUgdG8gY2hlY2sgZm9yIHdoZW4gZXhlY3V0aW5nIGxpc3RlbmVycy5cbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IEN1cnJlbnQgaW5zdGFuY2Ugb2YgRXZlbnRFbWl0dGVyIGZvciBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBwcm90by5zZXRPbmNlUmV0dXJuVmFsdWUgPSBmdW5jdGlvbiBzZXRPbmNlUmV0dXJuVmFsdWUodmFsdWUpIHtcbiAgICAgICAgdGhpcy5fb25jZVJldHVyblZhbHVlID0gdmFsdWU7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBGZXRjaGVzIHRoZSBjdXJyZW50IHZhbHVlIHRvIGNoZWNrIGFnYWluc3Qgd2hlbiBleGVjdXRpbmcgbGlzdGVuZXJzLiBJZlxuICAgICAqIHRoZSBsaXN0ZW5lcnMgcmV0dXJuIHZhbHVlIG1hdGNoZXMgdGhpcyBvbmUgdGhlbiBpdCBzaG91bGQgYmUgcmVtb3ZlZFxuICAgICAqIGF1dG9tYXRpY2FsbHkuIEl0IHdpbGwgcmV0dXJuIHRydWUgYnkgZGVmYXVsdC5cbiAgICAgKlxuICAgICAqIEByZXR1cm4geyp8Qm9vbGVhbn0gVGhlIGN1cnJlbnQgdmFsdWUgdG8gY2hlY2sgZm9yIG9yIHRoZSBkZWZhdWx0LCB0cnVlLlxuICAgICAqIEBhcGkgcHJpdmF0ZVxuICAgICAqL1xuICAgIHByb3RvLl9nZXRPbmNlUmV0dXJuVmFsdWUgPSBmdW5jdGlvbiBfZ2V0T25jZVJldHVyblZhbHVlKCkge1xuICAgICAgICBpZiAodGhpcy5oYXNPd25Qcm9wZXJ0eSgnX29uY2VSZXR1cm5WYWx1ZScpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fb25jZVJldHVyblZhbHVlO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogRmV0Y2hlcyB0aGUgZXZlbnRzIG9iamVjdCBhbmQgY3JlYXRlcyBvbmUgaWYgcmVxdWlyZWQuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IFRoZSBldmVudHMgc3RvcmFnZSBvYmplY3QuXG4gICAgICogQGFwaSBwcml2YXRlXG4gICAgICovXG4gICAgcHJvdG8uX2dldEV2ZW50cyA9IGZ1bmN0aW9uIF9nZXRFdmVudHMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9ldmVudHMgfHwgKHRoaXMuX2V2ZW50cyA9IHt9KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmV2ZXJ0cyB0aGUgZ2xvYmFsIHtAbGluayBFdmVudEVtaXR0ZXJ9IHRvIGl0cyBwcmV2aW91cyB2YWx1ZSBhbmQgcmV0dXJucyBhIHJlZmVyZW5jZSB0byB0aGlzIHZlcnNpb24uXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtGdW5jdGlvbn0gTm9uIGNvbmZsaWN0aW5nIEV2ZW50RW1pdHRlciBjbGFzcy5cbiAgICAgKi9cbiAgICBFdmVudEVtaXR0ZXIubm9Db25mbGljdCA9IGZ1bmN0aW9uIG5vQ29uZmxpY3QoKSB7XG4gICAgICAgIGV4cG9ydHMuRXZlbnRFbWl0dGVyID0gb3JpZ2luYWxHbG9iYWxWYWx1ZTtcbiAgICAgICAgcmV0dXJuIEV2ZW50RW1pdHRlcjtcbiAgICB9O1xuXG4gICAgLy8gRXhwb3NlIHRoZSBjbGFzcyBlaXRoZXIgdmlhIEFNRCwgQ29tbW9uSlMgb3IgdGhlIGdsb2JhbCBvYmplY3RcbiAgICBpZiAodHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kKSB7XG4gICAgICAgIGRlZmluZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gRXZlbnRFbWl0dGVyO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgZWxzZSBpZiAodHlwZW9mIG1vZHVsZSA9PT0gJ29iamVjdCcgJiYgbW9kdWxlLmV4cG9ydHMpe1xuICAgICAgICBtb2R1bGUuZXhwb3J0cyA9IEV2ZW50RW1pdHRlcjtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGV4cG9ydHMuRXZlbnRFbWl0dGVyID0gRXZlbnRFbWl0dGVyO1xuICAgIH1cbn0uY2FsbCh0aGlzKSk7XG4iLCJcbi8qKlxuICogTW9kdWxlIGRlcGVuZGVuY2llcy5cbiAqL1xuXG52YXIgZ2xvYmFsID0gKGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpczsgfSkoKTtcblxuLyoqXG4gKiBXZWJTb2NrZXQgY29uc3RydWN0b3IuXG4gKi9cblxudmFyIFdlYlNvY2tldCA9IGdsb2JhbC5XZWJTb2NrZXQgfHwgZ2xvYmFsLk1veldlYlNvY2tldDtcblxuLyoqXG4gKiBNb2R1bGUgZXhwb3J0cy5cbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IFdlYlNvY2tldCA/IHdzIDogbnVsbDtcblxuLyoqXG4gKiBXZWJTb2NrZXQgY29uc3RydWN0b3IuXG4gKlxuICogVGhlIHRoaXJkIGBvcHRzYCBvcHRpb25zIG9iamVjdCBnZXRzIGlnbm9yZWQgaW4gd2ViIGJyb3dzZXJzLCBzaW5jZSBpdCdzXG4gKiBub24tc3RhbmRhcmQsIGFuZCB0aHJvd3MgYSBUeXBlRXJyb3IgaWYgcGFzc2VkIHRvIHRoZSBjb25zdHJ1Y3Rvci5cbiAqIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL2VpbmFyb3Mvd3MvaXNzdWVzLzIyN1xuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSB1cmlcbiAqIEBwYXJhbSB7QXJyYXl9IHByb3RvY29scyAob3B0aW9uYWwpXG4gKiBAcGFyYW0ge09iamVjdCkgb3B0cyAob3B0aW9uYWwpXG4gKiBAYXBpIHB1YmxpY1xuICovXG5cbmZ1bmN0aW9uIHdzKHVyaSwgcHJvdG9jb2xzLCBvcHRzKSB7XG4gIHZhciBpbnN0YW5jZTtcbiAgaWYgKHByb3RvY29scykge1xuICAgIGluc3RhbmNlID0gbmV3IFdlYlNvY2tldCh1cmksIHByb3RvY29scyk7XG4gIH0gZWxzZSB7XG4gICAgaW5zdGFuY2UgPSBuZXcgV2ViU29ja2V0KHVyaSk7XG4gIH1cbiAgcmV0dXJuIGluc3RhbmNlO1xufVxuXG5pZiAoV2ViU29ja2V0KSB3cy5wcm90b3R5cGUgPSBXZWJTb2NrZXQucHJvdG90eXBlO1xuIiwiaW1wb3J0IHsgT3BlblZpZHUgfSBmcm9tICcuL09wZW5WaWR1JztcblxuLy9UaGlzIGV4cG9ydCB3aXRoIC0tc3RhbmRhbG9uZSBvcHRpb24gYWxsb3dzIHVzaW5nIE9wZW5WaWR1IGZyb20gYm93c2VyIHdpdGggbmFtZXNwYWNlXG4vL2V4cG9ydCB7IE9wZW5WaWR1IH0gZnJvbSAnLi9PcGVuVmlkdSc7XG5cbi8vVGhpcyBcImhhY2tcIiBhbGxvd3MgdG8gdXNlIE9wZW5WaWR1IGZyb20gdGhlIGdsb2JhbCBzcGFjZSB3aW5kb3dcbmlmKHdpbmRvdyl7XG4gICAgd2luZG93W1wiT3BlblZpZHVcIl0gPSBPcGVuVmlkdTtcbn1cblxuLy9Db21tYW5kIHRvIGdlbmVyYXRlIGJ1bmRsZS5qcyB3aXRob3V0IG5hbWVzcGFjZVxuLy93YXRjaGlmeSBNYWluLnRzIC1wIFsgdHNpZnkgXSAtLWV4Y2x1ZGUga3VyZW50by1icm93c2VyLWV4dGVuc2lvbnMgLS1kZWJ1ZyAtbyAuLi9zdGF0aWMvanMvT3BlblZpZHUuanMgLXYiLCIvKlxuICogKEMpIENvcHlyaWdodCAyMDE2IE9wZW5WaWR1IChodHRwOi8va3VyZW50by5vcmcvKVxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICovXG5pbXBvcnQgeyBPcGVuVmlkdUludGVybmFsIH0gZnJvbSAnLi4vT3BlblZpZHVJbnRlcm5hbC9PcGVuVmlkdUludGVybmFsJztcblxuaW1wb3J0IHsgU2Vzc2lvbiB9IGZyb20gJy4vU2Vzc2lvbic7XG5pbXBvcnQgeyBQdWJsaXNoZXIgfSBmcm9tICcuL1B1Ymxpc2hlcic7XG5cbmltcG9ydCAqIGFzIGFkYXB0ZXIgZnJvbSAnd2VicnRjLWFkYXB0ZXInO1xuXG5pZiAod2luZG93KSB7XG4gICAgd2luZG93W1wiYWRhcHRlclwiXSA9IGFkYXB0ZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBPcGVuVmlkdSB7XG5cbiAgICBvcGVuVmlkdTogT3BlblZpZHVJbnRlcm5hbDtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLm9wZW5WaWR1ID0gbmV3IE9wZW5WaWR1SW50ZXJuYWwoKTtcbiAgICB9O1xuXG4gICAgaW5pdFNlc3Npb24oYXBpS2V5OiBzdHJpbmcsIHNlc3Npb25JZDogc3RyaW5nKTogU2Vzc2lvbjtcbiAgICBpbml0U2Vzc2lvbihzZXNzaW9uSWQ6IHN0cmluZyk6IFNlc3Npb247XG5cbiAgICBpbml0U2Vzc2lvbihwYXJhbTEsIHBhcmFtMj8pOiBhbnkge1xuICAgICAgICBpZiAodGhpcy5jaGVja1N5c3RlbVJlcXVpcmVtZW50cygpKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHBhcmFtMiA9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBTZXNzaW9uKHRoaXMub3BlblZpZHUuaW5pdFNlc3Npb24ocGFyYW0yKSwgdGhpcyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgU2Vzc2lvbih0aGlzLm9wZW5WaWR1LmluaXRTZXNzaW9uKHBhcmFtMSksIHRoaXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYWxlcnQoXCJCcm93c2VyIG5vdCBzdXBwb3J0ZWRcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpbml0UHVibGlzaGVyKHBhcmVudElkOiBzdHJpbmcpOiBQdWJsaXNoZXI7XG4gICAgaW5pdFB1Ymxpc2hlcihwYXJlbnRJZDogc3RyaW5nLCBjYW1lcmFPcHRpb25zOiBhbnkpOiBQdWJsaXNoZXI7XG4gICAgaW5pdFB1Ymxpc2hlcihwYXJlbnRJZDogc3RyaW5nLCBjYW1lcmFPcHRpb25zOiBhbnksIGNhbGxiYWNrOiBhbnkpOiBQdWJsaXNoZXI7XG5cbiAgICBpbml0UHVibGlzaGVyKHBhcmVudElkOiBzdHJpbmcsIGNhbWVyYU9wdGlvbnM/OiBhbnksIGNhbGxiYWNrPzogRnVuY3Rpb24pOiBhbnkge1xuICAgICAgICBpZiAodGhpcy5jaGVja1N5c3RlbVJlcXVpcmVtZW50cygpKSB7XG4gICAgICAgICAgICBpZiAoY2FtZXJhT3B0aW9ucyAhPSBudWxsKSB7XG4gICAgICAgICAgICAgICAgbGV0IGNhbWVyYU9wdGlvbnNBdXggPSB7XG4gICAgICAgICAgICAgICAgICAgIGF1ZGlvOiBjYW1lcmFPcHRpb25zLmF1ZGlvICE9IG51bGwgPyBjYW1lcmFPcHRpb25zLmF1ZGlvIDogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgdmlkZW86IGNhbWVyYU9wdGlvbnMudmlkZW8gIT0gbnVsbCA/IGNhbWVyYU9wdGlvbnMudmlkZW8gOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBkYXRhOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBtZWRpYUNvbnN0cmFpbnRzOiB0aGlzLm9wZW5WaWR1LmdlbmVyYXRlTWVkaWFDb25zdHJhaW50cyhjYW1lcmFPcHRpb25zLnF1YWxpdHkpXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBjYW1lcmFPcHRpb25zID0gY2FtZXJhT3B0aW9uc0F1eDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY2FtZXJhT3B0aW9ucyA9IHtcbiAgICAgICAgICAgICAgICAgICAgYXVkaW86IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIHZpZGVvOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBkYXRhOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBtZWRpYUNvbnN0cmFpbnRzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhdWRpbzogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvOiB7IHdpZHRoOiB7IGlkZWFsOiAxMjgwIH0gfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gbmV3IFB1Ymxpc2hlcih0aGlzLm9wZW5WaWR1LmluaXRQdWJsaXNoZXJUYWdnZWQocGFyZW50SWQsIGNhbWVyYU9wdGlvbnMsIGNhbGxiYWNrKSwgcGFyZW50SWQpO1xuXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhbGVydChcIkJyb3dzZXIgbm90IHN1cHBvcnRlZFwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGNoZWNrU3lzdGVtUmVxdWlyZW1lbnRzKCk6IG51bWJlciB7XG4gICAgICAgIGxldCBicm93c2VyID0gYWRhcHRlci5icm93c2VyRGV0YWlscy5icm93c2VyO1xuICAgICAgICBsZXQgdmVyc2lvbiA9IGFkYXB0ZXIuYnJvd3NlckRldGFpbHMudmVyc2lvbjtcblxuICAgICAgICAvL0J1ZyBmaXg6ICduYXZpZ2F0b3IudXNlckFnZW50JyBpbiBGaXJlZm94IGZvciBVYnVudHUgMTQuMDQgZG9lcyBub3QgcmV0dXJuIFwiRmlyZWZveC9bdmVyc2lvbl1cIiBpbiB0aGUgc3RyaW5nLCBzbyB2ZXJzaW9uIHJldHVybmVkIGlzIG51bGxcbiAgICAgICAgaWYgKChicm93c2VyID09ICdmaXJlZm94JykgJiYgKHZlcnNpb24gPT0gbnVsbCkpIHtcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICB9XG4gICAgICAgIGlmICgoKGJyb3dzZXIgPT0gJ2Nocm9tZScpICYmICh2ZXJzaW9uID49IDI4KSkgfHwgKChicm93c2VyID09ICdlZGdlJykgJiYgKHZlcnNpb24gPj0gMTIpKSB8fCAoKGJyb3dzZXIgPT0gJ2ZpcmVmb3gnKSAmJiAodmVyc2lvbiA+PSAyMikpKSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZ2V0RGV2aWNlcyhjYWxsYmFjaykge1xuICAgICAgICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmVudW1lcmF0ZURldmljZXMoKS50aGVuKChkZXZpY2VJbmZvcykgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwgZGV2aWNlSW5mb3MpO1xuICAgICAgICB9KS5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiRXJyb3IgZ2V0dGluZyBkZXZpY2VzOiBcIiArIGVycm9yKTtcbiAgICAgICAgICAgIGNhbGxiYWNrKGVycm9yLCBudWxsKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG59XG4iLCIvKlxuICogb3B0aW9uczogbmFtZTogWFhYIGRhdGE6IHRydWUgKE1heWJlIHRoaXMgaXMgYmFzZWQgb24gd2VicnRjKSBhdWRpbzogdHJ1ZSxcbiAqIHZpZGVvOiB0cnVlLCB1cmw6IFwiZmlsZTovLy8uLi5cIiA+IFBsYXllciBzY3JlZW46IHRydWUgPiBEZXNrdG9wIChpbXBsaWNpdFxuICogdmlkZW86dHJ1ZSwgYXVkaW86ZmFsc2UpIGF1ZGlvOiB0cnVlLCB2aWRlbzogdHJ1ZSA+IFdlYmNhbVxuICpcbiAqIHN0cmVhbS5oYXNBdWRpbygpOyBzdHJlYW0uaGFzVmlkZW8oKTsgc3RyZWFtLmhhc0RhdGEoKTtcbiAqL1xuaW1wb3J0IHsgU3RyZWFtLCBTdHJlYW1PcHRpb25zLCBWaWRlb09wdGlvbnMgfSBmcm9tICcuLi9PcGVuVmlkdUludGVybmFsL1N0cmVhbSc7XG5pbXBvcnQgeyBTZXNzaW9uIH0gZnJvbSAnLi9TZXNzaW9uJztcblxuaW1wb3J0IEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ3dvbGZ5ODctZXZlbnRlbWl0dGVyJyk7XG5cbmV4cG9ydCBjbGFzcyBQdWJsaXNoZXIge1xuXG4gICAgcHJpdmF0ZSBlZSA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAgIGFjY2Vzc0FsbG93ZWQgPSBmYWxzZTtcbiAgICBlbGVtZW50OiBFbGVtZW50O1xuICAgIGlkOiBzdHJpbmc7XG4gICAgc3RyZWFtOiBTdHJlYW07XG4gICAgc2Vzc2lvbjogU2Vzc2lvbjsgLy9Jbml0aWFsaXplZCBieSBTZXNzaW9uLnB1Ymxpc2goUHVibGlzaGVyKVxuXG4gICAgY29uc3RydWN0b3Ioc3RyZWFtOiBTdHJlYW0sIHBhcmVudElkOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5zdHJlYW0gPSBzdHJlYW07XG5cbiAgICAgICAgdGhpcy5zdHJlYW0uYWRkRXZlbnRMaXN0ZW5lcignY2FtZXJhLWFjY2Vzcy1jaGFuZ2VkJywgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFjY2Vzc0FsbG93ZWQgPSBldmVudC5hY2Nlc3NBbGxvd2VkO1xuICAgICAgICAgICAgaWYgKHRoaXMuYWNjZXNzQWxsb3dlZCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdhY2Nlc3NBbGxvd2VkJyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdhY2Nlc3NEZW5pZWQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHBhcmVudElkKSAhPSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLmVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChwYXJlbnRJZCkhITtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1Ymxpc2hBdWRpbyh2YWx1ZTogYm9vbGVhbikge1xuICAgICAgICB0aGlzLnN0cmVhbS5nZXRXZWJSdGNQZWVyKCkuYXVkaW9FbmFibGVkID0gdmFsdWU7XG4gICAgfVxuXG4gICAgcHVibGlzaFZpZGVvKHZhbHVlOiBib29sZWFuKSB7XG4gICAgICAgIHRoaXMuc3RyZWFtLmdldFdlYlJ0Y1BlZXIoKS52aWRlb0VuYWJsZWQgPSB2YWx1ZTtcbiAgICB9XG5cbiAgICBkZXN0cm95KCkge1xuICAgICAgICB0aGlzLnNlc3Npb24udW5wdWJsaXNoKHRoaXMpO1xuICAgICAgICB0aGlzLnN0cmVhbS5kaXNwb3NlKCk7XG4gICAgICAgIHRoaXMuc3RyZWFtLnJlbW92ZVZpZGVvKHRoaXMuZWxlbWVudCk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIG9uKGV2ZW50TmFtZTogc3RyaW5nLCBjYWxsYmFjaykge1xuICAgICAgICB0aGlzLmVlLmFkZExpc3RlbmVyKGV2ZW50TmFtZSwgZXZlbnQgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2soZXZlbnQpO1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGV2ZW50TmFtZSA9PSAndmlkZW9FbGVtZW50Q3JlYXRlZCcpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0cmVhbS5pc1JlYWR5KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3ZpZGVvRWxlbWVudENyZWF0ZWQnLCBbe1xuICAgICAgICAgICAgICAgICAgICBlbGVtZW50OiB0aGlzLnN0cmVhbS5nZXRWaWRlb0VsZW1lbnQoKVxuICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdHJlYW0uYWRkRXZlbnRMaXN0ZW5lcigndmlkZW8tZWxlbWVudC1jcmVhdGVkLWJ5LXN0cmVhbScsIChlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignUHVibGlzaGVyIGVtaXR0aW5nIHZpZGVvRWxlbWVudENyZWF0ZWQnKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pZCA9IGVsZW1lbnQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCd2aWRlb0VsZW1lbnRDcmVhdGVkJywgW3tcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IGVsZW1lbnQuZWxlbWVudFxuICAgICAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50TmFtZSA9PSAnc3RyZWFtQ3JlYXRlZCcpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0cmVhbS5pc1JlYWR5KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3N0cmVhbUNyZWF0ZWQnLCBbeyBzdHJlYW06IHRoaXMuc3RyZWFtIH1dKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdHJlYW0uYWRkRXZlbnRMaXN0ZW5lcignc3RyZWFtLWNyZWF0ZWQtYnktcHVibGlzaGVyJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1B1Ymxpc2hlciBlbWl0dGluZyBzdHJlYW1DcmVhdGVkJyk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzdHJlYW1DcmVhdGVkJywgW3sgc3RyZWFtOiB0aGlzLnN0cmVhbSB9XSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50TmFtZSA9PSAnYWNjZXNzQWxsb3dlZCcpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnN0cmVhbS5hY2Nlc3NJc0FsbG93ZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnYWNjZXNzQWxsb3dlZCcpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbS5hZGRFdmVudExpc3RlbmVyKCdhY2Nlc3MtYWxsb3dlZC1ieS1wdWJsaXNoZXInLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdhY2Nlc3NBbGxvd2VkJyk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV2ZW50TmFtZSA9PSAnYWNjZXNzRGVuaWVkJykge1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RyZWFtLmFjY2Vzc0lzRGVuaWVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2FjY2Vzc0RlbmllZCcpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbS5hZGRFdmVudExpc3RlbmVyKCdhY2Nlc3MtZGVuaWVkLWJ5LXB1Ymxpc2hlcicsICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2FjY2Vzc0RlbmllZCcpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufSIsImltcG9ydCB7IFNlc3Npb25JbnRlcm5hbCwgU2Vzc2lvbk9wdGlvbnMgfSBmcm9tICcuLi9PcGVuVmlkdUludGVybmFsL1Nlc3Npb25JbnRlcm5hbCc7XG5pbXBvcnQgeyBTdHJlYW0gfSBmcm9tICcuLi9PcGVuVmlkdUludGVybmFsL1N0cmVhbSc7XG5pbXBvcnQgeyBDb25uZWN0aW9uIH0gZnJvbSBcIi4uL09wZW5WaWR1SW50ZXJuYWwvQ29ubmVjdGlvblwiO1xuXG5pbXBvcnQgeyBPcGVuVmlkdSB9IGZyb20gJy4vT3BlblZpZHUnO1xuaW1wb3J0IHsgUHVibGlzaGVyIH0gZnJvbSAnLi9QdWJsaXNoZXInO1xuaW1wb3J0IHsgU3Vic2NyaWJlciB9IGZyb20gJy4vU3Vic2NyaWJlcic7XG5cbmltcG9ydCBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCd3b2xmeTg3LWV2ZW50ZW1pdHRlcicpO1xuXG5leHBvcnQgY2xhc3MgU2Vzc2lvbiB7XG5cbiAgICBzZXNzaW9uSWQ6IFN0cmluZztcbiAgICAvL2NhcGFiaWxpdGllczogQ2FwYWJpbGl0aWVzXG4gICAgY29ubmVjdGlvbjogQ29ubmVjdGlvbjtcblxuICAgIHByaXZhdGUgZWUgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIHNlc3Npb246IFNlc3Npb25JbnRlcm5hbCwgcHJpdmF0ZSBvcGVuVmlkdTogT3BlblZpZHUpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uSWQgPSBzZXNzaW9uLmdldFNlc3Npb25JZCgpO1xuXG4gICAgICAgIC8vIExpc3RlbnMgdG8gdGhlIGRlYWN0aXZhdGlvbiBvZiB0aGUgZGVmYXVsdCBiZWhhdmlvdXIgdXBvbiB0aGUgZGVsZXRpb24gb2YgYSBTdHJlYW0gb2JqZWN0XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCdzdHJlYW0tZGVzdHJveWVkLWRlZmF1bHQnLCBldmVudCA9PiB7XG4gICAgICAgICAgICBldmVudC5zdHJlYW0ucmVtb3ZlVmlkZW8oKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gTGlzdGVucyB0byB0aGUgZGVhY3RpdmF0aW9uIG9mIHRoZSBkZWZhdWx0IGJlaGF2aW91ciB1cG9uIHRoZSBkaXNjb25uZWN0aW9uIG9mIGEgU2Vzc2lvblxuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcignc2Vzc2lvbi1kaXNjb25uZWN0ZWQtZGVmYXVsdCcsICgpID0+IHtcbiAgICAgICAgICAgIGxldCBzOiBTdHJlYW07XG4gICAgICAgICAgICBmb3IgKHMgb2YgdGhpcy5vcGVuVmlkdS5vcGVuVmlkdS5nZXRSZW1vdGVTdHJlYW1zKCkpIHtcbiAgICAgICAgICAgICAgICBzLnJlbW92ZVZpZGVvKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGhpcy5jb25uZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgc3RyZWFtSWQgaW4gdGhpcy5jb25uZWN0aW9uLmdldFN0cmVhbXMoKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uZ2V0U3RyZWFtcygpW3N0cmVhbUlkXS5yZW1vdmVWaWRlbygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gU2V0cyBvciB1cGRhdGVzIHRoZSB2YWx1ZSBvZiAnY29ubmVjdGlvbicgcHJvcGVydHkuIFRyaWdnZXJlZCBieSBTZXNzaW9uSW50ZXJuYWwgd2hlbiBzdWNjZXNmdWwgY29ubmVjdGlvblxuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcigndXBkYXRlLWNvbm5lY3Rpb24tb2JqZWN0JywgZXZlbnQgPT4ge1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uID0gZXZlbnQuY29ubmVjdGlvbjtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29ubmVjdCh0b2tlbjogc3RyaW5nLCBjYWxsYmFjazogYW55KTtcbiAgICBjb25uZWN0KHRva2VuOiBzdHJpbmcsIG1ldGFkYXRhOiBzdHJpbmcsIGNhbGxiYWNrOiBhbnkpO1xuXG4gICAgY29ubmVjdChwYXJhbTEsIHBhcmFtMiwgcGFyYW0zPykge1xuICAgICAgICAvLyBFYXJseSBjb25maWd1cmF0aW9uIHRvIGRlYWN0aXZhdGUgYXV0b21hdGljIHN1YnNjcmlwdGlvbiB0byBzdHJlYW1zXG4gICAgICAgIGlmICh0eXBlb2YgcGFyYW0yID09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5jb25maWd1cmUoe1xuICAgICAgICAgICAgICAgIHNlc3Npb25JZDogdGhpcy5zZXNzaW9uLmdldFNlc3Npb25JZCgpLFxuICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50SWQ6IHBhcmFtMSxcbiAgICAgICAgICAgICAgICBtZXRhZGF0YTogcGFyYW0yLFxuICAgICAgICAgICAgICAgIHN1YnNjcmliZVRvU3RyZWFtczogZmFsc2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLmNvbm5lY3QocGFyYW0xLCBwYXJhbTMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLmNvbmZpZ3VyZSh7XG4gICAgICAgICAgICAgICAgc2Vzc2lvbklkOiB0aGlzLnNlc3Npb24uZ2V0U2Vzc2lvbklkKCksXG4gICAgICAgICAgICAgICAgcGFydGljaXBhbnRJZDogcGFyYW0xLFxuICAgICAgICAgICAgICAgIG1ldGFkYXRhOiAnJyxcbiAgICAgICAgICAgICAgICBzdWJzY3JpYmVUb1N0cmVhbXM6IGZhbHNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5jb25uZWN0KHBhcmFtMSwgcGFyYW0yKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGRpc2Nvbm5lY3QoKSB7XG4gICAgICAgIHRoaXMub3BlblZpZHUub3BlblZpZHUuY2xvc2UoZmFsc2UpO1xuICAgICAgICB0aGlzLnNlc3Npb24uZW1pdEV2ZW50KCdzZXNzaW9uRGlzY29ubmVjdGVkJywgW3tcbiAgICAgICAgICAgIHByZXZlbnREZWZhdWx0OiAoKSA9PiB7IHRoaXMuc2Vzc2lvbi5yZW1vdmVFdmVudCgnc2Vzc2lvbi1kaXNjb25uZWN0ZWQtZGVmYXVsdCcpOyB9XG4gICAgICAgIH1dKTtcbiAgICAgICAgdGhpcy5zZXNzaW9uLmVtaXRFdmVudCgnc2Vzc2lvbi1kaXNjb25uZWN0ZWQtZGVmYXVsdCcsIFt7fV0pO1xuICAgIH1cblxuICAgIHB1Ymxpc2gocHVibGlzaGVyOiBQdWJsaXNoZXIpIHtcbiAgICAgICAgcHVibGlzaGVyLnNlc3Npb24gPSB0aGlzO1xuICAgICAgICBwdWJsaXNoZXIuc3RyZWFtLnB1Ymxpc2goKTtcbiAgICB9XG5cbiAgICB1bnB1Ymxpc2gocHVibGlzaGVyOiBQdWJsaXNoZXIpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLnVucHVibGlzaChwdWJsaXNoZXIuc3RyZWFtKTtcbiAgICB9XG5cbiAgICBvbihldmVudE5hbWU6IHN0cmluZywgY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBldmVudCA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhldmVudCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIG9uY2UoZXZlbnROYW1lOiBzdHJpbmcsIGNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRPbmNlRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIGV2ZW50ID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKGV2ZW50KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb2ZmKGV2ZW50TmFtZTogc3RyaW5nLCBldmVudEhhbmRsZXIpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLnJlbW92ZUxpc3RlbmVyKGV2ZW50TmFtZSwgZXZlbnRIYW5kbGVyKTtcbiAgICB9XG5cbiAgICBzdWJzY3JpYmUoc3RyZWFtOiBTdHJlYW0sIGh0bWxJZDogc3RyaW5nLCB2aWRlb09wdGlvbnM6IGFueSk6IFN1YnNjcmliZXI7XG4gICAgc3Vic2NyaWJlKHN0cmVhbTogU3RyZWFtLCBodG1sSWQ6IHN0cmluZyk6IFN1YnNjcmliZXI7XG5cbiAgICBzdWJzY3JpYmUocGFyYW0xLCBwYXJhbTIsIHBhcmFtMz8pOiBTdWJzY3JpYmVyIHtcbiAgICAgICAgLy8gU3Vic2NyaXB0aW9uXG4gICAgICAgIHRoaXMuc2Vzc2lvbi5zdWJzY3JpYmUocGFyYW0xKTtcbiAgICAgICAgbGV0IHN1YnNjcmliZXIgPSBuZXcgU3Vic2NyaWJlcihwYXJhbTEsIHBhcmFtMik7XG4gICAgICAgIHBhcmFtMS5wbGF5T25seVZpZGVvKHBhcmFtMiwgbnVsbCk7XG4gICAgICAgIHJldHVybiBzdWJzY3JpYmVyO1xuICAgIH1cblxuICAgIHVuc3Vic2NyaWJlKHN1YnNjcmliZXI6IFN1YnNjcmliZXIpIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLnVuc3VzY3JpYmUoc3Vic2NyaWJlci5zdHJlYW0pO1xuICAgICAgICBzdWJzY3JpYmVyLnN0cmVhbS5yZW1vdmVWaWRlbygpO1xuICAgIH1cblxuXG5cblxuICAgIC8qIFNob3J0Y3V0IGV2ZW50IEFQSSAqL1xuXG4gICAgb25TdHJlYW1DcmVhdGVkKGNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKFwic3RyZWFtQ3JlYXRlZFwiLCBzdHJlYW1FdmVudCA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhzdHJlYW1FdmVudC5zdHJlYW0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBvblN0cmVhbURlc3Ryb3llZChjYWxsYmFjaykge1xuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcihcInN0cmVhbURlc3Ryb3llZFwiLCBzdHJlYW1FdmVudCA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhzdHJlYW1FdmVudC5zdHJlYW0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBvblBhcnRpY2lwYW50Sm9pbmVkKGNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKFwicGFydGljaXBhbnQtam9pbmVkXCIsIHBhcnRpY2lwYW50RXZlbnQgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2socGFydGljaXBhbnRFdmVudC5jb25uZWN0aW9uKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb25QYXJ0aWNpcGFudExlZnQoY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoXCJwYXJ0aWNpcGFudC1sZWZ0XCIsIHBhcnRpY2lwYW50RXZlbnQgPT4ge1xuICAgICAgICAgICAgY2FsbGJhY2socGFydGljaXBhbnRFdmVudC5jb25uZWN0aW9uKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb25QYXJ0aWNpcGFudFB1Ymxpc2hlZChjYWxsYmFjaykge1xuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcihcInBhcnRpY2lwYW50LXB1Ymxpc2hlZFwiLCBwYXJ0aWNpcGFudEV2ZW50ID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKHBhcnRpY2lwYW50RXZlbnQuY29ubmVjdGlvbik7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIG9uUGFydGljaXBhbnRFdmljdGVkKGNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKFwicGFydGljaXBhbnQtZXZpY3RlZFwiLCBwYXJ0aWNpcGFudEV2ZW50ID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKHBhcnRpY2lwYW50RXZlbnQuY29ubmVjdGlvbik7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIG9uUm9vbUNsb3NlZChjYWxsYmFjaykge1xuICAgICAgICB0aGlzLnNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lcihcInJvb20tY2xvc2VkXCIsIHJvb21FdmVudCA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhyb29tRXZlbnQucm9vbSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIG9uTG9zdENvbm5lY3Rpb24oY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5zZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoXCJsb3N0LWNvbm5lY3Rpb25cIiwgcm9vbUV2ZW50ID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKHJvb21FdmVudC5yb29tKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb25NZWRpYUVycm9yKGNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKFwiZXJyb3ItbWVkaWFcIiwgZXJyb3JFdmVudCA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhlcnJvckV2ZW50LmVycm9yKVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKiBTaG9ydGN1dCBldmVudCBBUEkgKi9cbn1cbiIsImltcG9ydCB7IFN0cmVhbSwgU3RyZWFtT3B0aW9ucywgVmlkZW9PcHRpb25zIH0gZnJvbSAnLi4vT3BlblZpZHVJbnRlcm5hbC9TdHJlYW0nO1xuXG5pbXBvcnQgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnd29sZnk4Ny1ldmVudGVtaXR0ZXInKTtcblxuZXhwb3J0IGNsYXNzIFN1YnNjcmliZXIge1xuXG4gICAgcHJpdmF0ZSBlZSA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAgIGVsZW1lbnQ6IEVsZW1lbnQ7XG4gICAgaWQ6IHN0cmluZztcbiAgICBzdHJlYW06IFN0cmVhbTtcblxuICAgIGNvbnN0cnVjdG9yKHN0cmVhbTogU3RyZWFtLCBwYXJlbnRJZDogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuc3RyZWFtID0gc3RyZWFtO1xuICAgICAgICBpZiAoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQocGFyZW50SWQpICE9IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuZWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHBhcmVudElkKSEhO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb24oZXZlbnROYW1lOiBzdHJpbmcsIGNhbGxiYWNrKSB7XG4gICAgICAgIHRoaXMuZWUuYWRkTGlzdGVuZXIoZXZlbnROYW1lLCBldmVudCA9PiB7XG4gICAgICAgICAgICBjYWxsYmFjayhldmVudCk7XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoZXZlbnROYW1lID09ICd2aWRlb0VsZW1lbnRDcmVhdGVkJykge1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RyZWFtLmlzUmVhZHkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgndmlkZW9FbGVtZW50Q3JlYXRlZCcsIFt7XG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IHRoaXMuc3RyZWFtLmdldFZpZGVvRWxlbWVudCgpXG4gICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbS5hZGRFdmVudExpc3RlbmVyKCd2aWRlby1lbGVtZW50LWNyZWF0ZWQtYnktc3RyZWFtJywgZWxlbWVudCA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIlN1YnNjcmliZXIgZW1pdHRpbmcgdmlkZW9FbGVtZW50Q3JlYXRlZFwiKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pZCA9IGVsZW1lbnQuaWQ7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCd2aWRlb0VsZW1lbnRDcmVhdGVkJywgW3tcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQ6IGVsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufSIsImltcG9ydCB7IFN0cmVhbSwgU3RyZWFtT3B0aW9ucyB9IGZyb20gJy4vU3RyZWFtJztcbmltcG9ydCB7IE9wZW5WaWR1SW50ZXJuYWwgfSBmcm9tICcuL09wZW5WaWR1SW50ZXJuYWwnO1xuaW1wb3J0IHsgU2Vzc2lvbkludGVybmFsIH0gZnJvbSAnLi9TZXNzaW9uSW50ZXJuYWwnO1xuXG50eXBlIE9iak1hcDxUPiA9IHsgW3M6IHN0cmluZ106IFQ7IH1cblxuZXhwb3J0IGludGVyZmFjZSBDb25uZWN0aW9uT3B0aW9ucyB7XG4gICAgaWQ6IHN0cmluZztcbiAgICBtZXRhZGF0YTogc3RyaW5nO1xuICAgIHN0cmVhbXM/OiBTdHJlYW1PcHRpb25zW107XG59XG5cbmV4cG9ydCBjbGFzcyBDb25uZWN0aW9uIHtcblxuICAgIHB1YmxpYyBjb25uZWN0aW9uSWQ6IHN0cmluZztcbiAgICBwdWJsaWMgZGF0YTogc3RyaW5nO1xuICAgIHB1YmxpYyBjcmVhdGlvblRpbWU6IG51bWJlcjtcbiAgICBwcml2YXRlIHN0cmVhbXM6IE9iak1hcDxTdHJlYW0+ID0ge307XG4gICAgcHJpdmF0ZSBzdHJlYW1zT3B0czogU3RyZWFtT3B0aW9uc1tdID0gW107XG5cbiAgICBjb25zdHJ1Y3RvciggcHJpdmF0ZSBvcGVuVmlkdTogT3BlblZpZHVJbnRlcm5hbCwgcHJpdmF0ZSBsb2NhbDogYm9vbGVhbiwgcHJpdmF0ZSByb29tOiBTZXNzaW9uSW50ZXJuYWwsIHByaXZhdGUgb3B0aW9ucz86IENvbm5lY3Rpb25PcHRpb25zICkge1xuXG4gICAgICAgIGlmICggb3B0aW9ucyApIHtcblxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uSWQgPSBvcHRpb25zLmlkO1xuICAgICAgICAgICAgdGhpcy5kYXRhID0gb3B0aW9ucy5tZXRhZGF0YTtcblxuICAgICAgICAgICAgaWYgKCBvcHRpb25zLnN0cmVhbXMgKSB7XG5cbiAgICAgICAgICAgICAgICBmb3IgKCBsZXQgc3RyZWFtT3B0aW9ucyBvZiBvcHRpb25zLnN0cmVhbXMgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgbGV0IHN0cmVhbU9wdHMgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZDogc3RyZWFtT3B0aW9ucy5pZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb246IHRoaXMsXG4gICAgICAgICAgICAgICAgICAgICAgICByZWN2VmlkZW86ICggc3RyZWFtT3B0aW9ucy5yZWN2VmlkZW8gPT0gdW5kZWZpbmVkID8gdHJ1ZSA6IHN0cmVhbU9wdGlvbnMucmVjdlZpZGVvICksXG4gICAgICAgICAgICAgICAgICAgICAgICByZWN2QXVkaW86ICggc3RyZWFtT3B0aW9ucy5yZWN2QXVkaW8gPT0gdW5kZWZpbmVkID8gdHJ1ZSA6IHN0cmVhbU9wdGlvbnMucmVjdkF1ZGlvICksXG4gICAgICAgICAgICAgICAgICAgICAgICBhdWRpbzogc3RyZWFtT3B0aW9ucy5hdWRpbyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvOiBzdHJlYW1PcHRpb25zLnZpZGVvLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogc3RyZWFtT3B0aW9ucy5kYXRhLFxuICAgICAgICAgICAgICAgICAgICAgICAgbWVkaWFDb25zdHJhaW50czogc3RyZWFtT3B0aW9ucy5tZWRpYUNvbnN0cmFpbnRzXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgbGV0IHN0cmVhbSA9IG5ldyBTdHJlYW0oIG9wZW5WaWR1LCBmYWxzZSwgcm9vbSwgc3RyZWFtT3B0cyApO1xuXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWRkU3RyZWFtKCBzdHJlYW0gKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zdHJlYW1zT3B0cy5wdXNoKCBzdHJlYW1PcHRzICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBjb25zb2xlLmxvZyggXCJOZXcgXCIgKyAoIGxvY2FsID8gXCJsb2NhbCBcIiA6IFwicmVtb3RlIFwiICkgKyBcInBhcnRpY2lwYW50IFwiICsgdGhpcy5jb25uZWN0aW9uSWRcbiAgICAgICAgICAgICsgXCIsIHN0cmVhbXMgb3B0czogXCIsIHRoaXMuc3RyZWFtc09wdHMgKTtcbiAgICB9XG5cbiAgICBhZGRTdHJlYW0oIHN0cmVhbTogU3RyZWFtICkge1xuICAgICAgICB0aGlzLnN0cmVhbXNbc3RyZWFtLmdldElkSW5QYXJ0aWNpcGFudCgpXSA9IHN0cmVhbTtcbiAgICAgICAgdGhpcy5yb29tLmdldFN0cmVhbXMoKVtzdHJlYW0uZ2V0SWRJblBhcnRpY2lwYW50KCldID0gc3RyZWFtO1xuICAgIH1cblxuICAgIGdldFN0cmVhbXMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmVhbXM7XG4gICAgfVxuXG4gICAgZGlzcG9zZSgpIHtcbiAgICAgICAgZm9yICggbGV0IGtleSBpbiB0aGlzLnN0cmVhbXMgKSB7XG4gICAgICAgICAgICB0aGlzLnN0cmVhbXNba2V5XS5kaXNwb3NlKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzZW5kSWNlQ2FuZGlkYXRlKCBjYW5kaWRhdGUgKSB7XG5cbiAgICAgICAgY29uc29sZS5kZWJ1ZygoIHRoaXMubG9jYWwgPyBcIkxvY2FsXCIgOiBcIlJlbW90ZVwiICksIFwiY2FuZGlkYXRlIGZvclwiLFxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uSWQsIEpTT04uc3RyaW5naWZ5KCBjYW5kaWRhdGUgKSApO1xuXG4gICAgICAgIHRoaXMub3BlblZpZHUuc2VuZFJlcXVlc3QoIFwib25JY2VDYW5kaWRhdGVcIiwge1xuICAgICAgICAgICAgZW5kcG9pbnROYW1lOiB0aGlzLmNvbm5lY3Rpb25JZCxcbiAgICAgICAgICAgIGNhbmRpZGF0ZTogY2FuZGlkYXRlLmNhbmRpZGF0ZSxcbiAgICAgICAgICAgIHNkcE1pZDogY2FuZGlkYXRlLnNkcE1pZCxcbiAgICAgICAgICAgIHNkcE1MaW5lSW5kZXg6IGNhbmRpZGF0ZS5zZHBNTGluZUluZGV4XG4gICAgICAgIH0sIGZ1bmN0aW9uKCBlcnJvciwgcmVzcG9uc2UgKSB7XG4gICAgICAgICAgICBpZiAoIGVycm9yICkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoIFwiRXJyb3Igc2VuZGluZyBJQ0UgY2FuZGlkYXRlOiBcIlxuICAgICAgICAgICAgICAgICAgICArIEpTT04uc3RyaW5naWZ5KCBlcnJvciApICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbn0iLCIvKlxuICogKEMpIENvcHlyaWdodCAyMDE2IE9wZW5WaWR1IChodHRwOi8va3VyZW50by5vcmcvKVxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICovXG5pbXBvcnQgeyBTZXNzaW9uSW50ZXJuYWwsIFNlc3Npb25PcHRpb25zIH0gZnJvbSAnLi9TZXNzaW9uSW50ZXJuYWwnO1xuaW1wb3J0IHsgU3RyZWFtIH0gZnJvbSAnLi9TdHJlYW0nO1xuaW1wb3J0ICogYXMgUnBjQnVpbGRlciBmcm9tICdrdXJlbnRvLWpzb25ycGMnO1xuXG5leHBvcnQgdHlwZSBDYWxsYmFjazxUPiA9IChlcnJvcj86IGFueSwgb3BlblZpZHU/OiBUKSA9PiB2b2lkO1xuXG5leHBvcnQgY2xhc3MgT3BlblZpZHVJbnRlcm5hbCB7XG5cbiAgICBwcml2YXRlIHdzVXJpO1xuICAgIHByaXZhdGUgc2Vzc2lvbjogU2Vzc2lvbkludGVybmFsO1xuICAgIHByaXZhdGUganNvblJwY0NsaWVudDogYW55O1xuICAgIHByaXZhdGUgcnBjUGFyYW1zOiBhbnk7XG4gICAgcHJpdmF0ZSBjYWxsYmFjazogQ2FsbGJhY2s8T3BlblZpZHVJbnRlcm5hbD47XG4gICAgcHJpdmF0ZSBjYW1lcmE6IFN0cmVhbTtcbiAgICBwcml2YXRlIHJlbW90ZVN0cmVhbXM6IFN0cmVhbVtdID0gW107XG5cbiAgICBjb25zdHJ1Y3RvcigpIHsgfTtcblxuXG4gICAgLyogTkVXIE1FVEhPRFMgKi9cbiAgICBpbml0U2Vzc2lvbihzZXNzaW9uSWQpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJTZXNzaW9uIGluaXRpYWxpemVkIVwiKTtcbiAgICAgICAgdGhpcy5zZXNzaW9uID0gbmV3IFNlc3Npb25JbnRlcm5hbCh0aGlzLCBzZXNzaW9uSWQpO1xuICAgICAgICByZXR1cm4gdGhpcy5zZXNzaW9uO1xuICAgIH1cblxuICAgIGluaXRQdWJsaXNoZXJUYWdnZWQocGFyZW50SWQ6IHN0cmluZywgY2FtZXJhT3B0aW9uczogYW55LCBjYWxsYmFjaz8pIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJQdWJsaXNoZXIgdGFnZ2VkIGluaXRpYWxpemVkIVwiKTtcblxuICAgICAgICB0aGlzLmdldENhbWVyYShjYW1lcmFPcHRpb25zKTtcblxuICAgICAgICBpZiAoY2FsbGJhY2sgPT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5jYW1lcmEucmVxdWVzdENhbWVyYUFjY2VzcygoZXJyb3IsIGNhbWVyYSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIkVycm9yIGFjY2Vzc2luZyB0aGUgY2FtZXJhXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYW1lcmEuc2V0VmlkZW9FbGVtZW50KHRoaXMuY2FtZXJhUmVhZHkoY2FtZXJhISwgcGFyZW50SWQpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNhbWVyYTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuY2FtZXJhLnJlcXVlc3RDYW1lcmFBY2Nlc3MoKGVycm9yLCBjYW1lcmEpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2soZXJyb3IpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYW1lcmEuc2V0VmlkZW9FbGVtZW50KHRoaXMuY2FtZXJhUmVhZHkoY2FtZXJhISwgcGFyZW50SWQpKTtcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2sodW5kZWZpbmVkKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNhbWVyYTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGNhbWVyYVJlYWR5KGNhbWVyYTogU3RyZWFtLCBwYXJlbnRJZDogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMuY2FtZXJhID0gY2FtZXJhO1xuICAgICAgICBsZXQgdmlkZW9FbGVtZW50ID0gdGhpcy5jYW1lcmEucGxheU9ubHlWaWRlbyhwYXJlbnRJZCwgbnVsbCk7XG4gICAgICAgIHRoaXMuY2FtZXJhLmVtaXRTdHJlYW1SZWFkeUV2ZW50KCk7XG4gICAgICAgIHJldHVybiB2aWRlb0VsZW1lbnQ7XG4gICAgfVxuXG4gICAgaW5pdFB1Ymxpc2hlcihjYW1lcmFPcHRpb25zOiBhbnksIGNhbGxiYWNrKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiUHVibGlzaGVyIGluaXRpYWxpemVkIVwiKTtcblxuICAgICAgICB0aGlzLmdldENhbWVyYShjYW1lcmFPcHRpb25zKTtcbiAgICAgICAgdGhpcy5jYW1lcmEucmVxdWVzdENhbWVyYUFjY2VzcygoZXJyb3IsIGNhbWVyYSkgPT4ge1xuICAgICAgICAgICAgaWYgKGVycm9yKSBjYWxsYmFjayhlcnJvcik7XG4gICAgICAgICAgICBlbHNlIGNhbGxiYWNrKHVuZGVmaW5lZCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGdldExvY2FsU3RyZWFtKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jYW1lcmE7XG4gICAgfVxuXG4gICAgZ2V0UmVtb3RlU3RyZWFtcygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVtb3RlU3RyZWFtcztcbiAgICB9XG4gICAgLyogTkVXIE1FVEhPRFMgKi9cblxuICAgIGdldFdzVXJpKCkge1xuICAgICAgICByZXR1cm4gdGhpcy53c1VyaTtcbiAgICB9XG5cbiAgICBzZXRXc1VyaSh3c1VyaTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMud3NVcmkgPSB3c1VyaTtcbiAgICB9XG5cbiAgICBnZXRPcGVuVmlkdVNlcnZlclVSTCgpIHtcbiAgICAgICAgcmV0dXJuICdodHRwczovLycgKyB0aGlzLndzVXJpLnNwbGl0KFwid3NzOi8vXCIpWzFdLnNwbGl0KFwiL3Jvb21cIilbMF07XG4gICAgfVxuXG4gICAgZ2V0Um9vbSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2Vzc2lvbjtcbiAgICB9XG5cbiAgICBjb25uZWN0KGNhbGxiYWNrOiBDYWxsYmFjazxPcGVuVmlkdUludGVybmFsPik6IHZvaWQge1xuXG4gICAgICAgIHRoaXMuY2FsbGJhY2sgPSBjYWxsYmFjaztcblxuICAgICAgICB0aGlzLmluaXRKc29uUnBjQ2xpZW50KHRoaXMud3NVcmkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgaW5pdEpzb25ScGNDbGllbnQod3NVcmk6IHN0cmluZyk6IHZvaWQge1xuXG4gICAgICAgIGxldCBjb25maWcgPSB7XG4gICAgICAgICAgICBoZWFydGJlYXQ6IDMwMDAsXG4gICAgICAgICAgICBzZW5kQ2xvc2VNZXNzYWdlOiBmYWxzZSxcbiAgICAgICAgICAgIHdzOiB7XG4gICAgICAgICAgICAgICAgdXJpOiB3c1VyaSxcbiAgICAgICAgICAgICAgICB1c2VTb2NrSlM6IGZhbHNlLFxuICAgICAgICAgICAgICAgIG9uY29ubmVjdGVkOiB0aGlzLmNvbm5lY3RDYWxsYmFjay5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIG9uZGlzY29ubmVjdDogdGhpcy5kaXNjb25uZWN0Q2FsbGJhY2suYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBvbnJlY29ubmVjdGluZzogdGhpcy5yZWNvbm5lY3RpbmdDYWxsYmFjay5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIG9ucmVjb25uZWN0ZWQ6IHRoaXMucmVjb25uZWN0ZWRDYWxsYmFjay5iaW5kKHRoaXMpXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgcnBjOiB7XG4gICAgICAgICAgICAgICAgcmVxdWVzdFRpbWVvdXQ6IDE1MDAwLFxuICAgICAgICAgICAgICAgIC8vbm90aWZpY2F0aW9uc1xuICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50Sm9pbmVkOiB0aGlzLm9uUGFydGljaXBhbnRKb2luZWQuYmluZCh0aGlzKSxcbiAgICAgICAgICAgICAgICBwYXJ0aWNpcGFudFB1Ymxpc2hlZDogdGhpcy5vblBhcnRpY2lwYW50UHVibGlzaGVkLmJpbmQodGhpcyksXG4gICAgICAgICAgICAgICAgcGFydGljaXBhbnRVbnB1Ymxpc2hlZDogdGhpcy5vblBhcnRpY2lwYW50TGVmdC5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50TGVmdDogdGhpcy5vblBhcnRpY2lwYW50TGVmdC5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50RXZpY3RlZDogdGhpcy5vblBhcnRpY2lwYW50RXZpY3RlZC5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIHNlbmRNZXNzYWdlOiB0aGlzLm9uTmV3TWVzc2FnZS5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIGljZUNhbmRpZGF0ZTogdGhpcy5pY2VDYW5kaWRhdGVFdmVudC5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgIG1lZGlhRXJyb3I6IHRoaXMub25NZWRpYUVycm9yLmJpbmQodGhpcyksXG4gICAgICAgICAgICAgICAgY3VzdG9uTm90aWZpY2F0aW9uOiB0aGlzLmN1c3RvbU5vdGlmaWNhdGlvbi5iaW5kKHRoaXMpXG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5qc29uUnBjQ2xpZW50ID0gbmV3IFJwY0J1aWxkZXIuY2xpZW50cy5Kc29uUnBjQ2xpZW50KGNvbmZpZyk7XG4gICAgfVxuXG5cbiAgICBwcml2YXRlIGN1c3RvbU5vdGlmaWNhdGlvbihwYXJhbXMpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5lbWl0RXZlbnQoXCJjdXN0b20tbWVzc2FnZS1yZWNlaXZlZFwiLCBbeyBwYXJhbXM6IHBhcmFtcyB9XSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGNvbm5lY3RDYWxsYmFjayhlcnJvcikge1xuICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgIHRoaXMuY2FsbGJhY2soZXJyb3IpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jYWxsYmFjayhudWxsKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgaXNSb29tQXZhaWxhYmxlKCkge1xuICAgICAgICBpZiAodGhpcy5zZXNzaW9uICE9PSB1bmRlZmluZWQgJiYgdGhpcy5zZXNzaW9uIGluc3RhbmNlb2YgU2Vzc2lvbkludGVybmFsKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybignUm9vbSBpbnN0YW5jZSBub3QgZm91bmQnKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgZGlzY29ubmVjdENhbGxiYWNrKCkge1xuICAgICAgICBjb25zb2xlLmxvZygnV2Vic29ja2V0IGNvbm5lY3Rpb24gbG9zdCcpO1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uTG9zdENvbm5lY3Rpb24oKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGFsZXJ0KCdDb25uZWN0aW9uIGVycm9yLiBQbGVhc2UgcmVsb2FkIHBhZ2UuJyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHJlY29ubmVjdGluZ0NhbGxiYWNrKCkge1xuICAgICAgICBjb25zb2xlLmxvZygnV2Vic29ja2V0IGNvbm5lY3Rpb24gbG9zdCAocmVjb25uZWN0aW5nKScpO1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uTG9zdENvbm5lY3Rpb24oKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGFsZXJ0KCdDb25uZWN0aW9uIGVycm9yLiBQbGVhc2UgcmVsb2FkIHBhZ2UuJyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHJlY29ubmVjdGVkQ2FsbGJhY2soKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdXZWJzb2NrZXQgcmVjb25uZWN0ZWQnKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIG9uUGFydGljaXBhbnRKb2luZWQocGFyYW1zKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24ub25QYXJ0aWNpcGFudEpvaW5lZChwYXJhbXMpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblBhcnRpY2lwYW50UHVibGlzaGVkKHBhcmFtcykge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uUGFydGljaXBhbnRQdWJsaXNoZWQocGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgb25QYXJ0aWNpcGFudExlZnQocGFyYW1zKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24ub25QYXJ0aWNpcGFudExlZnQocGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgb25QYXJ0aWNpcGFudEV2aWN0ZWQocGFyYW1zKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24ub25QYXJ0aWNpcGFudEV2aWN0ZWQocGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgb25OZXdNZXNzYWdlKHBhcmFtcykge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uTmV3TWVzc2FnZShwYXJhbXMpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBpY2VDYW5kaWRhdGVFdmVudChwYXJhbXMpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5yZWN2SWNlQ2FuZGlkYXRlKHBhcmFtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIG9uUm9vbUNsb3NlZChwYXJhbXMpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb29tQXZhaWxhYmxlKCkpIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvbi5vblJvb21DbG9zZWQocGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgb25NZWRpYUVycm9yKHBhcmFtcykge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLm9uTWVkaWFFcnJvcihwYXJhbXMpO1xuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICBzZXRScGNQYXJhbXMocGFyYW1zOiBhbnkpIHtcbiAgICAgICAgdGhpcy5ycGNQYXJhbXMgPSBwYXJhbXM7XG4gICAgfVxuXG4gICAgc2VuZFJlcXVlc3QobWV0aG9kLCBwYXJhbXMsIGNhbGxiYWNrPykge1xuXG4gICAgICAgIGlmIChwYXJhbXMgJiYgcGFyYW1zIGluc3RhbmNlb2YgRnVuY3Rpb24pIHtcbiAgICAgICAgICAgIGNhbGxiYWNrID0gcGFyYW1zO1xuICAgICAgICAgICAgcGFyYW1zID0gdW5kZWZpbmVkO1xuICAgICAgICB9XG5cbiAgICAgICAgcGFyYW1zID0gcGFyYW1zIHx8IHt9O1xuXG4gICAgICAgIGlmICh0aGlzLnJwY1BhcmFtcyAmJiB0aGlzLnJwY1BhcmFtcyAhPT0gbnVsbCAmJiB0aGlzLnJwY1BhcmFtcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBpbmRleCBpbiB0aGlzLnJwY1BhcmFtcykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLnJwY1BhcmFtcy5oYXNPd25Qcm9wZXJ0eShpbmRleCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcGFyYW1zW2luZGV4XSA9IHRoaXMucnBjUGFyYW1zW2luZGV4XTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ1JQQyBwYXJhbSBhZGRlZCB0byByZXF1ZXN0IHsnICsgaW5kZXggKyAnOiAnICsgdGhpcy5ycGNQYXJhbXNbaW5kZXhdICsgJ30nKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmxvZygnU2VuZGluZyByZXF1ZXN0OiB7IG1ldGhvZDpcIicgKyBtZXRob2QgKyAnXCIsIHBhcmFtczogJyArIEpTT04uc3RyaW5naWZ5KHBhcmFtcykgKyAnIH0nKTtcblxuICAgICAgICB0aGlzLmpzb25ScGNDbGllbnQuc2VuZChtZXRob2QsIHBhcmFtcywgY2FsbGJhY2spO1xuICAgIH1cblxuICAgIGNsb3NlKGZvcmNlZCkge1xuICAgICAgICBpZiAodGhpcy5pc1Jvb21BdmFpbGFibGUoKSkge1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uLmxlYXZlKGZvcmNlZCwgdGhpcy5qc29uUnBjQ2xpZW50KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBkaXNjb25uZWN0UGFydGljaXBhbnQoc3RyZWFtKSB7XG4gICAgICAgIGlmICh0aGlzLmlzUm9vbUF2YWlsYWJsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnNlc3Npb24uZGlzY29ubmVjdChzdHJlYW0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZ2V0Q2FtZXJhKG9wdGlvbnM/KSB7XG5cbiAgICAgICAgaWYgKHRoaXMuY2FtZXJhKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jYW1lcmE7XG4gICAgICAgIH1cblxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7XG4gICAgICAgICAgICBhdWRpbzogdHJ1ZSxcbiAgICAgICAgICAgIHZpZGVvOiB0cnVlLFxuICAgICAgICAgICAgZGF0YTogdHJ1ZSxcbiAgICAgICAgICAgIG1lZGlhQ29uc3RyYWludHM6IHtcbiAgICAgICAgICAgICAgICBhdWRpbzogdHJ1ZSxcbiAgICAgICAgICAgICAgICB2aWRlbzogeyB3aWR0aDogeyBpZGVhbDogMTI4MCB9IH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIG9wdGlvbnMuY29ubmVjdGlvbiA9IHRoaXMuc2Vzc2lvbi5nZXRMb2NhbFBhcnRpY2lwYW50KCk7XG4gICAgICAgIHRoaXMuY2FtZXJhID0gbmV3IFN0cmVhbSh0aGlzLCB0cnVlLCB0aGlzLnNlc3Npb24sIG9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gdGhpcy5jYW1lcmE7XG4gICAgfTtcblxuICAgIC8qam9pblNlc3Npb24ob3B0aW9uczogU2Vzc2lvbk9wdGlvbnMsIGNhbGxiYWNrOiBDYWxsYmFjazxTZXNzaW9uPikge1xuICAgICAgICBcbiAgICAgICAgdGhpcy5zZXNzaW9uLmNvbmZpZ3VyZShvcHRpb25zKTtcbiAgICAgICAgXG4gICAgICAgIHRoaXMuc2Vzc2lvbi5jb25uZWN0MigpO1xuICAgICAgICBcbiAgICAgICAgdGhpcy5zZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoJ3Jvb20tY29ubmVjdGVkJywgcm9vbUV2ZW50ID0+IGNhbGxiYWNrKHVuZGVmaW5lZCx0aGlzLnNlc3Npb24pKTtcbiAgICAgICAgXG4gICAgICAgIHRoaXMuc2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCdlcnJvci1yb29tJywgZXJyb3IgPT4gY2FsbGJhY2soZXJyb3IpKTtcbiAgICAgICAgXG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb247XG4gICAgfTsqL1xuXG4gICAgLy9DSEFUXG4gICAgc2VuZE1lc3NhZ2Uocm9vbSwgdXNlciwgbWVzc2FnZSkge1xuICAgICAgICB0aGlzLnNlbmRSZXF1ZXN0KCdzZW5kTWVzc2FnZScsIHtcbiAgICAgICAgICAgIG1lc3NhZ2U6IG1lc3NhZ2UsXG4gICAgICAgICAgICB1c2VyTWVzc2FnZTogdXNlcixcbiAgICAgICAgICAgIHJvb21NZXNzYWdlOiByb29tXG4gICAgICAgIH0sIGZ1bmN0aW9uIChlcnJvciwgcmVzcG9uc2UpIHtcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgc2VuZEN1c3RvbVJlcXVlc3QocGFyYW1zLCBjYWxsYmFjaykge1xuICAgICAgICB0aGlzLnNlbmRSZXF1ZXN0KCdjdXN0b21SZXF1ZXN0JywgcGFyYW1zLCBjYWxsYmFjayk7XG4gICAgfTtcblxuXG5cblxuICAgIHRvZ2dsZUxvY2FsVmlkZW9UcmFjayhhY3RpdmF0ZTogYm9vbGVhbikge1xuICAgICAgICB0aGlzLmdldENhbWVyYSgpLmdldFdlYlJ0Y1BlZXIoKS52aWRlb0VuYWJsZWQgPSBhY3RpdmF0ZTtcbiAgICB9XG5cbiAgICB0b2dnbGVMb2NhbEF1ZGlvVHJhY2soYWN0aXZhdGU6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5nZXRDYW1lcmEoKS5nZXRXZWJSdGNQZWVyKCkuYXVkaW9FbmFibGVkID0gYWN0aXZhdGU7XG4gICAgfVxuXG4gICAgcHVibGlzaExvY2FsVmlkZW9BdWRpbygpIHtcbiAgICAgICAgdGhpcy50b2dnbGVMb2NhbFZpZGVvVHJhY2sodHJ1ZSk7XG4gICAgICAgIHRoaXMudG9nZ2xlTG9jYWxBdWRpb1RyYWNrKHRydWUpO1xuICAgIH1cblxuICAgIHVucHVibGlzaExvY2FsVmlkZW9BdWRpbygpIHtcbiAgICAgICAgdGhpcy50b2dnbGVMb2NhbFZpZGVvVHJhY2soZmFsc2UpO1xuICAgICAgICB0aGlzLnRvZ2dsZUxvY2FsQXVkaW9UcmFjayhmYWxzZSk7XG4gICAgfVxuXG4gICAgZ2VuZXJhdGVNZWRpYUNvbnN0cmFpbnRzKHF1YWxpdHk6IHN0cmluZykge1xuICAgICAgICBsZXQgbWVkaWFDb25zdHJhaW50cyA9IHtcbiAgICAgICAgICAgIGF1ZGlvOiB0cnVlLFxuICAgICAgICAgICAgdmlkZW86IHt9XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHcsIGg7XG4gICAgICAgIHN3aXRjaCAocXVhbGl0eSkge1xuICAgICAgICAgICAgY2FzZSAnTE9XJzpcbiAgICAgICAgICAgICAgICB3ID0gMzIwO1xuICAgICAgICAgICAgICAgIGggPSAyNDA7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdNRURJVU0nOlxuICAgICAgICAgICAgICAgIHcgPSA2NDA7XG4gICAgICAgICAgICAgICAgaCA9IDQ4MDtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ0hJR0gnOlxuICAgICAgICAgICAgICAgIHcgPSAxMjgwO1xuICAgICAgICAgICAgICAgIGggPSA3MjA7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHcgPSA2NDA7XG4gICAgICAgICAgICAgICAgaCA9IDQ4MDtcbiAgICAgICAgfVxuICAgICAgICBtZWRpYUNvbnN0cmFpbnRzLnZpZGVvWyd3aWR0aCddID0geyBleGFjdDogdyB9O1xuICAgICAgICBtZWRpYUNvbnN0cmFpbnRzLnZpZGVvWydoZWlnaHQnXSA9IHsgZXhhY3Q6IGggfTtcbiAgICAgICAgLy9tZWRpYUNvbnN0cmFpbnRzLnZpZGVvWydmcmFtZVJhdGUnXSA9IHsgaWRlYWw6IE51bWJlcigoPEhUTUxJbnB1dEVsZW1lbnQ+ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2ZyYW1lUmF0ZScpKS52YWx1ZSkgfTtcblxuICAgICAgICByZXR1cm4gbWVkaWFDb25zdHJhaW50cztcbiAgICB9XG5cbn1cbiIsImltcG9ydCB7IFN0cmVhbSB9IGZyb20gJy4vU3RyZWFtJztcbmltcG9ydCB7IE9wZW5WaWR1SW50ZXJuYWwgfSBmcm9tICcuL09wZW5WaWR1SW50ZXJuYWwnO1xuaW1wb3J0IHsgQ29ubmVjdGlvbiwgQ29ubmVjdGlvbk9wdGlvbnMgfSBmcm9tICcuL0Nvbm5lY3Rpb24nO1xuaW1wb3J0IEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoJ3dvbGZ5ODctZXZlbnRlbWl0dGVyJyk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2Vzc2lvbk9wdGlvbnMge1xuICAgIHNlc3Npb25JZDogc3RyaW5nO1xuICAgIHBhcnRpY2lwYW50SWQ6IHN0cmluZztcbiAgICBtZXRhZGF0YTogc3RyaW5nO1xuICAgIHN1YnNjcmliZVRvU3RyZWFtcz86IGJvb2xlYW47XG4gICAgdXBkYXRlU3BlYWtlckludGVydmFsPzogbnVtYmVyO1xuICAgIHRocmVzaG9sZFNwZWFrZXI/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBTZXNzaW9uSW50ZXJuYWwge1xuXG4gICAgcHJpdmF0ZSBpZDogc3RyaW5nO1xuICAgIHByaXZhdGUgZWUgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gICAgcHJpdmF0ZSBzdHJlYW1zID0ge307XG4gICAgcHJpdmF0ZSBwYXJ0aWNpcGFudHMgPSB7fTtcbiAgICBwcml2YXRlIHBhcnRpY2lwYW50c1NwZWFraW5nOiBDb25uZWN0aW9uW10gPSBbXTtcbiAgICBwcml2YXRlIGNvbm5lY3RlZCA9IGZhbHNlO1xuICAgIHB1YmxpYyBsb2NhbFBhcnRpY2lwYW50OiBDb25uZWN0aW9uO1xuICAgIHByaXZhdGUgc3Vic2NyaWJlVG9TdHJlYW1zOiBib29sZWFuO1xuICAgIHByaXZhdGUgdXBkYXRlU3BlYWtlckludGVydmFsOiBudW1iZXI7XG4gICAgcHVibGljIHRocmVzaG9sZFNwZWFrZXI6IG51bWJlcjtcbiAgICBwcml2YXRlIG9wdGlvbnM6IFNlc3Npb25PcHRpb25zXG5cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIG9wZW5WaWR1OiBPcGVuVmlkdUludGVybmFsLCBwcml2YXRlIHNlc3Npb25JZDogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMubG9jYWxQYXJ0aWNpcGFudCA9IG5ldyBDb25uZWN0aW9uKHRoaXMub3BlblZpZHUsIHRydWUsIHRoaXMpO1xuICAgICAgICBpZiAoIXRoaXMub3BlblZpZHUuZ2V0V3NVcmkoKSkge1xuICAgICAgICAgICAgdGhpcy5vcGVuVmlkdS5zZXRXc1VyaSh0aGlzLmNoZWNrTmdyb2tVcmkoc2Vzc2lvbklkKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjaGVja05ncm9rVXJpKHNlc3Npb25JZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgc2Vzc2lvbklkID0gc2Vzc2lvbklkLnN1YnN0cmluZygwLCBzZXNzaW9uSWQubGFzdEluZGV4T2YoJy8nKSkgKyAnL3Jvb20nO1xuICAgICAgICBpZiAoc2Vzc2lvbklkLmluZGV4T2YoXCIubmdyb2suaW9cIikgIT09IC0xKSB7XG4gICAgICAgICAgICAvLyBPcGVuVmlkdSBzZXJ2ZXIgVVJMIHJlZmVyZXMgdG8gYSBuZ3JvayBJUDogc2VjdXJlIHdzcyBwcm90b2NvbCBhbmQgZGVsZXRlIHBvcnQgb2YgVVJMXG4gICAgICAgICAgICBzZXNzaW9uSWQgPSBzZXNzaW9uSWQucmVwbGFjZShcIndzOi8vXCIsIFwid3NzOi8vXCIpO1xuICAgICAgICAgICAgbGV0IHJlZ2V4ID0gL1xcLm5ncm9rXFwuaW86XFxkKy87XG4gICAgICAgICAgICBzZXNzaW9uSWQgPSBzZXNzaW9uSWQucmVwbGFjZShyZWdleCwgXCIubmdyb2suaW9cIik7XG4gICAgICAgIH0gZWxzZSBpZiAoKHNlc3Npb25JZC5pbmRleE9mKFwibG9jYWxob3N0XCIpICE9PSAtMSkgfHwgKHNlc3Npb25JZC5pbmRleE9mKFwiMTI3LjAuMC4xXCIpICE9IC0xKSkge1xuICAgICAgICAgICAgLy8gT3BlblZpZHUgc2VydmVyIFVSTCByZWZlcmVzIHRvIGxvY2FsaG9zdCBJUFxuXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNlc3Npb25JZDtcbiAgICB9XG5cblxuXG4gICAgLyogTkVXIE1FVEhPRFMgKi9cbiAgICBjb25uZWN0KHRva2VuLCBjYWxsYmFjaykge1xuXG4gICAgICAgIHRoaXMub3BlblZpZHUuY29ubmVjdCgoZXJyb3IpID0+IHtcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKCdFUlJPUiBDT05ORUNUSU5HIFRPIE9QRU5WSURVJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcblxuICAgICAgICAgICAgICAgIGxldCBqb2luUGFyYW1zID0ge1xuICAgICAgICAgICAgICAgICAgICB0b2tlbjogdG9rZW4sXG4gICAgICAgICAgICAgICAgICAgIHNlc3Npb246IHRoaXMuc2Vzc2lvbklkLFxuICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YTogdGhpcy5vcHRpb25zLm1ldGFkYXRhLFxuICAgICAgICAgICAgICAgICAgICBkYXRhQ2hhbm5lbHM6IGZhbHNlXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMubG9jYWxQYXJ0aWNpcGFudCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoT2JqZWN0LmtleXModGhpcy5sb2NhbFBhcnRpY2lwYW50LmdldFN0cmVhbXMoKSkuc29tZShzdHJlYW1JZCA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zdHJlYW1zW3N0cmVhbUlkXS5pc0RhdGFDaGFubmVsRW5hYmxlZCgpKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgam9pblBhcmFtcy5kYXRhQ2hhbm5lbHMgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5vcGVuVmlkdS5zZW5kUmVxdWVzdCgnam9pblJvb20nLCBqb2luUGFyYW1zLCAoZXJyb3IsIHJlc3BvbnNlKSA9PiB7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFjaygnVU5BQkxFIFRPIEpPSU4gUk9PTScpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3RlZCA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBleFBhcnRpY2lwYW50cyA9IHJlc3BvbnNlLnZhbHVlO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJTVBPUlRBTlQ6IFVwZGF0ZSBjb25uZWN0aW9uSWQgd2l0aCB2YWx1ZSBzZW5kIGJ5IHNlcnZlclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2NhbFBhcnRpY2lwYW50LmNvbm5lY3Rpb25JZCA9IHJlc3BvbnNlLmlkO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wYXJ0aWNpcGFudHNbcmVzcG9uc2UuaWRdID0gdGhpcy5sb2NhbFBhcnRpY2lwYW50O1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgcm9vbUV2ZW50ID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50czogbmV3IEFycmF5PENvbm5lY3Rpb24+KCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyZWFtczogbmV3IEFycmF5PFN0cmVhbT4oKVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgbGVuZ3RoID0gZXhQYXJ0aWNpcGFudHMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGNvbm5lY3Rpb24gPSBuZXcgQ29ubmVjdGlvbih0aGlzLm9wZW5WaWR1LCBmYWxzZSwgdGhpcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhQYXJ0aWNpcGFudHNbaV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uY3JlYXRpb25UaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBhcnRpY2lwYW50c1tjb25uZWN0aW9uLmNvbm5lY3Rpb25JZF0gPSBjb25uZWN0aW9uO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcm9vbUV2ZW50LnBhcnRpY2lwYW50cy5wdXNoKGNvbm5lY3Rpb24pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHN0cmVhbXMgPSBjb25uZWN0aW9uLmdldFN0cmVhbXMoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBrZXkgaW4gc3RyZWFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb29tRXZlbnQuc3RyZWFtcy5wdXNoKHN0cmVhbXNba2V5XSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnN1YnNjcmliZVRvU3RyZWFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyZWFtc1trZXldLnN1YnNjcmliZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVcGRhdGUgbG9jYWwgQ29ubmVjdGlvbiBvYmplY3QgcHJvcGVydGllcyB3aXRoIHZhbHVlcyByZXR1cm5lZCBieSBzZXJ2ZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubG9jYWxQYXJ0aWNpcGFudC5kYXRhID0gcmVzcG9uc2UubWV0YWRhdGE7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxvY2FsUGFydGljaXBhbnQuY3JlYXRpb25UaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVwZGF0ZXMgdGhlIHZhbHVlIG9mIHByb3BlcnR5ICdjb25uZWN0aW9uJyBpbiBTZXNzaW9uIG9iamVjdFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3VwZGF0ZS1jb25uZWN0aW9uLW9iamVjdCcsIFt7IGNvbm5lY3Rpb246IHRoaXMubG9jYWxQYXJ0aWNpcGFudCB9XSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBPd24gY29ubmVjdGlvbiBjcmVhdGVkIGV2ZW50XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnY29ubmVjdGlvbkNyZWF0ZWQnLCBbeyBjb25uZWN0aW9uOiB0aGlzLmxvY2FsUGFydGljaXBhbnQgfV0pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBPbmUgY29ubmVjdGlvbiBjcmVhdGVkIGV2ZW50IGZvciBlYWNoIGV4aXN0aW5nIGNvbm5lY3Rpb24gaW4gdGhlIHNlc3Npb25cbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAobGV0IHBhcnQgb2Ygcm9vbUV2ZW50LnBhcnRpY2lwYW50cykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdjb25uZWN0aW9uQ3JlYXRlZCcsIFt7IGNvbm5lY3Rpb246IHBhcnQgfV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvL2lmICh0aGlzLnN1YnNjcmliZVRvU3RyZWFtcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgc3RyZWFtIG9mIHJvb21FdmVudC5zdHJlYW1zKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3N0cmVhbUNyZWF0ZWQnLCBbeyBzdHJlYW0gfV0pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQWRkaW5nIHRoZSByZW1vdGUgc3RyZWFtIHRvIHRoZSBPcGVuVmlkdSBvYmplY3RcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm9wZW5WaWR1LmdldFJlbW90ZVN0cmVhbXMoKS5wdXNoKHN0cmVhbSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAvL31cblxuICAgICAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2sodW5kZWZpbmVkKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaXNoKCkge1xuICAgICAgICB0aGlzLm9wZW5WaWR1LmdldENhbWVyYSgpLnB1Ymxpc2goKTtcbiAgICB9XG4gICAgLyogTkVXIE1FVEhPRFMgKi9cblxuXG5cblxuXG4gICAgY29uZmlndXJlKG9wdGlvbnM6IFNlc3Npb25PcHRpb25zKSB7XG4gICAgICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgICAgIHRoaXMuaWQgPSBvcHRpb25zLnNlc3Npb25JZDtcbiAgICAgICAgdGhpcy5zdWJzY3JpYmVUb1N0cmVhbXMgPSBvcHRpb25zLnN1YnNjcmliZVRvU3RyZWFtcyA9PSBudWxsID8gdHJ1ZSA6IG9wdGlvbnMuc3Vic2NyaWJlVG9TdHJlYW1zO1xuICAgICAgICB0aGlzLnVwZGF0ZVNwZWFrZXJJbnRlcnZhbCA9IG9wdGlvbnMudXBkYXRlU3BlYWtlckludGVydmFsIHx8IDE1MDA7XG4gICAgICAgIHRoaXMudGhyZXNob2xkU3BlYWtlciA9IG9wdGlvbnMudGhyZXNob2xkU3BlYWtlciB8fCAtNTA7XG4gICAgICAgIHRoaXMuYWN0aXZhdGVVcGRhdGVNYWluU3BlYWtlcigpO1xuICAgIH1cblxuICAgIGdldElkKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5pZDtcbiAgICB9XG5cbiAgICBnZXRTZXNzaW9uSWQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb25JZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFjdGl2YXRlVXBkYXRlTWFpblNwZWFrZXIoKSB7XG5cbiAgICAgICAgc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMucGFydGljaXBhbnRzU3BlYWtpbmcubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCd1cGRhdGUtbWFpbi1zcGVha2VyJywgW3tcbiAgICAgICAgICAgICAgICAgICAgcGFydGljaXBhbnRJZDogdGhpcy5wYXJ0aWNpcGFudHNTcGVha2luZ1t0aGlzLnBhcnRpY2lwYW50c1NwZWFraW5nLmxlbmd0aCAtIDFdXG4gICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCB0aGlzLnVwZGF0ZVNwZWFrZXJJbnRlcnZhbCk7XG4gICAgfVxuXG4gICAgZ2V0TG9jYWxQYXJ0aWNpcGFudCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxQYXJ0aWNpcGFudDtcbiAgICB9XG5cbiAgICBhZGRFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgbGlzdGVuZXIpIHtcbiAgICAgICAgdGhpcy5lZS5vbihldmVudE5hbWUsIGxpc3RlbmVyKTtcbiAgICB9XG5cbiAgICBhZGRPbmNlRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIGxpc3RlbmVyKSB7XG4gICAgICAgIHRoaXMuZWUub25jZShldmVudE5hbWUsIGxpc3RlbmVyKTtcbiAgICB9XG5cbiAgICByZW1vdmVMaXN0ZW5lcihldmVudE5hbWUsIGxpc3RlbmVyKSB7XG4gICAgICAgIHRoaXMuZWUub2ZmKGV2ZW50TmFtZSwgbGlzdGVuZXIpO1xuICAgIH1cblxuICAgIHJlbW92ZUV2ZW50KGV2ZW50TmFtZSkge1xuICAgICAgICB0aGlzLmVlLnJlbW92ZUV2ZW50KGV2ZW50TmFtZSk7XG4gICAgfVxuXG4gICAgZW1pdEV2ZW50KGV2ZW50TmFtZSwgZXZlbnRzQXJyYXkpIHtcbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoZXZlbnROYW1lLCBldmVudHNBcnJheSk7XG4gICAgfVxuXG5cbiAgICBzdWJzY3JpYmUoc3RyZWFtOiBTdHJlYW0pIHtcbiAgICAgICAgc3RyZWFtLnN1YnNjcmliZSgpO1xuICAgIH1cblxuICAgIHVuc3VzY3JpYmUoc3RyZWFtKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiVW5zdWJzY3JpYmluZyBmcm9tIFwiICsgc3RyZWFtLmdldElkKCkpO1xuICAgICAgICB0aGlzLm9wZW5WaWR1LnNlbmRSZXF1ZXN0KCd1bnN1YnNjcmliZUZyb21WaWRlbycsIHtcbiAgICAgICAgICAgIHNlbmRlcjogc3RyZWFtLmdldElkKClcbiAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChlcnJvciwgcmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiVW5zdWJzY3JpYmVkIGNvcnJlY3RseSBmcm9tIFwiICsgc3RyZWFtLmdldElkKCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIG9uUGFydGljaXBhbnRQdWJsaXNoZWQob3B0aW9ucykge1xuXG4gICAgICAgIG9wdGlvbnMubWV0YWRhdGEgPSB0aGlzLnBhcnRpY2lwYW50c1tvcHRpb25zLmlkXS5kYXRhO1xuXG4gICAgICAgIGxldCBjb25uZWN0aW9uID0gbmV3IENvbm5lY3Rpb24odGhpcy5vcGVuVmlkdSwgZmFsc2UsIHRoaXMsIG9wdGlvbnMpO1xuXG4gICAgICAgIGxldCBwaWQgPSBjb25uZWN0aW9uLmNvbm5lY3Rpb25JZDtcbiAgICAgICAgaWYgKCEocGlkIGluIHRoaXMucGFydGljaXBhbnRzKSkge1xuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiUHVibGlzaGVyIG5vdCBmb3VuZCBpbiBwYXJ0aWNpcGFudHMgbGlzdCBieSBpdHMgaWRcIiwgcGlkKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiUHVibGlzaGVyIGZvdW5kIGluIHBhcnRpY2lwYW50cyBsaXN0IGJ5IGl0cyBpZFwiLCBwaWQpO1xuICAgICAgICB9XG4gICAgICAgIC8vcmVwbGFjaW5nIG9sZCBjb25uZWN0aW9uICh0aGlzIG9uZSBoYXMgc3RyZWFtcylcbiAgICAgICAgY29ubmVjdGlvbi5jcmVhdGlvblRpbWUgPSB0aGlzLnBhcnRpY2lwYW50c1twaWRdLmNyZWF0aW9uVGltZTtcbiAgICAgICAgdGhpcy5wYXJ0aWNpcGFudHNbcGlkXSA9IGNvbm5lY3Rpb247XG5cbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3BhcnRpY2lwYW50LXB1Ymxpc2hlZCcsIFt7IGNvbm5lY3Rpb24gfV0pO1xuXG4gICAgICAgIGxldCBzdHJlYW1zID0gY29ubmVjdGlvbi5nZXRTdHJlYW1zKCk7XG4gICAgICAgIGZvciAobGV0IGtleSBpbiBzdHJlYW1zKSB7XG4gICAgICAgICAgICBsZXQgc3RyZWFtID0gc3RyZWFtc1trZXldO1xuXG4gICAgICAgICAgICBpZiAodGhpcy5zdWJzY3JpYmVUb1N0cmVhbXMpIHtcbiAgICAgICAgICAgICAgICBzdHJlYW0uc3Vic2NyaWJlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnc3RyZWFtQ3JlYXRlZCcsIFt7IHN0cmVhbSB9XSk7XG4gICAgICAgICAgICAvLyBBZGRpbmcgdGhlIHJlbW90ZSBzdHJlYW0gdG8gdGhlIE9wZW5WaWR1IG9iamVjdFxuICAgICAgICAgICAgdGhpcy5vcGVuVmlkdS5nZXRSZW1vdGVTdHJlYW1zKCkucHVzaChzdHJlYW0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb25QYXJ0aWNpcGFudEpvaW5lZChtc2cpIHtcblxuICAgICAgICBsZXQgY29ubmVjdGlvbiA9IG5ldyBDb25uZWN0aW9uKHRoaXMub3BlblZpZHUsIGZhbHNlLCB0aGlzLCBtc2cpO1xuICAgICAgICBjb25uZWN0aW9uLmNyZWF0aW9uVGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gICAgICAgIGxldCBwaWQgPSBjb25uZWN0aW9uLmNvbm5lY3Rpb25JZDtcbiAgICAgICAgaWYgKCEocGlkIGluIHRoaXMucGFydGljaXBhbnRzKSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXCJOZXcgcGFydGljaXBhbnQgdG8gcGFydGljaXBhbnRzIGxpc3Qgd2l0aCBpZFwiLCBwaWQpO1xuICAgICAgICAgICAgdGhpcy5wYXJ0aWNpcGFudHNbcGlkXSA9IGNvbm5lY3Rpb247XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvL3VzZSBleGlzdGluZyBzbyB0aGF0IHdlIGRvbid0IGxvc2Ugc3RyZWFtcyBpbmZvXG4gICAgICAgICAgICBjb25zb2xlLmluZm8oXCJQYXJ0aWNpcGFudCBhbHJlYWR5IGV4aXN0cyBpbiBwYXJ0aWNpcGFudHMgbGlzdCB3aXRoIFwiICtcbiAgICAgICAgICAgICAgICBcInRoZSBzYW1lIGlkLCBvbGQ6XCIsIHRoaXMucGFydGljaXBhbnRzW3BpZF0sIFwiLCBqb2luZWQgbm93OlwiLCBjb25uZWN0aW9uKTtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24gPSB0aGlzLnBhcnRpY2lwYW50c1twaWRdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3BhcnRpY2lwYW50LWpvaW5lZCcsIFt7XG4gICAgICAgICAgICBjb25uZWN0aW9uOiBjb25uZWN0aW9uXG4gICAgICAgIH1dKTtcblxuICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnY29ubmVjdGlvbkNyZWF0ZWQnLCBbe1xuICAgICAgICAgICAgY29ubmVjdGlvbjogY29ubmVjdGlvblxuICAgICAgICB9XSk7XG5cbiAgICB9XG5cbiAgICBvblBhcnRpY2lwYW50TGVmdChtc2cpIHtcblxuICAgICAgICBsZXQgY29ubmVjdGlvbiA9IHRoaXMucGFydGljaXBhbnRzW21zZy5uYW1lXTtcblxuICAgICAgICBpZiAoY29ubmVjdGlvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBkZWxldGUgdGhpcy5wYXJ0aWNpcGFudHNbbXNnLm5hbWVdO1xuXG4gICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgncGFydGljaXBhbnQtbGVmdCcsIFt7XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbjogY29ubmVjdGlvblxuICAgICAgICAgICAgfV0pO1xuXG4gICAgICAgICAgICBsZXQgc3RyZWFtcyA9IGNvbm5lY3Rpb24uZ2V0U3RyZWFtcygpO1xuICAgICAgICAgICAgZm9yIChsZXQga2V5IGluIHN0cmVhbXMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnc3RyZWFtRGVzdHJveWVkJywgW3tcbiAgICAgICAgICAgICAgICAgICAgc3RyZWFtOiBzdHJlYW1zW2tleV0sXG4gICAgICAgICAgICAgICAgICAgIHByZXZlbnREZWZhdWx0OiAoKSA9PiB7IHRoaXMuZWUucmVtb3ZlRXZlbnQoJ3N0cmVhbS1kZXN0cm95ZWQtZGVmYXVsdCcpOyB9XG4gICAgICAgICAgICAgICAgfV0pO1xuICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdzdHJlYW0tZGVzdHJveWVkLWRlZmF1bHQnLCBbe1xuICAgICAgICAgICAgICAgICAgICBzdHJlYW06IHN0cmVhbXNba2V5XVxuICAgICAgICAgICAgICAgIH1dKTtcblxuICAgICAgICAgICAgICAgIC8vIERlbGV0aW5nIHRoZSByZW1vdmVkIHN0cmVhbSBmcm9tIHRoZSBPcGVuVmlkdSBvYmplY3RcbiAgICAgICAgICAgICAgICBsZXQgaW5kZXggPSB0aGlzLm9wZW5WaWR1LmdldFJlbW90ZVN0cmVhbXMoKS5pbmRleE9mKHN0cmVhbXNba2V5XSk7XG4gICAgICAgICAgICAgICAgdGhpcy5vcGVuVmlkdS5nZXRSZW1vdGVTdHJlYW1zKCkuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29ubmVjdGlvbi5kaXNwb3NlKCk7XG5cbiAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdjb25uZWN0aW9uRGVzdHJveWVkJywgW3tcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uOiBjb25uZWN0aW9uXG4gICAgICAgICAgICB9XSk7XG5cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcIlBhcnRpY2lwYW50IFwiICsgbXNnLm5hbWVcbiAgICAgICAgICAgICAgICArIFwiIHVua25vd24uIFBhcnRpY2lwYW50czogXCJcbiAgICAgICAgICAgICAgICArIEpTT04uc3RyaW5naWZ5KHRoaXMucGFydGljaXBhbnRzKSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgb25QYXJ0aWNpcGFudEV2aWN0ZWQobXNnKSB7XG4gICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdwYXJ0aWNpcGFudC1ldmljdGVkJywgW3tcbiAgICAgICAgICAgIGxvY2FsUGFydGljaXBhbnQ6IHRoaXMubG9jYWxQYXJ0aWNpcGFudFxuICAgICAgICB9XSk7XG4gICAgfTtcblxuICAgIG9uTmV3TWVzc2FnZShtc2cpIHtcblxuICAgICAgICBjb25zb2xlLmxvZyhcIk5ldyBtZXNzYWdlOiBcIiArIEpTT04uc3RyaW5naWZ5KG1zZykpO1xuICAgICAgICBsZXQgcm9vbSA9IG1zZy5yb29tO1xuICAgICAgICBsZXQgdXNlciA9IG1zZy51c2VyO1xuICAgICAgICBsZXQgbWVzc2FnZSA9IG1zZy5tZXNzYWdlO1xuXG4gICAgICAgIGlmICh1c2VyICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCduZXdNZXNzYWdlJywgW3tcbiAgICAgICAgICAgICAgICByb29tOiByb29tLFxuICAgICAgICAgICAgICAgIHVzZXI6IHVzZXIsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogbWVzc2FnZVxuICAgICAgICAgICAgfV0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFwiVXNlciB1bmRlZmluZWQgaW4gbmV3IG1lc3NhZ2U6XCIsIG1zZyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZWN2SWNlQ2FuZGlkYXRlKG1zZykge1xuXG4gICAgICAgIGxldCBjYW5kaWRhdGUgPSB7XG4gICAgICAgICAgICBjYW5kaWRhdGU6IG1zZy5jYW5kaWRhdGUsXG4gICAgICAgICAgICBzZHBNaWQ6IG1zZy5zZHBNaWQsXG4gICAgICAgICAgICBzZHBNTGluZUluZGV4OiBtc2cuc2RwTUxpbmVJbmRleFxuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGNvbm5lY3Rpb24gPSB0aGlzLnBhcnRpY2lwYW50c1ttc2cuZW5kcG9pbnROYW1lXTtcbiAgICAgICAgaWYgKCFjb25uZWN0aW9uKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiUGFydGljaXBhbnQgbm90IGZvdW5kIGZvciBlbmRwb2ludCBcIiArXG4gICAgICAgICAgICAgICAgbXNnLmVuZHBvaW50TmFtZSArIFwiLiBJY2UgY2FuZGlkYXRlIHdpbGwgYmUgaWdub3JlZC5cIixcbiAgICAgICAgICAgICAgICBjYW5kaWRhdGUpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHN0cmVhbXMgPSBjb25uZWN0aW9uLmdldFN0cmVhbXMoKTtcbiAgICAgICAgZm9yIChsZXQga2V5IGluIHN0cmVhbXMpIHtcbiAgICAgICAgICAgIGxldCBzdHJlYW0gPSBzdHJlYW1zW2tleV07XG4gICAgICAgICAgICBzdHJlYW0uZ2V0V2ViUnRjUGVlcigpLmFkZEljZUNhbmRpZGF0ZShjYW5kaWRhdGUsIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgYWRkaW5nIGNhbmRpZGF0ZSBmb3IgXCIgKyBrZXlcbiAgICAgICAgICAgICAgICAgICAgICAgICsgXCIgc3RyZWFtIG9mIGVuZHBvaW50IFwiICsgbXNnLmVuZHBvaW50TmFtZVxuICAgICAgICAgICAgICAgICAgICAgICAgKyBcIjogXCIgKyBlcnJvcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvblJvb21DbG9zZWQobXNnKSB7XG5cbiAgICAgICAgY29uc29sZS5sb2coXCJSb29tIGNsb3NlZDogXCIgKyBKU09OLnN0cmluZ2lmeShtc2cpKTtcbiAgICAgICAgbGV0IHJvb20gPSBtc2cucm9vbTtcbiAgICAgICAgaWYgKHJvb20gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ3Jvb20tY2xvc2VkJywgW3tcbiAgICAgICAgICAgICAgICByb29tOiByb29tXG4gICAgICAgICAgICB9XSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJSb29tIHVuZGVmaW5lZCBpbiBvbiByb29tIGNsb3NlZFwiLCBtc2cpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb25Mb3N0Q29ubmVjdGlvbigpIHtcblxuICAgICAgICBpZiAoIXRoaXMuY29ubmVjdGVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oJ05vdCBjb25uZWN0ZWQgdG8gcm9vbTogaWYgeW91IGFyZSBub3QgZGVidWdnaW5nLCB0aGlzIGlzIHByb2JhYmx5IGEgY2VydGlmaWNhdGUgZXJyb3InKTtcbiAgICAgICAgICAgIGlmICh3aW5kb3cuY29uZmlybSgnSWYgeW91IGFyZSBub3QgZGVidWdnaW5nLCB0aGlzIGlzIHByb2JhYmx5IGEgY2VydGlmaWNhdGUgZXJyb3IgYXQgXFxcIicgKyB0aGlzLm9wZW5WaWR1LmdldE9wZW5WaWR1U2VydmVyVVJMKCkgKyAnXFxcIlxcblxcbkNsaWNrIE9LIHRvIG5hdmlnYXRlIGFuZCBhY2NlcHQgaXQnKSkge1xuICAgICAgICAgICAgICAgIGxvY2F0aW9uLmFzc2lnbih0aGlzLm9wZW5WaWR1LmdldE9wZW5WaWR1U2VydmVyVVJMKCkgKyAnL2FjY2VwdC1jZXJ0aWZpY2F0ZScpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUubG9nKCdMb3N0IGNvbm5lY3Rpb24gaW4gcm9vbSAnICsgdGhpcy5pZCk7XG4gICAgICAgIGxldCByb29tID0gdGhpcy5pZDtcbiAgICAgICAgaWYgKHJvb20gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhpcy5lZS5lbWl0RXZlbnQoJ2xvc3QtY29ubmVjdGlvbicsIFt7IHJvb20gfV0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKCdSb29tIHVuZGVmaW5lZCB3aGVuIGxvc3QgY29ubmVjdGlvbicpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb25NZWRpYUVycm9yKHBhcmFtcykge1xuXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJNZWRpYSBlcnJvcjogXCIgKyBKU09OLnN0cmluZ2lmeShwYXJhbXMpKTtcbiAgICAgICAgbGV0IGVycm9yID0gcGFyYW1zLmVycm9yO1xuICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdlcnJvci1tZWRpYScsIFt7XG4gICAgICAgICAgICAgICAgZXJyb3I6IGVycm9yXG4gICAgICAgICAgICB9XSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJSZWNlaXZlZCB1bmRlZmluZWQgbWVkaWEgZXJyb3IuIFBhcmFtczpcIiwgcGFyYW1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qXG4gICAgICogZm9yY2VkIG1lYW5zIHRoZSB1c2VyIHdhcyBldmljdGVkLCBubyBuZWVkIHRvIHNlbmQgdGhlICdsZWF2ZVJvb20nIHJlcXVlc3RcbiAgICAgKi9cbiAgICBsZWF2ZShmb3JjZWQsIGpzb25ScGNDbGllbnQpIHtcblxuICAgICAgICBmb3JjZWQgPSAhIWZvcmNlZDtcblxuICAgICAgICBjb25zb2xlLmxvZyhcIkxlYXZpbmcgcm9vbSAoZm9yY2VkPVwiICsgZm9yY2VkICsgXCIpXCIpO1xuXG4gICAgICAgIGlmICh0aGlzLmNvbm5lY3RlZCAmJiAhZm9yY2VkKSB7XG4gICAgICAgICAgICB0aGlzLm9wZW5WaWR1LnNlbmRSZXF1ZXN0KCdsZWF2ZVJvb20nLCBmdW5jdGlvbiAoZXJyb3IsIHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBqc29uUnBjQ2xpZW50LmNsb3NlKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGpzb25ScGNDbGllbnQuY2xvc2UoKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNvbm5lY3RlZCA9IGZhbHNlO1xuICAgICAgICBpZiAodGhpcy5wYXJ0aWNpcGFudHMpIHtcbiAgICAgICAgICAgIGZvciAobGV0IHBpZCBpbiB0aGlzLnBhcnRpY2lwYW50cykge1xuICAgICAgICAgICAgICAgIHRoaXMucGFydGljaXBhbnRzW3BpZF0uZGlzcG9zZSgpO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnBhcnRpY2lwYW50c1twaWRdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgZGlzY29ubmVjdChzdHJlYW06IFN0cmVhbSkge1xuXG4gICAgICAgIGxldCBjb25uZWN0aW9uID0gc3RyZWFtLmdldFBhcnRpY2lwYW50KCk7XG4gICAgICAgIGlmICghY29ubmVjdGlvbikge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIlN0cmVhbSB0byBkaXNjb25uZWN0IGhhcyBubyBwYXJ0aWNpcGFudFwiLCBzdHJlYW0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVsZXRlIHRoaXMucGFydGljaXBhbnRzW2Nvbm5lY3Rpb24uY29ubmVjdGlvbklkXTtcbiAgICAgICAgY29ubmVjdGlvbi5kaXNwb3NlKCk7XG5cbiAgICAgICAgaWYgKGNvbm5lY3Rpb24gPT09IHRoaXMubG9jYWxQYXJ0aWNpcGFudCkge1xuXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIlVucHVibGlzaGluZyBteSBtZWRpYSAoSSdtIFwiICsgY29ubmVjdGlvbi5jb25uZWN0aW9uSWQgKyBcIilcIik7XG4gICAgICAgICAgICBkZWxldGUgdGhpcy5sb2NhbFBhcnRpY2lwYW50O1xuICAgICAgICAgICAgdGhpcy5vcGVuVmlkdS5zZW5kUmVxdWVzdCgndW5wdWJsaXNoVmlkZW8nLCBmdW5jdGlvbiAoZXJyb3IsIHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIk1lZGlhIHVucHVibGlzaGVkIGNvcnJlY3RseVwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy51bnN1c2NyaWJlKHN0cmVhbSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB1bnB1Ymxpc2goc3RyZWFtOiBTdHJlYW0pIHtcblxuICAgICAgICBsZXQgY29ubmVjdGlvbiA9IHN0cmVhbS5nZXRQYXJ0aWNpcGFudCgpO1xuICAgICAgICBpZiAoIWNvbm5lY3Rpb24pIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJTdHJlYW0gdG8gZGlzY29ubmVjdCBoYXMgbm8gcGFydGljaXBhbnRcIiwgc3RyZWFtKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjb25uZWN0aW9uID09PSB0aGlzLmxvY2FsUGFydGljaXBhbnQpIHtcblxuICAgICAgICAgICAgZGVsZXRlIHRoaXMucGFydGljaXBhbnRzW2Nvbm5lY3Rpb24uY29ubmVjdGlvbklkXTtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24uZGlzcG9zZSgpO1xuXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIlVucHVibGlzaGluZyBteSBtZWRpYSAoSSdtIFwiICsgY29ubmVjdGlvbi5jb25uZWN0aW9uSWQgKyBcIilcIik7XG4gICAgICAgICAgICBkZWxldGUgdGhpcy5sb2NhbFBhcnRpY2lwYW50O1xuICAgICAgICAgICAgdGhpcy5vcGVuVmlkdS5zZW5kUmVxdWVzdCgndW5wdWJsaXNoVmlkZW8nLCBmdW5jdGlvbiAoZXJyb3IsIHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIk1lZGlhIHVucHVibGlzaGVkIGNvcnJlY3RseVwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGdldFN0cmVhbXMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmVhbXM7XG4gICAgfVxuXG4gICAgYWRkUGFydGljaXBhbnRTcGVha2luZyhwYXJ0aWNpcGFudElkKSB7XG4gICAgICAgIHRoaXMucGFydGljaXBhbnRzU3BlYWtpbmcucHVzaChwYXJ0aWNpcGFudElkKTtcbiAgICB9XG5cbiAgICByZW1vdmVQYXJ0aWNpcGFudFNwZWFraW5nKHBhcnRpY2lwYW50SWQpIHtcbiAgICAgICAgbGV0IHBvcyA9IC0xO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMucGFydGljaXBhbnRzU3BlYWtpbmcubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnBhcnRpY2lwYW50c1NwZWFraW5nW2ldID09IHBhcnRpY2lwYW50SWQpIHtcbiAgICAgICAgICAgICAgICBwb3MgPSBpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChwb3MgIT0gLTEpIHtcbiAgICAgICAgICAgIHRoaXMucGFydGljaXBhbnRzU3BlYWtpbmcuc3BsaWNlKHBvcywgMSk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCIvKlxuICogb3B0aW9uczogbmFtZTogWFhYIGRhdGE6IHRydWUgKE1heWJlIHRoaXMgaXMgYmFzZWQgb24gd2VicnRjKSBhdWRpbzogdHJ1ZSxcbiAqIHZpZGVvOiB0cnVlLCB1cmw6IFwiZmlsZTovLy8uLi5cIiA+IFBsYXllciBzY3JlZW46IHRydWUgPiBEZXNrdG9wIChpbXBsaWNpdFxuICogdmlkZW86dHJ1ZSwgYXVkaW86ZmFsc2UpIGF1ZGlvOiB0cnVlLCB2aWRlbzogdHJ1ZSA+IFdlYmNhbVxuICpcbiAqIHN0cmVhbS5oYXNBdWRpbygpOyBzdHJlYW0uaGFzVmlkZW8oKTsgc3RyZWFtLmhhc0RhdGEoKTtcbiAqL1xuaW1wb3J0IHsgQ29ubmVjdGlvbiB9IGZyb20gJy4vQ29ubmVjdGlvbic7XG5pbXBvcnQgeyBTZXNzaW9uSW50ZXJuYWwgfSBmcm9tICcuL1Nlc3Npb25JbnRlcm5hbCc7XG5pbXBvcnQgeyBPcGVuVmlkdUludGVybmFsLCBDYWxsYmFjayB9IGZyb20gJy4vT3BlblZpZHVJbnRlcm5hbCc7XG5pbXBvcnQgRXZlbnRFbWl0dGVyID0gcmVxdWlyZSgnd29sZnk4Ny1ldmVudGVtaXR0ZXInKTtcbmltcG9ydCAqIGFzIGt1cmVudG9VdGlscyBmcm9tICdrdXJlbnRvLXV0aWxzJztcblxuaW1wb3J0ICogYXMgYWRhcHRlciBmcm9tICd3ZWJydGMtYWRhcHRlcic7XG5kZWNsYXJlIHZhciBuYXZpZ2F0b3I6IGFueTtcbmRlY2xhcmUgdmFyIFJUQ1Nlc3Npb25EZXNjcmlwdGlvbjogYW55O1xuXG5pZiAod2luZG93KSB7XG4gICAgd2luZG93W1wiYWRhcHRlclwiXSA9IGFkYXB0ZXI7XG59XG5cbmZ1bmN0aW9uIGpxKGlkOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBpZC5yZXBsYWNlKC8oQHw6fFxcLnxcXFt8XFxdfCwpL2csIFwiXFxcXCQxXCIpO1xufVxuXG5mdW5jdGlvbiBzaG93KGlkOiBzdHJpbmcpIHtcbiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChqcShpZCkpIS5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcbn1cblxuZnVuY3Rpb24gaGlkZShpZDogc3RyaW5nKSB7XG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoanEoaWQpKSEuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTdHJlYW1PcHRpb25zIHtcbiAgICBpZDogc3RyaW5nO1xuICAgIGNvbm5lY3Rpb246IENvbm5lY3Rpb247XG4gICAgcmVjdlZpZGVvOiBhbnk7XG4gICAgcmVjdkF1ZGlvOiBhbnk7XG4gICAgdmlkZW86IGJvb2xlYW47XG4gICAgYXVkaW86IGJvb2xlYW47XG4gICAgZGF0YTogYm9vbGVhbjtcbiAgICBtZWRpYUNvbnN0cmFpbnRzOiBhbnk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmlkZW9PcHRpb25zIHtcbiAgICB0aHVtYjogc3RyaW5nO1xuICAgIHZpZGVvOiBIVE1MVmlkZW9FbGVtZW50O1xufVxuXG5leHBvcnQgY2xhc3MgU3RyZWFtIHtcblxuICAgIHB1YmxpYyBjb25uZWN0aW9uOiBDb25uZWN0aW9uO1xuXG4gICAgcHJpdmF0ZSBlZSA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgICBwcml2YXRlIHdyU3RyZWFtOiBhbnk7XG4gICAgcHJpdmF0ZSB3cDogYW55O1xuICAgIHByaXZhdGUgaWQ6IHN0cmluZztcbiAgICBwcml2YXRlIHZpZGVvOiBIVE1MVmlkZW9FbGVtZW50O1xuICAgIHByaXZhdGUgdmlkZW9FbGVtZW50czogVmlkZW9PcHRpb25zW10gPSBbXTtcbiAgICBwcml2YXRlIGVsZW1lbnRzOiBIVE1MRGl2RWxlbWVudFtdID0gW107XG4gICAgcHJpdmF0ZSBzcGVlY2hFdmVudDogYW55O1xuICAgIHByaXZhdGUgcmVjdlZpZGVvOiBhbnk7XG4gICAgcHJpdmF0ZSByZWN2QXVkaW86IGFueTtcbiAgICBwcml2YXRlIHNlbmRWaWRlbzogYm9vbGVhbjtcbiAgICBwcml2YXRlIHNlbmRBdWRpbzogYm9vbGVhbjtcbiAgICBwcml2YXRlIG1lZGlhQ29uc3RyYWludHM6IGFueTtcbiAgICBwcml2YXRlIHNob3dNeVJlbW90ZSA9IGZhbHNlO1xuICAgIHByaXZhdGUgbG9jYWxNaXJyb3JlZCA9IGZhbHNlO1xuICAgIHByaXZhdGUgY2hhbklkID0gMDtcbiAgICBwcml2YXRlIGRhdGFDaGFubmVsOiBib29sZWFuO1xuICAgIHByaXZhdGUgZGF0YUNoYW5uZWxPcGVuZWQgPSBmYWxzZTtcblxuICAgIHByaXZhdGUgdmlkZW9TcmM6IHN0cmluZztcbiAgICBwcml2YXRlIHBhcmVudElkOiBzdHJpbmc7XG4gICAgcHVibGljIGlzUmVhZHk6IGJvb2xlYW4gPSBmYWxzZTtcbiAgICBwdWJsaWMgYWNjZXNzSXNBbGxvd2VkOiBib29sZWFuID0gZmFsc2U7XG4gICAgcHVibGljIGFjY2Vzc0lzRGVuaWVkOiBib29sZWFuID0gZmFsc2U7XG5cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIG9wZW5WaWR1OiBPcGVuVmlkdUludGVybmFsLCBwcml2YXRlIGxvY2FsOiBib29sZWFuLCBwcml2YXRlIHJvb206IFNlc3Npb25JbnRlcm5hbCwgb3B0aW9uczogU3RyZWFtT3B0aW9ucykge1xuXG4gICAgICAgIGlmIChvcHRpb25zLmlkKSB7XG4gICAgICAgICAgICB0aGlzLmlkID0gb3B0aW9ucy5pZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuaWQgPSBcIndlYmNhbVwiO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jb25uZWN0aW9uID0gb3B0aW9ucy5jb25uZWN0aW9uO1xuICAgICAgICB0aGlzLnJlY3ZWaWRlbyA9IG9wdGlvbnMucmVjdlZpZGVvO1xuICAgICAgICB0aGlzLnJlY3ZBdWRpbyA9IG9wdGlvbnMucmVjdkF1ZGlvO1xuICAgICAgICB0aGlzLmRhdGFDaGFubmVsID0gb3B0aW9ucy5kYXRhIHx8IGZhbHNlO1xuICAgICAgICB0aGlzLnNlbmRWaWRlbyA9IG9wdGlvbnMudmlkZW87XG4gICAgICAgIHRoaXMuc2VuZEF1ZGlvID0gb3B0aW9ucy5hdWRpbztcbiAgICAgICAgdGhpcy5tZWRpYUNvbnN0cmFpbnRzID0gb3B0aW9ucy5tZWRpYUNvbnN0cmFpbnRzO1xuXG4gICAgICAgIHRoaXMuYWRkRXZlbnRMaXN0ZW5lcignc3JjLWFkZGVkJywgKHNyY0V2ZW50KSA9PiB7XG4gICAgICAgICAgICB0aGlzLnZpZGVvU3JjID0gc3JjRXZlbnQuc3JjO1xuICAgICAgICAgICAgaWYgKHRoaXMudmlkZW8pIHRoaXMudmlkZW8uc3JjID0gc3JjRXZlbnQuc3JjO1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFwiVmlkZW9zcmMgW1wiICsgc3JjRXZlbnQuc3JjICsgXCJdIGFkZGVkIHRvIHN0cmVhbSBbXCIgKyB0aGlzLmdldElkKCkgKyBcIl1cIik7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGVtaXRTcmNFdmVudCh3cnN0cmVhbSkge1xuICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnc3JjLWFkZGVkJywgW3tcbiAgICAgICAgICAgIHNyYzogVVJMLmNyZWF0ZU9iamVjdFVSTCh3cnN0cmVhbSlcbiAgICAgICAgfV0pO1xuICAgIH1cblxuICAgIGVtaXRTdHJlYW1SZWFkeUV2ZW50KCkge1xuICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnc3RyZWFtLXJlYWR5JyksIFt7fV07XG4gICAgfVxuXG4gICAgZ2V0VmlkZW9TcmMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnZpZGVvU3JjO1xuICAgIH1cblxuICAgIHJlbW92ZVZpZGVvKHBhcmVudEVsZW1lbnQ6IHN0cmluZyk7XG4gICAgcmVtb3ZlVmlkZW8ocGFyZW50RWxlbWVudDogRWxlbWVudCk7XG4gICAgcmVtb3ZlVmlkZW8oKTtcblxuICAgIHJlbW92ZVZpZGVvKHBhcmVudEVsZW1lbnQ/KSB7XG4gICAgICAgIGlmICh0eXBlb2YgcGFyZW50RWxlbWVudCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQocGFyZW50RWxlbWVudCkhLnJlbW92ZUNoaWxkKHRoaXMudmlkZW8pO1xuICAgICAgICB9IGVsc2UgaWYgKHBhcmVudEVsZW1lbnQgaW5zdGFuY2VvZiBFbGVtZW50KSB7XG4gICAgICAgICAgICBwYXJlbnRFbGVtZW50LnJlbW92ZUNoaWxkKHRoaXMudmlkZW8pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCFwYXJlbnRFbGVtZW50KSB7XG4gICAgICAgICAgICBpZiAoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5wYXJlbnRJZCkpIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnBhcmVudElkKSEucmVtb3ZlQ2hpbGQodGhpcy52aWRlbyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBnZXRWaWRlb0VsZW1lbnQoKTogSFRNTFZpZGVvRWxlbWVudCB7XG4gICAgICAgIHJldHVybiB0aGlzLnZpZGVvO1xuICAgIH1cblxuICAgIHNldFZpZGVvRWxlbWVudCh2aWRlbzogSFRNTFZpZGVvRWxlbWVudCkge1xuICAgICAgICB0aGlzLnZpZGVvID0gdmlkZW87XG4gICAgfVxuXG5cblxuXG5cblxuICAgIGdldFJlY3ZWaWRlbygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVjdlZpZGVvO1xuICAgIH1cblxuICAgIGdldFJlY3ZBdWRpbygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVjdkF1ZGlvO1xuICAgIH1cblxuXG4gICAgc3Vic2NyaWJlVG9NeVJlbW90ZSgpIHtcbiAgICAgICAgdGhpcy5zaG93TXlSZW1vdGUgPSB0cnVlO1xuICAgIH1cblxuICAgIGRpc3BsYXlNeVJlbW90ZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2hvd015UmVtb3RlO1xuICAgIH1cblxuICAgIG1pcnJvckxvY2FsU3RyZWFtKHdyKSB7XG4gICAgICAgIHRoaXMuc2hvd015UmVtb3RlID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5sb2NhbE1pcnJvcmVkID0gdHJ1ZTtcbiAgICAgICAgaWYgKHdyKSB7XG4gICAgICAgICAgICB0aGlzLndyU3RyZWFtID0gd3I7XG4gICAgICAgICAgICB0aGlzLmVtaXRTcmNFdmVudCh0aGlzLndyU3RyZWFtKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlzTG9jYWxNaXJyb3JlZCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxNaXJyb3JlZDtcbiAgICB9XG5cbiAgICBnZXRDaGFubmVsTmFtZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0SWQoKSArICdfJyArIHRoaXMuY2hhbklkKys7XG4gICAgfVxuXG5cbiAgICBpc0RhdGFDaGFubmVsRW5hYmxlZCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YUNoYW5uZWw7XG4gICAgfVxuXG5cbiAgICBpc0RhdGFDaGFubmVsT3BlbmVkKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kYXRhQ2hhbm5lbE9wZW5lZDtcbiAgICB9XG5cbiAgICBvbkRhdGFDaGFubmVsT3BlbihldmVudCkge1xuICAgICAgICBjb25zb2xlLmxvZygnRGF0YSBjaGFubmVsIGlzIG9wZW5lZCcpO1xuICAgICAgICB0aGlzLmRhdGFDaGFubmVsT3BlbmVkID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBvbkRhdGFDaGFubmVsQ2xvc2VkKGV2ZW50KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdEYXRhIGNoYW5uZWwgaXMgY2xvc2VkJyk7XG4gICAgICAgIHRoaXMuZGF0YUNoYW5uZWxPcGVuZWQgPSBmYWxzZTtcbiAgICB9XG5cbiAgICBzZW5kRGF0YShkYXRhKSB7XG4gICAgICAgIGlmICh0aGlzLndwID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignV2ViUlRDIHBlZXIgaGFzIG5vdCBiZWVuIGNyZWF0ZWQgeWV0Jyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0aGlzLmRhdGFDaGFubmVsT3BlbmVkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0RhdGEgY2hhbm5lbCBpcyBub3Qgb3BlbmVkJyk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc29sZS5sb2coXCJTZW5kaW5nIHRocm91Z2ggZGF0YSBjaGFubmVsOiBcIiArIGRhdGEpO1xuICAgICAgICB0aGlzLndwLnNlbmQoZGF0YSk7XG4gICAgfVxuXG4gICAgZ2V0V3JTdHJlYW0oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLndyU3RyZWFtO1xuICAgIH1cblxuICAgIGdldFdlYlJ0Y1BlZXIoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLndwO1xuICAgIH1cblxuICAgIGFkZEV2ZW50TGlzdGVuZXIoZXZlbnROYW1lOiBzdHJpbmcsIGxpc3RlbmVyOiBhbnkpIHtcbiAgICAgICAgdGhpcy5lZS5hZGRMaXN0ZW5lcihldmVudE5hbWUsIGxpc3RlbmVyKTtcbiAgICB9XG5cbiAgICBhZGRPbmNlRXZlbnRMaXN0ZW5lcihldmVudE5hbWU6IHN0cmluZywgbGlzdGVuZXI6IGFueSkge1xuICAgICAgICB0aGlzLmVlLmFkZE9uY2VMaXN0ZW5lcihldmVudE5hbWUsIGxpc3RlbmVyKTtcbiAgICB9XG5cbiAgICByZW1vdmVMaXN0ZW5lcihldmVudE5hbWUpIHtcbiAgICAgICAgdGhpcy5lZS5yZW1vdmVBbGxMaXN0ZW5lcnMoZXZlbnROYW1lKTtcbiAgICB9XG5cbiAgICBzaG93U3Bpbm5lcihzcGlubmVyUGFyZW50SWQ6IHN0cmluZykge1xuICAgICAgICBsZXQgcHJvZ3Jlc3MgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgcHJvZ3Jlc3MuaWQgPSAncHJvZ3Jlc3MtJyArIHRoaXMuZ2V0SWQoKTtcbiAgICAgICAgcHJvZ3Jlc3Muc3R5bGUuYmFja2dyb3VuZCA9IFwiY2VudGVyIHRyYW5zcGFyZW50IHVybCgnaW1nL3NwaW5uZXIuZ2lmJykgbm8tcmVwZWF0XCI7XG4gICAgICAgIGxldCBzcGlubmVyUGFyZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoc3Bpbm5lclBhcmVudElkKTtcbiAgICAgICAgaWYgKHNwaW5uZXJQYXJlbnQpIHtcbiAgICAgICAgICAgIHNwaW5uZXJQYXJlbnQuYXBwZW5kQ2hpbGQocHJvZ3Jlc3MpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaGlkZVNwaW5uZXIoc3Bpbm5lcklkPzogc3RyaW5nKSB7XG4gICAgICAgIHNwaW5uZXJJZCA9IChzcGlubmVySWQgPT09IHVuZGVmaW5lZCkgPyB0aGlzLmdldElkKCkgOiBzcGlubmVySWQ7XG4gICAgICAgIGhpZGUoJ3Byb2dyZXNzLScgKyBzcGlubmVySWQpO1xuICAgIH1cblxuICAgIHBsYXlPbmx5VmlkZW8ocGFyZW50RWxlbWVudCwgdGh1bWJuYWlsSWQpIHtcblxuICAgICAgICAvLyBUTy1ETzogY2hlY2sgc29tZWhvdyBpZiB0aGUgc3RyZWFtIGlzIGF1ZGlvIG9ubHksIHNvIHRoZSBlbGVtZW50IGNyZWF0ZWQgaXMgPGF1ZGlvPiBpbnN0ZWFkIG9mIDx2aWRlbz5cbiAgICBcbiAgICAgICAgdGhpcy52aWRlbyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3ZpZGVvJyk7XG5cbiAgICAgICAgdGhpcy52aWRlby5pZCA9ICduYXRpdmUtdmlkZW8tJyArIHRoaXMuZ2V0SWQoKTtcbiAgICAgICAgdGhpcy52aWRlby5hdXRvcGxheSA9IHRydWU7XG4gICAgICAgIHRoaXMudmlkZW8uY29udHJvbHMgPSBmYWxzZTtcbiAgICAgICAgdGhpcy52aWRlby5zcmMgPSB0aGlzLnZpZGVvU3JjO1xuXG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50cy5wdXNoKHtcbiAgICAgICAgICAgIHRodW1iOiB0aHVtYm5haWxJZCxcbiAgICAgICAgICAgIHZpZGVvOiB0aGlzLnZpZGVvXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICh0aGlzLmxvY2FsKSB7XG4gICAgICAgICAgICB0aGlzLnZpZGVvLm11dGVkID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMudmlkZW8udGl0bGUgPSB0aGlzLmdldElkKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHBhcmVudEVsZW1lbnQgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIHRoaXMucGFyZW50SWQgPSBwYXJlbnRFbGVtZW50O1xuXG4gICAgICAgICAgICBsZXQgcGFyZW50RWxlbWVudERvbSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHBhcmVudEVsZW1lbnQpO1xuICAgICAgICAgICAgaWYgKHBhcmVudEVsZW1lbnREb20pIHtcbiAgICAgICAgICAgICAgICB0aGlzLnZpZGVvID0gcGFyZW50RWxlbWVudERvbS5hcHBlbmRDaGlsZCh0aGlzLnZpZGVvKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMucGFyZW50SWQgPSBwYXJlbnRFbGVtZW50LmlkO1xuICAgICAgICAgICAgdGhpcy52aWRlbyA9IHBhcmVudEVsZW1lbnQuYXBwZW5kQ2hpbGQodGhpcy52aWRlbyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgndmlkZW8tZWxlbWVudC1jcmVhdGVkLWJ5LXN0cmVhbScsIFt7XG4gICAgICAgICAgICBlbGVtZW50OiB0aGlzLnZpZGVvXG4gICAgICAgIH1dKTtcblxuICAgICAgICB0aGlzLmVlLmVtaXRFdmVudCgnc3RyZWFtLWNyZWF0ZWQtYnktcHVibGlzaGVyJyk7XG5cbiAgICAgICAgdGhpcy5pc1JlYWR5ID0gdHJ1ZTtcblxuICAgICAgICByZXR1cm4gdGhpcy52aWRlbztcbiAgICB9XG5cbiAgICBwbGF5VGh1bWJuYWlsKHRodW1ibmFpbElkKSB7XG5cbiAgICAgICAgbGV0IGNvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICBjb250YWluZXIuY2xhc3NOYW1lID0gXCJwYXJ0aWNpcGFudFwiO1xuICAgICAgICBjb250YWluZXIuaWQgPSB0aGlzLmdldElkKCk7XG4gICAgICAgIGxldCB0aHVtYm5haWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aHVtYm5haWxJZCk7XG4gICAgICAgIGlmICh0aHVtYm5haWwpIHtcbiAgICAgICAgICAgIHRodW1ibmFpbC5hcHBlbmRDaGlsZChjb250YWluZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lbGVtZW50cy5wdXNoKGNvbnRhaW5lcik7XG5cbiAgICAgICAgbGV0IG5hbWUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgY29udGFpbmVyLmFwcGVuZENoaWxkKG5hbWUpO1xuICAgICAgICBsZXQgdXNlck5hbWUgPSB0aGlzLmdldElkKCkucmVwbGFjZSgnX3dlYmNhbScsICcnKTtcbiAgICAgICAgaWYgKHVzZXJOYW1lLmxlbmd0aCA+PSAxNikge1xuICAgICAgICAgICAgdXNlck5hbWUgPSB1c2VyTmFtZS5zdWJzdHJpbmcoMCwgMTYpICsgXCIuLi5cIjtcbiAgICAgICAgfVxuICAgICAgICBuYW1lLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHVzZXJOYW1lKSk7XG4gICAgICAgIG5hbWUuaWQgPSBcIm5hbWUtXCIgKyB0aGlzLmdldElkKCk7XG4gICAgICAgIG5hbWUuY2xhc3NOYW1lID0gXCJuYW1lXCI7XG4gICAgICAgIG5hbWUudGl0bGUgPSB0aGlzLmdldElkKCk7XG5cbiAgICAgICAgdGhpcy5zaG93U3Bpbm5lcih0aHVtYm5haWxJZCk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucGxheU9ubHlWaWRlbyhjb250YWluZXIsIHRodW1ibmFpbElkKTtcbiAgICB9XG5cbiAgICBnZXRJZEluUGFydGljaXBhbnQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmlkO1xuICAgIH1cblxuICAgIGdldFBhcnRpY2lwYW50KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25uZWN0aW9uO1xuICAgIH1cblxuICAgIGdldElkKCkge1xuICAgICAgICBpZiAodGhpcy5jb25uZWN0aW9uKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jb25uZWN0aW9uLmNvbm5lY3Rpb25JZCArIFwiX1wiICsgdGhpcy5pZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmlkICsgXCJfd2ViY2FtXCI7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBnZXRSVENQZWVyQ29ubmVjdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0V2ViUnRjUGVlcigpLnBlZXJDb25uZWN0aW9uO1xuICAgIH1cblxuICAgIHJlcXVlc3RDYW1lcmFBY2Nlc3MoY2FsbGJhY2s6IENhbGxiYWNrPFN0cmVhbT4pIHtcblxuICAgICAgICB0aGlzLmNvbm5lY3Rpb24uYWRkU3RyZWFtKHRoaXMpO1xuXG4gICAgICAgIGxldCBjb25zdHJhaW50cyA9IHRoaXMubWVkaWFDb25zdHJhaW50cztcblxuICAgICAgICAvKmxldCBjb25zdHJhaW50czIgPSB7XG4gICAgICAgICAgICBhdWRpbzogdHJ1ZSxcbiAgICAgICAgICAgIHZpZGVvOiB7XG4gICAgICAgICAgICAgICAgd2lkdGg6IHtcbiAgICAgICAgICAgICAgICAgICAgaWRlYWw6IDEyODBcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGZyYW1lUmF0ZToge1xuICAgICAgICAgICAgICAgICAgICBpZGVhbDogMTVcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH07Ki9cblxuICAgICAgICB0aGlzLnVzZXJNZWRpYUhhc1ZpZGVvKChoYXNWaWRlbykgPT4ge1xuICAgICAgICAgICAgaWYgKCFoYXNWaWRlbykge1xuICAgICAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kVmlkZW8gPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RDYW1lcmFBY2Nlc0F1eChjb25zdHJhaW50cywgY2FsbGJhY2spO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RDYW1lcmFBY2Nlc0F1eChjb25zdHJhaW50cywgY2FsbGJhY2spO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlcXVlc3RDYW1lcmFBY2Nlc0F1eChjb25zdHJhaW50cywgY2FsbGJhY2spIHtcbiAgICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEoY29uc3RyYWludHMpXG4gICAgICAgICAgICAudGhlbih1c2VyU3RyZWFtID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmFjY2Vzc0lzQWxsb3dlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5hY2Nlc3NJc0RlbmllZCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdhY2Nlc3MtYWxsb3dlZC1ieS1wdWJsaXNoZXInKTtcblxuICAgICAgICAgICAgICAgIGlmICh1c2VyU3RyZWFtLmdldEF1ZGlvVHJhY2tzKClbMF0gIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICB1c2VyU3RyZWFtLmdldEF1ZGlvVHJhY2tzKClbMF0uZW5hYmxlZCA9IHRoaXMuc2VuZEF1ZGlvO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAodXNlclN0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgdXNlclN0cmVhbS5nZXRWaWRlb1RyYWNrcygpWzBdLmVuYWJsZWQgPSB0aGlzLnNlbmRWaWRlbztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLndyU3RyZWFtID0gdXNlclN0cmVhbTtcbiAgICAgICAgICAgICAgICB0aGlzLmVtaXRTcmNFdmVudCh0aGlzLndyU3RyZWFtKTtcblxuICAgICAgICAgICAgICAgIGNhbGxiYWNrKHVuZGVmaW5lZCwgdGhpcyk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmFjY2Vzc0lzRGVuaWVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLmFjY2Vzc0lzQWxsb3dlZCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHRoaXMuZWUuZW1pdEV2ZW50KCdhY2Nlc3MtZGVuaWVkLWJ5LXB1Ymxpc2hlcicpO1xuXG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkFjY2VzcyBkZW5pZWRcIiwgZXJyb3IpO1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGVycm9yLCB0aGlzKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXNlck1lZGlhSGFzVmlkZW8oY2FsbGJhY2spIHtcbiAgICAgICAgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5lbnVtZXJhdGVEZXZpY2VzKCkudGhlbihmdW5jdGlvbiAobWVkaWFEZXZpY2VzKSB7XG4gICAgICAgICAgICB2YXIgdmlkZW9JbnB1dCA9IG1lZGlhRGV2aWNlcy5maWx0ZXIoZnVuY3Rpb24gKGRldmljZUluZm8pIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGV2aWNlSW5mby5raW5kID09PSAndmlkZW9pbnB1dCc7XG4gICAgICAgICAgICB9KVswXTtcbiAgICAgICAgICAgIGNhbGxiYWNrKHZpZGVvSW5wdXQgIT0gbnVsbCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1Ymxpc2hWaWRlb0NhbGxiYWNrKGVycm9yLCBzZHBPZmZlclBhcmFtLCB3cCkge1xuXG4gICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgcmV0dXJuIGNvbnNvbGUuZXJyb3IoXCIocHVibGlzaCkgU0RQIG9mZmVyIGVycm9yOiBcIlxuICAgICAgICAgICAgICAgICsgSlNPTi5zdHJpbmdpZnkoZXJyb3IpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUubG9nKFwiU2VuZGluZyBTRFAgb2ZmZXIgdG8gcHVibGlzaCBhcyBcIlxuICAgICAgICAgICAgKyB0aGlzLmdldElkKCksIHNkcE9mZmVyUGFyYW0pO1xuXG4gICAgICAgIHRoaXMub3BlblZpZHUuc2VuZFJlcXVlc3QoXCJwdWJsaXNoVmlkZW9cIiwge1xuICAgICAgICAgICAgc2RwT2ZmZXI6IHNkcE9mZmVyUGFyYW0sXG4gICAgICAgICAgICBkb0xvb3BiYWNrOiB0aGlzLmRpc3BsYXlNeVJlbW90ZSgpIHx8IGZhbHNlXG4gICAgICAgIH0sIChlcnJvciwgcmVzcG9uc2UpID0+IHtcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBvbiBwdWJsaXNoVmlkZW86IFwiICsgSlNPTi5zdHJpbmdpZnkoZXJyb3IpKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5yb29tLmVtaXRFdmVudCgnc3RyZWFtLXB1Ymxpc2hlZCcsIFt7XG4gICAgICAgICAgICAgICAgICAgIHN0cmVhbTogdGhpc1xuICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgICAgICB0aGlzLnByb2Nlc3NTZHBBbnN3ZXIocmVzcG9uc2Uuc2RwQW5zd2VyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgc3RhcnRWaWRlb0NhbGxiYWNrKGVycm9yLCBzZHBPZmZlclBhcmFtLCB3cCkge1xuICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25zb2xlLmVycm9yKFwiKHN1YnNjcmliZSkgU0RQIG9mZmVyIGVycm9yOiBcIlxuICAgICAgICAgICAgICAgICsgSlNPTi5zdHJpbmdpZnkoZXJyb3IpKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZyhcIlNlbmRpbmcgU0RQIG9mZmVyIHRvIHN1YnNjcmliZSB0byBcIlxuICAgICAgICAgICAgKyB0aGlzLmdldElkKCksIHNkcE9mZmVyUGFyYW0pO1xuICAgICAgICB0aGlzLm9wZW5WaWR1LnNlbmRSZXF1ZXN0KFwicmVjZWl2ZVZpZGVvRnJvbVwiLCB7XG4gICAgICAgICAgICBzZW5kZXI6IHRoaXMuZ2V0SWQoKSxcbiAgICAgICAgICAgIHNkcE9mZmVyOiBzZHBPZmZlclBhcmFtXG4gICAgICAgIH0sIChlcnJvciwgcmVzcG9uc2UpID0+IHtcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBvbiByZWN2VmlkZW9Gcm9tOiBcIiArIEpTT04uc3RyaW5naWZ5KGVycm9yKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMucHJvY2Vzc1NkcEFuc3dlcihyZXNwb25zZS5zZHBBbnN3ZXIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGluaXRXZWJSdGNQZWVyKHNkcE9mZmVyQ2FsbGJhY2spIHtcbiAgICAgICAgaWYgKHRoaXMubG9jYWwpIHtcblxuICAgICAgICAgICAgbGV0IHVzZXJNZWRpYUNvbnN0cmFpbnRzID0ge1xuICAgICAgICAgICAgICAgIGF1ZGlvOiB0aGlzLnNlbmRBdWRpbyxcbiAgICAgICAgICAgICAgICB2aWRlbzogdGhpcy5zZW5kVmlkZW9cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IG9wdGlvbnM6IGFueSA9IHtcbiAgICAgICAgICAgICAgICB2aWRlb1N0cmVhbTogdGhpcy53clN0cmVhbSxcbiAgICAgICAgICAgICAgICBtZWRpYUNvbnN0cmFpbnRzOiB1c2VyTWVkaWFDb25zdHJhaW50cyxcbiAgICAgICAgICAgICAgICBvbmljZWNhbmRpZGF0ZTogdGhpcy5jb25uZWN0aW9uLnNlbmRJY2VDYW5kaWRhdGUuYmluZCh0aGlzLmNvbm5lY3Rpb24pLFxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5kYXRhQ2hhbm5lbCkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZGF0YUNoYW5uZWxDb25maWcgPSB7XG4gICAgICAgICAgICAgICAgICAgIGlkOiB0aGlzLmdldENoYW5uZWxOYW1lKCksXG4gICAgICAgICAgICAgICAgICAgIG9ub3BlbjogdGhpcy5vbkRhdGFDaGFubmVsT3BlbixcbiAgICAgICAgICAgICAgICAgICAgb25jbG9zZTogdGhpcy5vbkRhdGFDaGFubmVsQ2xvc2VkXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmRhdGFDaGFubmVscyA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLmRpc3BsYXlNeVJlbW90ZSgpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy53cCA9IG5ldyBrdXJlbnRvVXRpbHMuV2ViUnRjUGVlci5XZWJSdGNQZWVyU2VuZHJlY3Yob3B0aW9ucywgZXJyb3IgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB0aGlzLndwLmdlbmVyYXRlT2ZmZXIoc2RwT2ZmZXJDYWxsYmFjay5iaW5kKHRoaXMpKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy53cCA9IG5ldyBrdXJlbnRvVXRpbHMuV2ViUnRjUGVlci5XZWJSdGNQZWVyU2VuZG9ubHkob3B0aW9ucywgZXJyb3IgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB0aGlzLndwLmdlbmVyYXRlT2ZmZXIoc2RwT2ZmZXJDYWxsYmFjay5iaW5kKHRoaXMpKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGxldCBvZmZlckNvbnN0cmFpbnRzID0ge1xuICAgICAgICAgICAgICAgIG1hbmRhdG9yeToge1xuICAgICAgICAgICAgICAgICAgICBPZmZlclRvUmVjZWl2ZVZpZGVvOiB0aGlzLnJlY3ZWaWRlbyxcbiAgICAgICAgICAgICAgICAgICAgT2ZmZXJUb1JlY2VpdmVBdWRpbzogdGhpcy5yZWN2QXVkaW9cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgY29uc29sZS5sb2coXCJDb25zdHJhaW50cyBvZiBnZW5lcmF0ZSBTRFAgb2ZmZXIgKHN1YnNjcmliaW5nKVwiLFxuICAgICAgICAgICAgICAgIG9mZmVyQ29uc3RyYWludHMpO1xuICAgICAgICAgICAgbGV0IG9wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgb25pY2VjYW5kaWRhdGU6IHRoaXMuY29ubmVjdGlvbi5zZW5kSWNlQ2FuZGlkYXRlLmJpbmQodGhpcy5jb25uZWN0aW9uKSxcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uQ29uc3RyYWludHM6IG9mZmVyQ29uc3RyYWludHNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMud3AgPSBuZXcga3VyZW50b1V0aWxzLldlYlJ0Y1BlZXIuV2ViUnRjUGVlclJlY3Zvbmx5KG9wdGlvbnMsIGVycm9yID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLndwLmdlbmVyYXRlT2ZmZXIoc2RwT2ZmZXJDYWxsYmFjay5iaW5kKHRoaXMpKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUubG9nKFwiV2FpdGluZyBmb3IgU0RQIG9mZmVyIHRvIGJlIGdlbmVyYXRlZCAoXCJcbiAgICAgICAgICAgICsgKHRoaXMubG9jYWwgPyBcImxvY2FsXCIgOiBcInJlbW90ZVwiKSArIFwiIHBlZXI6IFwiICsgdGhpcy5nZXRJZCgpICsgXCIpXCIpO1xuICAgIH1cblxuICAgIHB1Ymxpc2goKSB7XG5cbiAgICAgICAgLy8gRklYTUU6IFRocm93IGVycm9yIHdoZW4gc3RyZWFtIGlzIG5vdCBsb2NhbFxuICAgICAgICBpZiAodGhpcy5pc1JlYWR5KSB7XG4gICAgICAgICAgICB0aGlzLmluaXRXZWJSdGNQZWVyKHRoaXMucHVibGlzaFZpZGVvQ2FsbGJhY2spO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5lZS5vbmNlKCdzdHJlYW0tcmVhZHknLCBzdHJlYW1FdmVudCA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5wdWJsaXNoKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEZJWE1FOiBOb3cgd2UgaGF2ZSBjb3VwbGVkIGNvbm5lY3RpbmcgdG8gYSByb29tIGFuZCBhZGRpbmcgYVxuICAgICAgICAvLyBzdHJlYW0gdG8gdGhpcyByb29tLiBCdXQgaW4gdGhlIG5ldyBBUEksIHRoZXJlIGFyZSB0d28gc3RlcHMuXG4gICAgICAgIC8vIFRoaXMgaXMgdGhlIHNlY29uZCBzdGVwLiBGb3Igbm93LCBpdCBkbyBub3RoaW5nLlxuXG4gICAgfVxuXG4gICAgc3Vic2NyaWJlKCkge1xuXG4gICAgICAgIC8vIEZJWE1FOiBJbiB0aGUgY3VycmVudCBpbXBsZW1lbnRhdGlvbiBhbGwgcGFydGljaXBhbnRzIGFyZSBzdWJzY3JpYmVkXG4gICAgICAgIC8vIGF1dG9tYXRpY2FsbHkgdG8gYWxsIG90aGVyIHBhcnRpY2lwYW50cy4gV2UgdXNlIHRoaXMgbWV0aG9kIG9ubHkgdG9cbiAgICAgICAgLy8gbmVnb3RpYXRlIFNEUFxuXG4gICAgICAgIHRoaXMuaW5pdFdlYlJ0Y1BlZXIodGhpcy5zdGFydFZpZGVvQ2FsbGJhY2spO1xuICAgIH1cblxuICAgIHByb2Nlc3NTZHBBbnN3ZXIoc2RwQW5zd2VyKSB7XG5cbiAgICAgICAgbGV0IGFuc3dlciA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgICAgICAgdHlwZTogJ2Fuc3dlcicsXG4gICAgICAgICAgICBzZHA6IHNkcEFuc3dlcixcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnNvbGUubG9nKHRoaXMuZ2V0SWQoKSArIFwiOiBzZXQgcGVlciBjb25uZWN0aW9uIHdpdGggcmVjdmQgU0RQIGFuc3dlclwiLFxuICAgICAgICAgICAgc2RwQW5zd2VyKTtcbiAgICAgICAgbGV0IHBhcnRpY2lwYW50SWQgPSB0aGlzLmdldElkKCk7XG4gICAgICAgIGxldCBwYyA9IHRoaXMud3AucGVlckNvbm5lY3Rpb247XG4gICAgICAgIHBjLnNldFJlbW90ZURlc2NyaXB0aW9uKGFuc3dlciwgKCkgPT4ge1xuICAgICAgICAgICAgLy8gQXZvaWRzIHRvIHN1YnNjcmliZSB0byB5b3VyIG93biBzdHJlYW0gcmVtb3RlbHkgXG4gICAgICAgICAgICAvLyBleGNlcHQgd2hlbiBzaG93TXlSZW1vdGUgaXMgdHJ1ZVxuICAgICAgICAgICAgaWYgKCF0aGlzLmxvY2FsIHx8IHRoaXMuZGlzcGxheU15UmVtb3RlKCkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLndyU3RyZWFtID0gcGMuZ2V0UmVtb3RlU3RyZWFtcygpWzBdO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiUGVlciByZW1vdGUgc3RyZWFtXCIsIHRoaXMud3JTdHJlYW0pO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMud3JTdHJlYW0gIT0gdW5kZWZpbmVkKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lbWl0U3JjRXZlbnQodGhpcy53clN0cmVhbSk7XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zcGVlY2hFdmVudCA9IGt1cmVudG9VdGlscy5XZWJSdGNQZWVyLmhhcmsodGhpcy53clN0cmVhbSwgeyB0aHJlc2hvbGQ6IHRoaXMucm9vbS50aHJlc2hvbGRTcGVha2VyIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc3BlZWNoRXZlbnQub24oJ3NwZWFraW5nJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yb29tLmFkZFBhcnRpY2lwYW50U3BlYWtpbmcocGFydGljaXBhbnRJZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJvb20uZW1pdEV2ZW50KCdzdHJlYW0tc3BlYWtpbmcnLCBbe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50SWQ6IHBhcnRpY2lwYW50SWRcbiAgICAgICAgICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zcGVlY2hFdmVudC5vbignc3RvcHBlZF9zcGVha2luZycsICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucm9vbS5yZW1vdmVQYXJ0aWNpcGFudFNwZWFraW5nKHBhcnRpY2lwYW50SWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yb29tLmVtaXRFdmVudCgnc3RyZWFtLXN0b3BwZWQtc3BlYWtpbmcnLCBbe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRpY2lwYW50SWQ6IHBhcnRpY2lwYW50SWRcbiAgICAgICAgICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGZvciAobGV0IHZpZGVvRWxlbWVudCBvZiB0aGlzLnZpZGVvRWxlbWVudHMpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHRodW1ibmFpbElkID0gdmlkZW9FbGVtZW50LnRodW1iO1xuICAgICAgICAgICAgICAgICAgICBsZXQgdmlkZW8gPSB2aWRlb0VsZW1lbnQudmlkZW87XG4gICAgICAgICAgICAgICAgICAgIHZpZGVvLnNyYyA9IFVSTC5jcmVhdGVPYmplY3RVUkwodGhpcy53clN0cmVhbSk7XG4gICAgICAgICAgICAgICAgICAgIHZpZGVvLm9ucGxheSA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKHRoaXMuZ2V0SWQoKSArICc6ICcgKyAnVmlkZW8gcGxheWluZycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy9zaG93KHRodW1ibmFpbElkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vdGhpcy5oaWRlU3Bpbm5lcih0aGlzLmdldElkKCkpO1xuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLnJvb20uZW1pdEV2ZW50KCdzdHJlYW0tc3Vic2NyaWJlZCcsIFt7XG4gICAgICAgICAgICAgICAgICAgIHN0cmVhbTogdGhpc1xuICAgICAgICAgICAgICAgIH1dKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSwgZXJyb3IgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcih0aGlzLmdldElkKCkgKyBcIjogRXJyb3Igc2V0dGluZyBTRFAgdG8gdGhlIHBlZXIgY29ubmVjdGlvbjogXCJcbiAgICAgICAgICAgICAgICArIEpTT04uc3RyaW5naWZ5KGVycm9yKSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHVucHVibGlzaCgpIHtcbiAgICAgICAgaWYgKHRoaXMud3ApIHtcbiAgICAgICAgICAgIHRoaXMud3AuZGlzcG9zZSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKHRoaXMud3JTdHJlYW0pIHtcbiAgICAgICAgICAgICAgICB0aGlzLndyU3RyZWFtLmdldEF1ZGlvVHJhY2tzKCkuZm9yRWFjaChmdW5jdGlvbiAodHJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgdHJhY2suc3RvcCAmJiB0cmFjay5zdG9wKClcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIHRoaXMud3JTdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uICh0cmFjaykge1xuICAgICAgICAgICAgICAgICAgICB0cmFjay5zdG9wICYmIHRyYWNrLnN0b3AoKVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5zcGVlY2hFdmVudCkge1xuICAgICAgICAgICAgdGhpcy5zcGVlY2hFdmVudC5zdG9wKCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmxvZyh0aGlzLmdldElkKCkgKyBcIjogU3RyZWFtICdcIiArIHRoaXMuaWQgKyBcIicgdW5wdWJsaXNoZWRcIik7XG4gICAgfVxuXG4gICAgZGlzcG9zZSgpIHtcblxuICAgICAgICBmdW5jdGlvbiBkaXNwb3NlRWxlbWVudChlbGVtZW50KSB7XG4gICAgICAgICAgICBpZiAoZWxlbWVudCAmJiBlbGVtZW50LnBhcmVudE5vZGUpIHtcbiAgICAgICAgICAgICAgICBlbGVtZW50LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoZWxlbWVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmVsZW1lbnRzLmZvckVhY2goZSA9PiBkaXNwb3NlRWxlbWVudChlKSk7XG5cbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRzLmZvckVhY2godmUgPT4gZGlzcG9zZUVsZW1lbnQodmUpKTtcblxuICAgICAgICBkaXNwb3NlRWxlbWVudChcInByb2dyZXNzLVwiICsgdGhpcy5nZXRJZCgpKTtcblxuICAgICAgICBpZiAodGhpcy53cCkge1xuICAgICAgICAgICAgdGhpcy53cC5kaXNwb3NlKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAodGhpcy53clN0cmVhbSkge1xuICAgICAgICAgICAgICAgIHRoaXMud3JTdHJlYW0uZ2V0QXVkaW9UcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uICh0cmFjaykge1xuICAgICAgICAgICAgICAgICAgICB0cmFjay5zdG9wICYmIHRyYWNrLnN0b3AoKVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgdGhpcy53clN0cmVhbS5nZXRWaWRlb1RyYWNrcygpLmZvckVhY2goZnVuY3Rpb24gKHRyYWNrKSB7XG4gICAgICAgICAgICAgICAgICAgIHRyYWNrLnN0b3AgJiYgdHJhY2suc3RvcCgpXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLnNwZWVjaEV2ZW50KSB7XG4gICAgICAgICAgICB0aGlzLnNwZWVjaEV2ZW50LnN0b3AoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUubG9nKHRoaXMuZ2V0SWQoKSArIFwiOiBTdHJlYW0gJ1wiICsgdGhpcy5pZCArIFwiJyBkaXNwb3NlZFwiKTtcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgSm95ZW50LCBJbmMuIGFuZCBvdGhlciBOb2RlIGNvbnRyaWJ1dG9ycy5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYVxuLy8gY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZVxuLy8gXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nXG4vLyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsXG4vLyBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0XG4vLyBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGVcbi8vIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkXG4vLyBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTXG4vLyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GXG4vLyBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOXG4vLyBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSxcbi8vIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUlxuLy8gT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRVxuLy8gVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS5cblxuZnVuY3Rpb24gRXZlbnRFbWl0dGVyKCkge1xuICB0aGlzLl9ldmVudHMgPSB0aGlzLl9ldmVudHMgfHwge307XG4gIHRoaXMuX21heExpc3RlbmVycyA9IHRoaXMuX21heExpc3RlbmVycyB8fCB1bmRlZmluZWQ7XG59XG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50RW1pdHRlcjtcblxuLy8gQmFja3dhcmRzLWNvbXBhdCB3aXRoIG5vZGUgMC4xMC54XG5FdmVudEVtaXR0ZXIuRXZlbnRFbWl0dGVyID0gRXZlbnRFbWl0dGVyO1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLl9ldmVudHMgPSB1bmRlZmluZWQ7XG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLl9tYXhMaXN0ZW5lcnMgPSB1bmRlZmluZWQ7XG5cbi8vIEJ5IGRlZmF1bHQgRXZlbnRFbWl0dGVycyB3aWxsIHByaW50IGEgd2FybmluZyBpZiBtb3JlIHRoYW4gMTAgbGlzdGVuZXJzIGFyZVxuLy8gYWRkZWQgdG8gaXQuIFRoaXMgaXMgYSB1c2VmdWwgZGVmYXVsdCB3aGljaCBoZWxwcyBmaW5kaW5nIG1lbW9yeSBsZWFrcy5cbkV2ZW50RW1pdHRlci5kZWZhdWx0TWF4TGlzdGVuZXJzID0gMTA7XG5cbi8vIE9idmlvdXNseSBub3QgYWxsIEVtaXR0ZXJzIHNob3VsZCBiZSBsaW1pdGVkIHRvIDEwLiBUaGlzIGZ1bmN0aW9uIGFsbG93c1xuLy8gdGhhdCB0byBiZSBpbmNyZWFzZWQuIFNldCB0byB6ZXJvIGZvciB1bmxpbWl0ZWQuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnNldE1heExpc3RlbmVycyA9IGZ1bmN0aW9uKG4pIHtcbiAgaWYgKCFpc051bWJlcihuKSB8fCBuIDwgMCB8fCBpc05hTihuKSlcbiAgICB0aHJvdyBUeXBlRXJyb3IoJ24gbXVzdCBiZSBhIHBvc2l0aXZlIG51bWJlcicpO1xuICB0aGlzLl9tYXhMaXN0ZW5lcnMgPSBuO1xuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuZW1pdCA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgdmFyIGVyLCBoYW5kbGVyLCBsZW4sIGFyZ3MsIGksIGxpc3RlbmVycztcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcblxuICAvLyBJZiB0aGVyZSBpcyBubyAnZXJyb3InIGV2ZW50IGxpc3RlbmVyIHRoZW4gdGhyb3cuXG4gIGlmICh0eXBlID09PSAnZXJyb3InKSB7XG4gICAgaWYgKCF0aGlzLl9ldmVudHMuZXJyb3IgfHxcbiAgICAgICAgKGlzT2JqZWN0KHRoaXMuX2V2ZW50cy5lcnJvcikgJiYgIXRoaXMuX2V2ZW50cy5lcnJvci5sZW5ndGgpKSB7XG4gICAgICBlciA9IGFyZ3VtZW50c1sxXTtcbiAgICAgIGlmIChlciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAgIHRocm93IGVyOyAvLyBVbmhhbmRsZWQgJ2Vycm9yJyBldmVudFxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQXQgbGVhc3QgZ2l2ZSBzb21lIGtpbmQgb2YgY29udGV4dCB0byB0aGUgdXNlclxuICAgICAgICB2YXIgZXJyID0gbmV3IEVycm9yKCdVbmNhdWdodCwgdW5zcGVjaWZpZWQgXCJlcnJvclwiIGV2ZW50LiAoJyArIGVyICsgJyknKTtcbiAgICAgICAgZXJyLmNvbnRleHQgPSBlcjtcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGhhbmRsZXIgPSB0aGlzLl9ldmVudHNbdHlwZV07XG5cbiAgaWYgKGlzVW5kZWZpbmVkKGhhbmRsZXIpKVxuICAgIHJldHVybiBmYWxzZTtcblxuICBpZiAoaXNGdW5jdGlvbihoYW5kbGVyKSkge1xuICAgIHN3aXRjaCAoYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgLy8gZmFzdCBjYXNlc1xuICAgICAgY2FzZSAxOlxuICAgICAgICBoYW5kbGVyLmNhbGwodGhpcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAyOlxuICAgICAgICBoYW5kbGVyLmNhbGwodGhpcywgYXJndW1lbnRzWzFdKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDM6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzLCBhcmd1bWVudHNbMV0sIGFyZ3VtZW50c1syXSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgLy8gc2xvd2VyXG4gICAgICBkZWZhdWx0OlxuICAgICAgICBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgaGFuZGxlci5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICB9XG4gIH0gZWxzZSBpZiAoaXNPYmplY3QoaGFuZGxlcikpIHtcbiAgICBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICBsaXN0ZW5lcnMgPSBoYW5kbGVyLnNsaWNlKCk7XG4gICAgbGVuID0gbGlzdGVuZXJzLmxlbmd0aDtcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspXG4gICAgICBsaXN0ZW5lcnNbaV0uYXBwbHkodGhpcywgYXJncyk7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXIgPSBmdW5jdGlvbih0eXBlLCBsaXN0ZW5lcikge1xuICB2YXIgbTtcblxuICBpZiAoIWlzRnVuY3Rpb24obGlzdGVuZXIpKVxuICAgIHRocm93IFR5cGVFcnJvcignbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgdGhpcy5fZXZlbnRzID0ge307XG5cbiAgLy8gVG8gYXZvaWQgcmVjdXJzaW9uIGluIHRoZSBjYXNlIHRoYXQgdHlwZSA9PT0gXCJuZXdMaXN0ZW5lclwiISBCZWZvcmVcbiAgLy8gYWRkaW5nIGl0IHRvIHRoZSBsaXN0ZW5lcnMsIGZpcnN0IGVtaXQgXCJuZXdMaXN0ZW5lclwiLlxuICBpZiAodGhpcy5fZXZlbnRzLm5ld0xpc3RlbmVyKVxuICAgIHRoaXMuZW1pdCgnbmV3TGlzdGVuZXInLCB0eXBlLFxuICAgICAgICAgICAgICBpc0Z1bmN0aW9uKGxpc3RlbmVyLmxpc3RlbmVyKSA/XG4gICAgICAgICAgICAgIGxpc3RlbmVyLmxpc3RlbmVyIDogbGlzdGVuZXIpO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIC8vIE9wdGltaXplIHRoZSBjYXNlIG9mIG9uZSBsaXN0ZW5lci4gRG9uJ3QgbmVlZCB0aGUgZXh0cmEgYXJyYXkgb2JqZWN0LlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IGxpc3RlbmVyO1xuICBlbHNlIGlmIChpc09iamVjdCh0aGlzLl9ldmVudHNbdHlwZV0pKVxuICAgIC8vIElmIHdlJ3ZlIGFscmVhZHkgZ290IGFuIGFycmF5LCBqdXN0IGFwcGVuZC5cbiAgICB0aGlzLl9ldmVudHNbdHlwZV0ucHVzaChsaXN0ZW5lcik7XG4gIGVsc2VcbiAgICAvLyBBZGRpbmcgdGhlIHNlY29uZCBlbGVtZW50LCBuZWVkIHRvIGNoYW5nZSB0byBhcnJheS5cbiAgICB0aGlzLl9ldmVudHNbdHlwZV0gPSBbdGhpcy5fZXZlbnRzW3R5cGVdLCBsaXN0ZW5lcl07XG5cbiAgLy8gQ2hlY2sgZm9yIGxpc3RlbmVyIGxlYWtcbiAgaWYgKGlzT2JqZWN0KHRoaXMuX2V2ZW50c1t0eXBlXSkgJiYgIXRoaXMuX2V2ZW50c1t0eXBlXS53YXJuZWQpIHtcbiAgICBpZiAoIWlzVW5kZWZpbmVkKHRoaXMuX21heExpc3RlbmVycykpIHtcbiAgICAgIG0gPSB0aGlzLl9tYXhMaXN0ZW5lcnM7XG4gICAgfSBlbHNlIHtcbiAgICAgIG0gPSBFdmVudEVtaXR0ZXIuZGVmYXVsdE1heExpc3RlbmVycztcbiAgICB9XG5cbiAgICBpZiAobSAmJiBtID4gMCAmJiB0aGlzLl9ldmVudHNbdHlwZV0ubGVuZ3RoID4gbSkge1xuICAgICAgdGhpcy5fZXZlbnRzW3R5cGVdLndhcm5lZCA9IHRydWU7XG4gICAgICBjb25zb2xlLmVycm9yKCcobm9kZSkgd2FybmluZzogcG9zc2libGUgRXZlbnRFbWl0dGVyIG1lbW9yeSAnICtcbiAgICAgICAgICAgICAgICAgICAgJ2xlYWsgZGV0ZWN0ZWQuICVkIGxpc3RlbmVycyBhZGRlZC4gJyArXG4gICAgICAgICAgICAgICAgICAgICdVc2UgZW1pdHRlci5zZXRNYXhMaXN0ZW5lcnMoKSB0byBpbmNyZWFzZSBsaW1pdC4nLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLl9ldmVudHNbdHlwZV0ubGVuZ3RoKTtcbiAgICAgIGlmICh0eXBlb2YgY29uc29sZS50cmFjZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAvLyBub3Qgc3VwcG9ydGVkIGluIElFIDEwXG4gICAgICAgIGNvbnNvbGUudHJhY2UoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub24gPSBFdmVudEVtaXR0ZXIucHJvdG90eXBlLmFkZExpc3RlbmVyO1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9uY2UgPSBmdW5jdGlvbih0eXBlLCBsaXN0ZW5lcikge1xuICBpZiAoIWlzRnVuY3Rpb24obGlzdGVuZXIpKVxuICAgIHRocm93IFR5cGVFcnJvcignbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG5cbiAgdmFyIGZpcmVkID0gZmFsc2U7XG5cbiAgZnVuY3Rpb24gZygpIHtcbiAgICB0aGlzLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGcpO1xuXG4gICAgaWYgKCFmaXJlZCkge1xuICAgICAgZmlyZWQgPSB0cnVlO1xuICAgICAgbGlzdGVuZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9XG4gIH1cblxuICBnLmxpc3RlbmVyID0gbGlzdGVuZXI7XG4gIHRoaXMub24odHlwZSwgZyk7XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG4vLyBlbWl0cyBhICdyZW1vdmVMaXN0ZW5lcicgZXZlbnQgaWZmIHRoZSBsaXN0ZW5lciB3YXMgcmVtb3ZlZFxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHZhciBsaXN0LCBwb3NpdGlvbiwgbGVuZ3RoLCBpO1xuXG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIHJldHVybiB0aGlzO1xuXG4gIGxpc3QgPSB0aGlzLl9ldmVudHNbdHlwZV07XG4gIGxlbmd0aCA9IGxpc3QubGVuZ3RoO1xuICBwb3NpdGlvbiA9IC0xO1xuXG4gIGlmIChsaXN0ID09PSBsaXN0ZW5lciB8fFxuICAgICAgKGlzRnVuY3Rpb24obGlzdC5saXN0ZW5lcikgJiYgbGlzdC5saXN0ZW5lciA9PT0gbGlzdGVuZXIpKSB7XG4gICAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgICBpZiAodGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKVxuICAgICAgdGhpcy5lbWl0KCdyZW1vdmVMaXN0ZW5lcicsIHR5cGUsIGxpc3RlbmVyKTtcblxuICB9IGVsc2UgaWYgKGlzT2JqZWN0KGxpc3QpKSB7XG4gICAgZm9yIChpID0gbGVuZ3RoOyBpLS0gPiAwOykge1xuICAgICAgaWYgKGxpc3RbaV0gPT09IGxpc3RlbmVyIHx8XG4gICAgICAgICAgKGxpc3RbaV0ubGlzdGVuZXIgJiYgbGlzdFtpXS5saXN0ZW5lciA9PT0gbGlzdGVuZXIpKSB7XG4gICAgICAgIHBvc2l0aW9uID0gaTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHBvc2l0aW9uIDwgMClcbiAgICAgIHJldHVybiB0aGlzO1xuXG4gICAgaWYgKGxpc3QubGVuZ3RoID09PSAxKSB7XG4gICAgICBsaXN0Lmxlbmd0aCA9IDA7XG4gICAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIH0gZWxzZSB7XG4gICAgICBsaXN0LnNwbGljZShwb3NpdGlvbiwgMSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2V2ZW50cy5yZW1vdmVMaXN0ZW5lcilcbiAgICAgIHRoaXMuZW1pdCgncmVtb3ZlTGlzdGVuZXInLCB0eXBlLCBsaXN0ZW5lcik7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlQWxsTGlzdGVuZXJzID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIga2V5LCBsaXN0ZW5lcnM7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgcmV0dXJuIHRoaXM7XG5cbiAgLy8gbm90IGxpc3RlbmluZyBmb3IgcmVtb3ZlTGlzdGVuZXIsIG5vIG5lZWQgdG8gZW1pdFxuICBpZiAoIXRoaXMuX2V2ZW50cy5yZW1vdmVMaXN0ZW5lcikge1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKVxuICAgICAgdGhpcy5fZXZlbnRzID0ge307XG4gICAgZWxzZSBpZiAodGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgICAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIGVtaXQgcmVtb3ZlTGlzdGVuZXIgZm9yIGFsbCBsaXN0ZW5lcnMgb24gYWxsIGV2ZW50c1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIGZvciAoa2V5IGluIHRoaXMuX2V2ZW50cykge1xuICAgICAgaWYgKGtleSA9PT0gJ3JlbW92ZUxpc3RlbmVyJykgY29udGludWU7XG4gICAgICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycyhrZXkpO1xuICAgIH1cbiAgICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygncmVtb3ZlTGlzdGVuZXInKTtcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICBpZiAoaXNGdW5jdGlvbihsaXN0ZW5lcnMpKSB7XG4gICAgdGhpcy5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnMpO1xuICB9IGVsc2UgaWYgKGxpc3RlbmVycykge1xuICAgIC8vIExJRk8gb3JkZXJcbiAgICB3aGlsZSAobGlzdGVuZXJzLmxlbmd0aClcbiAgICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIodHlwZSwgbGlzdGVuZXJzW2xpc3RlbmVycy5sZW5ndGggLSAxXSk7XG4gIH1cbiAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJzID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIgcmV0O1xuICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIHJldCA9IFtdO1xuICBlbHNlIGlmIChpc0Z1bmN0aW9uKHRoaXMuX2V2ZW50c1t0eXBlXSkpXG4gICAgcmV0ID0gW3RoaXMuX2V2ZW50c1t0eXBlXV07XG4gIGVsc2VcbiAgICByZXQgPSB0aGlzLl9ldmVudHNbdHlwZV0uc2xpY2UoKTtcbiAgcmV0dXJuIHJldDtcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJDb3VudCA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgaWYgKHRoaXMuX2V2ZW50cykge1xuICAgIHZhciBldmxpc3RlbmVyID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gICAgaWYgKGlzRnVuY3Rpb24oZXZsaXN0ZW5lcikpXG4gICAgICByZXR1cm4gMTtcbiAgICBlbHNlIGlmIChldmxpc3RlbmVyKVxuICAgICAgcmV0dXJuIGV2bGlzdGVuZXIubGVuZ3RoO1xuICB9XG4gIHJldHVybiAwO1xufTtcblxuRXZlbnRFbWl0dGVyLmxpc3RlbmVyQ291bnQgPSBmdW5jdGlvbihlbWl0dGVyLCB0eXBlKSB7XG4gIHJldHVybiBlbWl0dGVyLmxpc3RlbmVyQ291bnQodHlwZSk7XG59O1xuXG5mdW5jdGlvbiBpc0Z1bmN0aW9uKGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuZnVuY3Rpb24gaXNOdW1iZXIoYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnbnVtYmVyJztcbn1cblxuZnVuY3Rpb24gaXNPYmplY3QoYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnb2JqZWN0JyAmJiBhcmcgIT09IG51bGw7XG59XG5cbmZ1bmN0aW9uIGlzVW5kZWZpbmVkKGFyZykge1xuICByZXR1cm4gYXJnID09PSB2b2lkIDA7XG59XG4iLCIvLyBzaGltIGZvciB1c2luZyBwcm9jZXNzIGluIGJyb3dzZXJcbnZhciBwcm9jZXNzID0gbW9kdWxlLmV4cG9ydHMgPSB7fTtcblxuLy8gY2FjaGVkIGZyb20gd2hhdGV2ZXIgZ2xvYmFsIGlzIHByZXNlbnQgc28gdGhhdCB0ZXN0IHJ1bm5lcnMgdGhhdCBzdHViIGl0XG4vLyBkb24ndCBicmVhayB0aGluZ3MuICBCdXQgd2UgbmVlZCB0byB3cmFwIGl0IGluIGEgdHJ5IGNhdGNoIGluIGNhc2UgaXQgaXNcbi8vIHdyYXBwZWQgaW4gc3RyaWN0IG1vZGUgY29kZSB3aGljaCBkb2Vzbid0IGRlZmluZSBhbnkgZ2xvYmFscy4gIEl0J3MgaW5zaWRlIGFcbi8vIGZ1bmN0aW9uIGJlY2F1c2UgdHJ5L2NhdGNoZXMgZGVvcHRpbWl6ZSBpbiBjZXJ0YWluIGVuZ2luZXMuXG5cbnZhciBjYWNoZWRTZXRUaW1lb3V0O1xudmFyIGNhY2hlZENsZWFyVGltZW91dDtcblxuZnVuY3Rpb24gZGVmYXVsdFNldFRpbW91dCgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3NldFRpbWVvdXQgaGFzIG5vdCBiZWVuIGRlZmluZWQnKTtcbn1cbmZ1bmN0aW9uIGRlZmF1bHRDbGVhclRpbWVvdXQgKCkge1xuICAgIHRocm93IG5ldyBFcnJvcignY2xlYXJUaW1lb3V0IGhhcyBub3QgYmVlbiBkZWZpbmVkJyk7XG59XG4oZnVuY3Rpb24gKCkge1xuICAgIHRyeSB7XG4gICAgICAgIGlmICh0eXBlb2Ygc2V0VGltZW91dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IHNldFRpbWVvdXQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gZGVmYXVsdFNldFRpbW91dDtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IGRlZmF1bHRTZXRUaW1vdXQ7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIGlmICh0eXBlb2YgY2xlYXJUaW1lb3V0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBjbGVhclRpbWVvdXQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBkZWZhdWx0Q2xlYXJUaW1lb3V0O1xuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBkZWZhdWx0Q2xlYXJUaW1lb3V0O1xuICAgIH1cbn0gKCkpXG5mdW5jdGlvbiBydW5UaW1lb3V0KGZ1bikge1xuICAgIGlmIChjYWNoZWRTZXRUaW1lb3V0ID09PSBzZXRUaW1lb3V0KSB7XG4gICAgICAgIC8vbm9ybWFsIGVudmlyb21lbnRzIGluIHNhbmUgc2l0dWF0aW9uc1xuICAgICAgICByZXR1cm4gc2V0VGltZW91dChmdW4sIDApO1xuICAgIH1cbiAgICAvLyBpZiBzZXRUaW1lb3V0IHdhc24ndCBhdmFpbGFibGUgYnV0IHdhcyBsYXR0ZXIgZGVmaW5lZFxuICAgIGlmICgoY2FjaGVkU2V0VGltZW91dCA9PT0gZGVmYXVsdFNldFRpbW91dCB8fCAhY2FjaGVkU2V0VGltZW91dCkgJiYgc2V0VGltZW91dCkge1xuICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gc2V0VGltZW91dDtcbiAgICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuLCAwKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgLy8gd2hlbiB3aGVuIHNvbWVib2R5IGhhcyBzY3Jld2VkIHdpdGggc2V0VGltZW91dCBidXQgbm8gSS5FLiBtYWRkbmVzc1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0VGltZW91dChmdW4sIDApO1xuICAgIH0gY2F0Y2goZSl7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBXaGVuIHdlIGFyZSBpbiBJLkUuIGJ1dCB0aGUgc2NyaXB0IGhhcyBiZWVuIGV2YWxlZCBzbyBJLkUuIGRvZXNuJ3QgdHJ1c3QgdGhlIGdsb2JhbCBvYmplY3Qgd2hlbiBjYWxsZWQgbm9ybWFsbHlcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0LmNhbGwobnVsbCwgZnVuLCAwKTtcbiAgICAgICAgfSBjYXRjaChlKXtcbiAgICAgICAgICAgIC8vIHNhbWUgYXMgYWJvdmUgYnV0IHdoZW4gaXQncyBhIHZlcnNpb24gb2YgSS5FLiB0aGF0IG11c3QgaGF2ZSB0aGUgZ2xvYmFsIG9iamVjdCBmb3IgJ3RoaXMnLCBob3BmdWxseSBvdXIgY29udGV4dCBjb3JyZWN0IG90aGVyd2lzZSBpdCB3aWxsIHRocm93IGEgZ2xvYmFsIGVycm9yXG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkU2V0VGltZW91dC5jYWxsKHRoaXMsIGZ1biwgMCk7XG4gICAgICAgIH1cbiAgICB9XG5cblxufVxuZnVuY3Rpb24gcnVuQ2xlYXJUaW1lb3V0KG1hcmtlcikge1xuICAgIGlmIChjYWNoZWRDbGVhclRpbWVvdXQgPT09IGNsZWFyVGltZW91dCkge1xuICAgICAgICAvL25vcm1hbCBlbnZpcm9tZW50cyBpbiBzYW5lIHNpdHVhdGlvbnNcbiAgICAgICAgcmV0dXJuIGNsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH1cbiAgICAvLyBpZiBjbGVhclRpbWVvdXQgd2Fzbid0IGF2YWlsYWJsZSBidXQgd2FzIGxhdHRlciBkZWZpbmVkXG4gICAgaWYgKChjYWNoZWRDbGVhclRpbWVvdXQgPT09IGRlZmF1bHRDbGVhclRpbWVvdXQgfHwgIWNhY2hlZENsZWFyVGltZW91dCkgJiYgY2xlYXJUaW1lb3V0KSB7XG4gICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGNsZWFyVGltZW91dDtcbiAgICAgICAgcmV0dXJuIGNsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICAvLyB3aGVuIHdoZW4gc29tZWJvZHkgaGFzIHNjcmV3ZWQgd2l0aCBzZXRUaW1lb3V0IGJ1dCBubyBJLkUuIG1hZGRuZXNzXG4gICAgICAgIHJldHVybiBjYWNoZWRDbGVhclRpbWVvdXQobWFya2VyKTtcbiAgICB9IGNhdGNoIChlKXtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFdoZW4gd2UgYXJlIGluIEkuRS4gYnV0IHRoZSBzY3JpcHQgaGFzIGJlZW4gZXZhbGVkIHNvIEkuRS4gZG9lc24ndCAgdHJ1c3QgdGhlIGdsb2JhbCBvYmplY3Qgd2hlbiBjYWxsZWQgbm9ybWFsbHlcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRDbGVhclRpbWVvdXQuY2FsbChudWxsLCBtYXJrZXIpO1xuICAgICAgICB9IGNhdGNoIChlKXtcbiAgICAgICAgICAgIC8vIHNhbWUgYXMgYWJvdmUgYnV0IHdoZW4gaXQncyBhIHZlcnNpb24gb2YgSS5FLiB0aGF0IG11c3QgaGF2ZSB0aGUgZ2xvYmFsIG9iamVjdCBmb3IgJ3RoaXMnLCBob3BmdWxseSBvdXIgY29udGV4dCBjb3JyZWN0IG90aGVyd2lzZSBpdCB3aWxsIHRocm93IGEgZ2xvYmFsIGVycm9yLlxuICAgICAgICAgICAgLy8gU29tZSB2ZXJzaW9ucyBvZiBJLkUuIGhhdmUgZGlmZmVyZW50IHJ1bGVzIGZvciBjbGVhclRpbWVvdXQgdnMgc2V0VGltZW91dFxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dC5jYWxsKHRoaXMsIG1hcmtlcik7XG4gICAgICAgIH1cbiAgICB9XG5cblxuXG59XG52YXIgcXVldWUgPSBbXTtcbnZhciBkcmFpbmluZyA9IGZhbHNlO1xudmFyIGN1cnJlbnRRdWV1ZTtcbnZhciBxdWV1ZUluZGV4ID0gLTE7XG5cbmZ1bmN0aW9uIGNsZWFuVXBOZXh0VGljaygpIHtcbiAgICBpZiAoIWRyYWluaW5nIHx8ICFjdXJyZW50UXVldWUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIGlmIChjdXJyZW50UXVldWUubGVuZ3RoKSB7XG4gICAgICAgIHF1ZXVlID0gY3VycmVudFF1ZXVlLmNvbmNhdChxdWV1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgIH1cbiAgICBpZiAocXVldWUubGVuZ3RoKSB7XG4gICAgICAgIGRyYWluUXVldWUoKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGRyYWluUXVldWUoKSB7XG4gICAgaWYgKGRyYWluaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIHRpbWVvdXQgPSBydW5UaW1lb3V0KGNsZWFuVXBOZXh0VGljayk7XG4gICAgZHJhaW5pbmcgPSB0cnVlO1xuXG4gICAgdmFyIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB3aGlsZShsZW4pIHtcbiAgICAgICAgY3VycmVudFF1ZXVlID0gcXVldWU7XG4gICAgICAgIHF1ZXVlID0gW107XG4gICAgICAgIHdoaWxlICgrK3F1ZXVlSW5kZXggPCBsZW4pIHtcbiAgICAgICAgICAgIGlmIChjdXJyZW50UXVldWUpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50UXVldWVbcXVldWVJbmRleF0ucnVuKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgICAgICBsZW4gPSBxdWV1ZS5sZW5ndGg7XG4gICAgfVxuICAgIGN1cnJlbnRRdWV1ZSA9IG51bGw7XG4gICAgZHJhaW5pbmcgPSBmYWxzZTtcbiAgICBydW5DbGVhclRpbWVvdXQodGltZW91dCk7XG59XG5cbnByb2Nlc3MubmV4dFRpY2sgPSBmdW5jdGlvbiAoZnVuKSB7XG4gICAgdmFyIGFyZ3MgPSBuZXcgQXJyYXkoYXJndW1lbnRzLmxlbmd0aCAtIDEpO1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgICBmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgYXJnc1tpIC0gMV0gPSBhcmd1bWVudHNbaV07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcXVldWUucHVzaChuZXcgSXRlbShmdW4sIGFyZ3MpKTtcbiAgICBpZiAocXVldWUubGVuZ3RoID09PSAxICYmICFkcmFpbmluZykge1xuICAgICAgICBydW5UaW1lb3V0KGRyYWluUXVldWUpO1xuICAgIH1cbn07XG5cbi8vIHY4IGxpa2VzIHByZWRpY3RpYmxlIG9iamVjdHNcbmZ1bmN0aW9uIEl0ZW0oZnVuLCBhcnJheSkge1xuICAgIHRoaXMuZnVuID0gZnVuO1xuICAgIHRoaXMuYXJyYXkgPSBhcnJheTtcbn1cbkl0ZW0ucHJvdG90eXBlLnJ1biA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmZ1bi5hcHBseShudWxsLCB0aGlzLmFycmF5KTtcbn07XG5wcm9jZXNzLnRpdGxlID0gJ2Jyb3dzZXInO1xucHJvY2Vzcy5icm93c2VyID0gdHJ1ZTtcbnByb2Nlc3MuZW52ID0ge307XG5wcm9jZXNzLmFyZ3YgPSBbXTtcbnByb2Nlc3MudmVyc2lvbiA9ICcnOyAvLyBlbXB0eSBzdHJpbmcgdG8gYXZvaWQgcmVnZXhwIGlzc3Vlc1xucHJvY2Vzcy52ZXJzaW9ucyA9IHt9O1xuXG5mdW5jdGlvbiBub29wKCkge31cblxucHJvY2Vzcy5vbiA9IG5vb3A7XG5wcm9jZXNzLmFkZExpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3Mub25jZSA9IG5vb3A7XG5wcm9jZXNzLm9mZiA9IG5vb3A7XG5wcm9jZXNzLnJlbW92ZUxpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlQWxsTGlzdGVuZXJzID0gbm9vcDtcbnByb2Nlc3MuZW1pdCA9IG5vb3A7XG5wcm9jZXNzLnByZXBlbmRMaXN0ZW5lciA9IG5vb3A7XG5wcm9jZXNzLnByZXBlbmRPbmNlTGlzdGVuZXIgPSBub29wO1xuXG5wcm9jZXNzLmxpc3RlbmVycyA9IGZ1bmN0aW9uIChuYW1lKSB7IHJldHVybiBbXSB9XG5cbnByb2Nlc3MuYmluZGluZyA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmJpbmRpbmcgaXMgbm90IHN1cHBvcnRlZCcpO1xufTtcblxucHJvY2Vzcy5jd2QgPSBmdW5jdGlvbiAoKSB7IHJldHVybiAnLycgfTtcbnByb2Nlc3MuY2hkaXIgPSBmdW5jdGlvbiAoZGlyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmNoZGlyIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn07XG5wcm9jZXNzLnVtYXNrID0gZnVuY3Rpb24oKSB7IHJldHVybiAwOyB9O1xuIl19
|